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


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@31230 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Chris Lattner 2006-10-27 21:36:01 +00:00
parent d0fffc8f29
commit 571e434a34
2 changed files with 186 additions and 23 deletions

View File

@ -89,8 +89,7 @@ public:
TrueBB(truebb), FalseBB(falsebb), ThisBB(me) {}
// CC - the condition code to use for the case block's setcc node
ISD::CondCode CC;
// CmpLHS/CmpRHS - The LHS/RHS of the comparison to emit. If CmpRHS is
// null, CmpLHS is treated as a bool condition for the branch.
// CmpLHS/CmpRHS - The LHS/RHS of the comparison to emit.
Value *CmpLHS, *CmpRHS;
// TrueBB/FalseBB - the block to branch to if the setcc is true/false.
MachineBasicBlock *TrueBB, *FalseBB;
@ -128,8 +127,6 @@ protected:
private:
void SplitCritEdgesForPHIConstants(BasicBlock *BB);
SDOperand CopyValueToVirtualRegister(SelectionDAGLowering &SDL,
Value *V, unsigned Reg);
void SelectBasicBlock(BasicBlock *BB, MachineFunction &MF,
FunctionLoweringInfo &FuncInfo);

View File

@ -184,6 +184,12 @@ namespace llvm {
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 @@ static bool isUsedOutsideOfDefiningBlock(Instruction *I) {
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 @@ public:
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 @@ public:
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 @@ void SelectionDAGLowering::visitRet(ReturnInst &I) {
&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 @@ void SelectionDAGLowering::visitBr(BranchInst &I) {
// 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 @@ void SelectionDAGLowering::visitSwitchCase(SelectionDAGISel::CaseBlock &CB) {
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 @@ bool SelectionDAGISel::runOnFunction(Function &Fn) {
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 @@ CopyValueToVirtualRegister(SelectionDAGLowering &SDL, Value *V, unsigned Reg) {
// 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 @@ CopyValueToVirtualRegister(SelectionDAGLowering &SDL, Value *V, unsigned Reg) {
// 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 @@ CopyValueToVirtualRegister(SelectionDAGLowering &SDL, Value *V, unsigned Reg) {
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 @@ LowerArguments(BasicBlock *BB, SelectionDAGLowering &SDL,
// 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 @@ void SelectionDAGISel::BuildSelectionDAG(SelectionDAG &DAG, BasicBlock *LLVMBB,
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 @@ void SelectionDAGISel::BuildSelectionDAG(SelectionDAG &DAG, BasicBlock *LLVMBB,
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 @@ void SelectionDAGISel::BuildSelectionDAG(SelectionDAG &DAG, BasicBlock *LLVMBB,
"Didn't codegen value into a register!??");
Reg = FuncInfo.CreateRegForValue(PHIOp);
UnorderedChains.push_back(
CopyValueToVirtualRegister(SDL, PHIOp, Reg));
SDL.CopyValueToVirtualRegister(PHIOp, Reg));
}
}