Changes in directory llvm/lib/CodeGen/SelectionDAG:
LegalizeDAG.cpp updated: 1.369 -> 1.370 ScheduleDAG.cpp updated: 1.81 -> 1.82 SelectionDAG.cpp updated: 1.301 -> 1.302 SelectionDAGISel.cpp updated: 1.223 -> 1.224 --- Log message: JumpTable support! What this represents is working asm and jit support for 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. --- Diffs of the changes: (+185 -8) LegalizeDAG.cpp | 20 ++++++- ScheduleDAG.cpp | 3 + SelectionDAG.cpp | 26 +++++++++ SelectionDAGISel.cpp | 144 ++++++++++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 185 insertions(+), 8 deletions(-) Index: llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp diff -u llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp:1.369 llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp:1.370 --- llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp:1.369 Wed Apr 19 18:17:50 2006 +++ llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp Sat Apr 22 13:53:45 2006 @@ -510,6 +510,7 @@ 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 @@ 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 @@ 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: llvm/lib/CodeGen/SelectionDAG/ScheduleDAG.cpp diff -u llvm/lib/CodeGen/SelectionDAG/ScheduleDAG.cpp:1.81 llvm/lib/CodeGen/SelectionDAG/ScheduleDAG.cpp:1.82 --- llvm/lib/CodeGen/SelectionDAG/ScheduleDAG.cpp:1.81 Fri Mar 24 01:15:07 2006 +++ llvm/lib/CodeGen/SelectionDAG/ScheduleDAG.cpp Sat Apr 22 13:53:45 2006 @@ -117,6 +117,9 @@ } 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: llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp diff -u llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp:1.301 llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp:1.302 --- llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp:1.301 Thu Apr 20 00:39:12 2006 +++ llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp Sat Apr 22 13:53:45 2006 @@ -387,6 +387,13 @@ 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 @@ 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 @@ 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 @@ 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 @@ // 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: llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp diff -u llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp:1.223 llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp:1.224 --- llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp:1.223 Fri Apr 21 12:16:16 2006 +++ llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp Sat Apr 22 13:53:45 2006 @@ -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 @@ /// 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 @@ 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 @@ // 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 @@ 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 @@ // 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 @@ 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 @@ // 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 @@ 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) { _______________________________________________ llvm-commits mailing list llvm-commits@cs.uiuc.edu http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits