More X86 floating point patterns.
[oota-llvm.git] / lib / Target / X86 / X86ISelLowering.cpp
index d4de67f09721dd40805ad5aac7f3b369616f9b8a..b419f31d47abe68d349686d9951270fe3b7b3ba9 100644 (file)
@@ -31,7 +31,6 @@ static cl::opt<bool> EnableFastCC("enable-x86-fastcc", cl::Hidden,
 
 X86TargetLowering::X86TargetLowering(TargetMachine &TM)
   : TargetLowering(TM) {
-
   // Set up the TargetLowering object.
 
   // X86 is weird, it always uses i8 for shift amounts and setcc results.
@@ -41,9 +40,6 @@ X86TargetLowering::X86TargetLowering(TargetMachine &TM)
   setShiftAmountFlavor(Mask);   // shl X, 32 == shl X, 0
 
   // Set up the register classes.
-  // FIXME: Eliminate these two classes when legalize can handle promotions
-  // well.
-  addRegisterClass(MVT::i1, X86::R8RegisterClass);
   addRegisterClass(MVT::i8, X86::R8RegisterClass);
   addRegisterClass(MVT::i16, X86::R16RegisterClass);
   addRegisterClass(MVT::i32, X86::R32RegisterClass);
@@ -84,10 +80,17 @@ X86TargetLowering::X86TargetLowering(TargetMachine &TM)
   setOperationAction(ISD::FP_TO_SINT       , MVT::i8   , Promote);
   setOperationAction(ISD::FP_TO_SINT       , MVT::i16  , Promote);
 
+  setOperationAction(ISD::BIT_CONVERT, MVT::f32, Expand);
+  setOperationAction(ISD::BIT_CONVERT, MVT::i32, Expand);
+
+  if (X86DAGIsel) {
+    setOperationAction(ISD::BRCOND         , MVT::Other, Custom);
+  }
   setOperationAction(ISD::BRCONDTWOWAY     , MVT::Other, Expand);
   setOperationAction(ISD::BRTWOWAY_CC      , MVT::Other, Expand);
   setOperationAction(ISD::MEMMOVE          , MVT::Other, Expand);
   setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i16  , Expand);
+  setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i8   , Expand);
   setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1   , Expand);
   setOperationAction(ISD::FP_ROUND_INREG   , MVT::f32  , Expand);
   setOperationAction(ISD::SEXTLOAD         , MVT::i1   , Expand);
@@ -115,6 +118,19 @@ X86TargetLowering::X86TargetLowering(TargetMachine &TM)
   // These should be promoted to a larger select which is supported.
   setOperationAction(ISD::SELECT           , MVT::i1   , Promote);
   setOperationAction(ISD::SELECT           , MVT::i8   , Promote);
