add FNEGS and FNEGD
[oota-llvm.git] / lib / Target / ARM / ARMISelDAGToDAG.cpp
index beb0d6775ad639d810500adb76e6cc47882fc4fd..0423cc8c6ccf4306d800c03e3806beff0253fbd4 100644 (file)
@@ -47,15 +47,28 @@ ARMTargetLowering::ARMTargetLowering(TargetMachine &TM)
   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);
@@ -79,38 +92,83 @@ namespace llvm {
       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;
   }
 }
 
@@ -121,11 +179,19 @@ 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";
   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";
   }
 }
 
@@ -217,7 +283,6 @@ static SDOperand LowerCALL(SDOperand Op, SelectionDAG &DAG) {
   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);
@@ -284,8 +349,8 @@ static SDOperand LowerCALL(SDOperand Op, SelectionDAG &DAG) {
 
       Ops.push_back(DAG.getRegister(Reg2, MVT::i32));
       SDVTList    VTs = DAG.getVTList(MVT::Other, MVT::Flag);
-      SDOperand Ops[] = {Chain, SDReg1, SDReg2, Arg}; //missing flag
-      Chain = DAG.getNode(ARMISD::FMRRD, VTs, Ops, 4);
+      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);
@@ -311,22 +376,30 @@ static SDOperand LowerCALL(SDOperand Op, SelectionDAG &DAG) {
   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,
@@ -408,8 +481,7 @@ static SDOperand LowerGlobalAddress(SDOperand Op,
   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,
@@ -467,7 +539,7 @@ static SDOperand LowerFORMAL_ARGUMENTS(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);
       }
@@ -509,15 +581,43 @@ static SDOperand LowerFORMAL_ARGUMENTS(SDOperand Op, SelectionDAG &DAG,
   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);
 }
 
@@ -527,9 +627,8 @@ static SDOperand LowerBR_CC(SDOperand Op, SelectionDAG &DAG) {
   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);
 }
 
@@ -545,6 +644,40 @@ static SDOperand LowerSINT_TO_FP(SDOperand Op, SelectionDAG &DAG) {
   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:
@@ -554,8 +687,14 @@ SDOperand ARMTargetLowering::LowerOperation(SDOperand Op, SelectionDAG &DAG) {
     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: