Enable ARM base register reuse to local stack slot allocation. Whenever a new
frame index reference to an object in the local block is seen, check if
it's near enough to any previously allocaated base register to re-use.
rdar://8277890
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@111443 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/CodeGen/LocalStackSlotAllocation.cpp b/lib/CodeGen/LocalStackSlotAllocation.cpp
index 219b845..61d6b10 100644
--- a/lib/CodeGen/LocalStackSlotAllocation.cpp
+++ b/lib/CodeGen/LocalStackSlotAllocation.cpp
@@ -43,8 +43,11 @@
namespace {
class LocalStackSlotPass: public MachineFunctionPass {
- void calculateFrameObjectOffsets(MachineFunction &Fn);
+ SmallVector<int64_t,16> LocalOffsets;
+ void AdjustStackOffset(MachineFrameInfo *MFI, int FrameIdx, int64_t &Offset,
+ unsigned &MaxAlign);
+ void calculateFrameObjectOffsets(MachineFunction &Fn);
void insertFrameReferenceRegisters(MachineFunction &Fn);
public:
static char ID; // Pass identification, replacement for typeid
@@ -70,18 +73,29 @@
}
bool LocalStackSlotPass::runOnMachineFunction(MachineFunction &MF) {
+ MachineFrameInfo *MFI = MF.getFrameInfo();
+ unsigned LocalObjectCount = MFI->getObjectIndexEnd();
+
+ // Early exit if there are no locals to consider
+ if (!LocalObjectCount)
+ return true;
+
+ // Make sure we have enough space to store the local offsets.
+ LocalOffsets.resize(MFI->getObjectIndexEnd());
+
// Lay out the local blob.
calculateFrameObjectOffsets(MF);
// Insert virtual base registers to resolve frame index references.
insertFrameReferenceRegisters(MF);
+
return true;
}
/// AdjustStackOffset - Helper function used to adjust the stack frame offset.
-static inline void
-AdjustStackOffset(MachineFrameInfo *MFI, int FrameIdx, int64_t &Offset,
- unsigned &MaxAlign) {
+void LocalStackSlotPass::AdjustStackOffset(MachineFrameInfo *MFI,
+ int FrameIdx, int64_t &Offset,
+ unsigned &MaxAlign) {
unsigned Align = MFI->getObjectAlignment(FrameIdx);
// If the alignment of this object is greater than that of the stack, then
@@ -93,6 +107,9 @@
DEBUG(dbgs() << "Allocate FI(" << FrameIdx << ") to local offset "
<< Offset << "\n");
+ // Keep the offset available for base register allocation
+ LocalOffsets[FrameIdx] = Offset;
+ // And tell MFI about it for PEI to use later
MFI->mapLocalFrameObject(FrameIdx, Offset);
Offset += MFI->getObjectSize(FrameIdx);
@@ -149,12 +166,16 @@
static inline bool
lookupCandidateBaseReg(const SmallVector<std::pair<unsigned, int64_t>, 8> &Regs,
std::pair<unsigned, int64_t> &RegOffset,
+ int64_t LocalFrameOffset,
const MachineInstr *MI,
const TargetRegisterInfo *TRI) {
unsigned e = Regs.size();
for (unsigned i = 0; i < e; ++i) {
RegOffset = Regs[i];
- if (TRI->isBaseRegInRange(MI, RegOffset.first, RegOffset.second))
+ // 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))
return true;
}
return false;
@@ -173,6 +194,9 @@
for (MachineFunction::iterator BB = Fn.begin(),
E = Fn.end(); BB != E; ++BB) {
+ // A base register definition is a register+offset pair.
+ SmallVector<std::pair<unsigned, int64_t>, 8> BaseRegisters;
+
for (MachineBasicBlock::iterator I = BB->begin(); I != BB->end(); ++I) {
MachineInstr *MI = I;
// Debug value instructions can't be out of range, so they don't need
@@ -183,9 +207,6 @@
if (MI->isDebugValue())
continue;
- // A base register definition is a register+offset pair.
- SmallVector<std::pair<unsigned, int64_t>, 8> BaseRegisters;
-
// For now, allocate the base register(s) within the basic block
// where they're used, and don't try to keep them around outside
// of that. It may be beneficial to try sharing them more broadly
@@ -212,10 +233,12 @@
// create a new one.
std::pair<unsigned, int64_t> RegOffset;
- if (lookupCandidateBaseReg(BaseRegisters, RegOffset, MI, TRI)) {
+ if (lookupCandidateBaseReg(BaseRegisters, RegOffset,
+ LocalOffsets[FrameIdx], MI, TRI)) {
+ DEBUG(dbgs() << " Reusing base register " << RegOffset.first);
// We found a register to reuse.
BaseReg = RegOffset.first;
- Offset = RegOffset.second;
+ Offset = LocalOffsets[FrameIdx] - RegOffset.second;
} else {
// No previously defined register was in range, so create a
// new one.
diff --git a/lib/Target/ARM/ARMBaseRegisterInfo.cpp b/lib/Target/ARM/ARMBaseRegisterInfo.cpp
index b498075..0330fac 100644
--- a/lib/Target/ARM/ARMBaseRegisterInfo.cpp
+++ b/lib/Target/ARM/ARMBaseRegisterInfo.cpp
@@ -1453,6 +1453,75 @@
bool ARMBaseRegisterInfo::isBaseRegInRange(const MachineInstr *MI,
unsigned Reg, int64_t Offset) const {
+ const TargetInstrDesc &Desc = MI->getDesc();
+ unsigned AddrMode = (Desc.TSFlags & ARMII::AddrModeMask);
+ unsigned i = 0;
+
+ while (!MI->getOperand(i).isFI()) {
+ ++i;
+ assert(i < MI->getNumOperands() &&"Instr doesn't have FrameIndex operand!");
+ }
+
+ // AddrMode4 and AddrMode6 cannot handle any offset.
+ if (AddrMode == ARMII::AddrMode4 || AddrMode == ARMII::AddrMode6)
+ return Offset == 0;
+
+ unsigned NumBits = 0;
+ unsigned Scale = 1;
+ unsigned ImmIdx = 0;
+ int InstrOffs;
+ 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
+ Offset += MI->getOperand(i+1).getImm();
+ if (Offset < 0) {
+ NumBits = 8;
+ Offset = -Offset;
+ } else {
+ NumBits = 12;
+ }
+ break;
+ case ARMII::AddrMode5: {
+ // VFP address mode.
+ const MachineOperand &OffOp = MI->getOperand(i+1);
+ int InstrOffs = ARM_AM::getAM5Offset(OffOp.getImm());
+ if (ARM_AM::getAM5Op(OffOp.getImm()) == ARM_AM::sub)
+ InstrOffs = -InstrOffs;
+ NumBits = 8;
+ Scale = 4;
+ break;
+ }
+ case ARMII::AddrMode2: {
+ ImmIdx = i+2;
+ InstrOffs = ARM_AM::getAM2Offset(MI->getOperand(ImmIdx).getImm());
+ if (ARM_AM::getAM2Op(MI->getOperand(ImmIdx).getImm()) == ARM_AM::sub)
+ InstrOffs = -InstrOffs;
+ NumBits = 12;
+ break;
+ }
+ case ARMII::AddrMode3: {
+ ImmIdx = i+2;
+ InstrOffs = ARM_AM::getAM3Offset(MI->getOperand(ImmIdx).getImm());
+ if (ARM_AM::getAM3Op(MI->getOperand(ImmIdx).getImm()) == ARM_AM::sub)
+ InstrOffs = -InstrOffs;
+ NumBits = 8;
+ break;
+ }
+ default:
+ llvm_unreachable("Unsupported addressing mode!");
+ break;
+ }
+
+ Offset += InstrOffs * Scale;
+ assert((Offset & (Scale-1)) == 0 && "Can't encode this offset!");
+ if (Offset < 0)
+ Offset = -Offset;
+
+ unsigned Mask = (1 << NumBits) - 1;
+ if ((unsigned)Offset <= Mask * Scale)
+ return true;
return false;
}