addRegisterClass(MVT::f32, ARM::FPRegsRegisterClass);
addRegisterClass(MVT::f64, ARM::DFPRegsRegisterClass);
+ 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::GlobalAddress, MVT::i32, Custom);
setOperationAction(ISD::ConstantPool, MVT::i32, Custom);
+ setOperationAction(ISD::SELECT, MVT::i32, Expand);
+
setOperationAction(ISD::SETCC, MVT::i32, Expand);
+ setOperationAction(ISD::SETCC, MVT::f32, Expand);
+ setOperationAction(ISD::SETCC, MVT::f64, Expand);
+
setOperationAction(ISD::SELECT_CC, MVT::i32, Custom);
setOperationAction(ISD::BR_CC, MVT::i32, Custom);
+ setOperationAction(ISD::BR_CC, MVT::f32, Custom);
+ setOperationAction(ISD::BR_CC, MVT::f64, Custom);
setOperationAction(ISD::VASTART, MVT::Other, Custom);
setOperationAction(ISD::VAEND, MVT::Other, Expand);
RET_FLAG,
CMP,
+ CMPE,
SELECT,
BR,
FSITOS,
+ FTOSIS,
FSITOD,
+ FTOSID,
+
+ FUITOS,
+ FTOUIS,
+
+ FUITOD,
+ FTOUID,
FMRRD,
- FMDRR
+ FMDRR,
+
+ FMSTAT
};
}
}
-/// DAGCCToARMCC - Convert a DAG integer condition code to an ARM CC
-static ARMCC::CondCodes DAGCCToARMCC(ISD::CondCode CC) {
+/// DAGFPCCToARMCC - Convert a DAG fp condition code to an ARM CC
+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: return ARMCC::LE;
- case ISD::SETLT: return ARMCC::LT;
+ assert(0 && "Unknown fp condition code!");
+// For the following conditions we use a comparison that throws exceptions,
+// so we may assume that V=0
+ case ISD::SETOEQ: return ARMCC::EQ;
+ case ISD::SETOGT: return ARMCC::GT;
+ case ISD::SETOGE: return ARMCC::GE;
+ case ISD::SETOLT: return ARMCC::LT;
+ case ISD::SETOLE: return ARMCC::LE;
+ case ISD::SETONE: return ARMCC::NE;
+// For the following conditions the result is undefined in case of a nan,
+// so we may assume that V=0
+ case ISD::SETEQ: return ARMCC::EQ;
case ISD::SETGT: return ARMCC::GT;
+ case ISD::SETGE: return ARMCC::GE;
+ case ISD::SETLT: return ARMCC::LT;
+ case ISD::SETLE: return ARMCC::LE;
case ISD::SETNE: return ARMCC::NE;
+// For the following we may not assume anything
+// SETO = N | Z | !C | !V = ???
+// SETUO = (!N & !Z & C & V) = ???
+// SETUEQ = (!N & !Z & C & V) | Z = ???
+// SETUGT = (!N & !Z & C & V) | (!Z & !N) = ???
+// SETUGE = (!N & !Z & C & V) | !N = !N = PL
+ case ISD::SETUGE: return ARMCC::PL;
+// SETULT = (!N & !Z & C & V) | N = ???
+// SETULE = (!N & !Z & C & V) | Z | N = ???
+// SETUNE = (!N & !Z & C & 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::SETUGE: return ARMCC::CS;
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::RET_FLAG: return "ARMISD::RET_FLAG";
case ARMISD::SELECT: return "ARMISD::SELECT";
case ARMISD::CMP: return "ARMISD::CMP";
+ case ARMISD::CMPE: return "ARMISD::CMPE";
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";
}
}
}
unsigned getStackSize(void) {
int last = is_reg.size() - 1;
+ if (last < 0)
+ return 0;
if (isRegister(last))
return 0;
return getOffset(last) + MVT::getSizeInBits(getType(last))/8;
last--;
return last;
}
- unsigned lastRegNum(void) {
+ int lastRegNum(void) {
int l = lastRegArg();
if (l < 0)
return -1;
assert(CallConv == CallingConv::C && "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);
// Build a sequence of copy-to-reg nodes chained together with token chain
// and flag operands which copy the outgoing args into the appropriate regs.
SDOperand InFlag;
- for (unsigned i = 0, e = Layout.lastRegArg(); i <= e; ++i) {
- SDOperand Arg = Op.getOperand(5+2*i);
- unsigned Reg = regs[Layout.getRegisterNum(i)];
- assert(Layout.getType(i) == Arg.getValueType());
- assert(Layout.getType(i) == MVT::i32);
- Chain = DAG.getCopyToReg(Chain, Reg, Arg, InFlag);
- InFlag = Chain.getValue(1);
+ for (int i = 0, e = Layout.lastRegArg(); i <= e; ++i) {
+ SDOperand Arg = Op.getOperand(5+2*i);
+ unsigned RegNum = Layout.getRegisterNum(i);
+ unsigned Reg1 = regs[RegNum];
+ MVT::ValueType VT = Layout.getType(i);
+ assert(VT == Arg.getValueType());
+ assert(VT == MVT::i32 || VT == MVT::f32 || VT == MVT::f64);
// Add argument register to the end of the list so that it is known live
// into the call.
- Ops.push_back(DAG.getRegister(Reg, Arg.getValueType()));
+ Ops.push_back(DAG.getRegister(Reg1, MVT::i32));
+ if (VT == MVT::f64) {
+ unsigned Reg2 = regs[RegNum + 1];
+ SDOperand SDReg1 = DAG.getRegister(Reg1, MVT::i32);
+ SDOperand SDReg2 = DAG.getRegister(Reg2, MVT::i32);
+
+ Ops.push_back(DAG.getRegister(Reg2, MVT::i32));
+ SDVTList VTs = DAG.getVTList(MVT::Other, MVT::Flag);
+ SDOperand Ops[] = {Chain, SDReg1, SDReg2, Arg, InFlag};
+ Chain = DAG.getNode(ARMISD::FMRRD, VTs, Ops, InFlag.Val ? 5 : 4);
+ } else {
+ if (VT == MVT::f32)
+ Arg = DAG.getNode(ISD::BIT_CONVERT, MVT::i32, Arg);
+ Chain = DAG.getCopyToReg(Chain, Reg1, Arg, InFlag);
+ }
+ InFlag = Chain.getValue(1);
}
std::vector<MVT::ValueType> NodeTys;
NodeTys.clear();
// If the call has results, copy the values out of the ret val registers.
- switch (Op.Val->getValueType(0)) {
- default: assert(0 && "Unexpected ret value!");
- case MVT::Other:
- break;
- case MVT::i32:
- Chain = DAG.getCopyFromReg(Chain, ARM::R0, MVT::i32, InFlag).getValue(1);
- ResultVals.push_back(Chain.getValue(0));
- NodeTys.push_back(MVT::i32);
+ MVT::ValueType VT = Op.Val->getValueType(0);
+ if (VT != MVT::Other) {
+ assert(VT == MVT::i32 || VT == MVT::f32 || VT == MVT::f64);
+
+ SDOperand Value1 = DAG.getCopyFromReg(Chain, ARM::R0, MVT::i32, InFlag);
+ Chain = Value1.getValue(1);
+ InFlag = Value1.getValue(2);
+ 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);
+ SDOperand Value = DAG.getNode(ARMISD::FMDRR, MVT::f64, Value1, Value2);
+ ResultVals.push_back(Value);
+ }
}
Chain = DAG.getNode(ISD::CALLSEQ_END, MVT::Other, Chain,
GlobalValue *GV = cast<GlobalAddressSDNode>(Op)->getGlobal();
int alignment = 2;
SDOperand CPAddr = DAG.getConstantPool(GV, MVT::i32, alignment);
- return DAG.getLoad(MVT::i32, DAG.getEntryNode(), CPAddr,
- DAG.getSrcValue(NULL));
+ return DAG.getLoad(MVT::i32, DAG.getEntryNode(), CPAddr, NULL, 0);
}
static SDOperand LowerVASTART(SDOperand Op, SelectionDAG &DAG,
unsigned Size = MVT::getSizeInBits(VT)/8;
int FI = MFI->CreateFixedObject(Size, Offset);
SDOperand FIN = DAG.getFrameIndex(FI, VT);
- Value = DAG.getLoad(VT, Root, FIN, DAG.getSrcValue(NULL));
+ Value = DAG.getLoad(VT, Root, FIN, NULL, 0);
} else {
Value = DAG.getNode(ISD::UNDEF, VT);
}
return DAG.getNode(ISD::MERGE_VALUES, RetVT, &ArgValues[0], ArgValues.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 || vt == MVT::f64);
+
+ bool isOrderedFloat = (vt == MVT::f32 || vt == MVT::f64) &&
+ (CC >= ISD::SETOEQ && CC <= ISD::SETONE);
+
+ SDOperand Cmp;
+ if (isOrderedFloat) {
+ Cmp = DAG.getNode(ARMISD::CMPE, MVT::Flag, LHS, RHS);
+ } else {
+ 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);
ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(4))->get();
SDOperand TrueVal = Op.getOperand(2);
SDOperand FalseVal = Op.getOperand(3);
- SDOperand ARMCC = DAG.getConstant(DAGCCToARMCC(CC), MVT::i32);
-
- SDOperand Cmp = DAG.getNode(ARMISD::CMP, MVT::Flag, LHS, RHS);
+ SDOperand Cmp = GetCMP(CC, LHS, RHS, DAG);
+ SDOperand ARMCC = GetARMCC(CC, LHS.getValueType(), DAG);
return DAG.getNode(ARMISD::SELECT, MVT::i32, TrueVal, FalseVal, ARMCC, Cmp);
}
SDOperand LHS = Op.getOperand(2);
SDOperand RHS = Op.getOperand(3);
SDOperand Dest = Op.getOperand(4);
- SDOperand ARMCC = DAG.getConstant(DAGCCToARMCC(CC), MVT::i32);
-
- SDOperand Cmp = DAG.getNode(ARMISD::CMP, MVT::Flag, LHS, RHS);
+ SDOperand Cmp = GetCMP(CC, LHS, RHS, DAG);
+ 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);
+ MVT::ValueType vt = Op.getValueType();
+ assert(vt == MVT::f32 ||
+ vt == MVT::f64);
+
+ SDOperand Tmp = DAG.getNode(ISD::BIT_CONVERT, MVT::f32, IntVal);
+ ARMISD::NodeType op = vt == MVT::f32 ? ARMISD::FUITOS : ARMISD::FUITOD;
+ 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:
return LowerFORMAL_ARGUMENTS(Op, DAG, VarArgsFrameIndex);
case ISD::CALL: