expand ISD::MEMSET
[oota-llvm.git] / lib / Target / ARM / ARMISelDAGToDAG.cpp
index 000efaadde19083d3277964cd2c4d2ca8b6e3ae1..43f54acd1cefc16b3d7b93b05388f8adb0a7bd39 100644 (file)
@@ -16,6 +16,7 @@
 #include "llvm/CallingConv.h"
 #include "llvm/DerivedTypes.h"
 #include "llvm/Function.h"
+#include "llvm/Constants.h"
 #include "llvm/Intrinsics.h"
 #include "llvm/CodeGen/MachineFrameInfo.h"
 #include "llvm/CodeGen/MachineFunction.h"
 #include "llvm/Target/TargetLowering.h"
 #include "llvm/Support/Debug.h"
 #include <iostream>
-#include <set>
+#include <vector>
 using namespace llvm;
 
 namespace {
   class ARMTargetLowering : public TargetLowering {
+    int VarArgsFrameIndex;            // FrameIndex for start of varargs area.
   public:
     ARMTargetLowering(TargetMachine &TM);
     virtual SDOperand LowerOperation(SDOperand Op, SelectionDAG &DAG);
@@ -41,9 +43,59 @@ namespace {
 
 ARMTargetLowering::ARMTargetLowering(TargetMachine &TM)
   : TargetLowering(TM) {
+  addRegisterClass(MVT::i32, ARM::IntRegsRegisterClass);
+  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::SIGN_EXTEND_INREG, MVT::i16, Expand);
+  setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i8 , Expand);
+  setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1 , Expand);
+
+  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::MEMSET, MVT::Other, Expand);
+
+  setOperationAction(ISD::BRIND, MVT::i32, Expand);
+  setOperationAction(ISD::BR_CC, MVT::i32, Custom);
+  setOperationAction(ISD::BR_CC, MVT::f32, Custom);
+  setOperationAction(ISD::BR_CC, MVT::f64, Custom);
+
+  setOperationAction(ISD::BRCOND,        MVT::Other, Expand);
+
+  setOperationAction(ISD::SHL_PARTS, MVT::i32, Expand);
+  setOperationAction(ISD::SRA_PARTS, MVT::i32, Expand);
+  setOperationAction(ISD::SRL_PARTS, MVT::i32, Expand);
+  setOperationAction(ISD::SDIV,      MVT::i32, Expand);
+  setOperationAction(ISD::UDIV,      MVT::i32, Expand);
+  setOperationAction(ISD::SREM,      MVT::i32, Expand);
+  setOperationAction(ISD::UREM,      MVT::i32, Expand);
+
+  setOperationAction(ISD::VASTART,       MVT::Other, Custom);
+  setOperationAction(ISD::VAEND,         MVT::Other, Expand);
+
+  setOperationAction(ISD::ConstantFP, MVT::f64, Expand);
+  setOperationAction(ISD::ConstantFP, MVT::f32, Expand);
+
+  setSchedulingPreference(SchedulingForRegPressure);
+  computeRegisterProperties();
 }
 
 namespace llvm {
@@ -55,61 +107,281 @@ namespace llvm {
       CALL,
 
       /// Return with a flag operand.
-      RET_FLAG
+      RET_FLAG,
+
+      CMP,
+
+      SELECT,
+
+      BR,
+
+      FSITOS,
+      FTOSIS,
+
+      FSITOD,
+      FTOSID,
+
+      FUITOS,
+      FTOUIS,
+
+      FUITOD,
+      FTOUID,
+
+      FMRRD,
+
+      FMDRR,
+
+      FMSTAT
     };
   }
 }
 
