diff --git a/lib/Target/ARM/ARMFastISel.cpp b/lib/Target/ARM/ARMFastISel.cpp index 46f707ca952..e9acb7fa2c1 100644 --- a/lib/Target/ARM/ARMFastISel.cpp +++ b/lib/Target/ARM/ARMFastISel.cpp @@ -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(*GTI)) { + const StructLayout *SL = TD.getStructLayout(STy); + unsigned Idx = cast(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(Obj); DenseMap::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(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; }