diff --git a/include/llvm/Target/TargetRegisterInfo.h b/include/llvm/Target/TargetRegisterInfo.h index e36cc4f9cec..43b6bad9b39 100644 --- a/include/llvm/Target/TargetRegisterInfo.h +++ b/include/llvm/Target/TargetRegisterInfo.h @@ -636,6 +636,12 @@ public: return false; } + /// getFrameIndexInstrOffset - Get the offset from the referenced frame + /// index in the instruction, if the is one. + virtual int64_t getFrameIndexInstrOffset(MachineInstr *MI, int Idx) const { + return 0; + } + /// needsFrameBaseReg - Returns true if the instruction's frame index /// reference would be better served by a base register other than FP /// or SP. Used by LocalStackFrameAllocation to determine which frame index @@ -647,8 +653,8 @@ public: /// materializeFrameBaseRegister - Insert defining instruction(s) for /// BaseReg to be a pointer to FrameIdx before insertion point I. virtual void materializeFrameBaseRegister(MachineBasicBlock::iterator I, - unsigned BaseReg, - int FrameIdx) const { + unsigned BaseReg, int FrameIdx, + int64_t Offset) const { assert(0 && "materializeFrameBaseRegister does not exist on this target"); } @@ -659,11 +665,11 @@ public: assert(0 && "resolveFrameIndex does not exist on this target"); } - /// isBaseRegInRange - Determine whether a given base register definition - /// is in range to resolve a frame index. - virtual bool isBaseRegInRange(const MachineInstr *MI, unsigned Reg, - int64_t Offset) const { - assert(0 && "isBaseRegInRange does not exist on this target"); + /// isFrameOffsetLegal - Determine whether a given offset immediate is + /// encodable to resolve a frame index. + virtual bool isFrameOffsetLegal(const MachineInstr *MI, + int64_t Offset) const { + assert(0 && "isFrameOffsetLegal does not exist on this target"); return false; // Must return a value in order to compile with VS 2005 } diff --git a/lib/CodeGen/LocalStackSlotAllocation.cpp b/lib/CodeGen/LocalStackSlotAllocation.cpp index a4a43875cee..01a1af1be60 100644 --- a/lib/CodeGen/LocalStackSlotAllocation.cpp +++ b/lib/CodeGen/LocalStackSlotAllocation.cpp @@ -182,7 +182,7 @@ lookupCandidateBaseReg(const SmallVector, 8> &Regs, // Check if the relative offset from the where the base register references // to the target address is in range for the instruction. int64_t Offset = LocalFrameOffset - RegOffset.second; - if (TRI->isBaseRegInRange(MI, RegOffset.first, Offset)) + if (TRI->isFrameOffsetLegal(MI, Offset)) return true; } return false; @@ -225,6 +225,7 @@ void LocalStackSlotPass::insertFrameReferenceRegisters(MachineFunction &Fn) { // an object allocated in the local block. if (MI->getOperand(i).isFI()) { int FrameIdx = MI->getOperand(i).getIndex(); + // Don't try this with values not in the local block. if (!MFI->isObjectPreAllocated(FrameIdx)) continue; @@ -232,13 +233,15 @@ void LocalStackSlotPass::insertFrameReferenceRegisters(MachineFunction &Fn) { DEBUG(dbgs() << "Considering: " << *MI); if (TRI->needsFrameBaseReg(MI, i)) { unsigned BaseReg = 0; - unsigned Offset = 0; + int64_t Offset = 0; DEBUG(dbgs() << " Replacing FI in: " << *MI); // If we have a suitable base register available, use it; otherwise - // create a new one. - + // create a new one. Note that any offset encoded in the + // instruction itself will be taken into account by the target, + // so we don't have to adjust for it here when reusing a base + // register. std::pair RegOffset; if (lookupCandidateBaseReg(BaseRegisters, RegOffset, LocalOffsets[FrameIdx], MI, TRI)) { @@ -250,15 +253,26 @@ void LocalStackSlotPass::insertFrameReferenceRegisters(MachineFunction &Fn) { } else { // No previously defined register was in range, so create a // new one. + int64_t InstrOffset = TRI->getFrameIndexInstrOffset(MI, i); const TargetRegisterClass *RC = TRI->getPointerRegClass(); BaseReg = Fn.getRegInfo().createVirtualRegister(RC); + DEBUG(dbgs() << " Materializing base register " << BaseReg << + " at frame local offset " << + LocalOffsets[FrameIdx] + InstrOffset << "\n"); // Tell the target to insert the instruction to initialize // the base register. - TRI->materializeFrameBaseRegister(I, BaseReg, FrameIdx); + TRI->materializeFrameBaseRegister(I, BaseReg, FrameIdx, + InstrOffset); - BaseRegisters.push_back(std::pair(BaseReg, - Offset)); + // The base register already includes any offset specified + // by the instruction, so account for that so it doesn't get + // applied twice. + Offset = -InstrOffset; + + BaseRegisters.push_back( + std::pair(BaseReg, + LocalOffsets[FrameIdx] + InstrOffset)); ++NumBaseRegisters; } assert(BaseReg != 0 && "Unable to allocate virtual base register!"); diff --git a/lib/Target/ARM/ARMBaseRegisterInfo.cpp b/lib/Target/ARM/ARMBaseRegisterInfo.cpp index ef316a53fc0..1408e34b2fb 100644 --- a/lib/Target/ARM/ARMBaseRegisterInfo.cpp +++ b/lib/Target/ARM/ARMBaseRegisterInfo.cpp @@ -1367,6 +1367,59 @@ eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB, MBB.erase(I); } + +int64_t ARMBaseRegisterInfo:: +getFrameIndexInstrOffset(MachineInstr *MI, int Idx) const { + const TargetInstrDesc &Desc = MI->getDesc(); + unsigned AddrMode = (Desc.TSFlags & ARMII::AddrModeMask); + int64_t InstrOffs = 0;; + int Scale = 1; + unsigned ImmIdx = 0; + switch(AddrMode) { + case ARMII::AddrModeT2_i8: + case ARMII::AddrModeT2_i12: + // i8 supports only negative, and i12 supports only positive, so + // based on Offset sign, consider the appropriate instruction + InstrOffs = MI->getOperand(Idx+1).getImm(); + Scale = 1; + break; + case ARMII::AddrMode5: { + // VFP address mode. + const MachineOperand &OffOp = MI->getOperand(Idx+1); + int InstrOffs = ARM_AM::getAM5Offset(OffOp.getImm()); + if (ARM_AM::getAM5Op(OffOp.getImm()) == ARM_AM::sub) + InstrOffs = -InstrOffs; + Scale = 4; + break; + } + case ARMII::AddrMode2: { + ImmIdx = Idx+2; + InstrOffs = ARM_AM::getAM2Offset(MI->getOperand(ImmIdx).getImm()); + if (ARM_AM::getAM2Op(MI->getOperand(ImmIdx).getImm()) == ARM_AM::sub) + InstrOffs = -InstrOffs; + break; + } + case ARMII::AddrMode3: { + ImmIdx = Idx+2; + InstrOffs = ARM_AM::getAM3Offset(MI->getOperand(ImmIdx).getImm()); + if (ARM_AM::getAM3Op(MI->getOperand(ImmIdx).getImm()) == ARM_AM::sub) + InstrOffs = -InstrOffs; + break; + } + case ARMII::AddrModeT1_s: { + ImmIdx = Idx+1; + InstrOffs = MI->getOperand(ImmIdx).getImm(); + Scale = 4; + break; + } + default: + llvm_unreachable("Unsupported addressing mode!"); + break; + } + + return InstrOffs * Scale; +} + /// needsFrameBaseReg - Returns true if the instruction's frame index /// reference would be better served by a base register other than FP /// or SP. Used by LocalStackFrameAllocation to determine which frame index @@ -1404,8 +1457,8 @@ needsFrameBaseReg(MachineInstr *MI, unsigned operand) const { /// materializeFrameBaseRegister - Insert defining instruction(s) for /// BaseReg to be a pointer to FrameIdx before insertion point I. void ARMBaseRegisterInfo:: -materializeFrameBaseRegister(MachineBasicBlock::iterator I, - unsigned BaseReg, int FrameIdx) const { +materializeFrameBaseRegister(MachineBasicBlock::iterator I, unsigned BaseReg, + int FrameIdx, int64_t Offset) const { ARMFunctionInfo *AFI = I->getParent()->getParent()->getInfo(); unsigned ADDriOpc = !AFI->isThumbFunction() ? ARM::ADDri : @@ -1413,7 +1466,7 @@ materializeFrameBaseRegister(MachineBasicBlock::iterator I, MachineInstrBuilder MIB = BuildMI(*I->getParent(), I, I->getDebugLoc(), TII.get(ADDriOpc), BaseReg) - .addFrameIndex(FrameIdx).addImm(0); + .addFrameIndex(FrameIdx).addImm(Offset); if (!AFI->isThumb1OnlyFunction()) AddDefaultCC(AddDefaultPred(MIB)); } @@ -1445,8 +1498,8 @@ ARMBaseRegisterInfo::resolveFrameIndex(MachineBasicBlock::iterator I, assert (Done && "Unable to resolve frame index!"); } -bool ARMBaseRegisterInfo::isBaseRegInRange(const MachineInstr *MI, - unsigned Reg, int64_t Offset) const { +bool ARMBaseRegisterInfo::isFrameOffsetLegal(const MachineInstr *MI, + int64_t Offset) const { const TargetInstrDesc &Desc = MI->getDesc(); unsigned AddrMode = (Desc.TSFlags & ARMII::AddrModeMask); unsigned i = 0; @@ -1464,6 +1517,7 @@ bool ARMBaseRegisterInfo::isBaseRegInRange(const MachineInstr *MI, unsigned Scale = 1; unsigned ImmIdx = 0; int InstrOffs = 0;; + bool isSigned = true; switch(AddrMode) { case ARMII::AddrModeT2_i8: case ARMII::AddrModeT2_i12: @@ -1509,6 +1563,7 @@ bool ARMBaseRegisterInfo::isBaseRegInRange(const MachineInstr *MI, InstrOffs = MI->getOperand(ImmIdx).getImm(); NumBits = 5; Scale = 4; + isSigned = false; break; } default: @@ -1518,7 +1573,7 @@ bool ARMBaseRegisterInfo::isBaseRegInRange(const MachineInstr *MI, Offset += InstrOffs * Scale; assert((Offset & (Scale-1)) == 0 && "Can't encode this offset!"); - if (Offset < 0) + if (isSigned && Offset < 0) Offset = -Offset; unsigned Mask = (1 << NumBits) - 1; diff --git a/lib/Target/ARM/ARMBaseRegisterInfo.h b/lib/Target/ARM/ARMBaseRegisterInfo.h index 716c91d9ad0..afd43eaeb36 100644 --- a/lib/Target/ARM/ARMBaseRegisterInfo.h +++ b/lib/Target/ARM/ARMBaseRegisterInfo.h @@ -105,13 +105,14 @@ public: bool canRealignStack(const MachineFunction &MF) const; bool needsStackRealignment(const MachineFunction &MF) const; + int64_t getFrameIndexInstrOffset(MachineInstr *MI, int Idx) const; bool needsFrameBaseReg(MachineInstr *MI, unsigned operand) const; void materializeFrameBaseRegister(MachineBasicBlock::iterator I, - unsigned BaseReg, int FrameIdx) const; + unsigned BaseReg, int FrameIdx, + int64_t Offset) const; void resolveFrameIndex(MachineBasicBlock::iterator I, unsigned BaseReg, int64_t Offset) const; - bool isBaseRegInRange(const MachineInstr *MI, unsigned Reg, - int64_t Offset) const; + bool isFrameOffsetLegal(const MachineInstr *MI, int64_t Offset) const; bool cannotEliminateFrame(const MachineFunction &MF) const;