Allow the specification of explicit alignments for constant pool entries.
[oota-llvm.git] / lib / Target / Alpha / AlphaISelLowering.cpp
index 92ba16e21bf9d20c404195fc09fb5feba74ad922..2990146899b507234363788c66ceb85304a4e57b 100644 (file)
 #include "llvm/CodeGen/SSARegMap.h"
 #include "llvm/Constants.h"
 #include "llvm/Function.h"
+#include "llvm/Module.h"
 #include "llvm/Support/CommandLine.h"
 #include <iostream>
 
 using namespace llvm;
 
 namespace llvm {
-  extern cl::opt<bool> EnableAlphaIDIV;
-  extern cl::opt<bool> EnableAlphaCount;
-  extern cl::opt<bool> EnableAlphaLSMark;
+  cl::opt<bool> EnableAlphaLSMark("enable-alpha-lsmark",
+    cl::desc("Emit symbols to correlate Mem ops to LLVM Values"),
+    cl::Hidden);
 }
 
 /// AddLiveIn - This helper function adds the specified physical register to the
@@ -68,21 +69,41 @@ AlphaTargetLowering::AlphaTargetLowering(TargetMachine &TM) : TargetLowering(TM)
   
   setOperationAction(ISD::TRUNCSTORE, MVT::i1, Promote);
 
+  if (EnableAlphaLSMark) {
+    setOperationAction(ISD::LOAD, MVT::i64, Custom);
+    setOperationAction(ISD::LOAD, MVT::f64, Custom);
+    setOperationAction(ISD::LOAD, MVT::f32, Custom);
+
+    setOperationAction(ISD::ZEXTLOAD, MVT::i8,  Custom);
+    setOperationAction(ISD::ZEXTLOAD, MVT::i16, Custom);
+    setOperationAction(ISD::SEXTLOAD, MVT::i32, Custom);
+
+    setOperationAction(ISD::EXTLOAD, MVT::i8,  Custom);
+    setOperationAction(ISD::EXTLOAD, MVT::i16, Custom);
+    setOperationAction(ISD::EXTLOAD, MVT::i32, Custom);
+  }
+
   setOperationAction(ISD::FREM, MVT::f32, Expand);
   setOperationAction(ISD::FREM, MVT::f64, Expand);
   
   setOperationAction(ISD::UINT_TO_FP, MVT::i64, Expand);
   setOperationAction(ISD::SINT_TO_FP, MVT::i64, Custom);
-  
+  setOperationAction(ISD::FP_TO_UINT, MVT::i64, Expand);
+  setOperationAction(ISD::FP_TO_SINT, MVT::i64, Custom);
+
   if (!TM.getSubtarget<AlphaSubtarget>().hasCT()) {
     setOperationAction(ISD::CTPOP    , MVT::i64  , Expand);
     setOperationAction(ISD::CTTZ     , MVT::i64  , Expand);
     setOperationAction(ISD::CTLZ     , MVT::i64  , Expand);
   }
+  setOperationAction(ISD::BSWAP    , MVT::i64, Expand);
+  setOperationAction(ISD::ROTL     , MVT::i64, Expand);
+  setOperationAction(ISD::ROTR     , MVT::i64, Expand);
   
-  //If this didn't legalize into a div....
-  //      setOperationAction(ISD::SREM     , MVT::i64, Expand);
-  //      setOperationAction(ISD::UREM     , MVT::i64, Expand);
+  setOperationAction(ISD::SREM     , MVT::i64, Custom);
+  setOperationAction(ISD::UREM     , MVT::i64, Custom);
+  setOperationAction(ISD::SDIV     , MVT::i64, Custom);
+  setOperationAction(ISD::UDIV     , MVT::i64, Custom);
   
   setOperationAction(ISD::MEMMOVE  , MVT::Other, Expand);
   setOperationAction(ISD::MEMSET   , MVT::Other, Expand);
@@ -91,17 +112,41 @@ AlphaTargetLowering::AlphaTargetLowering(TargetMachine &TM) : TargetLowering(TM)
   // We don't support sin/cos/sqrt
   setOperationAction(ISD::FSIN , MVT::f64, Expand);
   setOperationAction(ISD::FCOS , MVT::f64, Expand);
-  setOperationAction(ISD::FSQRT, MVT::f64, Expand);
   setOperationAction(ISD::FSIN , MVT::f32, Expand);
   setOperationAction(ISD::FCOS , MVT::f32, Expand);
