From 3308449afc6f1b8b8536e544e53bc6751c91b4e3 Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Sun, 18 Dec 2005 08:13:54 +0000 Subject: [PATCH] Give V8 select_cc, in the spirit of the PPC backend git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@24823 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/Sparc/SparcISelDAGToDAG.cpp | 158 ++++++++++++++++++--- lib/Target/Sparc/SparcInstrInfo.td | 63 ++++++-- lib/Target/SparcV8/SparcV8ISelDAGToDAG.cpp | 158 ++++++++++++++++++--- lib/Target/SparcV8/SparcV8InstrInfo.td | 63 ++++++-- 4 files changed, 378 insertions(+), 64 deletions(-) diff --git a/lib/Target/Sparc/SparcISelDAGToDAG.cpp b/lib/Target/Sparc/SparcISelDAGToDAG.cpp index 7c7378e61be..56dba150439 100644 --- a/lib/Target/Sparc/SparcISelDAGToDAG.cpp +++ b/lib/Target/Sparc/SparcISelDAGToDAG.cpp @@ -16,6 +16,7 @@ #include "llvm/Function.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/SelectionDAG.h" #include "llvm/CodeGen/SelectionDAGISel.h" #include "llvm/CodeGen/SSARegMap.h" @@ -40,6 +41,9 @@ namespace V8ISD { FTOI, // FP to Int within a FP register. ITOF, // Int to FP within a FP register. + + SELECT_ICC, // Select between two values using the current ICC flags. + SELECT_FCC, // Select between two values using the current FCC flags. }; } @@ -66,6 +70,8 @@ namespace { virtual std::pair LowerFrameReturnAddress(bool isFrameAddr, SDOperand Chain, unsigned Depth, SelectionDAG &DAG); + virtual MachineBasicBlock *InsertAtEndOfBasicBlock(MachineInstr *MI, + MachineBasicBlock *MBB); }; } @@ -82,9 +88,9 @@ SparcV8TargetLowering::SparcV8TargetLowering(TargetMachine &TM) setOperationAction(ISD::ConstantPool , MVT::i32, Custom); // Sparc doesn't have sext_inreg, replace them with shl/sra - setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i16 , Expand); - setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i8 , Expand); - setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1 , Expand); + setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i16, Expand); + setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i8 , Expand); + setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1 , Expand); // Sparc has no REM operation. setOperationAction(ISD::UREM, MVT::i32, Expand); @@ -116,6 +122,10 @@ SparcV8TargetLowering::SparcV8TargetLowering(TargetMachine &TM) setOperationAction(ISD::BR_CC, MVT::f32, Custom); setOperationAction(ISD::BR_CC, MVT::f64, Custom); + setOperationAction(ISD::SELECT_CC, MVT::i32, Custom); + setOperationAction(ISD::SELECT_CC, MVT::f32, Custom); + setOperationAction(ISD::SELECT_CC, MVT::f64, Custom); + computeRegisterProperties(); } @@ -243,22 +253,6 @@ SDOperand SparcV8TargetLowering:: LowerOperation(SDOperand Op, SelectionDAG &DAG) { switch (Op.getOpcode()) { default: assert(0 && "Should not custom lower this!"); - case ISD::BR_CC: { - SDOperand Chain = Op.getOperand(0); - SDOperand CC = Op.getOperand(1); - SDOperand LHS = Op.getOperand(2); - SDOperand RHS = Op.getOperand(3); - SDOperand Dest = Op.getOperand(4); - - // Get the condition flag. - if (LHS.getValueType() == MVT::i32) { - SDOperand Cond = DAG.getNode(V8ISD::CMPICC, MVT::Flag, LHS, RHS); - return DAG.getNode(V8ISD::BRICC, MVT::Other, Chain, Dest, CC, Cond); - } else { - SDOperand Cond = DAG.getNode(V8ISD::CMPFCC, MVT::Flag, LHS, RHS); - return DAG.getNode(V8ISD::BRFCC, MVT::Other, Chain, Dest, CC, Cond); - } - } case ISD::GlobalAddress: { GlobalValue *GV = cast(Op)->getGlobal(); SDOperand GA = DAG.getTargetGlobalAddress(GV, MVT::i32); @@ -298,10 +292,134 @@ LowerOperation(SDOperand Op, SelectionDAG &DAG) { // Convert the int value to FP in an FP register. return DAG.getNode(V8ISD::ITOF, Op.getValueType(), Op); } + case ISD::BR_CC: { + SDOperand Chain = Op.getOperand(0); + SDOperand CC = Op.getOperand(1); + SDOperand LHS = Op.getOperand(2); + SDOperand RHS = Op.getOperand(3); + SDOperand Dest = Op.getOperand(4); + + // Get the condition flag. + if (LHS.getValueType() == MVT::i32) { + SDOperand Cond = DAG.getNode(V8ISD::CMPICC, MVT::Flag, LHS, RHS); + return DAG.getNode(V8ISD::BRICC, MVT::Other, Chain, Dest, CC, Cond); + } else { + SDOperand Cond = DAG.getNode(V8ISD::CMPFCC, MVT::Flag, LHS, RHS); + return DAG.getNode(V8ISD::BRFCC, MVT::Other, Chain, Dest, CC, Cond); + } + } + case ISD::SELECT_CC: { + SDOperand LHS = Op.getOperand(0); + SDOperand RHS = Op.getOperand(1); + unsigned CC = cast(Op.getOperand(4))->get(); + SDOperand TrueVal = Op.getOperand(2); + SDOperand FalseVal = Op.getOperand(3); + + unsigned Opc; + Opc = LHS.getValueType() == MVT::i32 ? V8ISD::CMPICC : V8ISD::CMPFCC; + SDOperand CompareFlag = DAG.getNode(Opc, MVT::Flag, LHS, RHS); + + Opc = LHS.getValueType() == MVT::i32 ? + V8ISD::SELECT_ICC : V8ISD::SELECT_FCC; + return DAG.getNode(Opc, TrueVal.getValueType(), TrueVal, FalseVal, + DAG.getConstant(CC, MVT::i32), CompareFlag); + } } } - +MachineBasicBlock * +SparcV8TargetLowering::InsertAtEndOfBasicBlock(MachineInstr *MI, + MachineBasicBlock *BB) { + unsigned BROpcode; + // Figure out the conditional branch opcode to use for this select_cc. + switch (MI->getOpcode()) { + default: assert(0 && "Unknown SELECT_CC!"); + case V8::SELECT_CC_Int_ICC: + case V8::SELECT_CC_FP_ICC: + case V8::SELECT_CC_DFP_ICC: + // Integer compare. + switch ((ISD::CondCode)MI->getOperand(3).getImmedValue()) { + default: assert(0 && "Unknown integer condition code!"); + case ISD::SETEQ: BROpcode = V8::BE; break; + case ISD::SETNE: BROpcode = V8::BNE; break; + case ISD::SETLT: BROpcode = V8::BL; break; + case ISD::SETGT: BROpcode = V8::BG; break; + case ISD::SETLE: BROpcode = V8::BLE; break; + case ISD::SETGE: BROpcode = V8::BGE; break; + case ISD::SETULT: BROpcode = V8::BCS; break; + case ISD::SETULE: BROpcode = V8::BLEU; break; + case ISD::SETUGT: BROpcode = V8::BGU; break; + case ISD::SETUGE: BROpcode = V8::BCC; break; + } + break; + case V8::SELECT_CC_Int_FCC: + case V8::SELECT_CC_FP_FCC: + case V8::SELECT_CC_DFP_FCC: + // FP compare. + switch ((ISD::CondCode)MI->getOperand(3).getImmedValue()) { + default: assert(0 && "Unknown fp condition code!"); + case ISD::SETEQ: BROpcode = V8::FBE; break; + case ISD::SETNE: BROpcode = V8::FBNE; break; + case ISD::SETLT: BROpcode = V8::FBL; break; + case ISD::SETGT: BROpcode = V8::FBG; break; + case ISD::SETLE: BROpcode = V8::FBLE; break; + case ISD::SETGE: BROpcode = V8::FBGE; break; + case ISD::SETULT: BROpcode = V8::FBUL; break; + case ISD::SETULE: BROpcode = V8::FBULE; break; + case ISD::SETUGT: BROpcode = V8::FBUG; break; + case ISD::SETUGE: BROpcode = V8::FBUGE; break; + case ISD::SETUO: BROpcode = V8::FBU; break; + case ISD::SETO: BROpcode = V8::FBO; break; + case ISD::SETONE: BROpcode = V8::FBLG; break; + case ISD::SETUEQ: BROpcode = V8::FBUE; break; + } + break; + } + + // 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 = ... + // [f]bCC copy1MBB + // fallthrough --> copy0MBB + MachineBasicBlock *thisMBB = BB; + MachineBasicBlock *copy0MBB = new MachineBasicBlock(LLVM_BB); + MachineBasicBlock *sinkMBB = new MachineBasicBlock(LLVM_BB); + BuildMI(BB, BROpcode, 1).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, V8::PHI, 4, MI->getOperand(0).getReg()) + .addReg(MI->getOperand(2).getReg()).addMBB(copy0MBB) + .addReg(MI->getOperand(1).getReg()).addMBB(thisMBB); + + delete MI; // The pseudo instruction is gone now. + return BB; +} + //===----------------------------------------------------------------------===// // Instruction Selector Implementation //===----------------------------------------------------------------------===// diff --git a/lib/Target/Sparc/SparcInstrInfo.td b/lib/Target/Sparc/SparcInstrInfo.td index fe638ea6bf0..545b8923ed6 100644 --- a/lib/Target/Sparc/SparcInstrInfo.td +++ b/lib/Target/Sparc/SparcInstrInfo.td @@ -77,7 +77,10 @@ def SDTV8cmpfcc : SDTypeProfile<1, 2, [SDTCisVT<0, FlagVT>, SDTCisFP<1>, SDTCisSameAs<1, 2>]>; def SDTV8brcc : SDTypeProfile<0, 3, [SDTCisVT<0, OtherVT>, SDTCisVT<1, OtherVT>, - SDTCisVT<2, FlagVT>]>; + SDTCisVT<2, FlagVT>]>; +def SDTV8selectcc : +SDTypeProfile<1, 4, [SDTCisSameAs<0, 1>, SDTCisSameAs<1, 2>, + SDTCisVT<3, i32>, SDTCisVT<4, FlagVT>]>; def V8cmpicc : SDNode<"V8ISD::CMPICC", SDTV8cmpicc>; def V8cmpfcc : SDNode<"V8ISD::CMPFCC", SDTV8cmpfcc>; @@ -90,25 +93,61 @@ def V8lo : SDNode<"V8ISD::Lo", SDTIntUnaryOp>; def V8ftoi : SDNode<"V8ISD::FTOI", SDTFPUnaryOp>; def V8itof : SDNode<"V8ISD::ITOF", SDTFPUnaryOp>; +def V8selecticc : SDNode<"V8ISD::SELECT_ICC", SDTV8selectcc>; +def V8selectfcc : SDNode<"V8ISD::SELECT_FCC", SDTV8selectcc>; + //===----------------------------------------------------------------------===// // Instructions //===----------------------------------------------------------------------===// // Pseudo instructions. -class PseudoInstV8 : InstV8 { +class Pseudo pattern> : InstV8 { let AsmString = asmstr; dag OperandList = ops; + let Pattern = pattern; +} +def PHI : Pseudo<(ops variable_ops), "PHI", []>; +def ADJCALLSTACKDOWN : Pseudo<(ops i32imm:$amt), "!ADJCALLSTACKDOWN $amt",[]>; +def ADJCALLSTACKUP : Pseudo<(ops i32imm:$amt), "!ADJCALLSTACKUP $amt", []>; +def IMPLICIT_DEF : Pseudo<(ops IntRegs:$dst), "!IMPLICIT_DEF $dst", []>; +def FpMOVD : Pseudo<(ops DFPRegs:$dst, DFPRegs:$src), + "!FpMOVD", []>; // pseudo 64-bit double move + +// SELECT_CC_* - Used to implement the SELECT_CC DAG operation. Expanded by the +// scheduler into a branch sequence. This has to handle all permutations of +// selection between i32/f32/f64 on ICC and FCC. +let usesCustomDAGSchedInserter = 1 in { // Expanded by the scheduler. + def SELECT_CC_Int_ICC + : Pseudo<(ops IntRegs:$dst, IntRegs:$T, IntRegs:$F, i32imm:$Cond), + "; SELECT_CC_Int_ICC PSEUDO!", + [(set IntRegs:$dst, (V8selecticc IntRegs:$T, IntRegs:$F, + imm:$Cond, ICC))]>; + def SELECT_CC_Int_FCC + : Pseudo<(ops IntRegs:$dst, IntRegs:$T, IntRegs:$F, i32imm:$Cond), + "; SELECT_CC_Int_FCC PSEUDO!", + [(set IntRegs:$dst, (V8selectfcc IntRegs:$T, IntRegs:$F, + imm:$Cond, FCC))]>; + def SELECT_CC_FP_ICC + : Pseudo<(ops FPRegs:$dst, FPRegs:$T, FPRegs:$F, i32imm:$Cond), + "; SELECT_CC_FP_ICC PSEUDO!", + [(set FPRegs:$dst, (V8selecticc FPRegs:$T, FPRegs:$F, + imm:$Cond, ICC))]>; + def SELECT_CC_FP_FCC + : Pseudo<(ops FPRegs:$dst, FPRegs:$T, FPRegs:$F, i32imm:$Cond), + "; SELECT_CC_FP_FCC PSEUDO!", + [(set FPRegs:$dst, (V8selectfcc FPRegs:$T, FPRegs:$F, + imm:$Cond, FCC))]>; + def SELECT_CC_DFP_ICC + : Pseudo<(ops DFPRegs:$dst, DFPRegs:$T, DFPRegs:$F, i32imm:$Cond), + "; SELECT_CC_DFP_ICC PSEUDO!", + [(set DFPRegs:$dst, (V8selecticc DFPRegs:$T, DFPRegs:$F, + imm:$Cond, ICC))]>; + def SELECT_CC_DFP_FCC + : Pseudo<(ops DFPRegs:$dst, DFPRegs:$T, DFPRegs:$F, i32imm:$Cond), + "; SELECT_CC_DFP_FCC PSEUDO!", + [(set DFPRegs:$dst, (V8selectfcc DFPRegs:$T, DFPRegs:$F, + imm:$Cond, FCC))]>; } -def PHI : PseudoInstV8<"PHI", (ops variable_ops)>; -def ADJCALLSTACKDOWN : PseudoInstV8<"!ADJCALLSTACKDOWN $amt", - (ops i32imm:$amt)>; -def ADJCALLSTACKUP : PseudoInstV8<"!ADJCALLSTACKUP $amt", - (ops i32imm:$amt)>; -//def IMPLICIT_USE : PseudoInstV8<"!IMPLICIT_USE",(ops variable_ops)>; -def IMPLICIT_DEF : PseudoInstV8<"!IMPLICIT_DEF $dst", - (ops IntRegs:$dst)>; -def FpMOVD : PseudoInstV8<"!FpMOVD", // pseudo 64-bit double move - (ops DFPRegs:$dst, DFPRegs:$src)>; // Section A.3 - Synthetic Instructions, p. 85 // special cases of JMPL: diff --git a/lib/Target/SparcV8/SparcV8ISelDAGToDAG.cpp b/lib/Target/SparcV8/SparcV8ISelDAGToDAG.cpp index 7c7378e61be..56dba150439 100644 --- a/lib/Target/SparcV8/SparcV8ISelDAGToDAG.cpp +++ b/lib/Target/SparcV8/SparcV8ISelDAGToDAG.cpp @@ -16,6 +16,7 @@ #include "llvm/Function.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/SelectionDAG.h" #include "llvm/CodeGen/SelectionDAGISel.h" #include "llvm/CodeGen/SSARegMap.h" @@ -40,6 +41,9 @@ namespace V8ISD { FTOI, // FP to Int within a FP register. ITOF, // Int to FP within a FP register. + + SELECT_ICC, // Select between two values using the current ICC flags. + SELECT_FCC, // Select between two values using the current FCC flags. }; } @@ -66,6 +70,8 @@ namespace { virtual std::pair LowerFrameReturnAddress(bool isFrameAddr, SDOperand Chain, unsigned Depth, SelectionDAG &DAG); + virtual MachineBasicBlock *InsertAtEndOfBasicBlock(MachineInstr *MI, + MachineBasicBlock *MBB); }; } @@ -82,9 +88,9 @@ SparcV8TargetLowering::SparcV8TargetLowering(TargetMachine &TM) setOperationAction(ISD::ConstantPool , MVT::i32, Custom); // Sparc doesn't have sext_inreg, replace them with shl/sra - setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i16 , Expand); - setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i8 , Expand); - setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1 , Expand); + setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i16, Expand); + setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i8 , Expand); + setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1 , Expand); // Sparc has no REM operation. setOperationAction(ISD::UREM, MVT::i32, Expand); @@ -116,6 +122,10 @@ SparcV8TargetLowering::SparcV8TargetLowering(TargetMachine &TM) setOperationAction(ISD::BR_CC, MVT::f32, Custom); setOperationAction(ISD::BR_CC, MVT::f64, Custom); + setOperationAction(ISD::SELECT_CC, MVT::i32, Custom); + setOperationAction(ISD::SELECT_CC, MVT::f32, Custom); + setOperationAction(ISD::SELECT_CC, MVT::f64, Custom); + computeRegisterProperties(); } @@ -243,22 +253,6 @@ SDOperand SparcV8TargetLowering:: LowerOperation(SDOperand Op, SelectionDAG &DAG) { switch (Op.getOpcode()) { default: assert(0 && "Should not custom lower this!"); - case ISD::BR_CC: { - SDOperand Chain = Op.getOperand(0); - SDOperand CC = Op.getOperand(1); - SDOperand LHS = Op.getOperand(2); - SDOperand RHS = Op.getOperand(3); - SDOperand Dest = Op.getOperand(4); - - // Get the condition flag. - if (LHS.getValueType() == MVT::i32) { - SDOperand Cond = DAG.getNode(V8ISD::CMPICC, MVT::Flag, LHS, RHS); - return DAG.getNode(V8ISD::BRICC, MVT::Other, Chain, Dest, CC, Cond); - } else { - SDOperand Cond = DAG.getNode(V8ISD::CMPFCC, MVT::Flag, LHS, RHS); - return DAG.getNode(V8ISD::BRFCC, MVT::Other, Chain, Dest, CC, Cond); - } - } case ISD::GlobalAddress: { GlobalValue *GV = cast(Op)->getGlobal(); SDOperand GA = DAG.getTargetGlobalAddress(GV, MVT::i32); @@ -298,10 +292,134 @@ LowerOperation(SDOperand Op, SelectionDAG &DAG) { // Convert the int value to FP in an FP register. return DAG.getNode(V8ISD::ITOF, Op.getValueType(), Op); } + case ISD::BR_CC: { + SDOperand Chain = Op.getOperand(0); + SDOperand CC = Op.getOperand(1); + SDOperand LHS = Op.getOperand(2); + SDOperand RHS = Op.getOperand(3); + SDOperand Dest = Op.getOperand(4); + + // Get the condition flag. + if (LHS.getValueType() == MVT::i32) { + SDOperand Cond = DAG.getNode(V8ISD::CMPICC, MVT::Flag, LHS, RHS); + return DAG.getNode(V8ISD::BRICC, MVT::Other, Chain, Dest, CC, Cond); + } else { + SDOperand Cond = DAG.getNode(V8ISD::CMPFCC, MVT::Flag, LHS, RHS); + return DAG.getNode(V8ISD::BRFCC, MVT::Other, Chain, Dest, CC, Cond); + } + } + case ISD::SELECT_CC: { + SDOperand LHS = Op.getOperand(0); + SDOperand RHS = Op.getOperand(1); + unsigned CC = cast(Op.getOperand(4))->get(); + SDOperand TrueVal = Op.getOperand(2); + SDOperand FalseVal = Op.getOperand(3); + + unsigned Opc; + Opc = LHS.getValueType() == MVT::i32 ? V8ISD::CMPICC : V8ISD::CMPFCC; + SDOperand CompareFlag = DAG.getNode(Opc, MVT::Flag, LHS, RHS); + + Opc = LHS.getValueType() == MVT::i32 ? + V8ISD::SELECT_ICC : V8ISD::SELECT_FCC; + return DAG.getNode(Opc, TrueVal.getValueType(), TrueVal, FalseVal, + DAG.getConstant(CC, MVT::i32), CompareFlag); + } } } - +MachineBasicBlock * +SparcV8TargetLowering::InsertAtEndOfBasicBlock(MachineInstr *MI, + MachineBasicBlock *BB) { + unsigned BROpcode; + // Figure out the conditional branch opcode to use for this select_cc. + switch (MI->getOpcode()) { + default: assert(0 && "Unknown SELECT_CC!"); + case V8::SELECT_CC_Int_ICC: + case V8::SELECT_CC_FP_ICC: + case V8::SELECT_CC_DFP_ICC: + // Integer compare. + switch ((ISD::CondCode)MI->getOperand(3).getImmedValue()) { + default: assert(0 && "Unknown integer condition code!"); + case ISD::SETEQ: BROpcode = V8::BE; break; + case ISD::SETNE: BROpcode = V8::BNE; break; + case ISD::SETLT: BROpcode = V8::BL; break; + case ISD::SETGT: BROpcode = V8::BG; break; + case ISD::SETLE: BROpcode = V8::BLE; break; + case ISD::SETGE: BROpcode = V8::BGE; break; + case ISD::SETULT: BROpcode = V8::BCS; break; + case ISD::SETULE: BROpcode = V8::BLEU; break; + case ISD::SETUGT: BROpcode = V8::BGU; break; + case ISD::SETUGE: BROpcode = V8::BCC; break; + } + break; + case V8::SELECT_CC_Int_FCC: + case V8::SELECT_CC_FP_FCC: + case V8::SELECT_CC_DFP_FCC: + // FP compare. + switch ((ISD::CondCode)MI->getOperand(3).getImmedValue()) { + default: assert(0 && "Unknown fp condition code!"); + case ISD::SETEQ: BROpcode = V8::FBE; break; + case ISD::SETNE: BROpcode = V8::FBNE; break; + case ISD::SETLT: BROpcode = V8::FBL; break; + case ISD::SETGT: BROpcode = V8::FBG; break; + case ISD::SETLE: BROpcode = V8::FBLE; break; + case ISD::SETGE: BROpcode = V8::FBGE; break; + case ISD::SETULT: BROpcode = V8::FBUL; break; + case ISD::SETULE: BROpcode = V8::FBULE; break; + case ISD::SETUGT: BROpcode = V8::FBUG; break; + case ISD::SETUGE: BROpcode = V8::FBUGE; break; + case ISD::SETUO: BROpcode = V8::FBU; break; + case ISD::SETO: BROpcode = V8::FBO; break; + case ISD::SETONE: BROpcode = V8::FBLG; break; + case ISD::SETUEQ: BROpcode = V8::FBUE; break; + } + break; + } + + // 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 = ... + // [f]bCC copy1MBB + // fallthrough --> copy0MBB + MachineBasicBlock *thisMBB = BB; + MachineBasicBlock *copy0MBB = new MachineBasicBlock(LLVM_BB); + MachineBasicBlock *sinkMBB = new MachineBasicBlock(LLVM_BB); + BuildMI(BB, BROpcode, 1).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, V8::PHI, 4, MI->getOperand(0).getReg()) + .addReg(MI->getOperand(2).getReg()).addMBB(copy0MBB) + .addReg(MI->getOperand(1).getReg()).addMBB(thisMBB); + + delete MI; // The pseudo instruction is gone now. + return BB; +} + //===----------------------------------------------------------------------===// // Instruction Selector Implementation //===----------------------------------------------------------------------===// diff --git a/lib/Target/SparcV8/SparcV8InstrInfo.td b/lib/Target/SparcV8/SparcV8InstrInfo.td index fe638ea6bf0..545b8923ed6 100644 --- a/lib/Target/SparcV8/SparcV8InstrInfo.td +++ b/lib/Target/SparcV8/SparcV8InstrInfo.td @@ -77,7 +77,10 @@ def SDTV8cmpfcc : SDTypeProfile<1, 2, [SDTCisVT<0, FlagVT>, SDTCisFP<1>, SDTCisSameAs<1, 2>]>; def SDTV8brcc : SDTypeProfile<0, 3, [SDTCisVT<0, OtherVT>, SDTCisVT<1, OtherVT>, - SDTCisVT<2, FlagVT>]>; + SDTCisVT<2, FlagVT>]>; +def SDTV8selectcc : +SDTypeProfile<1, 4, [SDTCisSameAs<0, 1>, SDTCisSameAs<1, 2>, + SDTCisVT<3, i32>, SDTCisVT<4, FlagVT>]>; def V8cmpicc : SDNode<"V8ISD::CMPICC", SDTV8cmpicc>; def V8cmpfcc : SDNode<"V8ISD::CMPFCC", SDTV8cmpfcc>; @@ -90,25 +93,61 @@ def V8lo : SDNode<"V8ISD::Lo", SDTIntUnaryOp>; def V8ftoi : SDNode<"V8ISD::FTOI", SDTFPUnaryOp>; def V8itof : SDNode<"V8ISD::ITOF", SDTFPUnaryOp>; +def V8selecticc : SDNode<"V8ISD::SELECT_ICC", SDTV8selectcc>; +def V8selectfcc : SDNode<"V8ISD::SELECT_FCC", SDTV8selectcc>; + //===----------------------------------------------------------------------===// // Instructions //===----------------------------------------------------------------------===// // Pseudo instructions. -class PseudoInstV8 : InstV8 { +class Pseudo pattern> : InstV8 { let AsmString = asmstr; dag OperandList = ops; + let Pattern = pattern; +} +def PHI : Pseudo<(ops variable_ops), "PHI", []>; +def ADJCALLSTACKDOWN : Pseudo<(ops i32imm:$amt), "!ADJCALLSTACKDOWN $amt",[]>; +def ADJCALLSTACKUP : Pseudo<(ops i32imm:$amt), "!ADJCALLSTACKUP $amt", []>; +def IMPLICIT_DEF : Pseudo<(ops IntRegs:$dst), "!IMPLICIT_DEF $dst", []>; +def FpMOVD : Pseudo<(ops DFPRegs:$dst, DFPRegs:$src), + "!FpMOVD", []>; // pseudo 64-bit double move + +// SELECT_CC_* - Used to implement the SELECT_CC DAG operation. Expanded by the +// scheduler into a branch sequence. This has to handle all permutations of +// selection between i32/f32/f64 on ICC and FCC. +let usesCustomDAGSchedInserter = 1 in { // Expanded by the scheduler. + def SELECT_CC_Int_ICC + : Pseudo<(ops IntRegs:$dst, IntRegs:$T, IntRegs:$F, i32imm:$Cond), + "; SELECT_CC_Int_ICC PSEUDO!", + [(set IntRegs:$dst, (V8selecticc IntRegs:$T, IntRegs:$F, + imm:$Cond, ICC))]>; + def SELECT_CC_Int_FCC + : Pseudo<(ops IntRegs:$dst, IntRegs:$T, IntRegs:$F, i32imm:$Cond), + "; SELECT_CC_Int_FCC PSEUDO!", + [(set IntRegs:$dst, (V8selectfcc IntRegs:$T, IntRegs:$F, + imm:$Cond, FCC))]>; + def SELECT_CC_FP_ICC + : Pseudo<(ops FPRegs:$dst, FPRegs:$T, FPRegs:$F, i32imm:$Cond), + "; SELECT_CC_FP_ICC PSEUDO!", + [(set FPRegs:$dst, (V8selecticc FPRegs:$T, FPRegs:$F, + imm:$Cond, ICC))]>; + def SELECT_CC_FP_FCC + : Pseudo<(ops FPRegs:$dst, FPRegs:$T, FPRegs:$F, i32imm:$Cond), + "; SELECT_CC_FP_FCC PSEUDO!", + [(set FPRegs:$dst, (V8selectfcc FPRegs:$T, FPRegs:$F, + imm:$Cond, FCC))]>; + def SELECT_CC_DFP_ICC + : Pseudo<(ops DFPRegs:$dst, DFPRegs:$T, DFPRegs:$F, i32imm:$Cond), + "; SELECT_CC_DFP_ICC PSEUDO!", + [(set DFPRegs:$dst, (V8selecticc DFPRegs:$T, DFPRegs:$F, + imm:$Cond, ICC))]>; + def SELECT_CC_DFP_FCC + : Pseudo<(ops DFPRegs:$dst, DFPRegs:$T, DFPRegs:$F, i32imm:$Cond), + "; SELECT_CC_DFP_FCC PSEUDO!", + [(set DFPRegs:$dst, (V8selectfcc DFPRegs:$T, DFPRegs:$F, + imm:$Cond, FCC))]>; } -def PHI : PseudoInstV8<"PHI", (ops variable_ops)>; -def ADJCALLSTACKDOWN : PseudoInstV8<"!ADJCALLSTACKDOWN $amt", - (ops i32imm:$amt)>; -def ADJCALLSTACKUP : PseudoInstV8<"!ADJCALLSTACKUP $amt", - (ops i32imm:$amt)>; -//def IMPLICIT_USE : PseudoInstV8<"!IMPLICIT_USE",(ops variable_ops)>; -def IMPLICIT_DEF : PseudoInstV8<"!IMPLICIT_DEF $dst", - (ops IntRegs:$dst)>; -def FpMOVD : PseudoInstV8<"!FpMOVD", // pseudo 64-bit double move - (ops DFPRegs:$dst, DFPRegs:$src)>; // Section A.3 - Synthetic Instructions, p. 85 // special cases of JMPL: