* Added lowering hook for external weak global address. It inserts a load
  for Darwin.
* Added lowering hook for ISD::RET. It inserts CopyToRegs for the return
  value (or store / fld / copy to ST(0) for floating point value). This
  eliminate the need to write C++ code to handle RET with variable number
  of operands.

llvm-svn: 24888
diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp
index 496f105..ee6e320 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.cpp
+++ b/llvm/lib/Target/X86/X86ISelLowering.cpp
@@ -197,6 +197,68 @@
   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:
+      assert(X86ScalarSSE && "MVT::f32 only legal with scalar sse fp");
+      // Fallthrough intended
+    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);
+        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, Copy.getValue(1));
+}
+
 //===----------------------------------------------------------------------===//
 //                    C Calling Convention implementation
 //===----------------------------------------------------------------------===//
@@ -968,6 +1030,20 @@
     return DAG.getNode(X86ISD::BRCOND, Op.getValueType(),
                        Op.getOperand(0), Op.getOperand(2), CC, Cond);
   }
+  case ISD::GlobalAddress:
+    GlobalValue *GV = cast<GlobalAddressSDNode>(Op)->getGlobal();
+    // 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(), Op,
+                         DAG.getSrcValue(NULL));
+    else
+      return Op;
+    break;
   }
 }
 
@@ -978,6 +1054,8 @@
   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";
@@ -985,5 +1063,6 @@
   case X86ISD::TEST:               return "X86ISD::TEST";
   case X86ISD::CMOV:               return "X86ISD::CMOV";
   case X86ISD::BRCOND:             return "X86ISD::BRCOND";
+  case X86ISD::RET_FLAG:           return "X86ISD::RET_FLAG";
   }
 }