mirror of
https://github.com/RPCSX/llvm.git
synced 2025-01-08 04:52:50 +00:00
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
This commit is contained in:
parent
e0b313d599
commit
2b1e202e1c
@ -43,8 +43,11 @@ STATISTIC(NumReplacements, "Number of frame indices references replaced");
|
||||
|
||||
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 @@ FunctionPass *llvm::createLocalStackSlotAllocationPass() {
|
||||
}
|
||||
|
||||
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 @@ AdjustStackOffset(MachineFrameInfo *MFI, int FrameIdx, int64_t &Offset,
|
||||
|
||||
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 @@ void LocalStackSlotPass::calculateFrameObjectOffsets(MachineFunction &Fn) {
|
||||
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 @@ void LocalStackSlotPass::insertFrameReferenceRegisters(MachineFunction &Fn) {
|
||||
|
||||
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 @@ void LocalStackSlotPass::insertFrameReferenceRegisters(MachineFunction &Fn) {
|
||||
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 @@ void LocalStackSlotPass::insertFrameReferenceRegisters(MachineFunction &Fn) {
|
||||
// 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.
|
||||
|
@ -1453,6 +1453,75 @@ ARMBaseRegisterInfo::resolveFrameIndex(MachineBasicBlock::iterator I,
|
||||
|
||||
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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user