+/// DAGFPCCToARMCC - Convert a DAG fp condition code to an ARM CC
+// Unordered = !N & !Z & C & V = V
+// Ordered   =  N | Z | !C | !V = N | Z | !V
+static ARMCC::CondCodes DAGFPCCToARMCC(ISD::CondCode CC) {
+  switch (CC) {
+  default:
+    assert(0 && "Unknown fp condition code!");
+// SETOEQ = (N | Z | !V) & Z = Z                               = EQ
+  case ISD::SETEQ:
+  case ISD::SETOEQ: return ARMCC::EQ;
+// SETOGT = (N | Z | !V) & !N & !Z = !V &!N &!Z = (N = V) & !Z = GT
+  case ISD::SETGT:
+  case ISD::SETOGT: return ARMCC::GT;
+// SETOGE = (N | Z | !V) & !N = (Z | !V) & !N = !V & !N        = GE
+  case ISD::SETGE:
+  case ISD::SETOGE: return ARMCC::GE;
+// SETOLT = (N | Z | !V) & N = N                               = MI
+  case ISD::SETLT:
+  case ISD::SETOLT: return ARMCC::MI;
+// SETOLE = (N | Z | !V) & (N | Z) = N | Z = !C | Z            = LS
+  case ISD::SETLE:
+  case ISD::SETOLE: return ARMCC::LS;
+// SETONE = (N | Z | !V) & !Z = (N | !V) & Z = !V & Z = Z      = NE
+  case ISD::SETNE:
+  case ISD::SETONE: return ARMCC::NE;
+// SETO   = N | Z | !V = Z | !V = !V                           = VC
+  case ISD::SETO:   return ARMCC::VC;
+// SETUO  = V                                                  = VS
+  case ISD::SETUO:  return ARMCC::VS;
+// SETUEQ = V | Z                                              = ??
+// SETUGT = V | (!Z & !N) = !Z & !N = !Z & C                   = HI
+  case ISD::SETUGT: return ARMCC::HI;
+// SETUGE = V | !N = !N                                        = PL
+  case ISD::SETUGE: return ARMCC::PL;
+// SETULT = V | N                                              = ??
+// SETULE = V | Z | N                                          = ??
+// SETUNE = 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::SETULT: return ARMCC::CC;
+  case ISD::SETULE: return ARMCC::LS;
+  case ISD::SETUGT: return ARMCC::HI;
+  case ISD::SETUGE: return ARMCC::CS;
+  }
+}
+
 const char *ARMTargetLowering::getTargetNodeName(unsigned Opcode) const {
   switch (Opcode) {
   default: return 0;
   case ARMISD::CALL:          return "ARMISD::CALL";
   case ARMISD::RET_FLAG:      return "ARMISD::RET_FLAG";
+  case ARMISD::SELECT:        return "ARMISD::SELECT";
+  case ARMISD::CMP:           return "ARMISD::CMP";
+  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";
   }
 }
 
+class ArgumentLayout {
+  std::vector<bool>           is_reg;
+  std::vector<unsigned>       pos;
+  std::vector<MVT::ValueType> types;
+public:
+  ArgumentLayout(const std::vector<MVT::ValueType> &Types) {
+    types = Types;
+
+    unsigned      RegNum = 0;
+    unsigned StackOffset = 0;
+    for(std::vector<MVT::ValueType>::const_iterator I = Types.begin();
+        I != Types.end();
+        ++I) {
+      MVT::ValueType VT = *I;
+      assert(VT == MVT::i32 || VT == MVT::f32 || VT == MVT::f64);
+      unsigned     size = MVT::getSizeInBits(VT)/32;
+
+      RegNum = ((RegNum + size - 1) / size) * size;
+      if (RegNum < 4) {
+        pos.push_back(RegNum);
+        is_reg.push_back(true);
+        RegNum += size;
+      } else {
+        unsigned bytes = size * 32/8;
+        StackOffset = ((StackOffset + bytes - 1) / bytes) * bytes;
+        pos.push_back(StackOffset);
+        is_reg.push_back(false);
+        StackOffset += bytes;
+      }
+    }
+  }
+  unsigned getRegisterNum(unsigned argNum) {
+    assert(isRegister(argNum));
+    return pos[argNum];
+  }
+  unsigned getOffset(unsigned argNum) {
+    assert(isOffset(argNum));
+    return pos[argNum];
+  }
+  unsigned isRegister(unsigned argNum) {
+    assert(argNum < is_reg.size());
+    return is_reg[argNum];
+  }
+  unsigned isOffset(unsigned argNum) {
+    return !isRegister(argNum);
+  }
+  MVT::ValueType getType(unsigned argNum) {
+    assert(argNum < types.size());
+    return types[argNum];
+  }
+  unsigned getStackSize(void) {
+    int last = is_reg.size() - 1;
+    if (last < 0)
+      return 0;
+    if (isRegister(last))
+      return 0;
+    return getOffset(last) + MVT::getSizeInBits(getType(last))/8;
+  }
+  int lastRegArg(void) {
+    int size = is_reg.size();
+    int last = 0;
+    while(last < size && isRegister(last))
+      last++;
+    last--;
+    return last;
+  }
+  int lastRegNum(void) {
+    int            l = lastRegArg();
+    if (l < 0)
+      return -1;
+    unsigned       r = getRegisterNum(l);
+    MVT::ValueType t = getType(l);
+    assert(t == MVT::i32 || t == MVT::f32 || t == MVT::f64);
+    if (t == MVT::f64)
+      return r + 1;
+    return r;
+  }
+};
+
 // This transforms a ISD::CALL node into a
 // callseq_star <- ARMISD:CALL <- callseq_end
 // chain
 static SDOperand LowerCALL(SDOperand Op, SelectionDAG &DAG) {
   SDOperand Chain    = Op.getOperand(0);
   unsigned CallConv  = cast<ConstantSDNode>(Op.getOperand(1))->getValue();
-  assert(CallConv == CallingConv::C && "unknown calling convention");
+  assert((CallConv == CallingConv::C ||
+          CallConv == CallingConv::Fast)
+         && "unknown calling convention");
   bool isVarArg      = cast<ConstantSDNode>(Op.getOperand(2))->getValue() != 0;
-  assert(isVarArg == false && "VarArg not supported");
   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);