+
+  setOperationAction(ISD::FSQRT, MVT::f64, Expand);
   setOperationAction(ISD::FSQRT, MVT::f32, Expand);
 
-  //Doesn't work yet
-  setOperationAction(ISD::SETCC, MVT::f32,   Promote);
+  setOperationAction(ISD::SETCC, MVT::f32, Promote);
 
   // 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);
+
+  // Not implemented yet.
+  setOperationAction(ISD::STACKSAVE, MVT::Other, Expand); 
+  setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand);
+  setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i64, Expand);
+
+  // We want to legalize GlobalAddress and ConstantPool and
+  // ExternalSymbols nodes into the appropriate instructions to
+  // materialize the address.
+  setOperationAction(ISD::GlobalAddress,  MVT::i64, Custom);
+  setOperationAction(ISD::ConstantPool,   MVT::i64, Custom);
+  setOperationAction(ISD::ExternalSymbol, MVT::i64, Custom);
+
+  setOperationAction(ISD::VASTART, MVT::Other, Custom);
+  setOperationAction(ISD::VAEND,   MVT::Other, Expand);
+  setOperationAction(ISD::VACOPY,  MVT::Other, Custom);
+  setOperationAction(ISD::VAARG,   MVT::Other, Custom);
+  setOperationAction(ISD::VAARG,   MVT::i32,   Custom);
+
+  setStackPointerRegisterToSaveRestore(Alpha::R30);
+
+  setOperationAction(ISD::ConstantFP, MVT::f64, Expand);
+  setOperationAction(ISD::ConstantFP, MVT::f32, Expand);
   addLegalFPImmediate(+0.0); //F31
   addLegalFPImmediate(-0.0); //-F31
 
@@ -110,6 +155,34 @@ AlphaTargetLowering::AlphaTargetLowering(TargetMachine &TM) : TargetLowering(TM)
   useITOF = TM.getSubtarget<AlphaSubtarget>().hasF2I();
 }
 
+const char *AlphaTargetLowering::getTargetNodeName(unsigned Opcode) const {
+  switch (Opcode) {
+  default: return 0;
+  case AlphaISD::ITOFT_: return "Alpha::ITOFT_";
+  case AlphaISD::FTOIT_: return "Alpha::FTOIT_";
+  case AlphaISD::CVTQT_: return "Alpha::CVTQT_";
+  case AlphaISD::CVTQS_: return "Alpha::CVTQS_";
+  case AlphaISD::CVTTQ_: return "Alpha::CVTTQ_";
+  case AlphaISD::GPRelHi: return "Alpha::GPRelHi";
+  case AlphaISD::GPRelLo: return "Alpha::GPRelLo";
+  case AlphaISD::RelLit: return "Alpha::RelLit";
+  case AlphaISD::GlobalBaseReg: return "Alpha::GlobalBaseReg";
+  case AlphaISD::CALL:   return "Alpha::CALL";
+  case AlphaISD::DivCall: return "Alpha::DivCall";
+  case AlphaISD::LDQ_: return "Alpha::LDQ_";
+  case AlphaISD::LDT_: return "Alpha::LDT_";
+  case AlphaISD::LDS_: return "Alpha::LDS_";
+  case AlphaISD::LDL_: return "Alpha::LDL_";
+  case AlphaISD::LDWU_: return "Alpha::LDWU_";
+  case AlphaISD::LDBU_:  return "Alpha::LDBU_";
+  case AlphaISD::STQ_: return "Alpha::STQ_";
+  case AlphaISD::STT_: return "Alpha::STT_";
+  case AlphaISD::STS_: return "Alpha::STS_";
+  case AlphaISD::STL_: return "Alpha::STL_";
+  case AlphaISD::STW_: return "Alpha::STW_";
+  case AlphaISD::STB_:  return "Alpha::STB_";
+  }
+}
 
 //http://www.cs.arizona.edu/computer.help/policy/DIGITAL_unix/AA-PY8AC-TET1_html/callCH3.html#BLOCK21
 
@@ -288,8 +361,11 @@ AlphaTargetLowering::LowerCallTo(SDOperand Chain,
     RetVals.push_back(ActualRetTyVT);
   RetVals.push_back(MVT::Other);
 
-  SDOperand TheCall = SDOperand(DAG.getCall(RetVals,
-                                            Chain, Callee, args_to_use), 0);
+  std::vector<SDOperand> Ops;
+  Ops.push_back(Chain);
+  Ops.push_back(Callee);
+  Ops.insert(Ops.end(), args_to_use.begin(), args_to_use.end());
+  SDOperand TheCall = DAG.getNode(AlphaISD::CALL, RetVals, Ops);
   Chain = TheCall.getValue(RetTyVT != MVT::isVoid);
   Chain = DAG.getNode(ISD::CALLSEQ_END, MVT::Other, Chain,
                       DAG.getConstant(NumBytes, getPointerTy()));
@@ -304,80 +380,6 @@ AlphaTargetLowering::LowerCallTo(SDOperand Chain,
   return std::make_pair(RetVal, Chain);
 }
 
-SDOperand AlphaTargetLowering::LowerVAStart(SDOperand Chain, SDOperand VAListP,
-                                            Value *VAListV, SelectionDAG &DAG) {
-  // vastart stores the address of the VarArgsBase and VarArgsOffset
-  SDOperand FR  = DAG.getFrameIndex(VarArgsBase, MVT::i64);
-  SDOperand S1  = DAG.getNode(ISD::STORE, MVT::Other, Chain, FR, VAListP,
-                              DAG.getSrcValue(VAListV));
-  SDOperand SA2 = DAG.getNode(ISD::ADD, MVT::i64, VAListP,
-                              DAG.getConstant(8, MVT::i64));
-  return DAG.getNode(ISD::TRUNCSTORE, MVT::Other, S1,
-                     DAG.getConstant(VarArgsOffset, MVT::i64), SA2,
-                     DAG.getSrcValue(VAListV, 8), DAG.getValueType(MVT::i32));
-}
-
-std::pair<SDOperand,SDOperand> AlphaTargetLowering::
-LowerVAArg(SDOperand Chain, SDOperand VAListP, Value *VAListV,
-           const Type *ArgTy, SelectionDAG &DAG) {
-  SDOperand Base = DAG.getLoad(MVT::i64, Chain, VAListP,
-                               DAG.getSrcValue(VAListV));
-  SDOperand Tmp = DAG.getNode(ISD::ADD, MVT::i64, VAListP,
-                              DAG.getConstant(8, MVT::i64));
-  SDOperand Offset = DAG.getExtLoad(ISD::SEXTLOAD, MVT::i64, Base.getValue(1),
-                                    Tmp, DAG.getSrcValue(VAListV, 8), MVT::i32);
-  SDOperand DataPtr = DAG.getNode(ISD::ADD, MVT::i64, Base, Offset);
-  if (ArgTy->isFloatingPoint())
-  {
-    //if fp && Offset < 6*8, then subtract 6*8 from DataPtr
-      SDOperand FPDataPtr = DAG.getNode(ISD::SUB, MVT::i64, DataPtr,
-                                        DAG.getConstant(8*6, MVT::i64));
-      SDOperand CC = DAG.getSetCC(MVT::i64, Offset,
-                                  DAG.getConstant(8*6, MVT::i64), ISD::SETLT);
-      DataPtr = DAG.getNode(ISD::SELECT, MVT::i64, CC, FPDataPtr, DataPtr);
-  }
-
-  SDOperand Result;
-  if (ArgTy == Type::IntTy)
-    Result = DAG.getExtLoad(ISD::SEXTLOAD, MVT::i64, Offset.getValue(1),
-                            DataPtr, DAG.getSrcValue(NULL), MVT::i32);
-  else if (ArgTy == Type::UIntTy)
-    Result = DAG.getExtLoad(ISD::ZEXTLOAD, MVT::i64, Offset.getValue(1),
-                            DataPtr, DAG.getSrcValue(NULL), MVT::i32);
-  else
-    Result = DAG.getLoad(getValueType(ArgTy), Offset.getValue(1), DataPtr,
-                         DAG.getSrcValue(NULL));
-
-  SDOperand NewOffset = DAG.getNode(ISD::ADD, MVT::i64, Offset,
-                                    DAG.getConstant(8, MVT::i64));
-  SDOperand Update = DAG.getNode(ISD::TRUNCSTORE, MVT::Other,
-                                 Result.getValue(1), NewOffset,
-                                 Tmp, DAG.getSrcValue(VAListV, 8),
-                                 DAG.getValueType(MVT::i32));
-  Result = DAG.getNode(ISD::TRUNCATE, getValueType(ArgTy), Result);
-
-  return std::make_pair(Result, Update);
-}
-
-
-SDOperand AlphaTargetLowering::
-LowerVACopy(SDOperand Chain, SDOperand SrcP, Value *SrcV, SDOperand DestP,
-            Value *DestV, SelectionDAG &DAG) {
-  SDOperand Val = DAG.getLoad(getPointerTy(), Chain, SrcP,
-                              DAG.getSrcValue(SrcV));
-  SDOperand Result = DAG.getNode(ISD::STORE, MVT::Other, Val.getValue(1),
-                                 Val, DestP, DAG.getSrcValue(DestV));
-  SDOperand NP = DAG.getNode(ISD::ADD, MVT::i64, SrcP,
-                             DAG.getConstant(8, MVT::i64));
-  Val = DAG.getExtLoad(ISD::SEXTLOAD, MVT::i64, Result, NP,
-                       DAG.getSrcValue(SrcV, 8), MVT::i32);
-  SDOperand NPD = DAG.getNode(ISD::ADD, MVT::i64, DestP,
-                             DAG.getConstant(8, MVT::i64));
-  return DAG.getNode(ISD::TRUNCSTORE, MVT::Other, Val.getValue(1),
-                     Val, NPD, DAG.getSrcValue(DestV, 8),
-                     DAG.getValueType(MVT::i32));
-}
-
 void AlphaTargetLowering::restoreGP(MachineBasicBlock* BB)
 {
   BuildMI(BB, Alpha::BIS, 2, Alpha::R29).addReg(GP).addReg(GP);
@@ -388,6 +390,53 @@ void AlphaTargetLowering::restoreRA(MachineBasicBlock* BB)
 }
 
 
+
+static void getValueInfo(const Value* v, int& type, int& fun, int& offset)
+{
+  fun = type = offset = 0;
+  if (v == NULL) {
+    type = 0;
+  } else if (const GlobalValue* GV = dyn_cast<GlobalValue>(v)) {
+    type = 1;
+    const Module* M = GV->getParent();
+    for(Module::const_global_iterator ii = M->global_begin(); &*ii != GV; ++ii)
+      ++offset;
+  } else if (const Argument* Arg = dyn_cast<Argument>(v)) {
+    type = 2;
+    const Function* F = Arg->getParent();
+    const Module* M = F->getParent();
+    for(Module::const_iterator ii = M->begin(); &*ii != F; ++ii)
+      ++fun;
+    for(Function::const_arg_iterator ii = F->arg_begin(); &*ii != Arg; ++ii)
+      ++offset;
+  } else if (const Instruction* I = dyn_cast<Instruction>(v)) {
+    assert(dyn_cast<PointerType>(I->getType()));
+    type = 3;
+    const BasicBlock* bb = I->getParent();
+    const Function* F = bb->getParent();
+    const Module* M = F->getParent();
+    for(Module::const_iterator ii = M->begin(); &*ii != F; ++ii)
+      ++fun;
+    for(Function::const_iterator ii = F->begin(); &*ii != bb; ++ii)
+      offset += ii->size();
+    for(BasicBlock::const_iterator ii = bb->begin(); &*ii != I; ++ii)
+      ++offset;
+  } else if (const Constant* C = dyn_cast<Constant>(v)) {
+    //Don't know how to look these up yet
+    type = 0;
+  } else {
+    assert(0 && "Error in value marking");
+  }
+  //type = 4: register spilling
+  //type = 5: global address loading or constant loading
+}
+
+static int getUID()
+{
+  static int id = 0;
+  return ++id;
+}
+
 /// LowerOperation - Provide custom lowering hooks for some operations.
 ///
 SDOperand AlphaTargetLowering::LowerOperation(SDOperand Op, SelectionDAG &DAG) {
@@ -412,7 +461,247 @@ SDOperand AlphaTargetLowering::LowerOperation(SDOperand Op, SelectionDAG &DAG) {
                                isDouble?MVT::f64:MVT::f32, LD);
     return FP;
   }
+  case ISD::FP_TO_SINT: {
+    bool isDouble = MVT::f64 == Op.getOperand(0).getValueType();
+    SDOperand src = Op.getOperand(0);
+
+    if (!isDouble) //Promote
+      src = DAG.getNode(ISD::FP_EXTEND, MVT::f64, src);
+    
+    src = DAG.getNode(AlphaISD::CVTTQ_, MVT::f64, src);
+
+    if (useITOF) {
+      return DAG.getNode(AlphaISD::FTOIT_, MVT::i64, src);
+    } else {
+      int FrameIdx =
+        DAG.getMachineFunction().getFrameInfo()->CreateStackObject(8, 8);
+      SDOperand FI = DAG.getFrameIndex(FrameIdx, MVT::i64);
+      SDOperand ST = DAG.getNode(ISD::STORE, MVT::Other, DAG.getEntryNode(),
+                                 src, FI, DAG.getSrcValue(0));
+      return DAG.getLoad(MVT::i64, ST, FI, DAG.getSrcValue(0));
+      }
+  }
+  case ISD::ConstantPool: {
+    ConstantPoolSDNode *CP = cast<ConstantPoolSDNode>(Op);
+    Constant *C = CP->get();
+    SDOperand CPI = DAG.getTargetConstantPool(C, MVT::i64, CP->getAlignment());
+    
+    SDOperand Hi = DAG.getNode(AlphaISD::GPRelHi,  MVT::i64, CPI,
+                              DAG.getNode(AlphaISD::GlobalBaseReg, MVT::i64));
+    SDOperand Lo = DAG.getNode(AlphaISD::GPRelLo, MVT::i64, CPI, Hi);
+    return Lo;
+  }
+  case ISD::GlobalAddress: {
+    GlobalAddressSDNode *GSDN = cast<GlobalAddressSDNode>(Op);
+    GlobalValue *GV = GSDN->getGlobal();
+    SDOperand GA = DAG.getTargetGlobalAddress(GV, MVT::i64, GSDN->getOffset());
+
+    if (!GV->hasWeakLinkage() && !GV->isExternal()) {
+      SDOperand Hi = DAG.getNode(AlphaISD::GPRelHi,  MVT::i64, GA,
+                                DAG.getNode(AlphaISD::GlobalBaseReg, MVT::i64));
+      SDOperand Lo = DAG.getNode(AlphaISD::GPRelLo, MVT::i64, GA, Hi);
+      return Lo;
+    } else
+      return DAG.getNode(AlphaISD::RelLit, MVT::i64, GA, DAG.getNode(AlphaISD::GlobalBaseReg, MVT::i64));
+  }
+  case ISD::ExternalSymbol: {
+    return DAG.getNode(AlphaISD::RelLit, MVT::i64, 
+                      DAG.getTargetExternalSymbol(cast<ExternalSymbolSDNode>(Op)->getSymbol(), MVT::i64),
+                      DAG.getNode(AlphaISD::GlobalBaseReg, MVT::i64));
+  }
+
+  case ISD::SDIV:
+  case ISD::UDIV:
+  case ISD::UREM:
+  case ISD::SREM:
+    if (MVT::isInteger(Op.getValueType())) {
+      const char* opstr = 0;
+      switch(Op.getOpcode()) {
+      case ISD::UREM: opstr = "__remqu"; break;
+      case ISD::SREM: opstr = "__remq";  break;
+      case ISD::UDIV: opstr = "__divqu"; break;
+      case ISD::SDIV: opstr = "__divq";  break;
+      }
+      SDOperand Tmp1 = Op.getOperand(0),
+        Tmp2 = Op.getOperand(1),
+        Addr = DAG.getExternalSymbol(opstr, MVT::i64);
+      return DAG.getNode(AlphaISD::DivCall, MVT::i64, Addr, Tmp1, Tmp2);
+    }
+    break;
+
+  case ISD::LOAD:
+  case ISD::SEXTLOAD:
+  case ISD::ZEXTLOAD:
+  case ISD::EXTLOAD:
+    {
+      SDOperand Chain   = Op.getOperand(0);
+      SDOperand Address = Op.getOperand(1);
+
+      unsigned Opc;
+      unsigned opcode = Op.getOpcode();
+
+      if (opcode == ISD::LOAD)
+        switch (Op.Val->getValueType(0)) {
+        default: Op.Val->dump(); assert(0 && "Bad load!");
+        case MVT::i64: Opc = AlphaISD::LDQ_; break;
+        case MVT::f64: Opc = AlphaISD::LDT_; break;
+        case MVT::f32: Opc = AlphaISD::LDS_; break;
+        }
+      else
+        switch (cast<VTSDNode>(Op.getOperand(3))->getVT()) {
+        default: Op.Val->dump(); assert(0 && "Bad sign extend!");
+        case MVT::i32: Opc = AlphaISD::LDL_;
+          assert(opcode != ISD::ZEXTLOAD && "Not sext"); break;
+        case MVT::i16: Opc = AlphaISD::LDWU_;
+          assert(opcode != ISD::SEXTLOAD && "Not zext"); break;
+        case MVT::i1: //FIXME: Treat i1 as i8 since there are problems otherwise
+        case MVT::i8: Opc = AlphaISD::LDBU_;
+          assert(opcode != ISD::SEXTLOAD && "Not zext"); break;
+        }
+
+      int i, j, k;
+      getValueInfo(dyn_cast<SrcValueSDNode>(Op.getOperand(2))->getValue(), i, j, k);
+
+      SDOperand Zero = DAG.getConstant(0, MVT::i64);
+      std::vector<MVT::ValueType> VTS;
+      VTS.push_back(Op.Val->getValueType(0));
+      VTS.push_back(MVT::Other);
+      std::vector<SDOperand> ARGS;
+      ARGS.push_back(Chain);
+      ARGS.push_back(Zero);
+      ARGS.push_back(Address);
+      ARGS.push_back(DAG.getConstant(i, MVT::i64));
+      ARGS.push_back(DAG.getConstant(j, MVT::i64));
+      ARGS.push_back(DAG.getConstant(k, MVT::i64));
+      ARGS.push_back(DAG.getConstant(getUID(), MVT::i64));
+      return DAG.getNode(Opc, VTS, ARGS);
+    }
+
+  case ISD::TRUNCSTORE:
+  case ISD::STORE:
+    {
+      SDOperand Chain   = Op.getOperand(0);
+      SDOperand Value = Op.getOperand(1);
+      SDOperand Address = Op.getOperand(2);
+
+      unsigned Opc;
+      unsigned opcode = Op.getOpcode();
+
+      if (opcode == ISD::STORE) {
+        switch(Value.getValueType()) {
+        default: assert(0 && "unknown Type in store");
+        case MVT::i64: Opc = AlphaISD::STQ_; break;
+        case MVT::f64: Opc = AlphaISD::STT_; break;
+        case MVT::f32: Opc = AlphaISD::STS_; break;
+        }
+      } else { //ISD::TRUNCSTORE
+        switch(cast<VTSDNode>(Op.getOperand(4))->getVT()) {
+        default: assert(0 && "unknown Type in store");
+        case MVT::i8: Opc = AlphaISD::STB_; break;
+        case MVT::i16: Opc = AlphaISD::STW_; break;
+        case MVT::i32: Opc = AlphaISD::STL_; break;
+        }
+      }
+
+      int i, j, k;
+      getValueInfo(cast<SrcValueSDNode>(Op.getOperand(3))->getValue(), i, j, k);
+
+      SDOperand Zero = DAG.getConstant(0, MVT::i64);
+      std::vector<MVT::ValueType> VTS;
+      VTS.push_back(MVT::Other);
+      std::vector<SDOperand> ARGS;
+      ARGS.push_back(Chain);
+      ARGS.push_back(Value);
+      ARGS.push_back(Zero);
+      ARGS.push_back(Address);
+      ARGS.push_back(DAG.getConstant(i, MVT::i64));
+      ARGS.push_back(DAG.getConstant(j, MVT::i64));
+      ARGS.push_back(DAG.getConstant(k, MVT::i64));
+      ARGS.push_back(DAG.getConstant(getUID(), MVT::i64));
+      return DAG.getNode(Opc, VTS, ARGS);
+    }
+  case ISD::VAARG: {
+    SDOperand Chain = Op.getOperand(0);
+    SDOperand VAListP = Op.getOperand(1);
+    SDOperand VAListS = Op.getOperand(2);
+    
+    SDOperand Base = DAG.getLoad(MVT::i64, Chain, VAListP, VAListS);
+    SDOperand Tmp = DAG.getNode(ISD::ADD, MVT::i64, VAListP,
+                                DAG.getConstant(8, MVT::i64));
+    SDOperand Offset = DAG.getExtLoad(ISD::SEXTLOAD, MVT::i64, Base.getValue(1),
+                                      Tmp, DAG.getSrcValue(0), MVT::i32);
+    SDOperand DataPtr = DAG.getNode(ISD::ADD, MVT::i64, Base, Offset);
+    if (MVT::isFloatingPoint(Op.getValueType()))
+    {
+      //if fp && Offset < 6*8, then subtract 6*8 from DataPtr
+      SDOperand FPDataPtr = DAG.getNode(ISD::SUB, MVT::i64, DataPtr,
+                                        DAG.getConstant(8*6, MVT::i64));
+      SDOperand CC = DAG.getSetCC(MVT::i64, Offset,
+                                  DAG.getConstant(8*6, MVT::i64), ISD::SETLT);
+      DataPtr = DAG.getNode(ISD::SELECT, MVT::i64, CC, FPDataPtr, DataPtr);
+    }
+
+    SDOperand NewOffset = DAG.getNode(ISD::ADD, MVT::i64, Offset,
+                                      DAG.getConstant(8, MVT::i64));
+    SDOperand Update = DAG.getNode(ISD::TRUNCSTORE, MVT::Other,
+                                   Offset.getValue(1), NewOffset,
+                                   Tmp, DAG.getSrcValue(0),
+                                   DAG.getValueType(MVT::i32));
+    
+    SDOperand Result;
+    if (Op.getValueType() == MVT::i32)
+      Result = DAG.getExtLoad(ISD::SEXTLOAD, MVT::i64, Update, DataPtr,
+                              DAG.getSrcValue(0), MVT::i32);
+    else
+      Result = DAG.getLoad(Op.getValueType(), Update, DataPtr, 
+                           DAG.getSrcValue(0));
+    return Result;
+  }
+  case ISD::VACOPY: {
+    SDOperand Chain = Op.getOperand(0);
+    SDOperand DestP = Op.getOperand(1);
+    SDOperand SrcP = Op.getOperand(2);
+    SDOperand DestS = Op.getOperand(3);
+    SDOperand SrcS = Op.getOperand(4);
+    
+    SDOperand Val = DAG.getLoad(getPointerTy(), Chain, SrcP, SrcS);
+    SDOperand Result = DAG.getNode(ISD::STORE, MVT::Other, Val.getValue(1), Val,
+                                   DestP, DestS);
+    SDOperand NP = DAG.getNode(ISD::ADD, MVT::i64, SrcP, 
+                               DAG.getConstant(8, MVT::i64));
+    Val = DAG.getExtLoad(ISD::SEXTLOAD, MVT::i64, Result, NP,
+                         DAG.getSrcValue(0), MVT::i32);
+    SDOperand NPD = DAG.getNode(ISD::ADD, MVT::i64, DestP,
+                                DAG.getConstant(8, MVT::i64));
+    return DAG.getNode(ISD::TRUNCSTORE, MVT::Other, Val.getValue(1),
+                       Val, NPD, DAG.getSrcValue(0),DAG.getValueType(MVT::i32));
+  }
+  case ISD::VASTART: {
+    SDOperand Chain = Op.getOperand(0);
+    SDOperand VAListP = Op.getOperand(1);
+    SDOperand VAListS = Op.getOperand(2);
+    
+    // vastart stores the address of the VarArgsBase and VarArgsOffset
+    SDOperand FR  = DAG.getFrameIndex(VarArgsBase, MVT::i64);
+    SDOperand S1  = DAG.getNode(ISD::STORE, MVT::Other, Chain, FR, VAListP,
+                                VAListS);
+    SDOperand SA2 = DAG.getNode(ISD::ADD, MVT::i64, VAListP,
+                                DAG.getConstant(8, MVT::i64));
+    return DAG.getNode(ISD::TRUNCSTORE, MVT::Other, S1,
+                       DAG.getConstant(VarArgsOffset, MVT::i64), SA2,
+                       DAG.getSrcValue(0), DAG.getValueType(MVT::i32));
   }
+  }
+
   return SDOperand();
 }
 
+SDOperand AlphaTargetLowering::CustomPromoteOperation(SDOperand Op, 
+                                                      SelectionDAG &DAG) {
+  assert(Op.getValueType() == MVT::i32 && 
+         Op.getOpcode() == ISD::VAARG &&
+         "Unknown node to custom promote!");
+  
+  // The code in LowerOperation already handles i32 vaarg
+  return LowerOperation(Op, DAG);
+}