diff --git a/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp b/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp index 934f811fb145..4c06e3d97bc9 100644 --- a/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp +++ b/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp @@ -1400,8 +1400,17 @@ SDOperand PPC32DAGToDAGISel::Select(SDOperand Op) { Tmp.getValue(1)); break; } - - assert(0 && "Select_cc not implemented yet!"); + + SDOperand CCReg = SelectCC(Select(N->getOperand(0)), + Select(N->getOperand(1)), CC); + unsigned BROpc = getBCCForSetCC(CC); + + bool isFP = MVT::isFloatingPoint(N->getValueType(0)); + unsigned SelectCCOp = isFP ? PPC::SELECT_CC_FP : PPC::SELECT_CC_Int; + CurDAG->SelectNodeTo(N, SelectCCOp, N->getValueType(0), CCReg, + Select(N->getOperand(2)), Select(N->getOperand(3)), + getI32Imm(BROpc)); + break; } case ISD::CALLSEQ_START: diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp index d84552c5c0a6..beeb0f8c42a6 100644 --- a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp +++ b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp @@ -15,6 +15,7 @@ #include "PPC32TargetMachine.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/SelectionDAG.h" #include "llvm/Constants.h" #include "llvm/Function.h" @@ -553,3 +554,57 @@ LowerFrameReturnAddress(bool isFrameAddress, SDOperand Chain, unsigned Depth, assert(0 && "LowerFrameReturnAddress unimplemented"); abort(); } + +MachineBasicBlock * +PPC32TargetLowering::InsertAtEndOfBasicBlock(MachineInstr *MI, + MachineBasicBlock *BB) { + assert((MI->getOpcode() == PPC::SELECT_CC_Int || + MI->getOpcode() == PPC::SELECT_CC_FP) && + "Unexpected instr type to insert"); + + // To "insert" a SELECT_CC instruction, we actually have to insert the diamond + // control-flow pattern. The incoming instruction knows the destination vreg + // to set, the condition code register to branch on, the true/false values to + // select between, and a branch opcode to use. + const BasicBlock *LLVM_BB = BB->getBasicBlock(); + ilist::iterator It = BB; + ++It; + + // thisMBB: + // ... + // TrueVal = ... + // cmpTY ccX, r1, r2 + // bCC copy1MBB + // fallthrough --> copy0MBB + MachineBasicBlock *thisMBB = BB; + MachineBasicBlock *copy0MBB = new MachineBasicBlock(LLVM_BB); + MachineBasicBlock *sinkMBB = new MachineBasicBlock(LLVM_BB); + BuildMI(BB, MI->getOperand(4).getImmedValue(), 2) + .addReg(MI->getOperand(1).getReg()).addMBB(sinkMBB); + MachineFunction *F = BB->getParent(); + F->getBasicBlockList().insert(It, copy0MBB); + F->getBasicBlockList().insert(It, sinkMBB); + // Update machine-CFG edges + BB->addSuccessor(copy0MBB); + BB->addSuccessor(sinkMBB); + + // copy0MBB: + // %FalseValue = ... + // # fallthrough to sinkMBB + BB = copy0MBB; + + // Update machine-CFG edges + BB->addSuccessor(sinkMBB); + + // sinkMBB: + // %Result = phi [ %FalseValue, copy0MBB ], [ %TrueValue, thisMBB ] + // ... + BB = sinkMBB; + BuildMI(BB, PPC::PHI, 4, MI->getOperand(0).getReg()) + .addReg(MI->getOperand(3).getReg()).addMBB(copy0MBB) + .addReg(MI->getOperand(2).getReg()).addMBB(thisMBB); + + delete MI; // The pseudo instruction is gone now. + return BB; +} + diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.h b/llvm/lib/Target/PowerPC/PPCISelLowering.h index b2dd4daedde9..bdd55480b744 100644 --- a/llvm/lib/Target/PowerPC/PPCISelLowering.h +++ b/llvm/lib/Target/PowerPC/PPCISelLowering.h @@ -64,6 +64,9 @@ namespace llvm { virtual std::pair LowerFrameReturnAddress(bool isFrameAddr, SDOperand Chain, unsigned Depth, SelectionDAG &DAG); + + virtual MachineBasicBlock *InsertAtEndOfBasicBlock(MachineInstr *MI, + MachineBasicBlock *MBB); }; } diff --git a/llvm/lib/Target/PowerPC/PowerPCInstrInfo.td b/llvm/lib/Target/PowerPC/PowerPCInstrInfo.td index fc4566836ddd..595fd478007b 100644 --- a/llvm/lib/Target/PowerPC/PowerPCInstrInfo.td +++ b/llvm/lib/Target/PowerPC/PowerPCInstrInfo.td @@ -67,6 +67,16 @@ def ADJCALLSTACKUP : Pseudo<(ops u16imm), "; ADJCALLSTACKUP">; def IMPLICIT_DEF_GPR : Pseudo<(ops GPRC:$rD), "; $rD = IMPLICIT_DEF_GPRC">; def IMPLICIT_DEF_FP : Pseudo<(ops FPRC:$rD), "; %rD = IMPLICIT_DEF_FP">; +// SELECT_CC_* - Used to implement the SELECT_CC DAG operation. Expanded by the +// scheduler into a branch sequence. +let usesCustomDAGSchedInserter = 1 in { // Expanded by the scheduler. + def SELECT_CC_Int : Pseudo<(ops GPRC:$dst, CRRC:$cond, GPRC:$T, GPRC:$F, + i32imm:$BROPC), "; SELECT_CC PSEUDO!">; + def SELECT_CC_FP : Pseudo<(ops FPRC:$dst, CRRC:$cond, FPRC:$T, FPRC:$F, + i32imm:$BROPC), "; SELECT_CC PSEUDO!">; +} + + let Defs = [LR] in def MovePCtoLR : Pseudo<(ops piclabel:$label), "bl $label">;