+  static const unsigned regs[] = {
+    ARM::R0, ARM::R1, ARM::R2, ARM::R3
+  };
 
-  // Count how many bytes are to be pushed on the stack. Initially
-  // only the link register.
-  unsigned NumBytes = 4;
+  std::vector<MVT::ValueType> Types;
+  for (unsigned i = 0; i < NumOps; ++i) {
+    MVT::ValueType VT = Op.getOperand(5+2*i).getValueType();
+    Types.push_back(VT);
+  }
+  ArgumentLayout Layout(Types);
 
-  assert(NumOps <= 4); //no args on the stack
+  unsigned NumBytes = Layout.getStackSize();
 
-  // Adjust the stack pointer for the new arguments...
-  // These operations are automatically eliminated by the prolog/epilog pass
   Chain = DAG.getCALLSEQ_START(Chain,
                                DAG.getConstant(NumBytes, MVT::i32));
 
-  static const unsigned regs[] = {
-    ARM::R0, ARM::R1, ARM::R2, ARM::R3
-  };
-
-  std::vector<std::pair<unsigned, SDOperand> > RegsToPass;
-
-  for (unsigned i = 0; i != NumOps; ++i) {
-    SDOperand Arg = Op.getOperand(5+2*i);
-    RegsToPass.push_back(std::make_pair(regs[i], Arg));
+  //Build a sequence of stores
+  std::vector<SDOperand> MemOpChains;
+  for (unsigned i = Layout.lastRegArg() + 1; i < NumOps; ++i) {
+    SDOperand      Arg = Op.getOperand(5+2*i);
+    unsigned ArgOffset = Layout.getOffset(i);
+    SDOperand   PtrOff = DAG.getConstant(ArgOffset, StackPtr.getValueType());
+    PtrOff             = DAG.getNode(ISD::ADD, MVT::i32, StackPtr, PtrOff);
+    MemOpChains.push_back(DAG.getStore(Chain, Arg, PtrOff, NULL, 0));
   }
+  if (!MemOpChains.empty())
+    Chain = DAG.getNode(ISD::TokenFactor, MVT::Other,
+                        &MemOpChains[0], MemOpChains.size());
+
+  // 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.
+  // Likewise ExternalSymbol -> TargetExternalSymbol.
+  assert(Callee.getValueType() == MVT::i32);
+  if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee))
+    Callee = DAG.getTargetGlobalAddress(G->getGlobal(), MVT::i32);
+  else if (ExternalSymbolSDNode *E = dyn_cast<ExternalSymbolSDNode>(Callee))
+    Callee = DAG.getTargetExternalSymbol(E->getSymbol(), MVT::i32);
+
+  // If this is a direct call, pass the chain and the callee.
+  assert (Callee.Val);
+  std::vector<SDOperand> Ops;
+  Ops.push_back(Chain);
+  Ops.push_back(Callee);
 
   // Build a sequence of copy-to-reg nodes chained together with token chain
   // and flag operands which copy the outgoing args into the appropriate regs.
   SDOperand InFlag;
-  for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) {
-    Chain = DAG.getCopyToReg(Chain, RegsToPass[i].first, RegsToPass[i].second,
-                             InFlag);
+  for (int i = 0, e = Layout.lastRegArg(); i <= e; ++i) {
+    SDOperand     Arg = Op.getOperand(5+2*i);
+    unsigned   RegNum = Layout.getRegisterNum(i);
+    unsigned     Reg1 = regs[RegNum];
+    MVT::ValueType VT = Layout.getType(i);
+    assert(VT == Arg.getValueType());
+    assert(VT == MVT::i32 || VT == MVT::f32 || VT == MVT::f64);
+
+    // Add argument register to the end of the list so that it is known live
+    // into the call.
+    Ops.push_back(DAG.getRegister(Reg1, MVT::i32));
+    if (VT == MVT::f64) {
+      unsigned    Reg2 = regs[RegNum + 1];
+      SDOperand SDReg1 = DAG.getRegister(Reg1, MVT::i32);
+      SDOperand SDReg2 = DAG.getRegister(Reg2, MVT::i32);
+
+      Ops.push_back(DAG.getRegister(Reg2, MVT::i32));
+      SDVTList    VTs = DAG.getVTList(MVT::Other, MVT::Flag);
+      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);
+      Chain = DAG.getCopyToReg(Chain, Reg1, Arg, InFlag);
+    }
     InFlag = Chain.getValue(1);
   }
 
