Changes in directory llvm/lib/CodeGen/SelectionDAG:
SelectionDAGISel.cpp updated: 1.299 -> 1.300 --- Log message: Turn conditions like x<Y|z==q into multiple blocks. This compiles Regression/CodeGen/X86/or-branch.ll into: _foo: subl $12, %esp call L_bar$stub movl 20(%esp), %eax movl 16(%esp), %ecx cmpl $5, %eax jl LBB1_1 #cond_true LBB1_3: #entry testl %ecx, %ecx jne LBB1_2 #UnifiedReturnBlock LBB1_1: #cond_true call L_bar$stub addl $12, %esp ret LBB1_2: #UnifiedReturnBlock addl $12, %esp ret instead of: _foo: subl $12, %esp call L_bar$stub movl 20(%esp), %eax movl 16(%esp), %ecx cmpl $4, %eax setg %al testl %ecx, %ecx setne %cl testb %cl, %al jne LBB1_2 #UnifiedReturnBlock LBB1_1: #cond_true call L_bar$stub addl $12, %esp ret LBB1_2: #UnifiedReturnBlock addl $12, %esp ret And on ppc to: cmpwi cr0, r29, 5 blt cr0, LBB1_1 ;cond_true LBB1_3: ;entry cmplwi cr0, r30, 0 bne cr0, LBB1_2 ;UnifiedReturnBlock instead of: cmpwi cr7, r4, 4 mfcr r2 addic r4, r3, -1 subfe r30, r4, r3 rlwinm r29, r2, 30, 31, 31 and r2, r29, r30 cmplwi cr0, r2, 0 bne cr0, LBB1_2 ;UnifiedReturnBlock --- Diffs of the changes: (+185 -19) SelectionDAGISel.cpp | 204 ++++++++++++++++++++++++++++++++++++++++++++++----- 1 files changed, 185 insertions(+), 19 deletions(-) Index: llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp diff -u llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp:1.299 llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp:1.300 --- llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp:1.299 Thu Oct 26 01:15:43 2006 +++ llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp Fri Oct 27 16:36:01 2006 @@ -184,6 +184,12 @@ unsigned MakeReg(MVT::ValueType VT) { return RegMap->createVirtualRegister(TLI.getRegClassFor(VT)); } + + /// isExportedInst - Return true if the specified value is an instruction + /// exported from its block. + bool isExportedInst(const Value *V) { + return ValueMap.count(V); + } unsigned CreateRegForValue(const Value *V); @@ -203,6 +209,7 @@ BasicBlock *BB = I->getParent(); for (Value::use_iterator UI = I->use_begin(), E = I->use_end(); UI != E; ++UI) if (cast<Instruction>(*UI)->getParent() != BB || isa<PHINode>(*UI) || + // FIXME: Remove switchinst special case. isa<SwitchInst>(*UI)) return true; return false; @@ -448,6 +455,8 @@ return Root; } + SDOperand CopyValueToVirtualRegister(Value *V, unsigned Reg); + void visit(Instruction &I) { visit(I.getOpcode(), I); } void visit(unsigned Opcode, User &I) { @@ -485,6 +494,11 @@ std::set<unsigned> &OutputRegs, std::set<unsigned> &InputRegs); + void FindMergedConditions(Value *Cond, MachineBasicBlock *TBB, + MachineBasicBlock *FBB, MachineBasicBlock *CurBB, + unsigned Opc); + void ExportFromCurrentBlock(Value *V); + // Terminator instructions. void visitRet(ReturnInst &I); void visitBr(BranchInst &I); @@ -770,6 +784,128 @@ &NewValues[0], NewValues.size())); } +/// ExportFromCurrentBlock - If this condition isn't known to be exported from +/// the current basic block, add it to ValueMap now so that we'll get a +/// CopyTo/FromReg. +void SelectionDAGLowering::ExportFromCurrentBlock(Value *V) { + // No need to export constants. + if (!isa<Instruction>(V) && !isa<Argument>(V)) return; + + // Already exported? + if (FuncInfo.isExportedInst(V)) return; + + unsigned Reg = FuncInfo.InitializeRegForValue(V); + PendingLoads.push_back(CopyValueToVirtualRegister(V, Reg)); +} + +/// FindMergedConditions - If Cond is an expression like +void SelectionDAGLowering::FindMergedConditions(Value *Cond, + MachineBasicBlock *TBB, + MachineBasicBlock *FBB, + MachineBasicBlock *CurBB, + unsigned Opc) { + // FIXME: HANDLE AND. + // FIXME: HANDLE NOT + + // If this node is not part of the or/and tree, emit it as a branch. + BinaryOperator *BOp = dyn_cast<BinaryOperator>(Cond); + + if (!BOp || (unsigned)BOp->getOpcode() != Opc || !BOp->hasOneUse() || + BOp->getParent() != CurBB->getBasicBlock()) { + const BasicBlock *BB = CurBB->getBasicBlock(); + + // If the leaf of the tree is a setcond inst, merge the condition into the + // caseblock. + if (BOp && isa<SetCondInst>(BOp) && + // The operands of the setcc have to be in this block. We don't know + // how to export them from some other block. + (!isa<Instruction>(BOp->getOperand(0)) || + cast<Instruction>(BOp->getOperand(0))->getParent() == BB || + FuncInfo.isExportedInst(BOp->getOperand(0))) && + (!isa<Instruction>(BOp->getOperand(1)) || + cast<Instruction>(BOp->getOperand(1))->getParent() == BB || + FuncInfo.isExportedInst(BOp->getOperand(1)))) { + ExportFromCurrentBlock(BOp->getOperand(0)); + ExportFromCurrentBlock(BOp->getOperand(1)); + + ISD::CondCode SignCond, UnsCond, FPCond, Condition; + switch (BOp->getOpcode()) { + default: assert(0 && "Unknown setcc opcode!"); + case Instruction::SetEQ: + SignCond = ISD::SETEQ; + UnsCond = ISD::SETEQ; + FPCond = ISD::SETOEQ; + break; + case Instruction::SetNE: + SignCond = ISD::SETNE; + UnsCond = ISD::SETNE; + FPCond = ISD::SETUNE; + break; + case Instruction::SetLE: + SignCond = ISD::SETLE; + UnsCond = ISD::SETULE; + FPCond = ISD::SETOLE; + break; + case Instruction::SetGE: + SignCond = ISD::SETGE; + UnsCond = ISD::SETUGE; + FPCond = ISD::SETOGE; + break; + case Instruction::SetLT: + SignCond = ISD::SETLT; + UnsCond = ISD::SETULT; + FPCond = ISD::SETOLT; + break; + case Instruction::SetGT: + SignCond = ISD::SETGT; + UnsCond = ISD::SETUGT; + FPCond = ISD::SETOGT; + break; + } + + const Type *OpType = BOp->getOperand(0)->getType(); + if (const PackedType *PTy = dyn_cast<PackedType>(OpType)) + OpType = PTy->getElementType(); + + if (!FiniteOnlyFPMath() && OpType->isFloatingPoint()) + Condition = FPCond; + else if (OpType->isUnsigned()) + Condition = UnsCond; + else + Condition = SignCond; + + SelectionDAGISel::CaseBlock CB(Condition, BOp->getOperand(0), + BOp->getOperand(1), TBB, FBB, CurBB); + SwitchCases.push_back(CB); + return; + } + + // Create a CaseBlock record representing this branch. + SelectionDAGISel::CaseBlock CB(ISD::SETEQ, Cond, ConstantBool::getTrue(), + TBB, FBB, CurBB); + SwitchCases.push_back(CB); + ExportFromCurrentBlock(Cond); + return; + } + + // Codegen X | Y as: + // jmp_if_X TBB + // TmpBB: + // jmp_if_Y TBB + // jmp FBB + // + // This requires creation of TmpBB after CurBB. + MachineFunction::iterator BBI = CurBB; + MachineBasicBlock *TmpBB = new MachineBasicBlock(CurBB->getBasicBlock()); + CurBB->getParent()->getBasicBlockList().insert(++BBI, TmpBB); + + // Emit the LHS condition. + FindMergedConditions(BOp->getOperand(0), TBB, TmpBB, CurBB, Opc); + + // Emit the RHS condition into TmpBB. + FindMergedConditions(BOp->getOperand(1), TBB, FBB, TmpBB, Opc); +} + void SelectionDAGLowering::visitBr(BranchInst &I) { // Update machine-CFG edges. MachineBasicBlock *Succ0MBB = FuncInfo.MBBMap[I.getSuccessor(0)]; @@ -796,9 +932,38 @@ // now. Value *CondVal = I.getCondition(); MachineBasicBlock *Succ1MBB = FuncInfo.MBBMap[I.getSuccessor(1)]; + + // If this is a series of conditions that are or'd or and'd together, emit + // this as a sequence of branches instead of setcc's with and/or operations. + // For example, instead of something like: + // cmp A, B + // C = seteq + // cmp D, E + // F = setle + // or C, F + // jnz foo + // Emit: + // cmp A, B + // je foo + // cmp D, E + // jle foo + // + if (BinaryOperator *BOp = dyn_cast<BinaryOperator>(CondVal)) { + if (BOp->hasOneUse() && + (/*BOp->getOpcode() == Instruction::And ||*/ + BOp->getOpcode() == Instruction::Or)) { + FindMergedConditions(BOp, Succ0MBB, Succ1MBB, CurMBB, BOp->getOpcode()); + //std::cerr << "FOUND: " << SwitchCases.size() << " merged conditions:\n"; + //I.getParent()->dump(); + + visitSwitchCase(SwitchCases[0]); + SwitchCases.erase(SwitchCases.begin()); + return; + } + } // Create a CaseBlock record representing this branch. - SelectionDAGISel::CaseBlock CB(ISD::SETEQ, CondVal, 0, + SelectionDAGISel::CaseBlock CB(ISD::SETEQ, CondVal, ConstantBool::getTrue(), Succ0MBB, Succ1MBB, CurMBB); // Use visitSwitchCase to actually insert the fast branch sequence for this // cond branch. @@ -811,12 +976,15 @@ SDOperand Cond; SDOperand CondLHS = getValue(CB.CmpLHS); - // If the CaseBlock has both LHS/RHS comparisons, build the setcc now, - // otherwise, just use the LHS value as a bool comparison value. - if (CB.CmpRHS) - Cond = DAG.getSetCC(MVT::i1, CondLHS, getValue(CB.CmpRHS), CB.CC); - else + // Build the setcc now, fold "(X == true)" to X and "(X == false)" to !X to + // handle common cases produced by branch lowering. + if (CB.CmpRHS == ConstantBool::getTrue() && CB.CC == ISD::SETEQ) Cond = CondLHS; + else if (CB.CmpRHS == ConstantBool::getFalse() && CB.CC == ISD::SETEQ) { + SDOperand True = DAG.getConstant(1, CondLHS.getValueType()); + Cond = DAG.getNode(ISD::XOR, CondLHS.getValueType(), CondLHS, True); + } else + Cond = DAG.getSetCC(MVT::i1, CondLHS, getValue(CB.CmpRHS), CB.CC); // Set NextBlock to be the MBB immediately after the current one, if any. // This is used to avoid emitting unnecessary branches to the next block. @@ -3385,10 +3553,9 @@ return true; } - -SDOperand SelectionDAGISel:: -CopyValueToVirtualRegister(SelectionDAGLowering &SDL, Value *V, unsigned Reg) { - SDOperand Op = SDL.getValue(V); +SDOperand SelectionDAGLowering::CopyValueToVirtualRegister(Value *V, + unsigned Reg) { + SDOperand Op = getValue(V); assert((Op.getOpcode() != ISD::CopyFromReg || cast<RegisterSDNode>(Op.getOperand(1))->getReg() != Reg) && "Copy from a reg to the same reg!"); @@ -3397,9 +3564,8 @@ // register use. MVT::ValueType SrcVT = Op.getValueType(); MVT::ValueType DestVT = TLI.getTypeToTransformTo(SrcVT); - SelectionDAG &DAG = SDL.DAG; if (SrcVT == DestVT) { - return DAG.getCopyToReg(SDL.getRoot(), Reg, Op); + return DAG.getCopyToReg(getRoot(), Reg, Op); } else if (SrcVT == MVT::Vector) { // Handle copies from generic vectors to registers. MVT::ValueType PTyElementVT, PTyLegalElementVT; @@ -3416,7 +3582,7 @@ // VEXTRACT_VECTOR_ELT'ing them, converting them to PTyLegalElementVT, then // copying them into output registers. SmallVector<SDOperand, 8> OutChains; - SDOperand Root = SDL.getRoot(); + SDOperand Root = getRoot(); for (unsigned i = 0; i != NE; ++i) { SDOperand Elt = DAG.getNode(ISD::VEXTRACT_VECTOR_ELT, PTyElementVT, Op, DAG.getConstant(i, TLI.getPointerTy())); @@ -3449,14 +3615,14 @@ Op = DAG.getNode(ISD::FP_EXTEND, DestVT, Op); else Op = DAG.getNode(ISD::ANY_EXTEND, DestVT, Op); - return DAG.getCopyToReg(SDL.getRoot(), Reg, Op); + return DAG.getCopyToReg(getRoot(), Reg, Op); } else { // The src value is expanded into multiple registers. SDOperand Lo = DAG.getNode(ISD::EXTRACT_ELEMENT, DestVT, Op, DAG.getConstant(0, TLI.getPointerTy())); SDOperand Hi = DAG.getNode(ISD::EXTRACT_ELEMENT, DestVT, Op, DAG.getConstant(1, TLI.getPointerTy())); - Op = DAG.getCopyToReg(SDL.getRoot(), Reg, Lo); + Op = DAG.getCopyToReg(getRoot(), Reg, Lo); return DAG.getCopyToReg(Op, Reg+1, Hi); } } @@ -3480,7 +3646,7 @@ // whereever we got it to the vreg that other BB's will reference it as. if (FuncInfo.ValueMap.count(AI)) { SDOperand Copy = - CopyValueToVirtualRegister(SDL, AI, FuncInfo.ValueMap[AI]); + SDL.CopyValueToVirtualRegister(AI, FuncInfo.ValueMap[AI]); UnorderedChains.push_back(Copy); } } @@ -3516,7 +3682,7 @@ std::map<const Value*, unsigned>::iterator VMI =FuncInfo.ValueMap.find(I); if (VMI != FuncInfo.ValueMap.end()) UnorderedChains.push_back( - CopyValueToVirtualRegister(SDL, I, VMI->second)); + SDL.CopyValueToVirtualRegister(I, VMI->second)); } // Handle PHI nodes in successor blocks. Emit code into the SelectionDAG to @@ -3553,7 +3719,7 @@ if (RegOut == 0) { RegOut = FuncInfo.CreateRegForValue(C); UnorderedChains.push_back( - CopyValueToVirtualRegister(SDL, C, RegOut)); + SDL.CopyValueToVirtualRegister(C, RegOut)); } Reg = RegOut; } else { @@ -3564,7 +3730,7 @@ "Didn't codegen value into a register!??"); Reg = FuncInfo.CreateRegForValue(PHIOp); UnorderedChains.push_back( - CopyValueToVirtualRegister(SDL, PHIOp, Reg)); + SDL.CopyValueToVirtualRegister(PHIOp, Reg)); } } _______________________________________________ llvm-commits mailing list llvm-commits@cs.uiuc.edu http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits