namespace V8ISD {
enum {
FIRST_NUMBER = ISD::BUILTIN_OP_END+V8::INSTRUCTION_LIST_END,
- CMPICC, // Compare two GPR operands, set icc.
- CMPFCC, // Compare two FP operands, set fcc.
- BRICC, // Branch to dest on icc condition
- BRFCC, // Branch to dest on fcc condition
+ CMPICC, // Compare two GPR operands, set icc.
+ CMPFCC, // Compare two FP operands, set fcc.
+ BRICC, // Branch to dest on icc condition
+ BRFCC, // Branch to dest on fcc condition
+ SELECT_ICC, // Select between two values using the current ICC flags.
+ SELECT_FCC, // Select between two values using the current FCC flags.
- Hi, Lo, // Hi/Lo operations, typically on a global address.
+ Hi, Lo, // Hi/Lo operations, typically on a global address.
- 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.
-
- CALL, // A V8 call instruction.
- RET_FLAG, // Return with a flag operand.
+ FTOI, // FP to Int within a FP register.
+ ITOF, // Int to FP within a FP register.
+
+ CALL, // A V8 call instruction.
+ RET_FLAG, // Return with a flag operand.
};
}
+/// IntCondCCodeToICC - Convert a DAG integer condition code to a SPARC ICC
+/// condition.
+static V8CC::CondCodes IntCondCCodeToICC(ISD::CondCode CC) {
+ switch (CC) {
+ default: assert(0 && "Unknown integer condition code!");
+ case ISD::SETEQ: return V8CC::ICC_E;
+ case ISD::SETNE: return V8CC::ICC_NE;
+ case ISD::SETLT: return V8CC::ICC_L;
+ case ISD::SETGT: return V8CC::ICC_G;
+ case ISD::SETLE: return V8CC::ICC_LE;
+ case ISD::SETGE: return V8CC::ICC_GE;
+ case ISD::SETULT: return V8CC::ICC_CS;
+ case ISD::SETULE: return V8CC::ICC_LEU;
+ case ISD::SETUGT: return V8CC::ICC_GU;
+ case ISD::SETUGE: return V8CC::ICC_CC;
+ }
+}
+
+/// FPCondCCodeToFCC - Convert a DAG floatingp oint condition code to a SPARC
+/// FCC condition.
+static V8CC::CondCodes FPCondCCodeToFCC(ISD::CondCode CC) {
+ switch (CC) {
+ default: assert(0 && "Unknown fp condition code!");
+ case ISD::SETEQ: return V8CC::FCC_E;
+ case ISD::SETNE: return V8CC::FCC_NE;
+ case ISD::SETLT: return V8CC::FCC_L;
+ case ISD::SETGT: return V8CC::FCC_G;
+ case ISD::SETLE: return V8CC::FCC_LE;
+ case ISD::SETGE: return V8CC::FCC_GE;
+ case ISD::SETULT: return V8CC::FCC_UL;
+ case ISD::SETULE: return V8CC::FCC_ULE;
+ case ISD::SETUGT: return V8CC::FCC_UG;
+ case ISD::SETUGE: return V8CC::FCC_UGE;
+ case ISD::SETUO: return V8CC::FCC_U;
+ case ISD::SETO: return V8CC::FCC_O;
+ case ISD::SETONE: return V8CC::FCC_LG;
+ case ISD::SETUEQ: return V8CC::FCC_UE;
+ }
+}
+
namespace {
class SparcV8TargetLowering : public TargetLowering {
int VarArgsFrameOffset; // Frame offset to start of varargs area.
public:
SparcV8TargetLowering(TargetMachine &TM);
virtual SDOperand LowerOperation(SDOperand Op, SelectionDAG &DAG);
+
+ /// isMaskedValueZeroForTargetNode - Return true if 'Op & Mask' is known to
+ /// be zero. Op is expected to be a target specific node. Used by DAG
+ /// combiner.
+ virtual bool isMaskedValueZeroForTargetNode(const SDOperand &Op,
+ uint64_t Mask) const;
+
virtual std::vector<SDOperand>
LowerArguments(Function &F, SelectionDAG &DAG);
virtual std::pair<SDOperand, SDOperand>
setOperationAction(ISD::VAEND , MVT::Other, Expand);
setOperationAction(ISD::STACKSAVE , MVT::Other, Expand);
setOperationAction(ISD::STACKRESTORE , MVT::Other, Expand);
- setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i32, Expand);
+ setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i32 , Expand);
+ setOperationAction(ISD::ConstantFP, MVT::f64, Expand);
+ setOperationAction(ISD::ConstantFP, MVT::f32, Expand);
+
setStackPointerRegisterToSaveRestore(V8::O6);
+ if (TM.getSubtarget<SparcV8Subtarget>().isV9()) {
+ setOperationAction(ISD::CTPOP, MVT::i32, Legal);
+ }
+
computeRegisterProperties();
}
case V8ISD::CMPFCC: return "V8ISD::CMPFCC";
case V8ISD::BRICC: return "V8ISD::BRICC";
case V8ISD::BRFCC: return "V8ISD::BRFCC";
+ case V8ISD::SELECT_ICC: return "V8ISD::SELECT_ICC";
+ case V8ISD::SELECT_FCC: return "V8ISD::SELECT_FCC";
case V8ISD::Hi: return "V8ISD::Hi";
case V8ISD::Lo: return "V8ISD::Lo";
case V8ISD::FTOI: return "V8ISD::FTOI";
case V8ISD::ITOF: return "V8ISD::ITOF";
- case V8ISD::SELECT_ICC: return "V8ISD::SELECT_ICC";
- case V8ISD::SELECT_FCC: return "V8ISD::SELECT_FCC";
case V8ISD::CALL: return "V8ISD::CALL";
case V8ISD::RET_FLAG: return "V8ISD::RET_FLAG";
}
}
+/// isMaskedValueZeroForTargetNode - Return true if 'Op & Mask' is known to
+/// be zero. Op is expected to be a target specific node. Used by DAG
+/// combiner.
+bool SparcV8TargetLowering::
+isMaskedValueZeroForTargetNode(const SDOperand &Op, uint64_t Mask) const {
+ switch (Op.getOpcode()) {
+ default: return false;
+ case V8ISD::SELECT_ICC:
+ case V8ISD::SELECT_FCC:
+ assert(MVT::isInteger(Op.getValueType()) && "Not an integer select!");
+ // These operations are masked zero if both the left and the right are zero.
+ return MaskedValueIsZero(Op.getOperand(0), Mask) &&
+ MaskedValueIsZero(Op.getOperand(1), Mask);
+ }
+}
+
+
/// LowerArguments - V8 uses a very simple ABI, where all values are passed in
/// either one or two GPRs, including FP values. TODO: we should pass FP values
/// in FP registers for fastcc functions.
if (CurArgReg < ArgRegEnd) ++CurArgReg;
if (CurArgReg < ArgRegEnd) ++CurArgReg;
ArgValues.push_back(DAG.getNode(ISD::UNDEF, ObjectVT));
- } else if (CurArgReg == ArgRegEnd && ObjectVT == MVT::f64 &&
+ } else if (/* FIXME: Apparently this isn't safe?? */
+ 0 && CurArgReg == ArgRegEnd && ObjectVT == MVT::f64 &&
((CurArgReg-ArgRegs) & 1) == 0) {
// If this is a double argument and the whole thing lives on the stack,
// and the argument is aligned, load the double straight from the stack.
abort();
}
+// Look at LHS/RHS/CC and see if they are a lowered V8 setcc instruction. If so
+// set LHS/RHS and V8CC to the LHS/RHS of the setcc and V8CC to the condition.
+static void LookThroughSetCC(SDOperand &LHS, SDOperand &RHS,
+ ISD::CondCode CC, unsigned &V8CC) {
+ if (isa<ConstantSDNode>(RHS) && cast<ConstantSDNode>(RHS)->getValue() == 0 &&
+ CC == ISD::SETNE &&
+ ((LHS.getOpcode() == V8ISD::SELECT_ICC &&
+ LHS.getOperand(3).getOpcode() == V8ISD::CMPICC) ||
+ (LHS.getOpcode() == V8ISD::SELECT_FCC &&
+ LHS.getOperand(3).getOpcode() == V8ISD::CMPFCC)) &&
+ isa<ConstantSDNode>(LHS.getOperand(0)) &&
+ isa<ConstantSDNode>(LHS.getOperand(1)) &&
+ cast<ConstantSDNode>(LHS.getOperand(0))->getValue() == 1 &&
+ cast<ConstantSDNode>(LHS.getOperand(1))->getValue() == 0) {
+ SDOperand CMPCC = LHS.getOperand(3);
+ V8CC = cast<ConstantSDNode>(LHS.getOperand(2))->getValue();
+ LHS = CMPCC.getOperand(0);
+ RHS = CMPCC.getOperand(1);
+ }
+}
+
+
SDOperand SparcV8TargetLowering::
LowerOperation(SDOperand Op, SelectionDAG &DAG) {
switch (Op.getOpcode()) {
}
case ISD::ConstantPool: {
Constant *C = cast<ConstantPoolSDNode>(Op)->get();
- SDOperand CP = DAG.getTargetConstantPool(C, MVT::i32);
+ SDOperand CP = DAG.getTargetConstantPool(C, MVT::i32,
+ cast<ConstantPoolSDNode>(Op)->getAlignment());
SDOperand Hi = DAG.getNode(V8ISD::Hi, MVT::i32, CP);
SDOperand Lo = DAG.getNode(V8ISD::Lo, MVT::i32, CP);
return DAG.getNode(ISD::ADD, MVT::i32, Lo, Hi);
}
case ISD::BR_CC: {
SDOperand Chain = Op.getOperand(0);
- SDOperand CC = Op.getOperand(1);
+ ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(1))->get();
SDOperand LHS = Op.getOperand(2);
SDOperand RHS = Op.getOperand(3);
SDOperand Dest = Op.getOperand(4);
+ unsigned Opc, V8CC = ~0U;
+
+ // If this is a br_cc of a "setcc", and if the setcc got lowered into
+ // an CMP[IF]CC/SELECT_[IF]CC pair, find the original compared values.
+ LookThroughSetCC(LHS, RHS, CC, V8CC);
// Get the condition flag.
+ SDOperand CompareFlag;
if (LHS.getValueType() == MVT::i32) {
std::vector<MVT::ValueType> VTs;
VTs.push_back(MVT::i32);
std::vector<SDOperand> Ops;
Ops.push_back(LHS);
Ops.push_back(RHS);
- SDOperand Cond = DAG.getNode(V8ISD::CMPICC, VTs, Ops).getValue(1);
- return DAG.getNode(V8ISD::BRICC, MVT::Other, Chain, Dest, CC, Cond);
+ CompareFlag = DAG.getNode(V8ISD::CMPICC, VTs, Ops).getValue(1);
+ if (V8CC == ~0U) V8CC = IntCondCCodeToICC(CC);
+ Opc = V8ISD::BRICC;
} else {
- SDOperand Cond = DAG.getNode(V8ISD::CMPFCC, MVT::Flag, LHS, RHS);
- return DAG.getNode(V8ISD::BRFCC, MVT::Other, Chain, Dest, CC, Cond);
+ CompareFlag = DAG.getNode(V8ISD::CMPFCC, MVT::Flag, LHS, RHS);
+ if (V8CC == ~0U) V8CC = FPCondCCodeToFCC(CC);
+ Opc = V8ISD::BRFCC;
}
+ return DAG.getNode(Opc, MVT::Other, Chain, Dest,
+ DAG.getConstant(V8CC, MVT::i32), CompareFlag);
}
case ISD::SELECT_CC: {
SDOperand LHS = Op.getOperand(0);
SDOperand RHS = Op.getOperand(1);
- unsigned CC = cast<CondCodeSDNode>(Op.getOperand(4))->get();
+ ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(4))->get();
SDOperand TrueVal = Op.getOperand(2);
SDOperand FalseVal = Op.getOperand(3);
+ unsigned Opc, V8CC = ~0U;
+
+ // If this is a select_cc of a "setcc", and if the setcc got lowered into
+ // an CMP[IF]CC/SELECT_[IF]CC pair, find the original compared values.
+ LookThroughSetCC(LHS, RHS, CC, V8CC);
SDOperand CompareFlag;
- unsigned Opc;
if (LHS.getValueType() == MVT::i32) {
std::vector<MVT::ValueType> VTs;
VTs.push_back(LHS.getValueType()); // subcc returns a value
Ops.push_back(RHS);
CompareFlag = DAG.getNode(V8ISD::CMPICC, VTs, Ops).getValue(1);
Opc = V8ISD::SELECT_ICC;
+ if (V8CC == ~0U) V8CC = IntCondCCodeToICC(CC);
} else {
CompareFlag = DAG.getNode(V8ISD::CMPFCC, MVT::Flag, LHS, RHS);
Opc = V8ISD::SELECT_FCC;
+ if (V8CC == ~0U) V8CC = FPCondCCodeToFCC(CC);
}
return DAG.getNode(Opc, TrueVal.getValueType(), TrueVal, FalseVal,
- DAG.getConstant(CC, MVT::i32), CompareFlag);
+ DAG.getConstant(V8CC, MVT::i32), CompareFlag);
}
case ISD::VASTART: {
// vastart just stores the address of the VarArgsFrameIndex slot into the
SparcV8TargetLowering::InsertAtEndOfBasicBlock(MachineInstr *MI,
MachineBasicBlock *BB) {
unsigned BROpcode;
+ unsigned CC;
// 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;
- }
+ BROpcode = V8::BCOND;
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;
- }
+ BROpcode = V8::FBCOND;
break;
}
+
+ CC = (V8CC::CondCodes)MI->getOperand(3).getImmedValue();
// To "insert" a SELECT_CC instruction, we actually have to insert the diamond
// control-flow pattern. The incoming instruction knows the destination vreg
MachineBasicBlock *thisMBB = BB;
MachineBasicBlock *copy0MBB = new MachineBasicBlock(LLVM_BB);
MachineBasicBlock *sinkMBB = new MachineBasicBlock(LLVM_BB);
- BuildMI(BB, BROpcode, 1).addMBB(sinkMBB);
+ BuildMI(BB, BROpcode, 2).addMBB(sinkMBB).addImm(CC);
MachineFunction *F = BB->getParent();
F->getBasicBlockList().insert(It, copy0MBB);
F->getBasicBlockList().insert(It, sinkMBB);
namespace {
class SparcV8DAGToDAGISel : public SelectionDAGISel {
SparcV8TargetLowering V8Lowering;
+
+ /// Subtarget - Keep a pointer to the Sparc Subtarget around so that we can
+ /// make the right decision when generating code for different targets.
+ const SparcV8Subtarget &Subtarget;
public:
SparcV8DAGToDAGISel(TargetMachine &TM)
- : SelectionDAGISel(V8Lowering), V8Lowering(TM) {}
+ : SelectionDAGISel(V8Lowering), V8Lowering(TM),
+ Subtarget(TM.getSubtarget<SparcV8Subtarget>()) {
+ }
SDOperand Select(SDOperand Op);