@@ -117,36 +389,43 @@ static SDOperand LowerCALL(SDOperand Op, SelectionDAG &DAG) {
   NodeTys.push_back(MVT::Other);   // Returns a chain
   NodeTys.push_back(MVT::Flag);    // Returns a flag for retval copy to use.
 
-  // If the callee is a GlobalAddress/ExternalSymbol node (quite common, every
-  // direct call is) turn it into a TargetGlobalAddress/TargetExternalSymbol
-  // node so that legalize doesn't hack it.
-  if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee))
-    Callee = DAG.getTargetGlobalAddress(G->getGlobal(), Callee.getValueType());
-
-  // If this is a direct call, pass the chain and the callee.
-  assert (Callee.Val);
-  std::vector<SDOperand> Ops;
-  Ops.push_back(Chain);
-  Ops.push_back(Callee);
-
   unsigned CallOpc = ARMISD::CALL;
   if (InFlag.Val)
     Ops.push_back(InFlag);
-  Chain = DAG.getNode(CallOpc, NodeTys, Ops);
+  Chain = DAG.getNode(CallOpc, NodeTys, &Ops[0], Ops.size());
   InFlag = Chain.getValue(1);
 
   std::vector<SDOperand> ResultVals;
   NodeTys.clear();
 
   // If the call has results, copy the values out of the ret val registers.
