Added isLegalAddressExpression(). Only allows X +/- C for now.
[oota-llvm.git] / lib / Target / ARM / ARMISelLowering.cpp
index 60348c1a5b53b3e3a70f9e0098ec8a2bf278cd32..40ede7409aca8e2b396db11eb19362a2f9e3064c 100644 (file)
@@ -22,6 +22,7 @@
 #include "ARMTargetMachine.h"
 #include "llvm/CallingConv.h"
 #include "llvm/Constants.h"
+#include "llvm/Instruction.h"
 #include "llvm/CodeGen/MachineBasicBlock.h"
 #include "llvm/CodeGen/MachineFrameInfo.h"
 #include "llvm/CodeGen/MachineFunction.h"
@@ -30,6 +31,7 @@
 #include "llvm/CodeGen/SSARegMap.h"
 #include "llvm/Target/TargetOptions.h"
 #include "llvm/ADT/VectorExtras.h"
+#include "llvm/Support/MathExtras.h"
 using namespace llvm;
 
 ARMTargetLowering::ARMTargetLowering(TargetMachine &TM)
@@ -167,7 +169,7 @@ ARMTargetLowering::ARMTargetLowering(TargetMachine &TM)
   setOperationAction(ISD::LOCATION, MVT::Other, Expand);
   setOperationAction(ISD::DEBUG_LOC, MVT::Other, Expand);
   // FIXME - use subtarget debug flags
-  if (Subtarget->isTargetDarwin())
+  if (!Subtarget->isTargetDarwin())
     setOperationAction(ISD::LABEL, MVT::Other, Expand);
 
   setOperationAction(ISD::RET,           MVT::Other, Custom);
@@ -338,35 +340,42 @@ static bool FPCCToARMCC(ISD::CondCode CC, ARMCC::CondCodes &CondCode,
 }
 
 static void
