fix storing bools! eek!
[oota-llvm.git] / lib / Target / IA64 / IA64ISelLowering.cpp
index 2ffa24e78c0b42e4fbfc7347b3843037134cf20c..c4a4cdf94353bf02c7d228666ac6cefdb9e78c5d 100644 (file)
@@ -72,19 +72,39 @@ IA64TargetLowering::IA64TargetLowering(TargetMachine &TM)
       setOperationAction(ISD::FCOS , MVT::f32, Expand);
       setOperationAction(ISD::FSQRT, MVT::f32, Expand);
 
+      // We don't have line number support yet.
+      setOperationAction(ISD::LOCATION, MVT::Other, Expand);
+      setOperationAction(ISD::DEBUG_LOC, MVT::Other, Expand);
+      setOperationAction(ISD::DEBUG_LABEL, MVT::Other, Expand);
+
       //IA64 has these, but they are not implemented
       setOperationAction(ISD::CTTZ , MVT::i64  , Expand);
       setOperationAction(ISD::CTLZ , MVT::i64  , Expand);
+      setOperationAction(ISD::ROTL , MVT::i64  , Expand);
+      setOperationAction(ISD::ROTR , MVT::i64  , Expand);
+      setOperationAction(ISD::BSWAP, MVT::i64  , Expand);  // mux @rev
+
+      setOperationAction(ISD::STACKSAVE, MVT::Other, Expand);
+      setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand);
+      setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i64, Expand);
+
+      setStackPointerRegisterToSaveRestore(IA64::r12);
 
       computeRegisterProperties();
 
       addLegalFPImmediate(+0.0);
       addLegalFPImmediate(+1.0);
-      addLegalFPImmediate(-0.0);
-      addLegalFPImmediate(-1.0);
-    
 }
 