-  switch (Op.Val->getValueType(0)) {
-  default: assert(0 && "Unexpected ret value!");
-  case MVT::Other:
-    break;
-  case MVT::i32:
-    Chain = DAG.getCopyFromReg(Chain, ARM::R0, MVT::i32, InFlag).getValue(1);
-    ResultVals.push_back(Chain.getValue(0));
-    NodeTys.push_back(MVT::i32);
+  MVT::ValueType VT = Op.Val->getValueType(0);
+  if (VT != MVT::Other) {
+    assert(VT == MVT::i32 || VT == MVT::f32 || VT == MVT::f64);
+
+    SDOperand Value1 = DAG.getCopyFromReg(Chain, ARM::R0, MVT::i32, InFlag);
+    Chain            = Value1.getValue(1);
+    InFlag           = Value1.getValue(2);
+    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);
+      SDOperand Value  = DAG.getNode(ARMISD::FMDRR, MVT::f64, Value1, Value2);
+      ResultVals.push_back(Value);
+    }
   }
 
   Chain = DAG.getNode(ISD::CALLSEQ_END, MVT::Other, Chain,
@@ -157,13 +436,17 @@ static SDOperand LowerCALL(SDOperand Op, SelectionDAG &DAG) {
     return Chain;
 
   ResultVals.push_back(Chain);
-  SDOperand Res = DAG.getNode(ISD::MERGE_VALUES, NodeTys, ResultVals);
+  SDOperand Res = DAG.getNode(ISD::MERGE_VALUES, NodeTys, &ResultVals[0],
+                              ResultVals.size());
   return Res.getValue(Op.ResNo);
 }
 
 static SDOperand LowerRET(SDOperand Op, SelectionDAG &DAG) {
   SDOperand Copy;
   SDOperand Chain = Op.getOperand(0);
+  SDOperand    R0 = DAG.getRegister(ARM::R0, MVT::i32);
+  SDOperand    R1 = DAG.getRegister(ARM::R1, MVT::i32);
+
   switch(Op.getNumOperands()) {
   default:
     assert(0 && "Do not know how to return this many arguments!");
@@ -172,10 +455,37 @@ static SDOperand LowerRET(SDOperand Op, SelectionDAG &DAG) {
     SDOperand LR = DAG.getRegister(ARM::R14, MVT::i32);
     return DAG.getNode(ARMISD::RET_FLAG, MVT::Other, Chain);
   }
-  case 3:
-    Copy = DAG.getCopyToReg(Chain, ARM::R0, Op.getOperand(1), SDOperand());
-    if (DAG.getMachineFunction().liveout_empty())
+  case 3: {
+    SDOperand Val = Op.getOperand(1);
+    assert(Val.getValueType() == MVT::i32 ||
+          Val.getValueType() == MVT::f32 ||
+          Val.getValueType() == MVT::f64);
+
+    if (Val.getValueType() == MVT::f64) {
+      SDVTList    VTs = DAG.getVTList(MVT::Other, MVT::Flag);
+      SDOperand Ops[] = {Chain, R0, R1, Val};
+      Copy  = DAG.getNode(ARMISD::FMRRD, VTs, Ops, 4);
+    } else {
+      if (Val.getValueType() == MVT::f32)
+       Val = DAG.getNode(ISD::BIT_CONVERT, MVT::i32, Val);
+      Copy = DAG.getCopyToReg(Chain, R0, Val, SDOperand());
+    }
+
+    if (DAG.getMachineFunction().liveout_empty()) {
+      DAG.getMachineFunction().addLiveOut(ARM::R0);
+      if (Val.getValueType() == MVT::f64)
+        DAG.getMachineFunction().addLiveOut(ARM::R1);
+    }
+    break;
+  }
+  case 5:
+    Copy = DAG.getCopyToReg(Chain, ARM::R1, Op.getOperand(3), SDOperand());
+    Copy = DAG.getCopyToReg(Copy, ARM::R0, Op.getOperand(1), Copy.getValue(1));
+    // If we haven't noted the R0+R1 are live out, do so now.
+    if (DAG.getMachineFunction().liveout_empty()) {
       DAG.getMachineFunction().addLiveOut(ARM::R0);
+      DAG.getMachineFunction().addLiveOut(ARM::R1);
+    }
     break;
   }
 
@@ -183,46 +493,10 @@ static SDOperand LowerRET(SDOperand Op, SelectionDAG &DAG) {
   return DAG.getNode(ARMISD::RET_FLAG, MVT::Other, Copy, Copy.getValue(1));
 }
 
-static SDOperand LowerFORMAL_ARGUMENT(SDOperand Op, SelectionDAG &DAG,
-                                     unsigned ArgNo) {
-  MachineFunction &MF = DAG.getMachineFunction();
-  MVT::ValueType ObjectVT = Op.getValue(ArgNo).getValueType();
-  assert (ObjectVT == MVT::i32);
-  SDOperand Root = Op.getOperand(0);
-  SSARegMap *RegMap = MF.getSSARegMap();
-
-  unsigned num_regs = 4;
-  static const unsigned REGS[] = {
-    ARM::R0, ARM::R1, ARM::R2, ARM::R3
-  };
-
-  if(ArgNo < num_regs) {
-    unsigned VReg = RegMap->createVirtualRegister(&ARM::IntRegsRegClass);
-    MF.addLiveIn(REGS[ArgNo], VReg);
-    return DAG.getCopyFromReg(Root, VReg, MVT::i32);
-  } else {
-    // If the argument is actually used, emit a load from the right stack
-      // slot.
-    if (!Op.Val->hasNUsesOfValue(0, ArgNo)) {
-      unsigned ArgOffset = (ArgNo - num_regs) * 4;
-
-      MachineFrameInfo *MFI = MF.getFrameInfo();
-      unsigned ObjSize = MVT::getSizeInBits(ObjectVT)/8;
-      int FI = MFI->CreateFixedObject(ObjSize, ArgOffset);
-      SDOperand FIN = DAG.getFrameIndex(FI, MVT::i32);
-      return DAG.getLoad(ObjectVT, Root, FIN,
-                        DAG.getSrcValue(NULL));
-    } else {
-      // Don't emit a dead load.
-      return DAG.getNode(ISD::UNDEF, ObjectVT);
-    }
-  }
-}
-
 static SDOperand LowerConstantPool(SDOperand Op, SelectionDAG &DAG) {
   MVT::ValueType PtrVT = Op.getValueType();
   ConstantPoolSDNode *CP = cast<ConstantPoolSDNode>(Op);
-  Constant *C = CP->get();
+  Constant *C = CP->getConstVal();
   SDOperand CPI = DAG.getTargetConstantPool(C, PtrVT, CP->getAlignment());
 
   return CPI;
@@ -231,30 +505,196 @@ static SDOperand LowerConstantPool(SDOperand Op, SelectionDAG &DAG) {
 static SDOperand LowerGlobalAddress(SDOperand Op,
                                    SelectionDAG &DAG) {
   GlobalValue  *GV = cast<GlobalAddressSDNode>(Op)->getGlobal();
-  SDOperand CPAddr = DAG.getConstantPool(GV, MVT::i32, 2);
-  return DAG.getLoad(MVT::i32, DAG.getEntryNode(), CPAddr,
-                    DAG.getSrcValue(NULL));
+  int alignment = 2;
+  SDOperand CPAddr = DAG.getConstantPool(GV, MVT::i32, alignment);
+  return DAG.getLoad(MVT::i32, DAG.getEntryNode(), CPAddr, NULL, 0);
 }
 
-static SDOperand LowerFORMAL_ARGUMENTS(SDOperand Op, SelectionDAG &DAG) {
-  std::vector<SDOperand> ArgValues;
-  SDOperand Root = Op.getOperand(0);
+static SDOperand LowerVASTART(SDOperand Op, SelectionDAG &DAG,
+                              unsigned VarArgsFrameIndex) {
+  // vastart just stores the address of the VarArgsFrameIndex slot into the
+  // memory location argument.
+  MVT::ValueType PtrVT = DAG.getTargetLoweringInfo().getPointerTy();
+  SDOperand FR = DAG.getFrameIndex(VarArgsFrameIndex, PtrVT);
+  SrcValueSDNode *SV = cast<SrcValueSDNode>(Op.getOperand(2));
+  return DAG.getStore(Op.getOperand(0), FR, Op.getOperand(1), SV->getValue(),
+                      SV->getOffset());
+}
 
-  for (unsigned ArgNo = 0, e = Op.Val->getNumValues()-1; ArgNo != e; ++ArgNo) {
-    SDOperand ArgVal = LowerFORMAL_ARGUMENT(Op, DAG, ArgNo);
+static SDOperand LowerFORMAL_ARGUMENTS(SDOperand Op, SelectionDAG &DAG,
+                                      int &VarArgsFrameIndex) {
+  MachineFunction   &MF = DAG.getMachineFunction();
+  MachineFrameInfo *MFI = MF.getFrameInfo();
+  SSARegMap     *RegMap = MF.getSSARegMap();
+  unsigned      NumArgs = Op.Val->getNumValues()-1;
+  SDOperand        Root = Op.getOperand(0);
+  bool         isVarArg = cast<ConstantSDNode>(Op.getOperand(2))->getValue() != 0;
+  static const unsigned REGS[] = {
+    ARM::R0, ARM::R1, ARM::R2, ARM::R3
+  };
 
-    ArgValues.push_back(ArgVal);
+  std::vector<MVT::ValueType> Types(Op.Val->value_begin(), Op.Val->value_end() - 1);
+  ArgumentLayout Layout(Types);
+
+  std::vector<SDOperand> ArgValues;
+  for (unsigned ArgNo = 0; ArgNo < NumArgs; ++ArgNo) {
+    MVT::ValueType VT = Types[ArgNo];
+
+    SDOperand Value;
+    if (Layout.isRegister(ArgNo)) {
+      assert(VT == MVT::i32 || VT == MVT::f32 || VT == MVT::f64);
+      unsigned  RegNum = Layout.getRegisterNum(ArgNo);
+      unsigned    Reg1 = REGS[RegNum];
+      unsigned   VReg1 = RegMap->createVirtualRegister(&ARM::IntRegsRegClass);
+      SDOperand Value1 = DAG.getCopyFromReg(Root, VReg1, MVT::i32);
+      MF.addLiveIn(Reg1, VReg1);
+      if (VT == MVT::f64) {
+        unsigned    Reg2 = REGS[RegNum + 1];
+        unsigned   VReg2 = RegMap->createVirtualRegister(&ARM::IntRegsRegClass);
+        SDOperand Value2 = DAG.getCopyFromReg(Root, VReg2, MVT::i32);
+        MF.addLiveIn(Reg2, VReg2);
+        Value            = DAG.getNode(ARMISD::FMDRR, MVT::f64, Value1, Value2);
+      } else {
+        Value = Value1;
+        if (VT == MVT::f32)
+          Value = DAG.getNode(ISD::BIT_CONVERT, VT, Value);
+      }
+    } else {
+      // If the argument is actually used, emit a load from the right stack
+      // slot.
+      if (!Op.Val->hasNUsesOfValue(0, ArgNo)) {
+        unsigned Offset = Layout.getOffset(ArgNo);
+        unsigned   Size = MVT::getSizeInBits(VT)/8;
+        int          FI = MFI->CreateFixedObject(Size, Offset);
+        SDOperand   FIN = DAG.getFrameIndex(FI, VT);
+        Value = DAG.getLoad(VT, Root, FIN, NULL, 0);
+      } else {
+        Value = DAG.getNode(ISD::UNDEF, VT);
+      }
+    }
+    ArgValues.push_back(Value);
   }
 
-  bool isVarArg = cast<ConstantSDNode>(Op.getOperand(2))->getValue() != 0;
-  assert(!isVarArg);
+  unsigned NextRegNum = Layout.lastRegNum() + 1;
+
+  if (isVarArg) {
+    //If this function is vararg we must store the remaing
+    //registers so that they can be acessed with va_start
+    VarArgsFrameIndex = MFI->CreateFixedObject(MVT::getSizeInBits(MVT::i32)/8,
+                                               -16 + NextRegNum * 4);
+
+    SmallVector<SDOperand, 4> MemOps;
+    for (unsigned RegNo = NextRegNum; RegNo < 4; ++RegNo) {
+      int RegOffset = - (4 - RegNo) * 4;
+      int FI = MFI->CreateFixedObject(MVT::getSizeInBits(MVT::i32)/8,
+                                     RegOffset);
+      SDOperand FIN = DAG.getFrameIndex(FI, MVT::i32);
+
+      unsigned VReg = RegMap->createVirtualRegister(&ARM::IntRegsRegClass);
+      MF.addLiveIn(REGS[RegNo], VReg);
+
+      SDOperand Val = DAG.getCopyFromReg(Root, VReg, MVT::i32);
+      SDOperand Store = DAG.getStore(Val.getValue(1), Val, FIN, NULL, 0);
+      MemOps.push_back(Store);
+    }
+    Root = DAG.getNode(ISD::TokenFactor, MVT::Other,&MemOps[0],MemOps.size());
+  }
 
   ArgValues.push_back(Root);
 
   // Return the new list of results.
   std::vector<MVT::ValueType> RetVT(Op.Val->value_begin(),
                                     Op.Val->value_end());
-  return DAG.getNode(ISD::MERGE_VALUES, RetVT, ArgValues);
+  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);
+
+  SDOperand 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      Cmp = GetCMP(CC, LHS, RHS, DAG);
+  SDOperand    ARMCC = GetARMCC(CC, LHS.getValueType(), DAG);
+  return DAG.getNode(ARMISD::SELECT, MVT::i32, TrueVal, FalseVal, ARMCC, Cmp);
+}
+
+static SDOperand LowerBR_CC(SDOperand Op, SelectionDAG &DAG) {
+  SDOperand  Chain = Op.getOperand(0);
+  ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(1))->get();
+  SDOperand    LHS = Op.getOperand(2);
+  SDOperand    RHS = Op.getOperand(3);
+  SDOperand   Dest = Op.getOperand(4);
+  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);
+}
+
+static SDOperand LowerSINT_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::FSITOS : ARMISD::FSITOD;
+  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) {
@@ -266,12 +706,26 @@ 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);
+    return LowerFORMAL_ARGUMENTS(Op, DAG, VarArgsFrameIndex);
   case ISD::CALL:
     return LowerCALL(Op, DAG);
   case ISD::RET:
     return LowerRET(Op, DAG);
+  case ISD::SELECT_CC:
+    return LowerSELECT_CC(Op, DAG);
+  case ISD::BR_CC:
+    return LowerBR_CC(Op, DAG);
+  case ISD::VASTART:
+    return LowerVASTART(Op, DAG, VarArgsFrameIndex);
   }
 }
 