-HowToPassArgument(MVT::ValueType ObjectVT,
-                  unsigned NumGPRs, unsigned &ObjSize, unsigned &ObjGPRs) {
-  ObjSize = 0;
-  ObjGPRs = 0;
-
+HowToPassArgument(MVT::ValueType ObjectVT, unsigned NumGPRs,
+                  unsigned StackOffset, unsigned &NeededGPRs,
+                  unsigned &NeededStackSize, unsigned &GPRPad,
+                  unsigned &StackPad, unsigned Flags) {
+  NeededStackSize = 0;
+  NeededGPRs = 0;
+  StackPad = 0;
+  GPRPad = 0;
+  unsigned align = (Flags >> ISD::ParamFlags::OrigAlignmentOffs);
+  GPRPad = NumGPRs % ((align + 3)/4);
+  StackPad = StackOffset % align;
+  unsigned firstGPR = NumGPRs + GPRPad;
   switch (ObjectVT) {
   default: assert(0 && "Unhandled argument type!");
   case MVT::i32:
   case MVT::f32:
-    if (NumGPRs < 4)
-      ObjGPRs = 1;
+    if (firstGPR < 4)
+      NeededGPRs = 1;
     else
-      ObjSize = 4;
+      NeededStackSize = 4;
     break;
   case MVT::i64:
   case MVT::f64:
-    if (NumGPRs < 3)
-      ObjGPRs = 2;
-    else if (NumGPRs == 3) {
-      ObjGPRs = 1;
-      ObjSize = 4;
+    if (firstGPR < 3)
+      NeededGPRs = 2;
+    else if (firstGPR == 3) {
+      NeededGPRs = 1;
+      NeededStackSize = 4;
     } else
-      ObjSize = 8;
+      NeededStackSize = 8;
   }
 }
 
-// This transforms a ISD::CALL node into a
-// callseq_star <- ARMISD:CALL <- callseq_end
-// chain
+/// LowerCALL - Lowering a ISD::CALL node into a callseq_start <-
+/// ARMISD:CALL <- callseq_end chain. Also add input and output parameter
+/// nodes.
 SDOperand ARMTargetLowering::LowerCALL(SDOperand Op, SelectionDAG &DAG) {
   MVT::ValueType RetVT= Op.Val->getValueType(0);
   SDOperand Chain    = Op.getOperand(0);
@@ -383,12 +392,16 @@ SDOperand ARMTargetLowering::LowerCALL(SDOperand Op, SelectionDAG &DAG) {
 
   // Add up all the space actually used.
   for (unsigned i = 0; i < NumOps; ++i) {
-    unsigned ObjSize = 0;
-    unsigned ObjGPRs = 0;
+    unsigned ObjSize;
+    unsigned ObjGPRs;
+    unsigned StackPad;
+    unsigned GPRPad;
     MVT::ValueType ObjectVT = Op.getOperand(5+2*i).getValueType();
-    HowToPassArgument(ObjectVT, NumGPRs, ObjSize, ObjGPRs);
-    NumBytes += ObjSize;
-    NumGPRs += ObjGPRs;
+    unsigned Flags = Op.getConstantOperandVal(5+2*i+1);
+    HowToPassArgument(ObjectVT, NumGPRs, NumBytes, ObjGPRs, ObjSize,
+                      GPRPad, StackPad, Flags);
+    NumBytes += ObjSize + StackPad;
+    NumGPRs += ObjGPRs + GPRPad;
   }
 
   // Adjust the stack pointer for the new arguments...
@@ -407,18 +420,24 @@ SDOperand ARMTargetLowering::LowerCALL(SDOperand Op, SelectionDAG &DAG) {
   std::vector<SDOperand> MemOpChains;
   for (unsigned i = 0; i != NumOps; ++i) {
     SDOperand Arg = Op.getOperand(5+2*i);
+    unsigned Flags = Op.getConstantOperandVal(5+2*i+1);
     MVT::ValueType ArgVT = Arg.getValueType();
 
-    unsigned ObjSize = 0;
-    unsigned ObjGPRs = 0;
-    HowToPassArgument(ArgVT, NumGPRs, ObjSize, ObjGPRs);
+    unsigned ObjSize;
+    unsigned ObjGPRs;
+    unsigned GPRPad;
+    unsigned StackPad;
+    HowToPassArgument(ArgVT, NumGPRs, ArgOffset, ObjGPRs,
+                      ObjSize, GPRPad, StackPad, Flags);
+    NumGPRs += GPRPad;
+    ArgOffset += StackPad;
     if (ObjGPRs > 0) {
       switch (ArgVT) {
       default: assert(0 && "Unexpected ValueType for argument!");
       case MVT::i32:
         RegsToPass.push_back(std::make_pair(GPRArgRegs[NumGPRs], Arg));
         break;
-      case MVT::f32: 
+      case MVT::f32:
         RegsToPass.push_back(std::make_pair(GPRArgRegs[NumGPRs],
                                  DAG.getNode(ISD::BIT_CONVERT, MVT::i32, Arg)));
         break;
@@ -436,7 +455,7 @@ SDOperand ARMTargetLowering::LowerCALL(SDOperand Op, SelectionDAG &DAG) {
           MemOpChains.push_back(DAG.getStore(Chain, Hi, PtrOff, NULL, 0));
         }
         break;
-      } 
+      }
       case MVT::f64: {
         SDOperand Cvt = DAG.getNode(ARMISD::FMRRD,
                                     DAG.getVTList(MVT::i32, MVT::i32),
@@ -715,7 +734,7 @@ static SDOperand LowerVASTART(SDOperand Op, SelectionDAG &DAG,
 }
 
 static SDOperand LowerFORMAL_ARGUMENT(SDOperand Op, SelectionDAG &DAG,
-                                     unsigned *vRegs, unsigned ArgNo,
+                                      unsigned *vRegs, unsigned ArgNo,
                                       unsigned &NumGPRs, unsigned &ArgOffset) {
   MachineFunction &MF = DAG.getMachineFunction();
   MVT::ValueType ObjectVT = Op.getValue(ArgNo).getValueType();
@@ -727,9 +746,15 @@ static SDOperand LowerFORMAL_ARGUMENT(SDOperand Op, SelectionDAG &DAG,
     ARM::R0, ARM::R1, ARM::R2, ARM::R3
   };
 
-  unsigned ObjSize = 0;
-  unsigned ObjGPRs = 0;
-  HowToPassArgument(ObjectVT, NumGPRs, ObjSize, ObjGPRs);
+  unsigned ObjSize;
+  unsigned ObjGPRs;
+  unsigned GPRPad;
+  unsigned StackPad;
+  unsigned Flags = Op.getConstantOperandVal(ArgNo + 3);
+  HowToPassArgument(ObjectVT, NumGPRs, ArgOffset, ObjGPRs,
+                    ObjSize, GPRPad, StackPad, Flags);
+  NumGPRs += GPRPad;
+  ArgOffset += StackPad;
 
   SDOperand ArgValue;
   if (ObjGPRs == 1) {
@@ -808,13 +833,16 @@ ARMTargetLowering::LowerFORMAL_ARGUMENTS(SDOperand Op, SelectionDAG &DAG) {
     SSARegMap *RegMap = MF.getSSARegMap();
     MachineFrameInfo *MFI = MF.getFrameInfo();
     ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
-    unsigned VARegSaveSize = (4 - NumGPRs) * 4;
+    unsigned Align = MF.getTarget().getFrameInfo()->getStackAlignment();
+    unsigned VARegSize = (4 - NumGPRs) * 4;
+    unsigned VARegSaveSize = (VARegSize + Align - 1) & ~(Align - 1);
     if (VARegSaveSize) {
       // If this function is vararg, store any remaining integer argument regs
       // to their spots on the stack so that they may be loaded by deferencing
       // the result of va_next.
       AFI->setVarArgsRegSaveSize(VARegSaveSize);
-      VarArgsFrameIndex = MFI->CreateFixedObject(VARegSaveSize, ArgOffset);
+      VarArgsFrameIndex = MFI->CreateFixedObject(VARegSaveSize, ArgOffset +
+                                                 VARegSaveSize - VARegSize);
       SDOperand FIN = DAG.getFrameIndex(VarArgsFrameIndex, getPointerTy());
 
       SmallVector<SDOperand, 4> MemOps;
@@ -1242,17 +1270,104 @@ ARMTargetLowering::InsertAtEndOfBasicBlock(MachineInstr *MI,
 //                           ARM Optimization Hooks
 //===----------------------------------------------------------------------===//
 
-/// isLegalAddressImmediate - Return true if the integer value or
-/// GlobalValue can be used as the offset of the target addressing mode.
-bool ARMTargetLowering::isLegalAddressImmediate(int64_t V) const {
-  // ARM allows a 12-bit immediate field.
-  return V == V & ((1LL << 12) - 1);
+/// isLegalAddressExpression - Return true if the binary expression made up of
+/// specified opcode, operands, and type can be folded into target addressing
+/// mode for load / store of the given type.
+bool ARMTargetLowering::isLegalAddressExpression(unsigned Opc, Value *Op0,
+                                             Value *Op1, const Type *Ty) const {
+  if (ConstantInt *Op1C = dyn_cast<ConstantInt>(Op1)) {
+    if (Opc == Instruction::Add)
+      return isLegalAddressImmediate(Op1C->getSExtValue(), Ty);
+    if (Opc == Instruction::Sub)
+      return isLegalAddressImmediate(-Op1C->getSExtValue(), Ty);
+  }
+  return false;
+}
+
+/// isLegalAddressImmediate - Return true if the integer value can be used
+/// as the offset of the target addressing mode for load / store of the
+/// given type.
+bool ARMTargetLowering::isLegalAddressImmediate(int64_t V,const Type *Ty) const{
+  if (V == 0)
+    return true;
+
+  MVT::ValueType VT = getValueType(Ty);
+  if (Subtarget->isThumb()) {
+    if (V < 0)
+      return false;
+
+    unsigned Scale = 1;
+    switch (VT) {
+    default: return false;
+    case MVT::i1:
+    case MVT::i8:
+      // Scale == 1;
+      break;
+    case MVT::i16:
+      // Scale == 2;
+      Scale = 2;
+      break;
+    case MVT::i32:
+      // Scale == 4;
+      Scale = 4;
+      break;
+    }
+
+    if ((V & (Scale - 1)) != 0)
+      return false;
+    V /= Scale;
+    return V == V & ((1LL << 5) - 1);
+  }
+
+  if (V < 0)
+    V = - V;
+  switch (VT) {
+  default: return false;
+  case MVT::i1:
+  case MVT::i8:
+  case MVT::i32:
+    // +- imm12
+    return V == V & ((1LL << 12) - 1);
+  case MVT::i16:
+    // +- imm8
+    return V == V & ((1LL << 8) - 1);
+  case MVT::f32:
+  case MVT::f64:
+    if (!Subtarget->hasVFP2())
+      return false;
+    if ((V % 3) != 0)
+      return false;
+    V >>= 2;
+    return V == V & ((1LL << 8) - 1);
+  }
 }
 
 bool ARMTargetLowering::isLegalAddressImmediate(GlobalValue *GV) const {
   return false;
 }
 
+/// isLegalAddressScale - Return true if the integer value can be used as
+/// the scale of the target addressing mode for load / store of the given
+/// type.
+bool ARMTargetLowering::isLegalAddressScale(int64_t S, const Type *Ty) const {
+  if (Subtarget->isThumb())
+    return false;
+
+  MVT::ValueType VT = getValueType(Ty);
+  switch (VT) {
+  default: return false;
+  case MVT::i1:
+  case MVT::i8:
+  case MVT::i32:
+    // r + r
+    if (S == 2)
+      return true;
+    // r + r << imm
+    S &= ~1;
+    return isPowerOf2_32(S);
+  }
+}
+
 static bool getIndexedAddressParts(SDNode *Ptr, MVT::ValueType VT,
                                    bool isSEXTLoad, SDOperand &Base,
                                    SDOperand &Offset, bool &isInc,