setLoadXAction(ISD::EXTLOAD, MVT::f32, Expand);
+ setOperationAction(ISD::FP_TO_SINT, MVT::i32, Custom);
setOperationAction(ISD::SINT_TO_FP, MVT::i32, Custom);
+ setOperationAction(ISD::FP_TO_UINT, MVT::i32, Custom);
setOperationAction(ISD::UINT_TO_FP, MVT::i32, Custom);
setOperationAction(ISD::RET, MVT::Other, Custom);
setOperationAction(ISD::BR_CC, MVT::f32, Custom);
setOperationAction(ISD::BR_CC, MVT::f64, Custom);
+ setOperationAction(ISD::BRCOND, MVT::Other, Expand);
+
+ setOperationAction(ISD::SHL_PARTS, MVT::i32, Expand);
+ setOperationAction(ISD::SRA_PARTS, MVT::i32, Expand);
+ setOperationAction(ISD::SRL_PARTS, MVT::i32, Expand);
+ setOperationAction(ISD::SDIV, MVT::i32, Expand);
+ setOperationAction(ISD::UDIV, MVT::i32, Expand);
+ setOperationAction(ISD::SREM, MVT::i32, Expand);
+ setOperationAction(ISD::UREM, MVT::i32, Expand);
+
setOperationAction(ISD::VASTART, MVT::Other, Custom);
setOperationAction(ISD::VAEND, MVT::Other, Expand);
BR,
FSITOS,
+ FTOSIS,
FSITOD,
+ FTOSID,
FUITOS,
+ FTOUIS,
FUITOD,
+ FTOUID,
FMRRD,
}
}
-/// DAGCCToARMCC - Convert a DAG integer condition code to an ARM CC
-//Note: ARM doesn't have condition codes corresponding to the ordered
-//condition codes of LLVM. We use exception raising instructions so
-//that we can be sure that V == 0 and test only the rest of the expression.
-static ARMCC::CondCodes DAGCCToARMCC(ISD::CondCode CC) {
+/// DAGFPCCToARMCC - Convert a DAG fp condition code to an ARM CC
+// Unordered = !N & !Z & C & V = V
+// Ordered = N | Z | !C | !V = N | Z | !V
+static ARMCC::CondCodes DAGFPCCToARMCC(ISD::CondCode CC) {
switch (CC) {
default:
- std::cerr << "CC = " << CC << "\n";
- assert(0 && "Unknown condition code!");
- case ISD::SETUGT: return ARMCC::HI;
- case ISD::SETULE: return ARMCC::LS;
- case ISD::SETLE:
- case ISD::SETOLE: return ARMCC::LE;
- case ISD::SETLT:
- case ISD::SETOLT: return ARMCC::LT;
- case ISD::SETGT:
- case ISD::SETOGT: return ARMCC::GT;
- case ISD::SETNE: return ARMCC::NE;
+ assert(0 && "Unknown fp condition code!");
+// SETOEQ = (N | Z | !V) & Z = Z = EQ
case ISD::SETEQ:
case ISD::SETOEQ: return ARMCC::EQ;
+// SETOGT = (N | Z | !V) & !N & !Z = !V &!N &!Z = (N = V) & !Z = GT
+ case ISD::SETGT:
+ case ISD::SETOGT: return ARMCC::GT;
+// SETOGE = (N | Z | !V) & !N = (Z | !V) & !N = !V & !N = GE
case ISD::SETGE:
case ISD::SETOGE: return ARMCC::GE;
- case ISD::SETUGE: return ARMCC::CS;
+// SETOLT = (N | Z | !V) & N = N = MI
+ case ISD::SETLT:
+ case ISD::SETOLT: return ARMCC::MI;
+// SETOLE = (N | Z | !V) & (N | Z) = N | Z = !C | Z = LS
+ case ISD::SETLE:
+ case ISD::SETOLE: return ARMCC::LS;
+// SETONE = (N | Z | !V) & !Z = (N | !V) & Z = !V & Z = Z = NE
+ case ISD::SETNE:
+ case ISD::SETONE: return ARMCC::NE;
+// SETO = N | Z | !V = Z | !V = !V = VC
+ case ISD::SETO: return ARMCC::VC;
+// SETUO = V = VS
+ case ISD::SETUO: return ARMCC::VS;
+// SETUEQ = V | Z = ??
+// SETUGT = V | (!Z & !N) = !Z & !N = !Z & C = HI
+ case ISD::SETUGT: return ARMCC::HI;
+// SETUGE = V | !N = !N = PL
+ case ISD::SETUGE: return ARMCC::PL;
+// SETULT = V | N = ??
+// SETULE = V | Z | N = ??
+// SETUNE = V | !Z = !Z = NE
+ case ISD::SETUNE: return ARMCC::NE;
+ }
+}
+
+/// DAGIntCCToARMCC - Convert a DAG integer condition code to an ARM CC
+static ARMCC::CondCodes DAGIntCCToARMCC(ISD::CondCode CC) {
+ switch (CC) {
+ default:
+ assert(0 && "Unknown integer condition code!");
+ case ISD::SETEQ: return ARMCC::EQ;
+ case ISD::SETNE: return ARMCC::NE;
+ case ISD::SETLT: return ARMCC::LT;
+ case ISD::SETLE: return ARMCC::LE;
+ case ISD::SETGT: return ARMCC::GT;
+ case ISD::SETGE: return ARMCC::GE;
case ISD::SETULT: return ARMCC::CC;
+ case ISD::SETULE: return ARMCC::LS;
+ case ISD::SETUGT: return ARMCC::HI;
+ case ISD::SETUGE: return ARMCC::CS;
}
}
case ARMISD::CMP: return "ARMISD::CMP";
case ARMISD::BR: return "ARMISD::BR";
case ARMISD::FSITOS: return "ARMISD::FSITOS";
+ case ARMISD::FTOSIS: return "ARMISD::FTOSIS";
case ARMISD::FSITOD: return "ARMISD::FSITOD";
+ case ARMISD::FTOSID: return "ARMISD::FTOSID";
case ARMISD::FUITOS: return "ARMISD::FUITOS";
+ case ARMISD::FTOUIS: return "ARMISD::FTOUIS";
case ARMISD::FUITOD: return "ARMISD::FUITOD";
+ case ARMISD::FTOUID: return "ARMISD::FTOUID";
case ARMISD::FMRRD: return "ARMISD::FMRRD";
case ARMISD::FMDRR: return "ARMISD::FMDRR";
case ARMISD::FMSTAT: return "ARMISD::FMSTAT";
static SDOperand LowerCALL(SDOperand Op, SelectionDAG &DAG) {
SDOperand Chain = Op.getOperand(0);
unsigned CallConv = cast<ConstantSDNode>(Op.getOperand(1))->getValue();
- assert(CallConv == CallingConv::C && "unknown calling convention");
+ assert((CallConv == CallingConv::C ||
+ CallConv == CallingConv::Fast)
+ && "unknown calling convention");
bool isVarArg = cast<ConstantSDNode>(Op.getOperand(2))->getValue() != 0;
bool isTailCall = cast<ConstantSDNode>(Op.getOperand(3))->getValue() != 0;
- assert(isTailCall == false && "tail call not supported");
SDOperand Callee = Op.getOperand(4);
unsigned NumOps = (Op.getNumOperands() - 5) / 2;
SDOperand StackPtr = DAG.getRegister(ARM::R13, MVT::i32);
unsigned ArgOffset = Layout.getOffset(i);
SDOperand PtrOff = DAG.getConstant(ArgOffset, StackPtr.getValueType());
PtrOff = DAG.getNode(ISD::ADD, MVT::i32, StackPtr, PtrOff);
- MemOpChains.push_back(DAG.getStore(Chain, Arg, PtrOff,
- DAG.getSrcValue(NULL)));
+ MemOpChains.push_back(DAG.getStore(Chain, Arg, PtrOff, NULL, 0));
}
if (!MemOpChains.empty())
Chain = DAG.getNode(ISD::TokenFactor, MVT::Other,
&MemOpChains[0], MemOpChains.size());
- // If the callee is a GlobalAddress/ExternalSymbol node (quite common, every
- // direct call is) turn it into a TargetGlobalAddress/TargetExternalSymbol
- // node so that legalize doesn't hack it.
+ // If the callee is a GlobalAddress node (quite common, every direct call is)
+ // turn it into a TargetGlobalAddress node so that legalize doesn't hack it.
+ // Likewise ExternalSymbol -> TargetExternalSymbol.
+ assert(Callee.getValueType() == MVT::i32);
if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee))
- Callee = DAG.getTargetGlobalAddress(G->getGlobal(), Callee.getValueType());
+ Callee = DAG.getTargetGlobalAddress(G->getGlobal(), MVT::i32);
+ else if (ExternalSymbolSDNode *E = dyn_cast<ExternalSymbolSDNode>(Callee))
+ Callee = DAG.getTargetExternalSymbol(E->getSymbol(), MVT::i32);
// If this is a direct call, pass the chain and the callee.
assert (Callee.Val);
MVT::ValueType VT = Op.Val->getValueType(0);
if (VT != MVT::Other) {
assert(VT == MVT::i32 || VT == MVT::f32 || VT == MVT::f64);
- SDOperand Value;
SDOperand Value1 = DAG.getCopyFromReg(Chain, ARM::R0, MVT::i32, InFlag);
Chain = Value1.getValue(1);
InFlag = Value1.getValue(2);
- if (VT == MVT::i32)
- Value = Value1;
- if (VT == MVT::f32)
- Value = DAG.getNode(ISD::BIT_CONVERT, MVT::f32, Value1);
+ NodeTys.push_back(VT);
+ if (VT == MVT::i32) {
+ ResultVals.push_back(Value1);
+ if (Op.Val->getValueType(1) == MVT::i32) {
+ SDOperand Value2 = DAG.getCopyFromReg(Chain, ARM::R1, MVT::i32, InFlag);
+ Chain = Value2.getValue(1);
+ ResultVals.push_back(Value2);
+ NodeTys.push_back(VT);
+ }
+ }
+ if (VT == MVT::f32) {
+ SDOperand Value = DAG.getNode(ISD::BIT_CONVERT, MVT::f32, Value1);
+ ResultVals.push_back(Value);
+ }
if (VT == MVT::f64) {
SDOperand Value2 = DAG.getCopyFromReg(Chain, ARM::R1, MVT::i32, InFlag);
Chain = Value2.getValue(1);
- Value = DAG.getNode(ARMISD::FMDRR, MVT::f64, Value1, Value2);
+ SDOperand Value = DAG.getNode(ARMISD::FMDRR, MVT::f64, Value1, Value2);
+ ResultVals.push_back(Value);
}
- ResultVals.push_back(Value);
- NodeTys.push_back(VT);
}
Chain = DAG.getNode(ISD::CALLSEQ_END, MVT::Other, Chain,
// memory location argument.
MVT::ValueType PtrVT = DAG.getTargetLoweringInfo().getPointerTy();
SDOperand FR = DAG.getFrameIndex(VarArgsFrameIndex, PtrVT);
- return DAG.getStore(Op.getOperand(0), FR, Op.getOperand(1), Op.getOperand(2));
+ SrcValueSDNode *SV = cast<SrcValueSDNode>(Op.getOperand(2));
+ return DAG.getStore(Op.getOperand(0), FR, Op.getOperand(1), SV->getValue(),
+ SV->getOffset());
}
static SDOperand LowerFORMAL_ARGUMENTS(SDOperand Op, SelectionDAG &DAG,
MF.addLiveIn(REGS[RegNo], VReg);
SDOperand Val = DAG.getCopyFromReg(Root, VReg, MVT::i32);
- SDOperand Store = DAG.getStore(Val.getValue(1), Val, FIN,
- DAG.getSrcValue(NULL));
+ SDOperand Store = DAG.getStore(Val.getValue(1), Val, FIN, NULL, 0);
MemOps.push_back(Store);
}
Root = DAG.getNode(ISD::TokenFactor, MVT::Other,&MemOps[0],MemOps.size());
static SDOperand GetCMP(ISD::CondCode CC, SDOperand LHS, SDOperand RHS,
SelectionDAG &DAG) {
MVT::ValueType vt = LHS.getValueType();
- assert(vt == MVT::i32 || vt == MVT::f32);
- //Note: unordered floating point compares should use a non throwing
- //compare.
- bool isUnorderedFloat = vt == MVT::f32 &&
- (CC >= ISD::SETUO && CC <= ISD::SETUNE);
- assert(!isUnorderedFloat && "Unordered float compares are not supported");
-
- SDOperand Cmp = DAG.getNode(ARMISD::CMP, MVT::Flag, LHS, RHS);
+ assert(vt == MVT::i32 || vt == MVT::f32 || vt == MVT::f64);
+
+ SDOperand Cmp = DAG.getNode(ARMISD::CMP, MVT::Flag, LHS, RHS);
+
if (vt != MVT::i32)
Cmp = DAG.getNode(ARMISD::FMSTAT, MVT::Flag, Cmp);
return Cmp;
}
+static SDOperand GetARMCC(ISD::CondCode CC, MVT::ValueType vt,
+ SelectionDAG &DAG) {
+ assert(vt == MVT::i32 || vt == MVT::f32 || vt == MVT::f64);
+ if (vt == MVT::i32)
+ return DAG.getConstant(DAGIntCCToARMCC(CC), MVT::i32);
+ else
+ return DAG.getConstant(DAGFPCCToARMCC(CC), MVT::i32);
+}
+
static SDOperand LowerSELECT_CC(SDOperand Op, SelectionDAG &DAG) {
SDOperand LHS = Op.getOperand(0);
SDOperand RHS = Op.getOperand(1);
SDOperand TrueVal = Op.getOperand(2);
SDOperand FalseVal = Op.getOperand(3);
SDOperand Cmp = GetCMP(CC, LHS, RHS, DAG);
- SDOperand ARMCC = DAG.getConstant(DAGCCToARMCC(CC), MVT::i32);
+ SDOperand ARMCC = GetARMCC(CC, LHS.getValueType(), DAG);
return DAG.getNode(ARMISD::SELECT, MVT::i32, TrueVal, FalseVal, ARMCC, Cmp);
}
SDOperand RHS = Op.getOperand(3);
SDOperand Dest = Op.getOperand(4);
SDOperand Cmp = GetCMP(CC, LHS, RHS, DAG);
- SDOperand ARMCC = DAG.getConstant(DAGCCToARMCC(CC), MVT::i32);
+ SDOperand ARMCC = GetARMCC(CC, LHS.getValueType(), DAG);
return DAG.getNode(ARMISD::BR, MVT::Other, Chain, Dest, ARMCC, Cmp);
}
return DAG.getNode(op, vt, Tmp);
}
+static SDOperand LowerFP_TO_SINT(SDOperand Op, SelectionDAG &DAG) {
+ assert(Op.getValueType() == MVT::i32);
+ SDOperand FloatVal = Op.getOperand(0);
+ MVT::ValueType vt = FloatVal.getValueType();
+ assert(vt == MVT::f32 || vt == MVT::f64);
+
+ ARMISD::NodeType op = vt == MVT::f32 ? ARMISD::FTOSIS : ARMISD::FTOSID;
+ SDOperand Tmp = DAG.getNode(op, MVT::f32, FloatVal);
+ return DAG.getNode(ISD::BIT_CONVERT, MVT::i32, Tmp);
+}
+
static SDOperand LowerUINT_TO_FP(SDOperand Op, SelectionDAG &DAG) {
SDOperand IntVal = Op.getOperand(0);
assert(IntVal.getValueType() == MVT::i32);
return DAG.getNode(op, vt, Tmp);
}
+static SDOperand LowerFP_TO_UINT(SDOperand Op, SelectionDAG &DAG) {
+ assert(Op.getValueType() == MVT::i32);
+ SDOperand FloatVal = Op.getOperand(0);
+ MVT::ValueType vt = FloatVal.getValueType();
+ assert(vt == MVT::f32 || vt == MVT::f64);
+
+ ARMISD::NodeType op = vt == MVT::f32 ? ARMISD::FTOUIS : ARMISD::FTOUID;
+ SDOperand Tmp = DAG.getNode(op, MVT::f32, FloatVal);
+ return DAG.getNode(ISD::BIT_CONVERT, MVT::i32, Tmp);
+}
+
SDOperand ARMTargetLowering::LowerOperation(SDOperand Op, SelectionDAG &DAG) {
switch (Op.getOpcode()) {
default:
return LowerConstantPool(Op, DAG);
case ISD::GlobalAddress:
return LowerGlobalAddress(Op, DAG);
+ case ISD::FP_TO_SINT:
+ return LowerFP_TO_SINT(Op, DAG);
case ISD::SINT_TO_FP:
return LowerSINT_TO_FP(Op, DAG);
+ case ISD::FP_TO_UINT:
+ return LowerFP_TO_UINT(Op, DAG);
case ISD::UINT_TO_FP:
return LowerUINT_TO_FP(Op, DAG);
case ISD::FORMAL_ARGUMENTS:
bool SelectAddrRegImm(SDOperand N, SDOperand &Offset, SDOperand &Base);
bool SelectAddrMode1(SDOperand N, SDOperand &Arg, SDOperand &Shift,
SDOperand &ShiftType);
+ bool SelectAddrMode5(SDOperand N, SDOperand &Arg, SDOperand &Offset);
// Include the pieces autogenerated from the target description.
#include "ARMGenDAGISel.inc"
return true;
}
+bool ARMDAGToDAGISel::SelectAddrMode5(SDOperand N, SDOperand &Arg,
+ SDOperand &Offset) {
+ //TODO: detect offset
+ Offset = CurDAG->getTargetConstant(0, MVT::i32);
+ Arg = N;
+ return true;
+}
+
//register plus/minus 12 bit offset
bool ARMDAGToDAGISel::SelectAddrRegImm(SDOperand N, SDOperand &Offset,
SDOperand &Base) {