diff --git a/lib/Target/ARM/ARMISelDAGToDAG.cpp b/lib/Target/ARM/ARMISelDAGToDAG.cpp index f629bc3f80c..5dca92abf0a 100644 --- a/lib/Target/ARM/ARMISelDAGToDAG.cpp +++ b/lib/Target/ARM/ARMISelDAGToDAG.cpp @@ -92,6 +92,7 @@ namespace llvm { RET_FLAG, CMP, + CMPE, SELECT, @@ -118,30 +119,56 @@ namespace llvm { } } -/// 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 +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; - case ISD::SETEQ: + 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::SETGE: + case ISD::SETOGT: return ARMCC::GT; case ISD::SETOGE: return ARMCC::GE; - case ISD::SETUGE: return ARMCC::CS; + 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::SETULT: return ARMCC::CC; + case ISD::SETULE: return ARMCC::LS; + case ISD::SETUGT: return ARMCC::HI; + case ISD::SETUGE: return ARMCC::CS; } } @@ -152,6 +179,7 @@ const char *ARMTargetLowering::getTargetNodeName(unsigned Opcode) const { 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"; @@ -550,18 +578,31 @@ 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); - //Note: unordered floating point compares should use a non throwing - //compare. - bool isUnorderedFloat = (vt == MVT::f32 || vt == MVT::f64) && - (CC >= ISD::SETUO && CC <= ISD::SETUNE); - assert(!isUnorderedFloat && "Unordered float compares are not supported"); - SDOperand Cmp = DAG.getNode(ARMISD::CMP, MVT::Flag, LHS, RHS); + 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); @@ -569,7 +610,7 @@ static SDOperand LowerSELECT_CC(SDOperand Op, SelectionDAG &DAG) { 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); } @@ -580,7 +621,7 @@ static SDOperand LowerBR_CC(SDOperand Op, SelectionDAG &DAG) { 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); } diff --git a/lib/Target/ARM/ARMInstrInfo.td b/lib/Target/ARM/ARMInstrInfo.td index 4cf271bf018..b7e04471d12 100644 --- a/lib/Target/ARM/ARMInstrInfo.td +++ b/lib/Target/ARM/ARMInstrInfo.td @@ -76,6 +76,7 @@ def armbr : SDNode<"ARMISD::BR", SDTarmbr, [SDNPHasChain, SDNPInFlag]>; def SDTVoidBinOp : SDTypeProfile<0, 2, [SDTCisSameAs<0, 1>]>; def armcmp : SDNode<"ARMISD::CMP", SDTVoidBinOp, [SDNPOutFlag]>; +def armcmpe : SDNode<"ARMISD::CMPE", SDTVoidBinOp, [SDNPOutFlag]>; def armfsitos : SDNode<"ARMISD::FSITOS", SDTUnaryOp>; def armftosis : SDNode<"ARMISD::FTOSIS", SDTUnaryOp>; @@ -179,12 +180,20 @@ def cmp : InstARM<(ops IntRegs:$a, op_addr_mode1:$b), [(armcmp IntRegs:$a, addr_mode1:$b)]>; // Floating Point Compare +def fcmps : InstARM<(ops FPRegs:$a, FPRegs:$b), + "fcmps $a, $b", + [(armcmp FPRegs:$a, FPRegs:$b)]>; + def fcmpes : InstARM<(ops FPRegs:$a, FPRegs:$b), "fcmpes $a, $b", - [(armcmp FPRegs:$a, FPRegs:$b)]>; + [(armcmpe FPRegs:$a, FPRegs:$b)]>; def fcmped : InstARM<(ops DFPRegs:$a, DFPRegs:$b), "fcmped $a, $b", + [(armcmpe DFPRegs:$a, DFPRegs:$b)]>; + +def fcmpd : InstARM<(ops DFPRegs:$a, DFPRegs:$b), + "fcmpd $a, $b", [(armcmp DFPRegs:$a, DFPRegs:$b)]>; // Floating Point Conversion diff --git a/test/CodeGen/ARM/fpcmp.ll b/test/CodeGen/ARM/fpcmp.ll index 53529bcf04f..5c120ea65c8 100644 --- a/test/CodeGen/ARM/fpcmp.ll +++ b/test/CodeGen/ARM/fpcmp.ll @@ -5,7 +5,9 @@ ; RUN: llvm-as < %s | llc -march=arm | grep movge && ; RUN: llvm-as < %s | llc -march=arm | grep movle && ; RUN: llvm-as < %s | llc -march=arm | grep fcmpes && -; RUN: llvm-as < %s | llc -march=arm | grep fcmped +; RUN: llvm-as < %s | llc -march=arm | grep fcmps && +; RUN: llvm-as < %s | llc -march=arm | grep fcmped && +; RUN: llvm-as < %s | llc -march=arm | grep fcmpd int %f1(float %a) { entry: @@ -42,9 +44,23 @@ entry: ret int %tmp } +int %f6(float %a) { +entry: + %tmp = setne float %a, 1.000000e+00 ; [#uses=1] + %tmp = cast bool %tmp to int ; [#uses=1] + ret int %tmp +} + int %g1(double %a) { entry: %tmp = setlt double %a, 1.000000e+00 ; [#uses=1] %tmp = cast bool %tmp to int ; [#uses=1] ret int %tmp } + +int %g2(double %a) { +entry: + %tmp = setne double %a, 1.000000e+00 ; [#uses=1] + %tmp = cast bool %tmp to int ; [#uses=1] + ret int %tmp +}