JumpTable support! What this represents is working asm and jit support for
authorNate Begeman <natebegeman@mac.com>
Sat, 22 Apr 2006 18:53:45 +0000 (18:53 +0000)
committerNate Begeman <natebegeman@mac.com>
Sat, 22 Apr 2006 18:53:45 +0000 (18:53 +0000)
x86 and ppc for 100% dense switch statements when relocations are non-PIC.
This support will be extended and enhanced in the coming days to support
PIC, and less dense forms of jump tables.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@27947 91177308-0d34-0410-b5e6-96231b3b80d8

40 files changed:
include/llvm/CodeGen/AsmPrinter.h
include/llvm/CodeGen/MachineCodeEmitter.h
include/llvm/CodeGen/MachineFunction.h
include/llvm/CodeGen/MachineInstr.h
include/llvm/CodeGen/MachineJumpTableInfo.h [new file with mode: 0644]
include/llvm/CodeGen/ScheduleDAG.h
include/llvm/CodeGen/SelectionDAG.h
include/llvm/CodeGen/SelectionDAGISel.h
include/llvm/CodeGen/SelectionDAGNodes.h
lib/CodeGen/AsmPrinter.cpp
lib/CodeGen/ELFWriter.cpp
lib/CodeGen/MachineCodeEmitter.cpp
lib/CodeGen/MachineFunction.cpp
lib/CodeGen/MachineInstr.cpp
lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
lib/CodeGen/SelectionDAG/ScheduleDAG.cpp
lib/CodeGen/SelectionDAG/SelectionDAG.cpp
lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
lib/ExecutionEngine/ExecutionEngine.cpp
lib/ExecutionEngine/JIT/JITEmitter.cpp
lib/Target/Alpha/AlphaAsmPrinter.cpp
lib/Target/Alpha/AlphaISelLowering.cpp
lib/Target/IA64/IA64AsmPrinter.cpp
lib/Target/IA64/IA64ISelLowering.cpp
lib/Target/PowerPC/PPCAsmPrinter.cpp
lib/Target/PowerPC/PPCCodeEmitter.cpp
lib/Target/PowerPC/PPCISelDAGToDAG.cpp
lib/Target/PowerPC/PPCISelLowering.cpp
lib/Target/PowerPC/PPCInstrInfo.td
lib/Target/Sparc/SparcAsmPrinter.cpp
lib/Target/Sparc/SparcISelDAGToDAG.cpp
lib/Target/TargetSelectionDAG.td
lib/Target/X86/X86ATTAsmPrinter.cpp
lib/Target/X86/X86AsmPrinter.cpp
lib/Target/X86/X86AsmPrinter.h
lib/Target/X86/X86CodeEmitter.cpp
lib/Target/X86/X86ISelLowering.cpp
lib/Target/X86/X86InstrInfo.td
lib/Target/X86/X86IntelAsmPrinter.cpp
utils/TableGen/DAGISelEmitter.cpp

