Handle more complex GEP based loads and add a few TODOs to deal with
authorEric Christopher <echristo@apple.com>
Thu, 14 Oct 2010 09:29:41 +0000 (09:29 +0000)
committerEric Christopher <echristo@apple.com>
Thu, 14 Oct 2010 09:29:41 +0000 (09:29 +0000)
GEP + alloca.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@116474 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Target/ARM/ARMFastISel.cpp

index 46f707ca952c237b2cd3b2a0bb8e972b690302b0..e9acb7fa2c1cfee50a61a91b376cb5ab71272e3d 100644 (file)
@@ -138,6 +138,7 @@ class ARMFastISel : public FastISel {
     bool ARMEmitLoad(EVT VT, unsigned &ResultReg, unsigned Reg, int Offset);
     bool ARMEmitStore(EVT VT, unsigned SrcReg, unsigned Reg, int Offset);
     bool ARMComputeRegOffset(const Value *Obj, unsigned &Reg, int &Offset);
+    unsigned ARMSimplifyRegOffset(unsigned Reg, int &Offset);
     unsigned ARMMaterializeFP(const ConstantFP *CFP, EVT VT);
     unsigned ARMMaterializeInt(const Constant *C, EVT VT);
     unsigned ARMMaterializeGV(const GlobalValue *GV, EVT VT);
@@ -602,7 +603,39 @@ bool ARMFastISel::ARMComputeRegOffset(const Value *Obj, unsigned &Reg,
         return ARMComputeRegOffset(U->getOperand(0), Reg, Offset);
       break;
     }
+    case Instruction::GetElementPtr: {
+      int SavedOffset = Offset;
+      int TmpOffset = Offset;
+      
+      // Iterate through the GEP folding the constants into offsets where
+      // we can.
+      gep_type_iterator GTI = gep_type_begin(U);
+      for (User::const_op_iterator i = U->op_begin() + 1, e = U->op_end();
+           i != e; ++i, ++GTI) {
+        const Value *Op = *i;
+        if (const StructType *STy = dyn_cast<StructType>(*GTI)) {
+          const StructLayout *SL = TD.getStructLayout(STy);
+          unsigned Idx = cast<ConstantInt>(Op)->getZExtValue();
+          TmpOffset += SL->getElementOffset(Idx);
+        } else {
+          goto unsupported_gep;
+        }
+      }
+      
+      Offset = TmpOffset;
+      if (ARMComputeRegOffset(U->getOperand(0), Reg, Offset)) return true;
+      
+      Offset = SavedOffset;
+      break;
+      
+      unsupported_gep:
+      // errs() << "GEP: " << *U << "\n";
+      break;
+    }
     case Instruction::Alloca: {
+      // TODO: Fix this to do intermediate loads, etc.
+      if (Offset != 0) return false;
+      
       const AllocaInst *AI = cast<AllocaInst>(Obj);
       DenseMap<const AllocaInst*, int>::iterator SI =
         FuncInfo.StaticAllocaMap.find(AI);
@@ -629,16 +662,16 @@ bool ARMFastISel::ARMComputeRegOffset(const Value *Obj, unsigned &Reg,
   }
 
   // Try to get this in a register if nothing else has worked.
-  Reg = getRegForValue(Obj);
-  if (Reg == 0) return false;
+  if (Reg == 0) Reg = getRegForValue(Obj);
+  
+  return Reg != 0;
+}
+
+unsigned ARMFastISel::ARMSimplifyRegOffset(unsigned Reg, int &Offset) {
 
   // Since the offset may be too large for the load instruction
   // get the reg+offset into a register.
-  // TODO: Verify the additions work, otherwise we'll need to add the
-  // offset instead of 0 to the instructions and do all sorts of operand
-  // munging.
-  // TODO: Optimize this somewhat.
-  if (Offset != 0) {
+  if (Reg != ARM::SP && Offset != 0) {
     ARMCC::CondCodes Pred = ARMCC::AL;
     unsigned PredReg = 0;
 
@@ -652,8 +685,11 @@ bool ARMFastISel::ARMComputeRegOffset(const Value *Obj, unsigned &Reg,
                              Reg, Reg, Offset, Pred, PredReg,
                              static_cast<const ARMBaseInstrInfo&>(TII));
     }
+    
+    Offset = 0;
   }
-  return true;
+  
+  return Reg;
 }
 
 bool ARMFastISel::ARMEmitLoad(EVT VT, unsigned &ResultReg,
@@ -731,8 +767,10 @@ bool ARMFastISel::SelectLoad(const Instruction *I) {
   if (!ARMComputeRegOffset(I->getOperand(0), Reg, Offset))
     return false;
 
+  unsigned BaseReg = ARMSimplifyRegOffset(Reg, Offset);
+
   unsigned ResultReg;
-  if (!ARMEmitLoad(VT, ResultReg, Reg, Offset /* 0 */)) return false;
+  if (!ARMEmitLoad(VT, ResultReg, BaseReg, Offset)) return false;
 
   UpdateValueMap(I, ResultReg);
   return true;
@@ -808,7 +846,9 @@ bool ARMFastISel::SelectStore(const Instruction *I) {
   if (!ARMComputeRegOffset(I->getOperand(1), Reg, Offset))
     return false;
 
-  if (!ARMEmitStore(VT, SrcReg, Reg, Offset /* 0 */)) return false;
+  unsigned BaseReg = ARMSimplifyRegOffset(Reg, Offset);
+
+  if (!ARMEmitStore(VT, SrcReg, BaseReg, Offset)) return false;
 
   return true;
 }