@@ -292,9 +746,12 @@ public:
     : SelectionDAGISel(Lowering), Lowering(TM) {
   }
 
-  void Select(SDOperand &Result, SDOperand Op);
+  SDNode *Select(SDOperand Op);
   virtual void InstructionSelectBasicBlock(SelectionDAG &DAG);
   bool SelectAddrRegImm(SDOperand N, SDOperand &Offset, SDOperand &Base);
+  bool SelectAddrMode1(SDOperand N, SDOperand &Arg, SDOperand &Shift,
+                      SDOperand &ShiftType);
+  bool SelectAddrMode5(SDOperand N, SDOperand &Arg, SDOperand &Offset);
 
   // Include the pieces autogenerated from the target description.
 #include "ARMGenDAGISel.inc"
@@ -304,17 +761,123 @@ void ARMDAGToDAGISel::InstructionSelectBasicBlock(SelectionDAG &DAG) {
   DEBUG(BB->dump());
 
   DAG.setRoot(SelectRoot(DAG.getRoot()));
-  CodeGenMap.clear();
-  HandleMap.clear();
-  ReplaceMap.clear();
   DAG.RemoveDeadNodes();
 
   ScheduleAndEmitDAG(DAG);
 }
 
+static bool isInt12Immediate(SDNode *N, short &Imm) {
+  if (N->getOpcode() != ISD::Constant)
+    return false;
+
+  int32_t t = cast<ConstantSDNode>(N)->getValue();
+  int max = 1<<12;
+  int min = -max;
+  if (t > min && t < max) {
+    Imm = t;
+    return true;
+  }
+  else
+    return false;
+}
+
+static bool isInt12Immediate(SDOperand Op, short &Imm) {
+  return isInt12Immediate(Op.Val, Imm);
+}
+
+static uint32_t rotateL(uint32_t x) {
+  uint32_t bit31 = (x & (1 << 31)) >> 31;
+  uint32_t     t = x << 1;
+  return t | bit31;
+}
+
+static bool isUInt8Immediate(uint32_t x) {
+  return x < (1 << 8);
+}
+
+static bool isRotInt8Immediate(uint32_t x) {
+  int r;
+  for (r = 0; r < 16; r++) {
+    if (isUInt8Immediate(x))
+      return true;
+    x = rotateL(rotateL(x));
+  }
+  return false;
+}
+
+bool ARMDAGToDAGISel::SelectAddrMode1(SDOperand N,
+                                     SDOperand &Arg,
+                                     SDOperand &Shift,
+                                     SDOperand &ShiftType) {
+  switch(N.getOpcode()) {
+  case ISD::Constant: {
+    uint32_t val = cast<ConstantSDNode>(N)->getValue();
+    if(!isRotInt8Immediate(val)) {
+      Constant    *C = ConstantInt::get(Type::UIntTy, val);
+      int  alignment = 2;
+      SDOperand Addr = CurDAG->getTargetConstantPool(C, MVT::i32, alignment);
+      SDOperand    Z = CurDAG->getTargetConstant(0,     MVT::i32);
+      SDNode      *n = CurDAG->getTargetNode(ARM::ldr,  MVT::i32, Z, Addr);
+      Arg            = SDOperand(n, 0);
+    } else
+      Arg            = CurDAG->getTargetConstant(val,    MVT::i32);
+
+    Shift     = CurDAG->getTargetConstant(0,             MVT::i32);
+    ShiftType = CurDAG->getTargetConstant(ARMShift::LSL, MVT::i32);
+    return true;
+  }
+  case ISD::SRA:
+    Arg       = N.getOperand(0);
+    Shift     = N.getOperand(1);
+    ShiftType = CurDAG->getTargetConstant(ARMShift::ASR, MVT::i32);
+    return true;
+  case ISD::SRL:
+    Arg       = N.getOperand(0);
+    Shift     = N.getOperand(1);
+    ShiftType = CurDAG->getTargetConstant(ARMShift::LSR, MVT::i32);
+    return true;
+  case ISD::SHL:
+    Arg       = N.getOperand(0);
+    Shift     = N.getOperand(1);
+    ShiftType = CurDAG->getTargetConstant(ARMShift::LSL, MVT::i32);
+    return true;
+  }
+
+  Arg       = N;
+  Shift     = CurDAG->getTargetConstant(0, MVT::i32);
+  ShiftType = CurDAG->getTargetConstant(ARMShift::LSL, MVT::i32);
+  return true;
+}
+
+bool ARMDAGToDAGISel::SelectAddrMode5(SDOperand N, SDOperand &Arg,
+                                      SDOperand &Offset) {
+  //TODO: detect offset
+  Offset = CurDAG->getTargetConstant(0, MVT::i32);
+  Arg    = N;
+  return true;
+}
+
 //register plus/minus 12 bit offset
 bool ARMDAGToDAGISel::SelectAddrRegImm(SDOperand N, SDOperand &Offset,
                                    SDOperand &Base) {
+  if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(N)) {
+    Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32);
+    Offset = CurDAG->getTargetConstant(0, MVT::i32);
+    return true;
+  }
+  if (N.getOpcode() == ISD::ADD) {
+    short imm = 0;
+    if (isInt12Immediate(N.getOperand(1), imm)) {
+      Offset = CurDAG->getTargetConstant(imm, MVT::i32);
+      if (FrameIndexSDNode *FI = dyn_cast<FrameIndexSDNode>(N.getOperand(0))) {
+       Base = CurDAG->getTargetFrameIndex(FI->getIndex(), N.getValueType());
+      } else {
+       Base = N.getOperand(0);
+      }
+      return true; // [r+i]
+    }
+  }
+
   Offset = CurDAG->getTargetConstant(0, MVT::i32);
   if (FrameIndexSDNode *FI = dyn_cast<FrameIndexSDNode>(N)) {
     Base = CurDAG->getTargetFrameIndex(FI->getIndex(), N.getValueType());
@@ -324,14 +887,15 @@ bool ARMDAGToDAGISel::SelectAddrRegImm(SDOperand N, SDOperand &Offset,
   return true;      //any address fits in a register
 }
 
-void ARMDAGToDAGISel::Select(SDOperand &Result, SDOperand Op) {
+SDNode *ARMDAGToDAGISel::Select(SDOperand Op) {
   SDNode *N = Op.Val;
 
   switch (N->getOpcode()) {
   default:
-    SelectCode(Result, Op);
+    return SelectCode(Op);
     break;
   }
+  return NULL;
 }
 
 }  // end anonymous namespace