+const char *IA64TargetLowering::getTargetNodeName(unsigned Opcode) const {
+  switch (Opcode) {
+  default: return 0;
+  case IA64ISD::GETFD:  return "IA64ISD::GETFD";
+  case IA64ISD::BRCALL: return "IA64ISD::BRCALL";  
+  }
+}
+  
+
 /// isFloatingPointZero - Return true if this is 0.0 or -0.0.
 static bool isFloatingPointZero(SDOperand Op) {
   if (ConstantFPSDNode *CFP = dyn_cast<ConstantFPSDNode>(Op))
@@ -195,20 +215,21 @@ IA64TargetLowering::LowerArguments(Function &F, SelectionDAG &DAG) {
   VirtGPR = MF.getSSARegMap()->createVirtualRegister(getRegClassFor(MVT::i64));
   BuildMI(&BB, IA64::PSEUDO_ALLOC, 0, VirtGPR);
   // we create a PSEUDO_ALLOC (pseudo)instruction for now
-
+/*
   BuildMI(&BB, IA64::IDEF, 0, IA64::r1);
 
   // hmm:
   BuildMI(&BB, IA64::IDEF, 0, IA64::r12);
   BuildMI(&BB, IA64::IDEF, 0, IA64::rp);
   // ..hmm.
-
+  
   BuildMI(&BB, IA64::MOV, 1, GP).addReg(IA64::r1);
 
   // hmm:
   BuildMI(&BB, IA64::MOV, 1, SP).addReg(IA64::r12);
   BuildMI(&BB, IA64::MOV, 1, RP).addReg(IA64::rp);
   // ..hmm.
+*/
 
   unsigned tempOffset=0;
 
@@ -280,13 +301,26 @@ IA64TargetLowering::LowerCallTo(SDOperand Chain,
   MF.getInfo<IA64FunctionInfo>()->outRegsUsed=
     std::max(outRegsUsed, MF.getInfo<IA64FunctionInfo>()->outRegsUsed);
 
+  // keep stack frame 16-byte aligned
+  //assert(NumBytes==((NumBytes+15) & ~15) && "stack frame not 16-byte aligned!");
+  NumBytes = (NumBytes+15) & ~15;
+  
   Chain = DAG.getNode(ISD::CALLSEQ_START, MVT::Other, Chain,
                         DAG.getConstant(NumBytes, getPointerTy()));
 
-  std::vector<SDOperand> args_to_use;
+  SDOperand StackPtr, NullSV;
+  std::vector<SDOperand> Stores;
+  std::vector<SDOperand> Converts;
+  std::vector<SDOperand> RegValuesToPass;
+  unsigned ArgOffset = 16;
+  
   for (unsigned i = 0, e = Args.size(); i != e; ++i)
     {
-      switch (getValueType(Args[i].second)) {
+      SDOperand Val = Args[i].first;
+      MVT::ValueType ObjectVT = Val.getValueType();
+      SDOperand ValToStore(0, 0), ValToConvert(0, 0);
+      unsigned ObjSize=8;
+      switch (ObjectVT) {
       default: assert(0 && "unexpected argument type!");
       case MVT::i1:
       case MVT::i8:
@@ -295,34 +329,195 @@ IA64TargetLowering::LowerCallTo(SDOperand Chain,
         //promote to 64-bits, sign/zero extending based on type
         //of the argument
         if(Args[i].second->isSigned())
-          Args[i].first = DAG.getNode(ISD::SIGN_EXTEND, MVT::i64,
-              Args[i].first);
+          Val = DAG.getNode(ISD::SIGN_EXTEND, MVT::i64, Val);
         else
-          Args[i].first = DAG.getNode(ISD::ZERO_EXTEND, MVT::i64,
-              Args[i].first);
+          Val = DAG.getNode(ISD::ZERO_EXTEND, MVT::i64, Val);
+        // XXX: fall through
+      case MVT::i64:
+        //ObjSize = 8;
+        if(RegValuesToPass.size() >= 8) {
+          ValToStore = Val;
+        } else {
+          RegValuesToPass.push_back(Val);
+        }
         break;
       case MVT::f32:
         //promote to 64-bits
-        Args[i].first = DAG.getNode(ISD::FP_EXTEND, MVT::f64, Args[i].first);
+        Val = DAG.getNode(ISD::FP_EXTEND, MVT::f64, Val);
+        // XXX: fall through
       case MVT::f64:
-      case MVT::i64:
+        if(RegValuesToPass.size() >= 8) {
+          ValToStore = Val;
+        } else {
+          RegValuesToPass.push_back(Val);
+         if(1 /* TODO: if(calling external or varadic function)*/ ) {
+           ValToConvert = Val; // additionally pass this FP value as an int
+         }
+        }
         break;
       }
-      args_to_use.push_back(Args[i].first);
+      
+      if(ValToStore.Val) {
+        if(!StackPtr.Val) {
+          StackPtr = DAG.getRegister(IA64::r12, MVT::i64);
+          NullSV = DAG.getSrcValue(NULL);
+        }
+        SDOperand PtrOff = DAG.getConstant(ArgOffset, getPointerTy());
+        PtrOff = DAG.getNode(ISD::ADD, MVT::i64, StackPtr, PtrOff);
+        Stores.push_back(DAG.getNode(ISD::STORE, MVT::Other, Chain,
+                                     ValToStore, PtrOff, NullSV));
+        ArgOffset += ObjSize;
+      }
+
+      if(ValToConvert.Val) {
+       Converts.push_back(DAG.getNode(IA64ISD::GETFD, MVT::i64, ValToConvert)); 
+      }
     }
 
+  // Emit all stores, make sure they occur before any copies into physregs.
+  if (!Stores.empty())
+    Chain = DAG.getNode(ISD::TokenFactor, MVT::Other, Stores);
+
+  static const unsigned IntArgRegs[] = {
+    IA64::out0, IA64::out1, IA64::out2, IA64::out3, 
+    IA64::out4, IA64::out5, IA64::out6, IA64::out7
+  };
+
+  static const unsigned FPArgRegs[] = {
+    IA64::F8,  IA64::F9,  IA64::F10, IA64::F11, 
+    IA64::F12, IA64::F13, IA64::F14, IA64::F15
+  };
+
+  SDOperand InFlag;
+  
+  // save the current GP, SP and RP : FIXME: do we need to do all 3 always?
+  SDOperand GPBeforeCall = DAG.getCopyFromReg(Chain, IA64::r1, MVT::i64, InFlag);
+  Chain = GPBeforeCall.getValue(1);
+  InFlag = Chain.getValue(2);
+  SDOperand SPBeforeCall = DAG.getCopyFromReg(Chain, IA64::r12, MVT::i64, InFlag);
+  Chain = SPBeforeCall.getValue(1);
+  InFlag = Chain.getValue(2);
+  SDOperand RPBeforeCall = DAG.getCopyFromReg(Chain, IA64::rp, MVT::i64, InFlag);
+  Chain = RPBeforeCall.getValue(1);
+  InFlag = Chain.getValue(2);
+
+  // Build a sequence of copy-to-reg nodes chained together with token chain
+  // and flag operands which copy the outgoing integer args into regs out[0-7]
+  // mapped 1:1 and the FP args into regs F8-F15 "lazily"
+  // TODO: for performance, we should only copy FP args into int regs when we
+  // know this is required (i.e. for varardic or external (unknown) functions)
+
+  // first to the FP->(integer representation) conversions, these are
+  // flagged for now, but shouldn't have to be (TODO)
+  unsigned seenConverts = 0;
+  for (unsigned i = 0, e = RegValuesToPass.size(); i != e; ++i) {
+    if(MVT::isFloatingPoint(RegValuesToPass[i].getValueType())) {
+      Chain = DAG.getCopyToReg(Chain, IntArgRegs[i], Converts[seenConverts++], InFlag);
+      InFlag = Chain.getValue(1);
+    }
+  }
+
+  // next copy args into the usual places, these are flagged
+  unsigned usedFPArgs = 0;
+  for (unsigned i = 0, e = RegValuesToPass.size(); i != e; ++i) {
+    Chain = DAG.getCopyToReg(Chain,
+      MVT::isInteger(RegValuesToPass[i].getValueType()) ?
+                                          IntArgRegs[i] : FPArgRegs[usedFPArgs++],
+      RegValuesToPass[i], InFlag);
+    InFlag = Chain.getValue(1);
+  }
+
+  // If the callee is a GlobalAddress node (quite common, every direct call is)
+  // turn it into a TargetGlobalAddress node so that legalize doesn't hack it.
+/*
+  if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) {
+    Callee = DAG.getTargetGlobalAddress(G->getGlobal(), MVT::i64);
+  }
+*/
+
+  std::vector<MVT::ValueType> NodeTys;
+  std::vector<SDOperand> CallOperands;
+  NodeTys.push_back(MVT::Other);   // Returns a chain
+  NodeTys.push_back(MVT::Flag);    // Returns a flag for retval copy to use.
+  CallOperands.push_back(Chain);
+  CallOperands.push_back(Callee);
+
+  // emit the call itself
+  if (InFlag.Val)
+    CallOperands.push_back(InFlag);
+  else
+    assert(0 && "this should never happen!\n");
+
+/* out with the old...
+    Chain = SDOperand(DAG.getCall(NodeTys, Chain, Callee, InFlag), 0);
+  else
+    Chain = SDOperand(DAG.getCall(NodeTys, Chain, Callee), 0);
+*/
+  // to make way for a hack:
+  Chain = DAG.getNode(IA64ISD::BRCALL, NodeTys, CallOperands);
+  InFlag = Chain.getValue(1);
+
+  // restore the GP, SP and RP after the call  
+  Chain = DAG.getCopyToReg(Chain, IA64::r1, GPBeforeCall, InFlag);
+  InFlag = Chain.getValue(1);
+  Chain = DAG.getCopyToReg(Chain, IA64::r12, SPBeforeCall, InFlag);
+  InFlag = Chain.getValue(1);
+  Chain = DAG.getCopyToReg(Chain, IA64::rp, RPBeforeCall, InFlag);
+  InFlag = Chain.getValue(1);
   std::vector<MVT::ValueType> RetVals;
-  MVT::ValueType RetTyVT = getValueType(RetTy);
-  if (RetTyVT != MVT::isVoid)
-    RetVals.push_back(RetTyVT);
   RetVals.push_back(MVT::Other);
-
-  SDOperand TheCall = SDOperand(DAG.getCall(RetVals, Chain,
-                                            Callee, args_to_use), 0);
-  Chain = TheCall.getValue(RetTyVT != MVT::isVoid);
+  RetVals.push_back(MVT::Flag);
+  MVT::ValueType RetTyVT = getValueType(RetTy);
+  SDOperand RetVal;
+  if (RetTyVT != MVT::isVoid) {
+    switch (RetTyVT) {
+    default: assert(0 && "Unknown value type to return!");
+    case MVT::i1: { // bools are just like other integers (returned in r8)
+      SDOperand boolInR8 = DAG.getCopyFromReg(Chain, IA64::r8, MVT::i64, InFlag);
+      InFlag = boolInR8.getValue(2);
+      Chain = boolInR8.getValue(1);
+      SDOperand zeroReg = DAG.getCopyFromReg(Chain, IA64::r0, MVT::i64, InFlag);
+      InFlag = zeroReg.getValue(2);
+      Chain = zeroReg.getValue(1);     
+      
+      RetVal = DAG.getSetCC(MVT::i1, boolInR8, zeroReg, ISD::SETNE);
+      break;
+    }
+    case MVT::i8:
+    case MVT::i16:
+    case MVT::i32:
+      RetVal = DAG.getCopyFromReg(Chain, IA64::r8, MVT::i64, InFlag);
+      Chain = RetVal.getValue(1);
+      
+      // keep track of whether it is sign or zero extended (todo: bools?)
+      RetVal = DAG.getNode(RetTy->isSigned() ? ISD::AssertSext :ISD::AssertZext,
+                           MVT::i64, RetVal, DAG.getValueType(RetTyVT));
+      RetVal = DAG.getNode(ISD::TRUNCATE, RetTyVT, RetVal);
+      break;
+    case MVT::i64:
+      RetVal = DAG.getCopyFromReg(Chain, IA64::r8, MVT::i64, InFlag);
+      Chain = RetVal.getValue(1);
+      InFlag = RetVal.getValue(2); // XXX dead
+      break;
+    case MVT::f32:
+      RetVal = DAG.getCopyFromReg(Chain, IA64::F8, MVT::f64, InFlag);
+      Chain = RetVal.getValue(1);
+      RetVal = DAG.getNode(ISD::TRUNCATE, MVT::f32, RetVal);
+      break;
+    case MVT::f64:
+      RetVal = DAG.getCopyFromReg(Chain, IA64::F8, MVT::f64, InFlag);
+      Chain = RetVal.getValue(1);
+      InFlag = RetVal.getValue(2); // XXX dead
+      break;
+    }
+  }
+  
   Chain = DAG.getNode(ISD::CALLSEQ_END, MVT::Other, Chain,
                       DAG.getConstant(NumBytes, getPointerTy()));
-  return std::make_pair(TheCall, Chain);
+  
+  return std::make_pair(RetVal, Chain);
 }
 
 SDOperand