+  // X86 wants to expand cmov itself.
+  if (X86DAGIsel) {
+    setOperationAction(ISD::SELECT         , MVT::i16  , Custom);
+    setOperationAction(ISD::SELECT         , MVT::i32  , Custom);
+    setOperationAction(ISD::SETCC          , MVT::i8   , Custom);
+    setOperationAction(ISD::SETCC          , MVT::i16  , Custom);
+    setOperationAction(ISD::SETCC          , MVT::i32  , Custom);
+    setOperationAction(ISD::GlobalAddress  , MVT::i32  , Custom);
+  }
+
+  // We don't have line number support yet.
+  setOperationAction(ISD::LOCATION, MVT::Other, Expand);
+  setOperationAction(ISD::DEBUG_LOC, MVT::Other, Expand);
 
   if (X86ScalarSSE) {
     // Set up the FP register classes.
@@ -189,6 +205,71 @@ X86TargetLowering::LowerCallTo(SDOperand Chain, const Type *RetTy,
   return  LowerCCCCallTo(Chain, RetTy, isVarArg, isTailCall, Callee, Args, DAG);
 }
 
+SDOperand X86TargetLowering::LowerReturnTo(SDOperand Chain, SDOperand Op,
+                                           SelectionDAG &DAG) {
+  if (!X86DAGIsel)
+    return DAG.getNode(ISD::RET, MVT::Other, Chain, Op);
+
+  SDOperand Copy;
+  MVT::ValueType OpVT = Op.getValueType();
+  switch (OpVT) {
+    default: assert(0 && "Unknown type to return!");
+    case MVT::i32:
+      Copy = DAG.getCopyToReg(Chain, X86::EAX, Op, SDOperand());
+      break;
+    case MVT::i64: {
+      SDOperand Hi = DAG.getNode(ISD::EXTRACT_ELEMENT, MVT::i32, Op, 
+                                 DAG.getConstant(1, MVT::i32));
+      SDOperand Lo = DAG.getNode(ISD::EXTRACT_ELEMENT, MVT::i32, Op,
+                                 DAG.getConstant(0, MVT::i32));
+      Copy = DAG.getCopyToReg(Chain, X86::EAX, Hi, SDOperand());
+      Copy = DAG.getCopyToReg(Copy,  X86::EDX, Lo, Copy.getValue(1));
+      break;
+    }
+    case MVT::f32:
+    case MVT::f64:
+      if (!X86ScalarSSE) {
+        std::vector<MVT::ValueType> Tys;
+        Tys.push_back(MVT::Other);
+        Tys.push_back(MVT::Flag);
+        std::vector<SDOperand> Ops;
+        Ops.push_back(Chain);
+        if (OpVT == MVT::f32)
+          Op = DAG.getNode(ISD::FP_EXTEND, MVT::f64, Op);
+        Ops.push_back(Op);
+        Copy = DAG.getNode(X86ISD::FP_SET_RESULT, Tys, Ops);
+      } else {
+        // Spill the value to memory and reload it into top of stack.
+        unsigned Size = MVT::getSizeInBits(OpVT)/8;
+        MachineFunction &MF = DAG.getMachineFunction();
+        int SSFI = MF.getFrameInfo()->CreateStackObject(Size, Size);
+        SDOperand StackSlot = DAG.getFrameIndex(SSFI, getPointerTy());
+        Chain = DAG.getNode(ISD::STORE, MVT::Other, Chain, Op,
+                            StackSlot, DAG.getSrcValue(NULL));
+        std::vector<MVT::ValueType> Tys;
+        Tys.push_back(MVT::f64);
+        Tys.push_back(MVT::Other);
+        std::vector<SDOperand> Ops;
+        Ops.push_back(Chain);
+        Ops.push_back(StackSlot);
+        Ops.push_back(DAG.getValueType(OpVT));
+        Copy = DAG.getNode(X86ISD::FLD, Tys, Ops);
+        Tys.clear();
+        Tys.push_back(MVT::Other);
+        Tys.push_back(MVT::Flag);
+        Ops.clear();
+        Ops.push_back(Copy.getValue(1));
+        Ops.push_back(Copy);
+        Copy = DAG.getNode(X86ISD::FP_SET_RESULT, Tys, Ops);
+      }
+      break;
+  }
+
+  return DAG.getNode(X86ISD::RET_FLAG, MVT::Other,
+                     Copy, DAG.getConstant(getBytesToPopOnReturn(), MVT::i16),
+                     Copy.getValue(1));
+}
+
 //===----------------------------------------------------------------------===//
 //                    C Calling Convention implementation
 //===----------------------------------------------------------------------===//
@@ -929,5 +1010,100 @@ SDOperand X86TargetLowering::LowerOperation(SDOperand Op, SelectionDAG &DAG) {
     Tys.push_back(MVT::Other);
     return DAG.getNode(ISD::MERGE_VALUES, Tys, Ops);
   }
+  case ISD::SETCC: {
+    assert(Op.getValueType() == MVT::i8 && "SetCC type must be 8-bit integer");
+    SDOperand CC   = Op.getOperand(2);
+    SDOperand Cond = DAG.getNode(X86ISD::CMP, MVT::Flag,
+                                 Op.getOperand(0), Op.getOperand(1));
+    return DAG.getNode(X86ISD::SETCC, MVT::i8, CC, Cond);
   }
+  case ISD::SELECT: {
+    SDOperand Cond  = Op.getOperand(0);
+    SDOperand CC;
+    if (Cond.getOpcode() == X86ISD::SETCC) {
+      CC = Cond.getOperand(0);
+      Cond = Cond.getOperand(1);
+    } else if (Cond.getOpcode() == ISD::SETCC) {
+      CC = Cond.getOperand(2);
+      Cond = DAG.getNode(X86ISD::CMP, MVT::Flag,
+                         Cond.getOperand(0), Cond.getOperand(1));
+    } else {
+      CC = DAG.getCondCode(ISD::SETEQ);
+      Cond = DAG.getNode(X86ISD::TEST, MVT::Flag, Cond, Cond);
+    }
+    return DAG.getNode(X86ISD::CMOV, Op.getValueType(),
+                       Op.getOperand(1), Op.getOperand(2), CC, Cond);
+  }
+  case ISD::BRCOND: {
+    SDOperand Cond  = Op.getOperand(1);
+    SDOperand Dest  = Op.getOperand(2);
+    SDOperand CC;
+    // TODO: handle Cond == OR / AND / XOR
+    if (Cond.getOpcode() == X86ISD::SETCC) {
+      CC = Cond.getOperand(0);
+      Cond = Cond.getOperand(1);
+    } else if (Cond.getOpcode() == ISD::SETCC) {
+      CC = Cond.getOperand(2);
+      Cond = DAG.getNode(X86ISD::CMP, MVT::Flag,
+                         Cond.getOperand(0), Cond.getOperand(1));
+    } else {
+      CC = DAG.getCondCode(ISD::SETNE);
+      Cond = DAG.getNode(X86ISD::TEST, MVT::Flag, Cond, Cond);
+    }
+    return DAG.getNode(X86ISD::BRCOND, Op.getValueType(),
+                       Op.getOperand(0), Op.getOperand(2), CC, Cond);
+  }
+  case ISD::GlobalAddress: {
+    GlobalValue *GV = cast<GlobalAddressSDNode>(Op)->getGlobal();
+    SDOperand GVOp = DAG.getTargetGlobalAddress(GV, getPointerTy());
+    // For Darwin, external and weak symbols are indirect, so we want to load
+    // the value at address GV, not the value of GV itself.  This means that
+    // the GlobalAddress must be in the base or index register of the address,
+    // not the GV offset field.
+    if (getTargetMachine().
+        getSubtarget<X86Subtarget>().getIndirectExternAndWeakGlobals() &&
+        (GV->hasWeakLinkage() || GV->isExternal()))
+      return DAG.getLoad(MVT::i32, DAG.getEntryNode(),
+                         GVOp, DAG.getSrcValue(NULL));
+    else
+      return GVOp;
+    break;
+  }
+  }
+}
+
+const char *X86TargetLowering::getTargetNodeName(unsigned Opcode) const {
+  switch (Opcode) {
+  default: return NULL;
+  case X86ISD::FILD64m:            return "X86ISD::FILD64m";
+  case X86ISD::FP_TO_INT16_IN_MEM: return "X86ISD::FP_TO_INT16_IN_MEM";
+  case X86ISD::FP_TO_INT32_IN_MEM: return "X86ISD::FP_TO_INT32_IN_MEM";
+  case X86ISD::FP_TO_INT64_IN_MEM: return "X86ISD::FP_TO_INT64_IN_MEM";
+  case X86ISD::FLD:                return "X86ISD::FLD";
+  case X86ISD::FP_SET_RESULT:      return "X86ISD::FP_SET_RESULT";
+  case X86ISD::CALL:               return "X86ISD::CALL";
+  case X86ISD::TAILCALL:           return "X86ISD::TAILCALL";
+  case X86ISD::RDTSC_DAG:          return "X86ISD::RDTSC_DAG";
+  case X86ISD::CMP:                return "X86ISD::CMP";
+  case X86ISD::TEST:               return "X86ISD::TEST";
+  case X86ISD::SETCC:              return "X86ISD::SETCC";
+  case X86ISD::CMOV:               return "X86ISD::CMOV";
+  case X86ISD::BRCOND:             return "X86ISD::BRCOND";
+  case X86ISD::RET_FLAG:           return "X86ISD::RET_FLAG";
+  }
+}
+
+bool X86TargetLowering::isMaskedValueZeroForTargetNode(const SDOperand &Op,
+                                                       uint64_t Mask) const {
+
+  unsigned Opc = Op.getOpcode();
+
+  switch (Opc) {
+  default:
+    assert(Opc >= ISD::BUILTIN_OP_END && "Expected a target specific node");
+    break;
+  case X86ISD::SETCC: return (Mask & 1) == 0;
+  }
+
+  return false;
 }