implement unordered floating point compares
authorRafael Espindola <rafael.espindola@gmail.com>
Fri, 13 Oct 2006 13:14:59 +0000 (13:14 +0000)
committerRafael Espindola <rafael.espindola@gmail.com>
Fri, 13 Oct 2006 13:14:59 +0000 (13:14 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@30928 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Target/ARM/ARMISelDAGToDAG.cpp
lib/Target/ARM/ARMInstrInfo.td
test/CodeGen/ARM/fpcmp.ll

index f629bc3f80c4c73c1ab25ff6ca1cfc98b6469a0c..5dca92abf0a8a1f2ac94820baa03f1f424f9168f 100644 (file)
@@ -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);
 }
 
index 4cf271bf018b33ab2fff352825122a411100c451..b7e04471d12aa1e43a83fa1db9333ace6e893041 100644 (file)
@@ -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
index 53529bcf04fd3d3ccaf53ca6353c5a7b478d78c2..5c120ea65c893103d14c187620615ed70ddd55fd 100644 (file)
@@ -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             ; <bool> [#uses=1]
+       %tmp = cast bool %tmp to int            ; <int> [#uses=1]
+       ret int %tmp
+}
+
 int %g1(double %a) {
 entry:
        %tmp = setlt double %a, 1.000000e+00            ; <bool> [#uses=1]
        %tmp = cast bool %tmp to int            ; <int> [#uses=1]
        ret int %tmp
 }
+
+int %g2(double %a) {
+entry:
+       %tmp = setne double %a, 1.000000e+00            ; <bool> [#uses=1]
+       %tmp = cast bool %tmp to int            ; <int> [#uses=1]
+       ret int %tmp
+}