index bb948ebc9da19641c4c137c4ea37128050319b52..2a56543612e5db5cecc4d3824c70684875323b04 100644 (file)
@@ -140,6 +140,10 @@ namespace llvm {
     /// before emitting the constant pool for a function.
     const char *ConstantPoolSection;     // Defaults to "\t.section .rodata\n"
 
+    /// JumpTableSection - This is the section that we SwitchToSection right
+    /// before emitting the jump tables for a function.
+    const char *JumpTableSection;     // Defaults to "\t.section .rodata\n"
+    
     /// StaticCtorsSection - This is the directive that is emitted to switch to
     /// a section to emit the static constructor list.
     /// Defaults to "\t.section .ctors,\"aw\",@progbits".
@@ -231,6 +235,11 @@ namespace llvm {
     ///
     void EmitConstantPool(MachineConstantPool *MCP);
 
+    /// EmitJumpTableInfo - Print assembly representations of the jump tables 
+    /// used by the current function to the current output stream.  
+    ///
+    void EmitJumpTableInfo(MachineJumpTableInfo *MJTI);
+    
     /// EmitSpecialLLVMGlobal - Check to see if the specified global is a
     /// special global used by LLVM.  If so, emit it and return true, otherwise
     /// do nothing and return false.
@@ -257,6 +266,11 @@ namespace llvm {
     /// printInlineAsm - This method formats and prints the specified machine
     /// instruction that is an inline asm.
     void printInlineAsm(const MachineInstr *MI) const;
+    
+    /// printBasicBlockLabel - This method prints the label for the specified
+    /// MachineBasicBlock
+    virtual void printBasicBlockLabel(const MachineBasicBlock *MBB) const;
+    
   private:
     void EmitXXStructorList(Constant *List);
 
index f5ee2e62371cfa19f2bb2a8b08c13f9579bd30f1..f4b7c2290d89bfedbd3beda52f0fbf194c8ebd52 100644 (file)
 #define LLVM_CODEGEN_MACHINECODEEMITTER_H
 
 #include "llvm/Support/DataTypes.h"
+#include <map>
 
 namespace llvm {
 
 class MachineBasicBlock;
 class MachineConstantPool;
+class MachineJumpTableInfo;
 class MachineFunction;
 class MachineRelocation;
 class Value;
@@ -47,6 +49,17 @@ public:
   /// for the function.
   virtual void emitConstantPool(MachineConstantPool *MCP) {}
 
+  /// initJumpTableInfo - This callback is invoked by the JIT to allocate the
+  /// necessary memory to hold the jump tables.
+  virtual void initJumpTableInfo(MachineJumpTableInfo *MJTI) {}
+  
+  /// emitJumpTableInfo - This callback is invoked to output the jump tables
+  /// for the function.  In addition to a pointer to the MachineJumpTableInfo,
+  /// this function also takes a map of MBBs to addresses, so that the final
+  /// addresses of the MBBs can be written to the jump tables.
+  virtual void emitJumpTableInfo(MachineJumpTableInfo *MJTI,
+                                 std::map<MachineBasicBlock*,uint64_t> &MBBM) {}
+  
   /// startFunctionStub - This callback is invoked when the JIT needs the
   /// address of a function that has not been code generated yet.  The StubSize
   /// specifies the total size required by the stub.  Stubs are not allowed to
@@ -94,6 +107,11 @@ public:
   //
   virtual uint64_t getConstantPoolEntryAddress(unsigned Index) = 0;
 
+  // getJumpTablelEntryAddress - Return the address of the jump table with index
+  // 'Index' in the function that last called initJumpTableInfo.
+  //
+  virtual uint64_t getJumpTableEntryAddress(unsigned Index) = 0;
+  
   // allocateGlobal - Allocate some space for a global variable.
   virtual unsigned char* allocateGlobal(unsigned size, unsigned alignment) = 0;
 
index 83f696f5d7f2f50ae823568e347dcffb168e2ac6..0f511e3d917b39e18d3670be41ecf7c28228a05b 100644 (file)
@@ -29,6 +29,7 @@ class TargetMachine;
 class SSARegMap;
 class MachineFrameInfo;
 class MachineConstantPool;
+class MachineJumpTableInfo;
 
 // ilist_traits
 template <>
@@ -93,6 +94,9 @@ class MachineFunction : private Annotation {
 
   // Keep track of constants which are spilled to memory
   MachineConstantPool *ConstantPool;
+  
+  // Keep track of jump tables for switch instructions
+  MachineJumpTableInfo *JumpTableInfo;
 
   // Function-level unique numbering for MachineBasicBlocks.  When a
   // MachineBasicBlock is inserted into a MachineFunction is it automatically
@@ -138,6 +142,12 @@ public:
   ///
   MachineFrameInfo *getFrameInfo() const { return FrameInfo; }
 
+  /// getJumpTableInfo - Return the jump table info object for the current 
+  /// function.  This object contains information about jump tables for switch
+  /// instructions in the current function.
+  ///
+  MachineJumpTableInfo *getJumpTableInfo() const { return JumpTableInfo; }
+  
   /// getConstantPool - Return the constant pool object for the current
   /// function.
   ///
index e98caa56afa0331cea16829cc813c24da5878b03..d02493bfc785aff0a20ef785e6ed12f6a0e1313e 100644 (file)
@@ -105,6 +105,7 @@ public:
     MO_MachineBasicBlock,       // MachineBasicBlock reference
     MO_FrameIndex,              // Abstract Stack Frame Index
     MO_ConstantPoolIndex,       // Address of indexed Constant in Constant Pool
+    MO_JumpTableIndex,          // Address of indexed Jump Table for switch
     MO_ExternalSymbol,          // Name of external global symbol
     MO_GlobalAddress            // Address of a global value
   };
@@ -242,6 +243,7 @@ public:
   }
   bool isFrameIndex() const { return opType == MO_FrameIndex; }
   bool isConstantPoolIndex() const { return opType == MO_ConstantPoolIndex; }
+  bool isJumpTableIndex() const { return opType == MO_JumpTableIndex; }
   bool isGlobalAddress() const { return opType == MO_GlobalAddress; }
   bool isExternalSymbol() const { return opType == MO_ExternalSymbol; }
 
@@ -285,6 +287,10 @@ public:
     assert(isConstantPoolIndex() && "Wrong MachineOperand accessor");
     return (unsigned)contents.immedVal;
   }
+  unsigned getJumpTableIndex() const {
+    assert(isJumpTableIndex() && "Wrong MachineOperand accessor");
+    return (unsigned)contents.immedVal;
+  }
   GlobalValue *getGlobal() const {
     assert(isGlobalAddress() && "Wrong MachineOperand accessor");
     return (GlobalValue*)contents.value;
@@ -348,7 +354,8 @@ public:
   }
 
   void setOffset(int Offset) {
-    assert((isGlobalAddress() || isExternalSymbol() || isConstantPoolIndex()) &&
+    assert((isGlobalAddress() || isExternalSymbol() || isConstantPoolIndex() ||
+            isJumpTableIndex()) &&
         "Wrong MachineOperand accessor");
     extra.offset = Offset;
   }
@@ -611,6 +618,15 @@ public:
     operands.push_back(MachineOperand(I, MachineOperand::MO_ConstantPoolIndex));
   }
 
+  /// addJumpTableIndexOperand - Add a jump table object index to the
+  /// instruction.
+  ///
+  void addJumpTableIndexOperand(unsigned I) {
+    assert(!OperandsComplete() &&
+           "Trying to add an operand to a machine instr that is already done!");
+    operands.push_back(MachineOperand(I, MachineOperand::MO_JumpTableIndex));
+  }
+  
   void addGlobalAddressOperand(GlobalValue *GV, bool isPCRelative, int Offset) {
     assert(!OperandsComplete() &&
            "Trying to add an operand to a machine instr that is already done!");
diff --git a/include/llvm/CodeGen/MachineJumpTableInfo.h b/include/llvm/CodeGen/MachineJumpTableInfo.h
new file mode 100644 (file)
index 0000000..192fb65
--- /dev/null
@@ -0,0 +1,73 @@
+//===-- CodeGen/MachineJumpTableInfo.h - Abstract Jump Tables  --*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file was developed by Nate Begeman and is distributed under the
+// University of Illinois Open Source License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// The MachineJumpTableInfo class keeps track of jump tables referenced by
+// lowered switch instructions in the MachineFunction.
+//
+// Instructions reference the address of these jump tables through the use of 
+// MO_JumpTableIndex values.  When emitting assembly or machine code, these 
+// virtual address references are converted to refer to the address of the 
+// function jump tables.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CODEGEN_MACHINEJUMPTABLEINFO_H
+#define LLVM_CODEGEN_MACHINEJUMPTABLEINFO_H
+
+#include "llvm/Target/TargetData.h"
+#include <vector>
+#include <iosfwd>
+
+namespace llvm {
+
+class MachineBasicBlock;
+
+/// MachineJumpTableEntry - One jump table in the jump table info.
+///
+struct MachineJumpTableEntry {
+  /// MBBs - The vector of basic blocks from which to create the jump table.
+  std::vector<MachineBasicBlock*> MBBs;
+  
+  MachineJumpTableEntry(std::vector<MachineBasicBlock*> &M) : MBBs(M) {}
+};
+  
+class MachineJumpTableInfo {
+  const TargetData &TD;
+  std::vector<MachineJumpTableEntry> JumpTables;
+public:
+  MachineJumpTableInfo(const TargetData &td) : TD(td) {}
+    
+  /// getJumpTableIndex - Create a new jump table or return an existing one.
+  ///
+  unsigned getJumpTableIndex(std::vector<MachineBasicBlock*> &DestBBs);
+  
+  /// isEmpty - Return true if there are no jump tables.
+  ///
+  bool isEmpty() const { return JumpTables.empty(); }
+
+  const std::vector<MachineJumpTableEntry> &getJumpTables() const {
+    return JumpTables;
+  }
+  
+  unsigned getEntrySize() const { return TD.getPointerSize(); }
+  unsigned getAlignment() const { return TD.getPointerAlignment(); }
+  
+  /// print - Used by the MachineFunction printer to print information about
+  /// jump tables.  Implemented in MachineFunction.cpp
+  ///
+  void print(std::ostream &OS) const;
+
+  /// dump - Call print(std::cerr) to be called from the debugger.
+  ///
+  void dump() const;
+};
+
+} // End llvm namespace
+
+#endif
index b2a2a9c9b8c59390a3e6106bedd2fd70dcbed7bf..f72285e0f45b9f3ccf6d3e641c1511ca39de3a91 100644 (file)
@@ -100,6 +100,7 @@ namespace llvm {
       if (isa<BasicBlockSDNode>(Node))     return true;
       if (isa<FrameIndexSDNode>(Node))     return true;
       if (isa<ConstantPoolSDNode>(Node))   return true;
+      if (isa<JumpTableSDNode>(Node))      return true;
       if (isa<ExternalSymbolSDNode>(Node)) return true;
       return false;
     }
index 01f56a9e866529a994dbeeac2f96c0afc4592284..f05b5b96bd051dedbdffb174462db22c30b9e816 100644 (file)
@@ -120,6 +120,8 @@ public:
                                    int offset = 0);
   SDOperand getFrameIndex(int FI, MVT::ValueType VT);
   SDOperand getTargetFrameIndex(int FI, MVT::ValueType VT);
+  SDOperand getJumpTable(int JTI, MVT::ValueType VT);
+  SDOperand getTargetJumpTable(int JTI, MVT::ValueType VT);
   SDOperand getConstantPool(Constant *C, MVT::ValueType VT,
                            unsigned Alignment=0,  int offset = 0);
   SDOperand getTargetConstantPool(Constant *C, MVT::ValueType VT,
@@ -468,7 +470,8 @@ private:
   std::map<std::pair<uint64_t, MVT::ValueType>, SDNode*> TargetConstants;
   std::map<std::pair<uint64_t, MVT::ValueType>, SDNode*> ConstantFPs;
   std::map<std::pair<uint64_t, MVT::ValueType>, SDNode*> TargetConstantFPs;
-  std::map<int, SDNode*> FrameIndices, TargetFrameIndices;
+  std::map<int, SDNode*> FrameIndices, TargetFrameIndices, JumpTableIndices,
+    TargetJumpTableIndices;
   std::map<std::pair<Constant *,
                      std::pair<int, unsigned> >, SDNode*> ConstantPoolIndices;
   std::map<std::pair<Constant *,
index 2bf34071990747d79830e4dd9ea0d6018a7986cb..0e59d7b91363e63dc30e694756f194ba3378cd3a 100644 (file)
@@ -18,6 +18,7 @@
 #include "llvm/Pass.h"
 #include "llvm/Constant.h"
 #include "llvm/CodeGen/SelectionDAGNodes.h"
+#include <set>
 
 namespace llvm {
   class SelectionDAG;
@@ -40,7 +41,7 @@ public:
   SelectionDAG *CurDAG;
   MachineBasicBlock *BB;
 
-  SelectionDAGISel(TargetLowering &tli) : TLI(tli) {}
+  SelectionDAGISel(TargetLowering &tli) : TLI(tli), JT(0,0,0) {}
 
   virtual void getAnalysisUsage(AnalysisUsage &AU) const;
 
@@ -87,6 +88,20 @@ public:
     // ThisBB - the blcok into which to emit the code for the setcc and branches
     MachineBasicBlock *ThisBB;
   };
+  struct JumpTable {
+    JumpTable(unsigned R, unsigned J, MachineBasicBlock *me) : Reg(R), JTI(J),
+              MBB(me) {}
+    // Reg - the virtual register containing the index of the jump table entry
+    // to jump to.
+    unsigned Reg;
+    // JTI - the JumpTableIndex for this jump table in the function.
+    unsigned JTI;
+    // MBB - the MBB into which to emit the code for the indirect jump.
+    MachineBasicBlock *MBB;
+    // SuccMBBs - a vector of unique successor MBBs used for updating CFG info
+    // and PHI nodes.
+    std::set<MachineBasicBlock*> SuccMBBs;
+  };
   
 protected:
   /// Pick a safe ordering and emit instructions for each target node in the
@@ -114,6 +129,9 @@ private:
   /// SwitchCases - Vector of CaseBlock structures used to communicate
   /// SwitchInst code generation information.
   std::vector<CaseBlock> SwitchCases;
+
+  /// JT - Record which holds necessary information for emitting a jump table
+  JumpTable JT;
 };
 
 }
index 1b7e8e659a720c07941b907b89cf94760d281b74..7f317c5e98eef6ab44de8a024029450d71dd3640 100644 (file)
@@ -65,7 +65,7 @@ namespace ISD {
     // Various leaf nodes.
     STRING, BasicBlock, VALUETYPE, CONDCODE, Register,
     Constant, ConstantFP,
-    GlobalAddress, FrameIndex, ConstantPool, ExternalSymbol,
+    GlobalAddress, FrameIndex, JumpTable, ConstantPool, ExternalSymbol,
 
     // TargetConstant* - Like Constant*, but the DAG does not do any folding or
     // simplification of the constant.
@@ -77,6 +77,7 @@ namespace ISD {
     // dag, turning into a GlobalAddress operand.
     TargetGlobalAddress,
     TargetFrameIndex,
+    TargetJumpTable,
     TargetConstantPool,
     TargetExternalSymbol,
     
@@ -388,6 +389,11 @@ namespace ISD {
     // operand, the second is the MBB to branch to.
     BR,
 
+    // BRIND - Indirect branch.  The first operand is the chain, the second
+    // is the value to branch to, which must be of the same type as the target's
+    // pointer type.
+    BRIND,
+    
     // BRCOND - Conditional branch.  The first operand is the chain,
     // the second is the condition, the third is the block to branch
     // to if the condition is true.
@@ -1165,6 +1171,24 @@ public:
   }
 };
 
+class JumpTableSDNode : public SDNode {
+  int JTI;
+protected:
+  friend class SelectionDAG;
+  JumpTableSDNode(int jti, MVT::ValueType VT, bool isTarg)
+    : SDNode(isTarg ? ISD::TargetJumpTable : ISD::JumpTable, VT), 
+    JTI(jti) {}
+public:
+    
+    int getIndex() const { return JTI; }
+  
+  static bool classof(const JumpTableSDNode *) { return true; }
+  static bool classof(const SDNode *N) {
+    return N->getOpcode() == ISD::JumpTable ||
+           N->getOpcode() == ISD::TargetJumpTable;
+  }
+};
+
 class ConstantPoolSDNode : public SDNode {
   Constant *C;
   int Offset;
index 11c6f231b9f29729edae3168a1c64cfd93499509..48d4a20a83f55c6ef5442fc7815154edec15b5a4 100644 (file)
@@ -17,6 +17,7 @@
 #include "llvm/Constants.h"
 #include "llvm/Module.h"
 #include "llvm/CodeGen/MachineConstantPool.h"
+#include "llvm/CodeGen/MachineJumpTableInfo.h"
 #include "llvm/Support/Mangler.h"
 #include "llvm/Support/MathExtras.h"
 #include "llvm/Target/TargetMachine.h"
@@ -46,6 +47,7 @@ AsmPrinter::AsmPrinter(std::ostream &o, TargetMachine &tm)
   AlignmentIsInBytes(true),
   SwitchToSectionDirective("\t.section\t"),
   ConstantPoolSection("\t.section .rodata\n"),
+  JumpTableSection("\t.section .rodata\n"),
   StaticCtorsSection("\t.section .ctors,\"aw\",@progbits"),
   StaticDtorsSection("\t.section .dtors,\"aw\",@progbits"),
   LCOMMDirective(0),
@@ -127,6 +129,33 @@ void AsmPrinter::EmitConstantPool(MachineConstantPool *MCP) {
   }
 }
 
+/// EmitJumpTableInfo - Print assembly representations of the jump tables used
+/// by the current function to the current output stream.  
+///
+void AsmPrinter::EmitJumpTableInfo(MachineJumpTableInfo *MJTI) {
+  const std::vector<MachineJumpTableEntry> &JT = MJTI->getJumpTables();
+  if (JT.empty()) return;
+  const TargetData &TD = TM.getTargetData();
+  
+  // FIXME: someday we need to handle PIC jump tables
+  assert((TM.getRelocationModel() == Reloc::Static ||
+          TM.getRelocationModel() == Reloc::DynamicNoPIC) &&
+         "Unhandled relocation model emitting jump table information!");
+  
+  SwitchSection(JumpTableSection, 0);
+  EmitAlignment(Log2_32(TD.getPointerAlignment()));
+  for (unsigned i = 0, e = JT.size(); i != e; ++i) {
+    O << PrivateGlobalPrefix << "JTI" << getFunctionNumber() << '_' << i 
+      << ":\n";
+    const std::vector<MachineBasicBlock*> &JTBBs = JT[i].MBBs;
+    for (unsigned ii = 0, ee = JTBBs.size(); ii != ee; ++ii) {
+      O << Data32bitsDirective << ' ';
+      printBasicBlockLabel(JTBBs[ii]);
+      O << '\n';
+    }
+  }
+}
+
 /// EmitSpecialLLVMGlobal - Check to see if the specified global is a
 /// special global used by LLVM.  If so, emit it and return true, otherwise
 /// do nothing and return false.
@@ -654,3 +683,12 @@ bool AsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
   // Target doesn't support this yet!
   return true;
 }
+
+/// printBasicBlockLabel - This method prints the label for the specified
+/// MachineBasicBlock
+void AsmPrinter::printBasicBlockLabel(const MachineBasicBlock *MBB) const {
+  O << PrivateGlobalPrefix << "LBB" 
+    << Mang->getValueName(MBB->getParent()->getFunction())
+    << "_" << MBB->getNumber() << '\t' << CommentString
+    << MBB->getBasicBlock()->getName();
+}
index c0b2cdfd2aa369b2af8df99d1a4b5808d1a463a6..4be24198864dba389efaaf4f2c981c8bb4512313 100644 (file)
@@ -84,7 +84,10 @@ namespace llvm {
       assert(0 && "CP not implementated yet!");
       return 0;
     }
-
+    virtual uint64_t getJumpTableEntryAddress(unsigned Index) {
+      assert(0 && "JT not implementated yet!");
+      return 0;
+    }
     virtual unsigned char* allocateGlobal(unsigned size, unsigned alignment) {
       assert(0 && "Globals not implemented yet!");
       return 0;
index d37fef4003ca126dc822aaa6067e1f833cc71d00..4243076d3e5811b6e3ff668ec3d2da15ea70feaa 100644 (file)
@@ -56,6 +56,7 @@ namespace {
     { return 0; }
 
     uint64_t getConstantPoolEntryAddress(unsigned Num) { return 0; }
+    uint64_t getJumpTableEntryAddress(unsigned Num) { return 0; }
     uint64_t getCurrentPCValue() { return 0; }
     uint64_t getCurrentPCOffset() { return 0; }
   };
@@ -97,7 +98,14 @@ namespace {
     void emitConstantPool(MachineConstantPool *MCP) {
       MCE.emitConstantPool(MCP);
     }
-
+    void initJumpTableInfo(MachineJumpTableInfo *MJTI) {
+      MCE.initJumpTableInfo(MJTI);
+    }
+    void emitJumpTableInfo(MachineJumpTableInfo *MJTI,
+                           std::map<MachineBasicBlock*,uint64_t> &MBBM) {
+      MCE.emitJumpTableInfo(MJTI, MBBM);
+    }
+    
     void startFunctionStub(unsigned StubSize) {
       MCE.startFunctionStub(StubSize);
     }
@@ -146,7 +154,9 @@ namespace {
     uint64_t getConstantPoolEntryAddress(unsigned Num) {
       return MCE.getConstantPoolEntryAddress(Num);
     }
-
+    uint64_t getJumpTableEntryAddress(unsigned Num) {
+      return MCE.getJumpTableEntryAddress(Num);
+    }
     virtual unsigned char* allocateGlobal(unsigned size, unsigned alignment)
     { return MCE.allocateGlobal(size, alignment); }
 
index 65c902fd4b356c27d9d6b23c889cc8ace559ab15..da89ea1821fcb6ae6edd53094644d944618e1bd5 100644 (file)
@@ -18,6 +18,7 @@
 #include "llvm/CodeGen/SSARegMap.h"
 #include "llvm/CodeGen/MachineFrameInfo.h"
 #include "llvm/CodeGen/MachineConstantPool.h"
+#include "llvm/CodeGen/MachineJumpTableInfo.h"
 #include "llvm/CodeGen/Passes.h"
 #include "llvm/Target/TargetMachine.h"
 #include "llvm/Target/TargetFrameInfo.h"
@@ -113,6 +114,7 @@ MachineFunction::MachineFunction(const Function *F,
   MFInfo = 0;
   FrameInfo = new MachineFrameInfo();
   ConstantPool = new MachineConstantPool(TM.getTargetData());
+  JumpTableInfo = new MachineJumpTableInfo(TM.getTargetData());
   BasicBlocks.Parent = this;
 }
 
@@ -122,6 +124,7 @@ MachineFunction::~MachineFunction() {
   delete MFInfo;
   delete FrameInfo;
   delete ConstantPool;
+  delete JumpTableInfo;
   delete[] UsedPhysRegs;
 }
 
@@ -132,6 +135,9 @@ void MachineFunction::print(std::ostream &OS) const {
 
   // Print Frame Information
   getFrameInfo()->print(*this, OS);
+  
+  // Print JumpTable Information
+  getJumpTableInfo()->print(OS);
 
   // Print Constant Pool
   getConstantPool()->print(OS);
@@ -333,6 +339,36 @@ void MachineFrameInfo::dump(const MachineFunction &MF) const {
 }
 
 
+//===----------------------------------------------------------------------===//
+//  MachineJumpTableInfo implementation
+//===----------------------------------------------------------------------===//
+
+/// getJumpTableIndex - Create a new jump table entry in the jump table info
+/// or return an existing one.
+///
+unsigned MachineJumpTableInfo::getJumpTableIndex(
+                                     std::vector<MachineBasicBlock*> &DestBBs) {
+  for (unsigned i = 0, e = JumpTables.size(); i != e; ++i)
+    if (JumpTables[i].MBBs == DestBBs)
+      return i;
+  
+  JumpTables.push_back(MachineJumpTableEntry(DestBBs));
+  return JumpTables.size()-1;
+}
+
+
+void MachineJumpTableInfo::print(std::ostream &OS) const {
+  // FIXME: this is lame, maybe we could print out the MBB numbers or something
+  // like {1, 2, 4, 5, 3, 0}
+  for (unsigned i = 0, e = JumpTables.size(); i != e; ++i) {
+    OS << "  <jt #" << i << "> has " << JumpTables[i].MBBs.size() 
+       << " entries\n";
+  }
+}
+
+void MachineJumpTableInfo::dump() const { print(std::cerr); }
+
+
 //===----------------------------------------------------------------------===//
 //  MachineConstantPool implementation
 //===----------------------------------------------------------------------===//
index 973e3ec1e6ee0621e0235484078d9a2a341dae19..f92c0844d8a26fdf391b6f8f44d1c74f837ea5b4 100644 (file)
@@ -238,6 +238,9 @@ static void print(const MachineOperand &MO, std::ostream &OS,
   case MachineOperand::MO_ConstantPoolIndex:
     OS << "<cp#" << MO.getConstantPoolIndex() << ">";
     break;
+  case MachineOperand::MO_JumpTableIndex:
+    OS << "<jt#" << MO.getJumpTableIndex() << ">";
+    break;
   case MachineOperand::MO_GlobalAddress:
     OS << "<ga:" << ((Value*)MO.getGlobal())->getName();
     if (MO.getOffset()) OS << "+" << MO.getOffset();
@@ -377,6 +380,9 @@ std::ostream &operator<<(std::ostream &OS, const MachineOperand &MO) {
   case MachineOperand::MO_ConstantPoolIndex:
     OS << "<cp#" << MO.getConstantPoolIndex() << ">";
     break;
+  case MachineOperand::MO_JumpTableIndex:
+    OS << "<jt#" << MO.getJumpTableIndex() << ">";
+    break;
   case MachineOperand::MO_GlobalAddress:
     OS << "<ga:" << ((Value*)MO.getGlobal())->getName() << ">";
     break;
index d635747d8010ab092ff5e19fb46123762656ab42..6f9e97748e8e6c9aad519d0db4c9f10159de2eaf 100644 (file)
@@ -510,6 +510,7 @@ SDOperand SelectionDAGLegalize::LegalizeOp(SDOperand Op) {
   case ISD::Register:
   case ISD::BasicBlock:
   case ISD::TargetFrameIndex:
+  case ISD::TargetJumpTable:
   case ISD::TargetConstant:
   case ISD::TargetConstantFP:
   case ISD::TargetConstantPool:
@@ -552,7 +553,8 @@ SDOperand SelectionDAGLegalize::LegalizeOp(SDOperand Op) {
     abort();
   case ISD::GlobalAddress:
   case ISD::ExternalSymbol:
-  case ISD::ConstantPool:           // Nothing to do.
+  case ISD::ConstantPool:
+  case ISD::JumpTable: // Nothing to do.
     switch (TLI.getOperationAction(Node->getOpcode(), Node->getValueType(0))) {
     default: assert(0 && "This action is not supported yet!");
     case TargetLowering::Custom:
@@ -1183,7 +1185,21 @@ SDOperand SelectionDAGLegalize::LegalizeOp(SDOperand Op) {
     
     Result = DAG.UpdateNodeOperands(Result, Tmp1, Node->getOperand(1));
     break;
-
+  case ISD::BRIND:
+    Tmp1 = LegalizeOp(Node->getOperand(0));  // Legalize the chain.
+    // Ensure that libcalls are emitted before a branch.
+    Tmp1 = DAG.getNode(ISD::TokenFactor, MVT::Other, Tmp1, LastCALLSEQ_END);
+    Tmp1 = LegalizeOp(Tmp1);
+    LastCALLSEQ_END = DAG.getEntryNode();
+    
+    switch (getTypeAction(Node->getOperand(1).getValueType())) {
+    default: assert(0 && "Indirect target must be legal type (pointer)!");
+    case Legal:
+      Tmp2 = LegalizeOp(Node->getOperand(1)); // Legalize the condition.
+      break;
+    }
+    Result = DAG.UpdateNodeOperands(Result, Tmp1, Tmp2);
+    break;
   case ISD::BRCOND:
     Tmp1 = LegalizeOp(Node->getOperand(0));  // Legalize the chain.
     // Ensure that libcalls are emitted before a return.
index c0118aff8e1521c8eb67d85aa59c47eb0e7fa945..bf95a92555afc73b02a4fdd7337a77f3da2abf6b 100644 (file)
@@ -117,6 +117,9 @@ void ScheduleDAG::AddOperand(MachineInstr *MI, SDOperand Op,
   } else if (FrameIndexSDNode *FI =
              dyn_cast<FrameIndexSDNode>(Op)) {
     MI->addFrameIndexOperand(FI->getIndex());
+  } else if (JumpTableSDNode *JT =
+             dyn_cast<JumpTableSDNode>(Op)) {
+    MI->addJumpTableIndexOperand(JT->getIndex());
   } else if (ConstantPoolSDNode *CP = 
              dyn_cast<ConstantPoolSDNode>(Op)) {
     int Offset = CP->getOffset();
index ec1050fd72a2028900bc3112a72aa599768b1ec4..c26632a41e882bf7cfc412594de99dd9639b536c 100644 (file)
@@ -387,6 +387,13 @@ void SelectionDAG::RemoveNodeFromCSEMaps(SDNode *N) {
   case ISD::TargetFrameIndex:
     Erased = TargetFrameIndices.erase(cast<FrameIndexSDNode>(N)->getIndex());
     break;
+  case ISD::JumpTable:
+    Erased = JumpTableIndices.erase(cast<JumpTableSDNode>(N)->getIndex());
+    break;
+  case ISD::TargetJumpTable:
+    Erased = 
+      TargetJumpTableIndices.erase(cast<JumpTableSDNode>(N)->getIndex());
+    break;
   case ISD::ConstantPool:
     Erased = ConstantPoolIndices.
       erase(std::make_pair(cast<ConstantPoolSDNode>(N)->get(),
@@ -741,6 +748,22 @@ SDOperand SelectionDAG::getTargetFrameIndex(int FI, MVT::ValueType VT) {
   return SDOperand(N, 0);
 }
 
+SDOperand SelectionDAG::getJumpTable(int JTI, MVT::ValueType VT) {
+  SDNode *&N = JumpTableIndices[JTI];
+  if (N) return SDOperand(N, 0);
+  N = new JumpTableSDNode(JTI, VT, false);
+  AllNodes.push_back(N);
+  return SDOperand(N, 0);
+}
+
+SDOperand SelectionDAG::getTargetJumpTable(int JTI, MVT::ValueType VT) {
+  SDNode *&N = TargetJumpTableIndices[JTI];
+  if (N) return SDOperand(N, 0);
+  N = new JumpTableSDNode(JTI, VT, true);
+  AllNodes.push_back(N);
+  return SDOperand(N, 0);
+}
+
 SDOperand SelectionDAG::getConstantPool(Constant *C, MVT::ValueType VT,
                                         unsigned Alignment,  int Offset) {
   SDNode *&N = ConstantPoolIndices[std::make_pair(C,
@@ -2742,6 +2765,7 @@ const char *SDNode::getOperationName(const SelectionDAG *G) const {
   case ISD::ConstantFP:    return "ConstantFP";
   case ISD::GlobalAddress: return "GlobalAddress";
   case ISD::FrameIndex:    return "FrameIndex";
+  case ISD::JumpTable:     return "JumpTable";
   case ISD::ConstantPool:  return "ConstantPool";
   case ISD::ExternalSymbol: return "ExternalSymbol";
   case ISD::INTRINSIC_WO_CHAIN: {
@@ -2759,6 +2783,7 @@ const char *SDNode::getOperationName(const SelectionDAG *G) const {
   case ISD::TargetConstantFP:return "TargetConstantFP";
   case ISD::TargetGlobalAddress: return "TargetGlobalAddress";
   case ISD::TargetFrameIndex: return "TargetFrameIndex";
+  case ISD::TargetJumpTable:  return "TargetJumpTable";
   case ISD::TargetConstantPool:  return "TargetConstantPool";
   case ISD::TargetExternalSymbol: return "TargetExternalSymbol";
 
@@ -2849,6 +2874,7 @@ const char *SDNode::getOperationName(const SelectionDAG *G) const {
 
     // Control flow instructions
   case ISD::BR:      return "br";
+  case ISD::BRIND:   return "brind";
   case ISD::BRCOND:  return "brcond";
   case ISD::BR_CC:   return "br_cc";
   case ISD::RET:     return "ret";
index 96a81e0938340be41ee9ab33c0feeaa8adba7d0e..7fcaaf59af9aed58be2e2a21a6d14050848a5d21 100644 (file)
@@ -27,6 +27,7 @@
 #include "llvm/CodeGen/MachineDebugInfo.h"
 #include "llvm/CodeGen/MachineFunction.h"
 #include "llvm/CodeGen/MachineFrameInfo.h"
+#include "llvm/CodeGen/MachineJumpTableInfo.h"
 #include "llvm/CodeGen/MachineInstrBuilder.h"
 #include "llvm/CodeGen/SelectionDAG.h"
 #include "llvm/CodeGen/SSARegMap.h"
@@ -398,6 +399,7 @@ public:
   /// SwitchCases - Vector of CaseBlock structures used to communicate
   /// SwitchInst code generation information.
   std::vector<SelectionDAGISel::CaseBlock> SwitchCases;
+  SelectionDAGISel::JumpTable JT;
   
   /// FuncInfo - Information about the function as a whole.
   ///
@@ -406,7 +408,7 @@ public:
   SelectionDAGLowering(SelectionDAG &dag, TargetLowering &tli,
                        FunctionLoweringInfo &funcinfo)
     : TLI(tli), DAG(dag), TD(DAG.getTarget().getTargetData()),
-      FuncInfo(funcinfo) {
+      JT(0,0,0), FuncInfo(funcinfo) {
   }
 
   /// getRoot - Return the current virtual root of the Selection DAG.
@@ -474,6 +476,7 @@ public:
 
   // Helper for visitSwitch
   void visitSwitchCase(SelectionDAGISel::CaseBlock &CB);
+  void visitJumpTable(SelectionDAGISel::JumpTable &JT);
   
   // These all get lowered before this pass.
   void visitInvoke(InvokeInst &I) { assert(0 && "TODO"); }
@@ -816,6 +819,30 @@ void SelectionDAGLowering::visitSwitchCase(SelectionDAGISel::CaseBlock &CB) {
   CurMBB->addSuccessor(CB.RHSBB);
 }
 
+/// visitSwitchCase - Emits the necessary code to represent a single node in
+/// the binary search tree resulting from lowering a switch instruction.
+void SelectionDAGLowering::visitJumpTable(SelectionDAGISel::JumpTable &JT) {
+  // FIXME: Need to emit different code for PIC vs. Non-PIC, specifically,
+  // we need to add the address of the jump table to the value loaded, since
+  // the entries in the jump table will be differences rather than absolute
+  // addresses.
+  
+  // Emit the code for the jump table
+  MVT::ValueType PTy = TLI.getPointerTy();
+  unsigned PTyBytes = MVT::getSizeInBits(PTy)/8;
+  SDOperand Copy = DAG.getCopyFromReg(getRoot(), JT.Reg, PTy);
+  SDOperand IDX = DAG.getNode(ISD::MUL, PTy, Copy,
+                              DAG.getConstant(PTyBytes, PTy));
+  SDOperand ADD = DAG.getNode(ISD::ADD, PTy, IDX, DAG.getJumpTable(JT.JTI,PTy));
+  SDOperand LD  = DAG.getLoad(PTy, Copy.getValue(1), ADD, DAG.getSrcValue(0));
+  DAG.setRoot(DAG.getNode(ISD::BRIND, MVT::Other, LD.getValue(1), LD));
+
+  // Update successor info
+  for (std::set<MachineBasicBlock*>::iterator ii = JT.SuccMBBs.begin(), 
+       ee = JT.SuccMBBs.end(); ii != ee; ++ii)
+    JT.MBB->addSuccessor(*ii);
+}
+
 void SelectionDAGLowering::visitSwitch(SwitchInst &I) {
   // Figure out which block is immediately after the current one.
   MachineBasicBlock *NextBlock = 0;
@@ -850,11 +877,88 @@ void SelectionDAGLowering::visitSwitch(SwitchInst &I) {
   // search tree.
   Value *SV = I.getOperand(0);
   MachineBasicBlock *Default = FuncInfo.MBBMap[I.getDefaultDest()];
-  
-  // Get the current MachineFunction and LLVM basic block, for use in creating
-  // and inserting new MBBs during the creation of the binary search tree.
+
+  // Get the MachineFunction which holds the current MBB.  This is used during
+  // emission of jump tables, and when inserting any additional MBBs necessary
+  // to represent the switch.
   MachineFunction *CurMF = CurMBB->getParent();
   const BasicBlock *LLVMBB = CurMBB->getBasicBlock();
+  Reloc::Model Relocs = TLI.getTargetMachine().getRelocationModel();
+
+  // If the switch has more than 3 blocks, and is 100% dense, then emit a jump
+  // table rather than lowering the switch to a binary tree of conditional
+  // branches.
+  // FIXME: Make this work with 64 bit targets someday, possibly by always
+  // doing differences there so that entries stay 32 bits.
+  // FIXME: Make this work with PIC code
+  if (TLI.isOperationLegal(ISD::BRIND, TLI.getPointerTy()) &&
+      TLI.getPointerTy() == MVT::i32 &&
+      (Relocs == Reloc::Static || Relocs == Reloc::DynamicNoPIC) &&
+      Cases.size() > 3) {
+    uint64_t First = cast<ConstantIntegral>(Cases.front().first)->getRawValue();
+    uint64_t Last  = cast<ConstantIntegral>(Cases.back().first)->getRawValue();
+
+    // Determine density
+    // FIXME: support sub-100% density
+    if (((Last - First) + 1ULL) == (uint64_t)Cases.size()) {
+      // Create a new basic block to hold the code for loading the address
+      // of the jump table, and jumping to it.  Update successor information;
+      // we will either branch to the default case for the switch, or the jump
+      // table.
+      MachineBasicBlock *JumpTableBB = new MachineBasicBlock(LLVMBB);
+      CurMF->getBasicBlockList().insert(BBI, JumpTableBB);
+      CurMBB->addSuccessor(Default);
+      CurMBB->addSuccessor(JumpTableBB);
+      
+      // Subtract the lowest switch case value from the value being switched on
+      // and conditional branch to default mbb if the result is greater than the
+      // difference between smallest and largest cases.
+      SDOperand SwitchOp = getValue(SV);
+      MVT::ValueType VT = SwitchOp.getValueType();
+      SDOperand SUB = DAG.getNode(ISD::SUB, VT, SwitchOp, 
+                                  DAG.getConstant(First, VT));
+
+      // The SDNode we just created, which holds the value being switched on
+      // minus the the smallest case value, needs to be copied to a virtual
+      // register so it can be used as an index into the jump table in a 
+      // subsequent basic block.  This value may be smaller or larger than the
+      // target's pointer type, and therefore require extension or truncating.
+      if (VT > TLI.getPointerTy())
+        SwitchOp = DAG.getNode(ISD::TRUNCATE, TLI.getPointerTy(), SUB);
+      else
+        SwitchOp = DAG.getNode(ISD::ZERO_EXTEND, TLI.getPointerTy(), SUB);
+      unsigned JumpTableReg = FuncInfo.MakeReg(TLI.getPointerTy());
+      SDOperand CopyTo = DAG.getCopyToReg(getRoot(), JumpTableReg, SwitchOp);
+      
+      // Emit the range check for the jump table, and branch to the default
+      // block for the switch statement if the value being switched on exceeds
+      // the largest case in the switch.
+      SDOperand CMP = DAG.getSetCC(TLI.getSetCCResultTy(), SUB,
+                                   DAG.getConstant(Last-First,VT), ISD::SETUGT);
+      DAG.setRoot(DAG.getNode(ISD::BRCOND, MVT::Other, CopyTo, CMP, 
+                              DAG.getBasicBlock(Default)));
+
+      // Build a sorted vector of destination BBs, corresponding to each target
+      // of the switch.
+      // FIXME: need to insert DefaultMBB for each "hole" in the jump table,
+      // when we support jump tables with < 100% density.
+      std::set<MachineBasicBlock*> UniqueBBs;
+      std::vector<MachineBasicBlock*> DestBBs;
+      for (CaseItr ii = Cases.begin(), ee = Cases.end(); ii != ee; ++ii) {
+        DestBBs.push_back(ii->second);
+        UniqueBBs.insert(ii->second);
+      }
+      unsigned JTI = CurMF->getJumpTableInfo()->getJumpTableIndex(DestBBs);
+      
+      // Set the jump table information so that we can codegen it as a second
+      // MachineBasicBlock
+      JT.Reg = JumpTableReg;
+      JT.JTI = JTI;
+      JT.MBB = JumpTableBB;
+      JT.SuccMBBs = UniqueBBs;
+      return;
+    }
+  }
   
   // Push the initial CaseRec onto the worklist
   std::vector<CaseRec> CaseVec;
@@ -3022,9 +3126,10 @@ void SelectionDAGISel::BuildSelectionDAG(SelectionDAG &DAG, BasicBlock *LLVMBB,
   SDL.visit(*LLVMBB->getTerminator());
 
   // Copy over any CaseBlock records that may now exist due to SwitchInst
-  // lowering.
+  // lowering, as well as any jump table information.
   SwitchCases.clear();
   SwitchCases = SDL.SwitchCases;
+  JT = SDL.JT;
   
   // Make sure the root of the DAG is up-to-date.
   DAG.setRoot(SDL.getRoot());
@@ -3074,7 +3179,7 @@ void SelectionDAGISel::SelectBasicBlock(BasicBlock *LLVMBB, MachineFunction &MF,
   
   // Next, now that we know what the last MBB the LLVM BB expanded is, update
   // PHI nodes in successors.
-  if (SwitchCases.empty()) {
+  if (SwitchCases.empty() && JT.Reg == 0) {
     for (unsigned i = 0, e = PHINodesToUpdate.size(); i != e; ++i) {
       MachineInstr *PHI = PHINodesToUpdate[i].first;
       assert(PHI->getOpcode() == TargetInstrInfo::PHI &&
@@ -3085,6 +3190,33 @@ void SelectionDAGISel::SelectBasicBlock(BasicBlock *LLVMBB, MachineFunction &MF,
     return;
   }
   
+  // If we need to emit a jump table, 
+  if (JT.Reg) {
+    assert(SwitchCases.empty() && "Cannot have jump table and lowered switch");
+    SelectionDAG SDAG(TLI, MF, getAnalysisToUpdate<MachineDebugInfo>());
+    CurDAG = &SDAG;
+    SelectionDAGLowering SDL(SDAG, TLI, FuncInfo);
+    // Set the current basic block to the mbb we wish to insert the code into
+    BB = JT.MBB;
+    SDL.setCurrentBasicBlock(BB);
+    // Emit the code
+    SDL.visitJumpTable(JT);
+    SDAG.setRoot(SDL.getRoot());
+    CodeGenAndEmitDAG(SDAG);
+    // Update PHI Nodes
+    for (unsigned pi = 0, pe = PHINodesToUpdate.size(); pi != pe; ++pi) {
+      MachineInstr *PHI = PHINodesToUpdate[pi].first;
+      MachineBasicBlock *PHIBB = PHI->getParent();
+      assert(PHI->getOpcode() == TargetInstrInfo::PHI &&
+             "This is not a machine PHI node that we are updating!");
+      if (JT.SuccMBBs.find(PHIBB) != JT.SuccMBBs.end()) {
+        PHI->addRegOperand(PHINodesToUpdate[pi].second);
+        PHI->addMachineBasicBlockOperand(BB);
+      }
+    }
+    return;
+  }
+  
   // If we generated any switch lowering information, build and codegen any
   // additional DAGs necessary.
   for(unsigned i = 0, e = SwitchCases.size(); i != e; ++i) {
index 5cd83ff51a353d8a5c35ea989cc9fc1137754728..b99497fd88be6adf1473729bcc6febb15f4c669f 100644 (file)
@@ -328,7 +328,10 @@ GenericValue ExecutionEngine::getConstantValue(const Constant *C) {
   return Result;
 }
 
-/// FIXME: document
+/// StoreValueToMemory - Stores the data in Val of type Ty at address Ptr.  Ptr
+/// is the address of the memory at which to store Val, cast to GenericValue *.
+/// It is not a pointer to a GenericValue containing the address at which to
+/// store Val.
 ///
 void ExecutionEngine::StoreValueToMemory(GenericValue Val, GenericValue *Ptr,
                                          const Type *Ty) {
index a5bb7c690ade07e4a0a922f08c026b35b4d99a9c..b67dfe1953b550a8b878176f964d48e409062722 100644 (file)
@@ -20,7 +20,9 @@
 #include "llvm/CodeGen/MachineCodeEmitter.h"
 #include "llvm/CodeGen/MachineFunction.h"
 #include "llvm/CodeGen/MachineConstantPool.h"
+#include "llvm/CodeGen/MachineJumpTableInfo.h"
 #include "llvm/CodeGen/MachineRelocation.h"
+#include "llvm/ExecutionEngine/GenericValue.h"
 #include "llvm/Target/TargetData.h"
 #include "llvm/Target/TargetJITInfo.h"
 #include "llvm/Support/Debug.h"
@@ -430,7 +432,15 @@ namespace {
     /// ConstantPoolBase - A pointer to the first entry in the constant pool.
     ///
     void *ConstantPoolBase;
-  public:
+
+    /// ConstantPool - The constant pool for the current function.
+    ///
+    MachineJumpTableInfo *JumpTable;
+    
+    /// JumpTableBase - A pointer to the first entry in the jump table.
+    ///
+    void *JumpTableBase;
+public:
     JITEmitter(JIT &jit) : MemMgr(jit.getJITInfo().needsGOT()) {
       TheJIT = &jit;
       DEBUG(std::cerr <<
@@ -441,6 +451,9 @@ namespace {
     virtual void startFunction(MachineFunction &F);
     virtual void finishFunction(MachineFunction &F);
     virtual void emitConstantPool(MachineConstantPool *MCP);
+    virtual void initJumpTableInfo(MachineJumpTableInfo *MJTI);
+    virtual void emitJumpTableInfo(MachineJumpTableInfo *MJTI,
+                                   std::map<MachineBasicBlock*,uint64_t> &MBBM);
     virtual void startFunctionStub(unsigned StubSize);
     virtual void* finishFunctionStub(const Function *F);
     virtual void emitByte(unsigned char B);
@@ -454,6 +467,7 @@ namespace {
     virtual uint64_t getCurrentPCValue();
     virtual uint64_t getCurrentPCOffset();
     virtual uint64_t getConstantPoolEntryAddress(unsigned Entry);
+    virtual uint64_t getJumpTableEntryAddress(unsigned Entry);
     virtual unsigned char* allocateGlobal(unsigned size, unsigned alignment);
 
   private:
@@ -583,6 +597,57 @@ void JITEmitter::emitConstantPool(MachineConstantPool *MCP) {
   }
 }
 
+void JITEmitter::initJumpTableInfo(MachineJumpTableInfo *MJTI) {
+  const std::vector<MachineJumpTableEntry> &JT = MJTI->getJumpTables();
+  if (JT.empty()) return;
+  
+  unsigned Size = 0;
+  unsigned EntrySize = MJTI->getEntrySize();
+  for (unsigned i = 0, e = JT.size(); i != e; ++i)
+    Size += JT[i].MBBs.size() * EntrySize;
+  
+  // Just allocate space for all the jump tables now.  We will fix up the actual
+  // MBB entries in the tables after we emit the code for each block, since then
+  // we will know the final locations of the MBBs in memory.
+  JumpTable = MJTI;
+  JumpTableBase = MemMgr.allocateConstant(Size, MJTI->getAlignment());
+}
+
+void JITEmitter::emitJumpTableInfo(MachineJumpTableInfo *MJTI,
+                                   std::map<MachineBasicBlock*,uint64_t> &MBBM){
+  const std::vector<MachineJumpTableEntry> &JT = MJTI->getJumpTables();
+  if (JT.empty()) return;
+
+  unsigned Offset = 0;
+  unsigned EntrySize = MJTI->getEntrySize();
+  
+  // For each jump table, map each target in the jump table to the address of 
+  // an emitted MachineBasicBlock.
+  for (unsigned i = 0, e = JT.size(); i != e; ++i) {
+    const std::vector<MachineBasicBlock*> &MBBs = JT[i].MBBs;
+    for (unsigned mi = 0, me = MBBs.size(); mi != me; ++mi) {
+      uint64_t addr = MBBM[MBBs[mi]];
+      GenericValue addrgv;
+      const Type *Ty;
+      if (EntrySize == 4) {
+        addrgv.UIntVal = addr;
+        Ty = Type::UIntTy;
+      } else if (EntrySize == 8) {
+        addrgv.ULongVal = addr;
+        Ty = Type::ULongTy;
+      } else {
+        assert(0 && "Unhandled jump table entry size!");
+        abort();
+      }
+      // Store the address of the basic block for this jump table slot in the
+      // memory we allocated for the jump table in 'initJumpTableInfo'
+      void *ptr = (void *)((char *)JumpTableBase + Offset);
+      TheJIT->StoreValueToMemory(addrgv, (GenericValue *)ptr, Ty);
+      Offset += EntrySize;
+    }
+  }
+}
+
 void JITEmitter::startFunctionStub(unsigned StubSize) {
   SavedCurBlock = CurBlock;  SavedCurByte = CurByte;
   CurByte = CurBlock = MemMgr.allocateStub(StubSize);
@@ -621,6 +686,22 @@ uint64_t JITEmitter::getConstantPoolEntryAddress(unsigned ConstantNum) {
          ConstantPool->getConstants()[ConstantNum].Offset;
 }
 
+// getJumpTableEntryAddress - Return the address of the JumpTable with index
+// 'Index' in the jumpp table that was last initialized with 'initJumpTableInfo'
+//
+uint64_t JITEmitter::getJumpTableEntryAddress(unsigned Index) {
+  const std::vector<MachineJumpTableEntry> &JT = JumpTable->getJumpTables();
+  assert(Index < JT.size() && "Invalid jump table index!");
+  
+  unsigned Offset = 0;
+  unsigned EntrySize = JumpTable->getEntrySize();
+  
+  for (unsigned i = 0; i < Index; ++i)
+    Offset += JT[i].MBBs.size() * EntrySize;
+  
+  return (uint64_t)((char *)JumpTableBase + Offset);
+}
+
 unsigned char* JITEmitter::allocateGlobal(unsigned size, unsigned alignment)
 {
   return MemMgr.allocateGlobal(size, alignment);
index 6f45fb5497f98df0e6486c857456dff551724278..5d1f522ca0aeee9c431f722c9ec0eec2aca01af7 100644 (file)
@@ -115,14 +115,9 @@ void AlphaAsmPrinter::printOp(const MachineOperand &MO, bool IsCallOp) {
     abort();
     return;
 
-  case MachineOperand::MO_MachineBasicBlock: {
-    MachineBasicBlock *MBBOp = MO.getMachineBasicBlock();
-    O << PrivateGlobalPrefix << "LBB"
-      << Mang->getValueName(MBBOp->getParent()->getFunction())
-      << "_" << MBBOp->getNumber() << "\t" << CommentString << " "
-      << MBBOp->getBasicBlock()->getName();
+  case MachineOperand::MO_MachineBasicBlock:
+    printBasicBlockLabel(MO.getMachineBasicBlock());
     return;
-  }
 
   case MachineOperand::MO_ConstantPoolIndex:
     O << PrivateGlobalPrefix << "CPI" << getFunctionNumber() << "_"
index fee6457d7d84b6e590a9c3737707b47b32a08852..3c72e7f9815ef2f3c4f75f1be789d83449ba4af4 100644 (file)
@@ -193,6 +193,7 @@ AlphaTargetLowering::AlphaTargetLowering(TargetMachine &TM) : TargetLowering(TM)
   addRegisterClass(MVT::f64, Alpha::F8RCRegisterClass);
   addRegisterClass(MVT::f32, Alpha::F4RCRegisterClass);
   
+  setOperationAction(ISD::BRIND,        MVT::i64,   Expand);
   setOperationAction(ISD::BR_CC,        MVT::Other, Expand);
   setOperationAction(ISD::SELECT_CC,    MVT::Other, Expand);
   
index 2cd156124a7b13de5c2028a4f2ab5a800a93b765..359b64410447968066605fb71f6d595a5db2cff1 100644 (file)
@@ -189,14 +189,9 @@ void IA64AsmPrinter::printOp(const MachineOperand &MO,
   case MachineOperand::MO_UnextendedImmed:
     O << /*(unsigned int)*/MO.getImmedValue();
     return;
-  case MachineOperand::MO_MachineBasicBlock: {
-    MachineBasicBlock *MBBOp = MO.getMachineBasicBlock();
-    O << PrivateGlobalPrefix << "LBB"
-      << Mang->getValueName(MBBOp->getParent()->getFunction())
-      << "_" << MBBOp->getNumber () << "\t// "
-      << MBBOp->getBasicBlock ()->getName ();
+  case MachineOperand::MO_MachineBasicBlock:
+    printBasicBlockLabel(MO.getMachineBasicBlock());
     return;
-  }
   case MachineOperand::MO_PCRelativeDisp:
     std::cerr << "Shouldn't use addPCDisp() when building IA64 MachineInstrs";
     abort ();
index 85e6737d4b3cc0f58961b2a724d4f46389c2e2d9..9de54472de2859c085352ce7cfaa025048a7ab73 100644 (file)
@@ -35,6 +35,7 @@ IA64TargetLowering::IA64TargetLowering(TargetMachine &TM)
       // register class for predicate registers
       addRegisterClass(MVT::i1, IA64::PRRegisterClass);
 
+      setOperationAction(ISD::BRIND            , MVT::i64,   Expand);
       setOperationAction(ISD::BR_CC            , MVT::Other, Expand);
       setOperationAction(ISD::FP_ROUND_INREG   , MVT::f32  , Expand);
 
index b34bf9a8a217813c7962856a2e971d494b1eac28..11c0ec008b55d68ef812ba510f9ac938f2dde1fa 100644 (file)
@@ -233,6 +233,8 @@ namespace {
       printOperand(MI, OpNo+1);
     }
     
+    virtual void printBasicBlockLabel(const MachineBasicBlock *MBB) const; 
+    
     virtual bool runOnMachineFunction(MachineFunction &F) = 0;
     virtual bool doFinalization(Module &M) = 0;
     
@@ -277,6 +279,8 @@ namespace {
       Data64bitsDirective = 0;       // we can't emit a 64-bit unit
       AlignmentIsInBytes = false;    // Alignment is by power of 2.
       ConstantPoolSection = "\t.const\t";
+      // FIXME: Conditionalize jump table section based on PIC
+      JumpTableSection = ".const";
       LCOMMDirective = "\t.lcomm\t";
       StaticCtorsSection = ".mod_init_func";
       StaticDtorsSection = ".mod_term_func";
@@ -373,13 +377,14 @@ void PPCAsmPrinter::printOp(const MachineOperand &MO) {
     abort();
     return;
 
-  case MachineOperand::MO_MachineBasicBlock: {
-    MachineBasicBlock *MBBOp = MO.getMachineBasicBlock();
-    O << PrivateGlobalPrefix << "BB" << getFunctionNumber() << "_"
-      << MBBOp->getNumber() << "\t; " << MBBOp->getBasicBlock()->getName();
+  case MachineOperand::MO_MachineBasicBlock:
+    printBasicBlockLabel(MO.getMachineBasicBlock());
+    return;
+  case MachineOperand::MO_JumpTableIndex:
+    O << PrivateGlobalPrefix << "JTI" << getFunctionNumber()
+      << '_' << MO.getJumpTableIndex();
+    // FIXME: PIC relocation model
     return;
-  }
-
   case MachineOperand::MO_ConstantPoolIndex:
     O << PrivateGlobalPrefix << "CPI" << getFunctionNumber()
       << '_' << MO.getConstantPoolIndex();
@@ -500,6 +505,11 @@ void PPCAsmPrinter::printMachineInstruction(const MachineInstr *MI) {
   return;
 }
 
+void PPCAsmPrinter::printBasicBlockLabel(const MachineBasicBlock *MBB) const {
+  O << PrivateGlobalPrefix << "BB" << getFunctionNumber() << "_"
+    << MBB->getNumber() << '\t' << CommentString
+    << MBB->getBasicBlock()->getName();
+}
 
 /// runOnMachineFunction - This uses the printMachineInstruction()
 /// method to print assembly for each instruction.
@@ -514,6 +524,9 @@ bool DarwinAsmPrinter::runOnMachineFunction(MachineFunction &MF) {
   // Print out constants referenced by the function
   EmitConstantPool(MF.getConstantPool());
 
+  // Print out jump tables referenced by the function
+  EmitJumpTableInfo(MF.getJumpTableInfo());
+
   // Print out labels for the function.
   const Function *F = MF.getFunction();
   switch (F->getLinkage()) {
index 8d4e1b669a36db77314673d3bf15cb4cf7db634e..c7f2acbd77ce5c471e49a273421a8ed81508000a 100644 (file)
@@ -34,7 +34,7 @@ namespace {
     // Tracks which instruction references which BasicBlock
     std::vector<std::pair<MachineBasicBlock*, unsigned*> > BBRefs;
     // Tracks where each BasicBlock starts
-    std::map<MachineBasicBlock*, long> BBLocations;
+    std::map<MachineBasicBlock*, uint64_t> BBLocations;
 
     /// getMachineOpValue - evaluates the MachineOperand of a given MachineInstr
     ///
@@ -91,8 +91,10 @@ bool PPCCodeEmitter::runOnMachineFunction(MachineFunction &MF) {
          "JIT relocation model must be set to static or default!");
   MCE.startFunction(MF);
   MCE.emitConstantPool(MF.getConstantPool());
+  MCE.initJumpTableInfo(MF.getJumpTableInfo());
   for (MachineFunction::iterator BB = MF.begin(), E = MF.end(); BB != E; ++BB)
     emitBasicBlock(*BB);
+  MCE.emitJumpTableInfo(MF.getJumpTableInfo(), BBLocations);
   MCE.finishFunction(MF);
 
   // Resolve branches to BasicBlocks for the entire function
@@ -192,10 +194,13 @@ int PPCCodeEmitter::getMachineOpValue(MachineInstr &MI, MachineOperand &MO) {
   } else if (MO.isMachineBasicBlock()) {
     unsigned* CurrPC = (unsigned*)(intptr_t)MCE.getCurrentPCValue();
     BBRefs.push_back(std::make_pair(MO.getMachineBasicBlock(), CurrPC));
-  } else if (MO.isConstantPoolIndex()) {
-    unsigned index = MO.getConstantPoolIndex();
+  } else if (MO.isConstantPoolIndex() || MO.isJumpTableIndex()) {
+    if (MO.isConstantPoolIndex())
+      rv = MCE.getConstantPoolEntryAddress(MO.getConstantPoolIndex());
+    else
+      rv = MCE.getJumpTableEntryAddress(MO.getJumpTableIndex());
+
     unsigned Opcode = MI.getOpcode();
-    rv = MCE.getConstantPoolEntryAddress(index);
     if (Opcode == PPC::LIS || Opcode == PPC::ADDIS) {
       // lis wants hi16(addr)
       if ((short)rv < 0) rv += 1 << 16;
@@ -206,7 +211,7 @@ int PPCCodeEmitter::getMachineOpValue(MachineInstr &MI, MachineOperand &MO) {
       // These load opcodes want lo16(addr)
       rv &= 0xffff;
     } else {
-      assert(0 && "Unknown constant pool using instruction!");
+      assert(0 && "Unknown constant pool or jump table using instruction!");
     }
   } else {
     std::cerr << "ERROR: Unknown type of MachineOperand: " << MO << "\n";
index b699b92afb3d778a9d0bf2e9b14e28592393ce1c..10f074f6ef1dcb4380c82e46c72cce2217f9a2ec 100644 (file)
@@ -520,7 +520,8 @@ bool PPCDAGToDAGISel::SelectAddrImm(SDOperand N, SDOperand &Disp,
              && "Cannot handle constant offsets yet!");
       Disp = N.getOperand(1).getOperand(0);  // The global address.
       assert(Disp.getOpcode() == ISD::TargetGlobalAddress ||
-             Disp.getOpcode() == ISD::TargetConstantPool);
+             Disp.getOpcode() == ISD::TargetConstantPool ||
+             Disp.getOpcode() == ISD::TargetJumpTable);
       Base = N.getOperand(0);
       return true;  // [&g+r]
     }
@@ -661,7 +662,8 @@ bool PPCDAGToDAGISel::SelectAddrImmShift(SDOperand N, SDOperand &Disp,
              && "Cannot handle constant offsets yet!");
       Disp = N.getOperand(1).getOperand(0);  // The global address.
       assert(Disp.getOpcode() == ISD::TargetGlobalAddress ||
-             Disp.getOpcode() == ISD::TargetConstantPool);
+             Disp.getOpcode() == ISD::TargetConstantPool ||
+             Disp.getOpcode() == ISD::TargetJumpTable);
       Base = N.getOperand(0);
       return true;  // [&g+r]
     }
@@ -1241,6 +1243,15 @@ void PPCDAGToDAGISel::Select(SDOperand &Result, SDOperand Op) {
                                   N->getOperand(4), Chain);
     return;
   }
+  case ISD::BRIND: {
+    SDOperand Chain, Target;
+    Select(Chain, N->getOperand(0));
+    Select(Target,N->getOperand(1));
+    Chain = SDOperand(CurDAG->getTargetNode(PPC::MTCTR, MVT::Other, Target,
+                                            Chain), 0);
+    Result = CurDAG->SelectNodeTo(N, PPC::BCTR, MVT::Other, Chain);
+    return;
+  }
   }
   
   SelectCode(Result, Op);
index 18404fcfef7e3994b6d9d029ea25dac606be8dfb..fac2806c1208d25429e7160e9d5a06a01ba0fa5e 100644 (file)
@@ -123,6 +123,7 @@ PPCTargetLowering::PPCTargetLowering(TargetMachine &TM)
   // appropriate instructions to materialize the address.
   setOperationAction(ISD::GlobalAddress, MVT::i32, Custom);
   setOperationAction(ISD::ConstantPool,  MVT::i32, Custom);
+  setOperationAction(ISD::JumpTable,     MVT::i32, Custom);
 
   // RET must be custom lowered, to meet ABI requirements
   setOperationAction(ISD::RET               , MVT::Other, Custom);
@@ -605,6 +606,36 @@ static SDOperand LowerConstantPool(SDOperand Op, SelectionDAG &DAG) {
   return Lo;
 }
 
+static SDOperand LowerJumpTable(SDOperand Op, SelectionDAG &DAG) {
+  JumpTableSDNode *JT = cast<JumpTableSDNode>(Op);
+  SDOperand JTI = DAG.getTargetJumpTable(JT->getIndex(), MVT::i32);
+  SDOperand Zero = DAG.getConstant(0, MVT::i32);
+  
+  const TargetMachine &TM = DAG.getTarget();
+  
+  // If this is a non-darwin platform, we don't support non-static relo models
+  // yet.
+  if (TM.getRelocationModel() == Reloc::Static ||
+      !TM.getSubtarget<PPCSubtarget>().isDarwin()) {
+    // Generate non-pic code that has direct accesses to the constant pool.
+    // The address of the global is just (hi(&g)+lo(&g)).
+    SDOperand Hi = DAG.getNode(PPCISD::Hi, MVT::i32, JTI, Zero);
+    SDOperand Lo = DAG.getNode(PPCISD::Lo, MVT::i32, JTI, Zero);
+    return DAG.getNode(ISD::ADD, MVT::i32, Hi, Lo);
+  }
+  
+  SDOperand Hi = DAG.getNode(PPCISD::Hi, MVT::i32, JTI, Zero);
+  if (TM.getRelocationModel() == Reloc::PIC) {
+    // With PIC, the first instruction is actually "GR+hi(&G)".
+    Hi = DAG.getNode(ISD::ADD, MVT::i32,
+                     DAG.getNode(PPCISD::GlobalBaseReg, MVT::i32), Hi);
+  }
+  
+  SDOperand Lo = DAG.getNode(PPCISD::Lo, MVT::i32, JTI, Zero);
+  Lo = DAG.getNode(ISD::ADD, MVT::i32, Hi, Lo);
+  return Lo;
+}
+
 static SDOperand LowerGlobalAddress(SDOperand Op, SelectionDAG &DAG) {
   GlobalAddressSDNode *GSDN = cast<GlobalAddressSDNode>(Op);
   GlobalValue *GV = GSDN->getGlobal();
@@ -1652,6 +1683,7 @@ SDOperand PPCTargetLowering::LowerOperation(SDOperand Op, SelectionDAG &DAG) {
   default: assert(0 && "Wasn't expecting to be able to lower this!"); 
   case ISD::ConstantPool:       return LowerConstantPool(Op, DAG);
   case ISD::GlobalAddress:      return LowerGlobalAddress(Op, DAG);
+  case ISD::JumpTable:          return LowerJumpTable(Op, DAG);
   case ISD::SETCC:              return LowerSETCC(Op, DAG);
   case ISD::VASTART:            return LowerVASTART(Op, DAG, VarArgsFrameIndex);
   case ISD::RET:                return LowerRET(Op, DAG);
index 449c3bd9cde4513ecf5367245a0d935eae7afd4e..8333873f082ba2c83311554ed8c1c8702238eee7 100644 (file)
@@ -702,7 +702,7 @@ def MTCTR : XFXForm_7_ext<31, 467, 9, (ops GPRC:$rS), "mtctr $rS", SprMTSPR>,
 
 def MTLR  : XFXForm_7_ext<31, 467, 8, (ops GPRC:$rS), "mtlr $rS", SprMTSPR>,
             PPC970_DGroup_First, PPC970_Unit_FXU;
-def MFLR  : XFXForm_1_ext<31, 339, 8, (ops GPRC:$rT), "mflr $rT",  SprMFSPR>,
+def MFLR  : XFXForm_1_ext<31, 339, 8, (ops GPRC:$rT), "mflr $rT", SprMFSPR>,
             PPC970_DGroup_First, PPC970_Unit_FXU;
 
 // Move to/from VRSAVE: despite being a SPR, the VRSAVE register is renamed like
@@ -1015,10 +1015,14 @@ def : Pat<(PPChi tglobaladdr:$in, 0), (LIS tglobaladdr:$in)>;
 def : Pat<(PPClo tglobaladdr:$in, 0), (LI tglobaladdr:$in)>;
 def : Pat<(PPChi tconstpool:$in, 0), (LIS tconstpool:$in)>;
 def : Pat<(PPClo tconstpool:$in, 0), (LI tconstpool:$in)>;
+def : Pat<(PPChi tjumptable:$in, 0), (LIS tjumptable:$in)>;
+def : Pat<(PPClo tjumptable:$in, 0), (LI tjumptable:$in)>;
 def : Pat<(add GPRC:$in, (PPChi tglobaladdr:$g, 0)),
           (ADDIS GPRC:$in, tglobaladdr:$g)>;
 def : Pat<(add GPRC:$in, (PPChi tconstpool:$g, 0)),
           (ADDIS GPRC:$in, tconstpool:$g)>;
+def : Pat<(add GPRC:$in, (PPChi tjumptable:$g, 0)),
+          (ADDIS GPRC:$in, tjumptable:$g)>;
 
 // Fused negative multiply subtract, alternate pattern
 def : Pat<(fsub F8RC:$B, (fmul F8RC:$A, F8RC:$C)),
index 4565a997e274472a363dfc6b2b1bfe81cc288d58..dc1ab545d768966ca0804ee019d8e6e3087e587c 100644 (file)
@@ -163,13 +163,9 @@ void SparcAsmPrinter::printOperand(const MachineInstr *MI, int opNum) {
   case MachineOperand::MO_UnextendedImmed:
     O << (int)MO.getImmedValue();
     break;
-  case MachineOperand::MO_MachineBasicBlock: {
-    MachineBasicBlock *MBBOp = MO.getMachineBasicBlock();
-    O << ".LBB" << Mang->getValueName(MBBOp->getParent()->getFunction())
-      << "_" << MBBOp->getNumber () << "\t! "
-      << MBBOp->getBasicBlock ()->getName ();
+  case MachineOperand::MO_MachineBasicBlock:
+    printBasicBlockLabel(MO.getMachineBasicBlock());
     return;
-  }
   case MachineOperand::MO_PCRelativeDisp:
     std::cerr << "Shouldn't use addPCDisp() when building Sparc MachineInstrs";
     abort ();
index 03902382c4bd6931fda5e34201b597ff7d1a7f0e..a910b3e0473e888bb7571cffb5b19858de99d0bd 100644 (file)
@@ -167,6 +167,7 @@ SparcTargetLowering::SparcTargetLowering(TargetMachine &TM)
   
   // Sparc doesn't have BRCOND either, it has BR_CC.
   setOperationAction(ISD::BRCOND, MVT::Other, Expand);
+  setOperationAction(ISD::BRIND, MVT::i32, Expand);
   setOperationAction(ISD::BR_CC, MVT::i32, Custom);
   setOperationAction(ISD::BR_CC, MVT::f32, Custom);
   setOperationAction(ISD::BR_CC, MVT::f64, Custom);
index 61283ae2dfba35cee1c0f69685e136f92c40e575..f37e53c715597552beaabd0fddcdc4493353a2f5 100644 (file)
@@ -150,6 +150,10 @@ def SDTBrcond : SDTypeProfile<0, 2, [ // brcond
   SDTCisInt<0>, SDTCisVT<1, OtherVT>
 ]>;
 
+def SDTBrind : SDTypeProfile<0, 1, [ // brind
+  SDTCisPtrTy<0>
+]>;
+
 def SDTRet : SDTypeProfile<0, 0, []>; // ret
 
 def SDTLoad : SDTypeProfile<1, 1, [ // load
@@ -217,6 +221,10 @@ def constpool   : SDNode<"ISD::ConstantPool",         SDTPtrLeaf, [],
                          "ConstantPoolSDNode">;
 def tconstpool  : SDNode<"ISD::TargetConstantPool",   SDTPtrLeaf, [],
                          "ConstantPoolSDNode">;
+def jumptable   : SDNode<"ISD::JumpTable",            SDTPtrLeaf, [],
+                         "JumpTableSDNode">;
+def tjumptable  : SDNode<"ISD::TargetJumpTable",      SDTPtrLeaf, [],
+                         "JumpTableSDNode">;
 def frameindex  : SDNode<"ISD::FrameIndex",           SDTPtrLeaf, [],
                          "FrameIndexSDNode">;
 def tframeindex : SDNode<"ISD::TargetFrameIndex",     SDTPtrLeaf, [],
@@ -293,6 +301,7 @@ def select     : SDNode<"ISD::SELECT"     , SDTSelect>;
 def selectcc   : SDNode<"ISD::SELECT_CC"  , SDTSelectCC>;
 
 def brcond     : SDNode<"ISD::BRCOND"     , SDTBrcond, [SDNPHasChain]>;
+def brind      : SDNode<"ISD::BRIND"      , SDTBrind,  [SDNPHasChain]>;
 def br         : SDNode<"ISD::BR"         , SDTBr,     [SDNPHasChain]>;
 def ret        : SDNode<"ISD::RET"        , SDTRet,    [SDNPHasChain]>;
 
index 5a3490a703457b423f8b599785ec95407244f87f..e3c48180853d40efb141b55f9b598729fcaf072d 100755 (executable)
@@ -38,6 +38,9 @@ bool X86ATTAsmPrinter::runOnMachineFunction(MachineFunction &MF) {
   // Print out constants referenced by the function
   EmitConstantPool(MF.getConstantPool());
 
+  // Print out jump tables referenced by the function
+  EmitJumpTableInfo(MF.getJumpTableInfo());
+  
   // Print out labels for the function.
   const Function *F = MF.getFunction();
   switch (F->getLinkage()) {
@@ -120,18 +123,21 @@ void X86ATTAsmPrinter::printOperand(const MachineInstr *MI, unsigned OpNo,
       O << '$';
     O << (int)MO.getImmedValue();
     return;
-  case MachineOperand::MO_MachineBasicBlock: {
-    MachineBasicBlock *MBBOp = MO.getMachineBasicBlock();
-    O << PrivateGlobalPrefix << "BB"
-      << Mang->getValueName(MBBOp->getParent()->getFunction())
-      << "_" << MBBOp->getNumber () << "\t# "
-      << MBBOp->getBasicBlock ()->getName ();
+  case MachineOperand::MO_MachineBasicBlock:
+    printBasicBlockLabel(MO.getMachineBasicBlock());
     return;
-  }
   case MachineOperand::MO_PCRelativeDisp:
     std::cerr << "Shouldn't use addPCDisp() when building X86 MachineInstrs";
     abort ();
     return;
+  case MachineOperand::MO_JumpTableIndex: {
+    bool isMemOp  = Modifier && !strcmp(Modifier, "mem");
+    if (!isMemOp) O << '$';
+    O << PrivateGlobalPrefix << "JTI" << getFunctionNumber() << "_"
+      << MO.getJumpTableIndex();
+    // FIXME: PIC relocation model
+    return;
+  }
   case MachineOperand::MO_ConstantPoolIndex: {
     bool isMemOp  = Modifier && !strcmp(Modifier, "mem");
     if (!isMemOp) O << '$';
index 990951ea7b8126fdb3dcffcd1cbe2319a428d226..ee1383e6c2e9be522aad8a354d49226775f298a4 100644 (file)
@@ -54,6 +54,7 @@ bool X86SharedAsmPrinter::doInitialization(Module &M) {
     ZeroDirective = "\t.space\t";  // ".space N" emits N zeros.
     PrivateGlobalPrefix = "L";     // Marker for constant pool idxs
     ConstantPoolSection = "\t.const\n";
+    JumpTableSection = "\t.const\n"; // FIXME: depends on PIC mode
     LCOMMDirective = "\t.lcomm\t";
     COMMDirectiveTakesAlignment = false;
     HasDotTypeDotSizeDirective = false;
@@ -205,6 +206,14 @@ bool X86SharedAsmPrinter::doFinalization(Module &M) {
   return false; // success
 }
 
+void X86SharedAsmPrinter::printBasicBlockLabel(const MachineBasicBlock *MBB) 
+     const {
+  O << PrivateGlobalPrefix << "BB" 
+  << Mang->getValueName(MBB->getParent()->getFunction())
+  << "_" << MBB->getNumber() << '\t' << CommentString
+  << MBB->getBasicBlock()->getName();
+}
+
 /// createX86CodePrinterPass - Returns a pass that prints the X86 assembly code
 /// for a MachineFunction to the given output stream, using the given target
 /// machine description.
index c4d67b6ac70431b8c5a4f9fa77fdb6ef1157acba..fa84c9ec132d89429d49a241afea9189162c57ca 100755 (executable)
@@ -88,6 +88,8 @@ struct X86SharedAsmPrinter : public AsmPrinter {
        MI->getOperand(Op+3).isGlobalAddress() ||
        MI->getOperand(Op+3).isConstantPoolIndex());
   }
+
+  virtual void printBasicBlockLabel(const MachineBasicBlock *MBB) const; 
 };
 
 } // end namespace llvm
index 51be7b82dec8522e7c7e563f0111fa6ef461a995..bac310cd6b5b932225329f9282260ee968027c77 100644 (file)
@@ -35,8 +35,8 @@ namespace {
   class Emitter : public MachineFunctionPass {
     const X86InstrInfo  *II;
     MachineCodeEmitter  &MCE;
-    std::map<const MachineBasicBlock*, unsigned> BasicBlockAddrs;
-    std::vector<std::pair<const MachineBasicBlock *, unsigned> > BBRefs;
+    std::map<MachineBasicBlock*, uint64_t> BasicBlockAddrs;
+    std::vector<std::pair<MachineBasicBlock *, unsigned> > BBRefs;
   public:
     explicit Emitter(MachineCodeEmitter &mce) : II(0), MCE(mce) {}
     Emitter(MachineCodeEmitter &mce, const X86InstrInfo& ii)
@@ -51,9 +51,8 @@ namespace {
     void emitInstruction(const MachineInstr &MI);
 
   private:
-    void emitBasicBlock(const MachineBasicBlock &MBB);
-
-    void emitPCRelativeBlockAddress(const MachineBasicBlock *BB);
+    void emitBasicBlock(MachineBasicBlock &MBB);
+    void emitPCRelativeBlockAddress(MachineBasicBlock *MBB);
     void emitPCRelativeValue(unsigned Address);
     void emitGlobalAddressForCall(GlobalValue *GV, bool isTailCall);
     void emitGlobalAddressForPtr(GlobalValue *GV, int Disp = 0);
@@ -84,8 +83,10 @@ bool Emitter::runOnMachineFunction(MachineFunction &MF) {
 
   MCE.startFunction(MF);
   MCE.emitConstantPool(MF.getConstantPool());
+  MCE.initJumpTableInfo(MF.getJumpTableInfo());
   for (MachineFunction::iterator I = MF.begin(), E = MF.end(); I != E; ++I)
     emitBasicBlock(*I);
+  MCE.emitJumpTableInfo(MF.getJumpTableInfo(), BasicBlockAddrs);
   MCE.finishFunction(MF);
 
   // Resolve all forward branches now...
@@ -99,7 +100,7 @@ bool Emitter::runOnMachineFunction(MachineFunction &MF) {
   return false;
 }
 
-void Emitter::emitBasicBlock(const MachineBasicBlock &MBB) {
+void Emitter::emitBasicBlock(MachineBasicBlock &MBB) {
   if (uint64_t Addr = MCE.getCurrentPCValue())
     BasicBlockAddrs[&MBB] = Addr;
 
@@ -119,11 +120,10 @@ void Emitter::emitPCRelativeValue(unsigned Address) {
 /// (because this is a forward branch), it keeps track of the information
 /// necessary to resolve this address later (and emits a dummy value).
 ///
-void Emitter::emitPCRelativeBlockAddress(const MachineBasicBlock *MBB) {
+void Emitter::emitPCRelativeBlockAddress(MachineBasicBlock *MBB) {
   // If this is a backwards branch, we already know the address of the target,
   // so just emit the value.
-  std::map<const MachineBasicBlock*, unsigned>::iterator I =
-    BasicBlockAddrs.find(MBB);
+  std::map<MachineBasicBlock*,uint64_t>::iterator I = BasicBlockAddrs.find(MBB);
   if (I != BasicBlockAddrs.end()) {
     emitPCRelativeValue(I->second);
   } else {
@@ -242,6 +242,8 @@ void Emitter::emitMemModRMByte(const MachineInstr &MI,
   } else if (Op3.isConstantPoolIndex()) {
     DispVal += MCE.getConstantPoolEntryAddress(Op3.getConstantPoolIndex());
     DispVal += Op3.getOffset();
+  } else if (Op3.isJumpTableIndex()) {
+    DispVal += MCE.getJumpTableEntryAddress(Op3.getJumpTableIndex());
   } else {
     DispVal = Op3.getImmedValue();
   }
@@ -445,6 +447,10 @@ void Emitter::emitInstruction(const MachineInstr &MI) {
         assert(sizeOfImm(Desc) == 4 &&
                "Don't know how to emit non-pointer values!");
         emitExternalSymbolAddress(MO1.getSymbolName(), false, false);
+      } else if (MO1.isJumpTableIndex()) {
+        assert(sizeOfImm(Desc) == 4 &&
+               "Don't know how to emit non-pointer values!");
+        emitConstant(MCE.getJumpTableEntryAddress(MO1.getJumpTableIndex()), 4);
       } else {
         emitConstant(MO1.getImmedValue(), sizeOfImm(Desc));
       }
index db2b5dd5c68965de8ce5687ca3c4c48490113dd0..3861fc35940256cfb4a91295b8764fe570d54818 100644 (file)
@@ -169,6 +169,7 @@ X86TargetLowering::X86TargetLowering(TargetMachine &TM)
   setOperationAction(ISD::RET             , MVT::Other, Custom);
   // Darwin ABI issue.
   setOperationAction(ISD::ConstantPool    , MVT::i32  , Custom);
+  setOperationAction(ISD::JumpTable       , MVT::i32  , Custom);
   setOperationAction(ISD::GlobalAddress   , MVT::i32  , Custom);
   setOperationAction(ISD::ExternalSymbol  , MVT::i32  , Custom);
   // 64-bit addm sub, shl, sra, srl (iff 32-bit x86)
@@ -2792,8 +2793,8 @@ SDOperand X86TargetLowering::LowerOperation(SDOperand Op, SelectionDAG &DAG) {
     return Chain;
   }
 
-  // ConstantPool, GlobalAddress, and ExternalSymbol are lowered as their
-  // target countpart wrapped in the X86ISD::Wrapper node. Suppose N is
+  // ConstantPool, JumpTable, GlobalAddress, and ExternalSymbol are lowered as 
+  // their target countpart wrapped in the X86ISD::Wrapper node. Suppose N is
   // one of the above mentioned nodes. It has to be wrapped because otherwise
   // Select(N) returns N. So the raw TargetGlobalAddress nodes, etc. can only
   // be used to form addressing mode. These wrapped nodes will be selected
@@ -2812,6 +2813,20 @@ SDOperand X86TargetLowering::LowerOperation(SDOperand Op, SelectionDAG &DAG) {
 
     return Result;
   }
+  case ISD::JumpTable: {
+    JumpTableSDNode *JT = cast<JumpTableSDNode>(Op);
+    SDOperand Result = DAG.getNode(X86ISD::Wrapper, getPointerTy(),
+                                   DAG.getTargetJumpTable(JT->getIndex(),
+                                                          getPointerTy()));
+    if (Subtarget->isTargetDarwin()) {
+      // With PIC, the address is actually $g + Offset.
+      if (getTargetMachine().getRelocationModel() == Reloc::PIC)
+        Result = DAG.getNode(ISD::ADD, getPointerTy(),
+                DAG.getNode(X86ISD::GlobalBaseReg, getPointerTy()), Result);    
+    }
+
+    return Result;
+  }
   case ISD::GlobalAddress: {
     GlobalValue *GV = cast<GlobalAddressSDNode>(Op)->getGlobal();
     SDOperand Result = DAG.getNode(X86ISD::Wrapper, getPointerTy(),
index 172f33e9019e177017f9b62f8b14271f519e28ad..84d824d8a0c3f38afb4c421fa01def9aea1279ea 100644 (file)
@@ -365,10 +365,18 @@ let isBranch = 1, isTerminator = 1, noResults = 1 in
   class IBr<bits<8> opcode, dag ops, string asm, list<dag> pattern> :
         I<opcode, RawFrm, ops, asm, pattern>;
 
-// Conditional branches
+// Indirect branches
 let isBarrier = 1 in
   def JMP : IBr<0xE9, (ops brtarget:$dst), "jmp $dst", [(br bb:$dst)]>;
 
+let isBranch = 1, isTerminator = 1, noResults = 1, isBarrier = 1 in {
+  def JMP32r     : I<0xFF, MRM4r, (ops R32:$dst), "jmp{l} {*}$dst",
+                     [(brind R32:$dst)]>;
+  def JMP32m     : I<0xFF, MRM4m, (ops i32mem:$dst), "jmp{l} {*}$dst",
+                     [(brind (loadi32 addr:$dst))]>;
+}
+
+// Conditional branches
 def JE  : IBr<0x84, (ops brtarget:$dst), "je $dst",
               [(X86brcond bb:$dst, X86_COND_E)]>, TB;
 def JNE : IBr<0x85, (ops brtarget:$dst), "jne $dst",
@@ -2302,16 +2310,20 @@ def DWARF_LABEL : I<0, Pseudo, (ops i32imm:$id),
 
 // ConstantPool GlobalAddress, ExternalSymbol
 def : Pat<(i32 (X86Wrapper tconstpool  :$dst)), (MOV32ri tconstpool  :$dst)>;
+def : Pat<(i32 (X86Wrapper tjumptable  :$dst)), (MOV32ri tjumptable  :$dst)>;
 def : Pat<(i32 (X86Wrapper tglobaladdr :$dst)), (MOV32ri tglobaladdr :$dst)>;
 def : Pat<(i32 (X86Wrapper texternalsym:$dst)), (MOV32ri texternalsym:$dst)>;
 
 def : Pat<(add R32:$src1, (X86Wrapper tconstpool:$src2)),
           (ADD32ri R32:$src1, tconstpool:$src2)>;
+def : Pat<(add R32:$src1, (X86Wrapper tjumptable:$src2)),
+          (ADD32ri R32:$src1, tjumptable:$src2)>;
 def : Pat<(add R32:$src1, (X86Wrapper tglobaladdr :$src2)),
           (ADD32ri R32:$src1, tglobaladdr:$src2)>;
 def : Pat<(add R32:$src1, (X86Wrapper texternalsym:$src2)),
           (ADD32ri R32:$src1, texternalsym:$src2)>;
 
+// FIXME: can you really ever store to a constant pool?
 def : Pat<(store (X86Wrapper tconstpool:$src), addr:$dst),
           (MOV32mi addr:$dst, tconstpool:$src)>;
 def : Pat<(store (X86Wrapper tglobaladdr:$src), addr:$dst),
index 718a95b9ab996ebf09bbf38701550ce2a8752453..5f758554b3628818878696019e33f08f940a943b 100755 (executable)
@@ -112,14 +112,9 @@ void X86IntelAsmPrinter::printOp(const MachineOperand &MO,
   case MachineOperand::MO_UnextendedImmed:
     O << (int)MO.getImmedValue();
     return;
-  case MachineOperand::MO_MachineBasicBlock: {
-    MachineBasicBlock *MBBOp = MO.getMachineBasicBlock();
-    O << PrivateGlobalPrefix << "BB"
-      << Mang->getValueName(MBBOp->getParent()->getFunction())
-      << "_" << MBBOp->getNumber () << "\t# "
-      << MBBOp->getBasicBlock ()->getName ();
+  case MachineOperand::MO_MachineBasicBlock:
+    printBasicBlockLabel(MO.getMachineBasicBlock());
     return;
-  }
   case MachineOperand::MO_PCRelativeDisp:
     assert(0 && "Shouldn't use addPCDisp() when building X86 MachineInstrs");
     abort ();
index e7ee71564c50ce2ffac6eedf5c058050d414b394..e81421119136ee5ae3fa823fd1bf94bac93442f3 100644 (file)
@@ -3225,6 +3225,7 @@ void DAGISelEmitter::EmitInstructionSelector(std::ostream &OS) {
      << "  case ISD::TargetConstant:\n"
      << "  case ISD::TargetConstantPool:\n"
      << "  case ISD::TargetFrameIndex:\n"
+     << "  case ISD::TargetJumpTable:\n"
      << "  case ISD::TargetGlobalAddress: {\n"
      << "    Result = N;\n"
      << "    return;\n"