Skip to content

[RegScavenger] Simplify state tracking for backwards scavenging #71202

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 1 addition & 13 deletions llvm/include/llvm/CodeGen/RegisterScavenging.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,6 @@ class RegScavenger {
MachineBasicBlock *MBB = nullptr;
MachineBasicBlock::iterator MBBI;

/// True if RegScavenger is currently tracking the liveness of registers.
bool Tracking = false;

/// Information on scavenged registers (held in a spill slot).
struct ScavengedInfo {
ScavengedInfo(int FI = -1) : FrameIndex(FI) {}
Expand Down Expand Up @@ -95,21 +92,12 @@ class RegScavenger {
/// method gives precise results even in the absence of kill flags.
void backward();

/// Call backward() as long as the internal iterator does not point to \p I.
/// Call backward() to update internal register state to just before \p *I.
void backward(MachineBasicBlock::iterator I) {
while (MBBI != I)
backward();
}

/// Move the internal MBB iterator but do not update register states.
void skipTo(MachineBasicBlock::iterator I) {
if (I == MachineBasicBlock::iterator(nullptr))
Tracking = false;
MBBI = I;
}

MachineBasicBlock::iterator getCurrentPosition() const { return MBBI; }

/// Return if a specific register is currently used.
bool isRegUsed(Register Reg, bool includeReserved = true) const;

Expand Down
7 changes: 1 addition & 6 deletions llvm/lib/CodeGen/PrologEpilogInserter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1499,7 +1499,7 @@ void PEI::replaceFrameIndicesBackward(MachineBasicBlock *BB,

// Step backwards to get the liveness state at (immedately after) MI.
if (LocalRS)
LocalRS->backward(MI);
LocalRS->backward(I);

bool RemovedMI = false;
for (const auto &[Idx, Op] : enumerate(MI.operands())) {
Expand All @@ -1515,11 +1515,6 @@ void PEI::replaceFrameIndicesBackward(MachineBasicBlock *BB,
break;
}

// Refresh the scavenger's internal iterator in case MI was removed or more
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice cleanup here. LocalRS->MBBI now points after MI, to an instruction which will not have been affected by the call to TRI.eliminateFrameIndex, so there is no need to refresh anything.

// instructions were inserted after it.
if (LocalRS)
LocalRS->skipTo(std::prev(I));

if (!RemovedMI)
--I;
}
Expand Down
34 changes: 9 additions & 25 deletions llvm/lib/CodeGen/RegisterScavenging.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,30 +65,22 @@ void RegScavenger::init(MachineBasicBlock &MBB) {
SI.Reg = 0;
SI.Restore = nullptr;
}

Tracking = false;
}

void RegScavenger::enterBasicBlock(MachineBasicBlock &MBB) {
init(MBB);
LiveUnits.addLiveIns(MBB);
MBBI = MBB.begin();
}

void RegScavenger::enterBasicBlockEnd(MachineBasicBlock &MBB) {
init(MBB);
LiveUnits.addLiveOuts(MBB);

// Move internal iterator at the last instruction of the block.
if (!MBB.empty()) {
MBBI = std::prev(MBB.end());
Tracking = true;
}
MBBI = MBB.end();
}

void RegScavenger::backward() {
assert(Tracking && "Must be tracking to determine kills and defs");

const MachineInstr &MI = *MBBI;
const MachineInstr &MI = *--MBBI;
LiveUnits.stepBackward(MI);

// Expire scavenge spill frameindex uses.
Expand All @@ -98,12 +90,6 @@ void RegScavenger::backward() {
I.Restore = nullptr;
}
}

if (MBBI == MBB->begin()) {
MBBI = MachineBasicBlock::iterator(nullptr);
Tracking = false;
} else
--MBBI;
}

bool RegScavenger::isRegUsed(Register Reg, bool includeReserved) const {
Expand Down Expand Up @@ -317,9 +303,8 @@ Register RegScavenger::scavengeRegisterBackwards(const TargetRegisterClass &RC,
// Find the register whose use is furthest away.
MachineBasicBlock::iterator UseMI;
ArrayRef<MCPhysReg> AllocationOrder = RC.getRawAllocationOrder(MF);
std::pair<MCPhysReg, MachineBasicBlock::iterator> P =
findSurvivorBackwards(*MRI, MBBI, To, LiveUnits, AllocationOrder,
RestoreAfter);
std::pair<MCPhysReg, MachineBasicBlock::iterator> P = findSurvivorBackwards(
*MRI, std::prev(MBBI), To, LiveUnits, AllocationOrder, RestoreAfter);
MCPhysReg Reg = P.first;
MachineBasicBlock::iterator SpillBefore = P.second;
// Found an available register?
Expand All @@ -334,9 +319,8 @@ Register RegScavenger::scavengeRegisterBackwards(const TargetRegisterClass &RC,

assert(Reg != 0 && "No register left to scavenge!");

MachineBasicBlock::iterator ReloadAfter =
RestoreAfter ? std::next(MBBI) : MBBI;
MachineBasicBlock::iterator ReloadBefore = std::next(ReloadAfter);
MachineBasicBlock::iterator ReloadBefore =
RestoreAfter ? std::next(MBBI) : MBBI;
if (ReloadBefore != MBB.end())
LLVM_DEBUG(dbgs() << "Reload before: " << *ReloadBefore << '\n');
ScavengedInfo &Scavenged = spill(Reg, RC, SPAdj, SpillBefore, ReloadBefore);
Expand Down Expand Up @@ -414,9 +398,9 @@ static bool scavengeFrameVirtualRegsInBlock(MachineRegisterInfo &MRI,
unsigned InitialNumVirtRegs = MRI.getNumVirtRegs();
bool NextInstructionReadsVReg = false;
for (MachineBasicBlock::iterator I = MBB.end(); I != MBB.begin(); ) {
--I;
// Move RegScavenger to the position between *I and *std::next(I).
// Move RegScavenger to the position between *std::prev(I) and *I.
RS.backward(I);
--I;

// Look for unassigned vregs in the uses of *std::next(I).
if (NextInstructionReadsVReg) {
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3426,7 +3426,7 @@ void AArch64FrameLowering::processFunctionBeforeFrameFinalized(
// function.
DebugLoc DL;
RS->enterBasicBlockEnd(MBB);
RS->backward(std::prev(MBBI));
RS->backward(MBBI);
Register DstReg = RS->FindUnusedReg(&AArch64::GPR64commonRegClass);
assert(DstReg && "There must be a free register after frame setup");
BuildMI(MBB, MBBI, DL, TII.get(AArch64::MOVi64imm), DstReg).addImm(-2);
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/Target/AArch64/AArch64SpeculationHardening.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ bool AArch64SpeculationHardening::instrumentControlFlow(
if (I == MBB.begin())
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The I == MBB.begin() is not needed. We could clean this up further by just calling RS.backward(I) unconditionally. I left it in just in case there was some performance reason for having a special case for start-of-block.

RS.enterBasicBlock(MBB);
else
RS.backward(std::prev(I));
RS.backward(I);
// FIXME: The below just finds *a* unused register. Maybe code could be
// optimized more if this looks for the register that isn't used for the
// longest time around this place, to enable more scheduling freedom. Not
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/Target/AMDGPU/SIFrameLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1358,7 +1358,7 @@ void SIFrameLowering::processFunctionBeforeFrameFinalized(
TRI->isAGPR(MRI, VReg))) {
assert(RS != nullptr);
RS->enterBasicBlockEnd(MBB);
RS->backward(MI);
RS->backward(std::next(MI.getIterator()));
TRI->eliminateFrameIndex(MI, 0, FIOp, RS);
SpillFIs.set(FI);
continue;
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/Target/AMDGPU/SIInstrInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -681,7 +681,7 @@ static void indirectCopyToAGPR(const SIInstrInfo &TII,
}

RS.enterBasicBlockEnd(MBB);
RS.backward(MI);
RS.backward(std::next(MI));

// Ideally we want to have three registers for a long reg_sequence copy
// to hide 2 waitstates between v_mov_b32 and accvgpr_write.
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/Target/Mips/Mips16InstrInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,7 @@ unsigned Mips16InstrInfo::loadImmediate(unsigned FrameReg, int64_t Imm,
int SpReg = 0;

rs.enterBasicBlockEnd(MBB);
rs.backward(II);
rs.backward(std::next(II));
//
// We need to know which registers can be used, in the case where there
// are not enough free registers. We exclude all registers that
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/Target/PowerPC/PPCFrameLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -466,7 +466,7 @@ PPCFrameLowering::findScratchRegister(MachineBasicBlock *MBB,
RS.enterBasicBlock(*MBB);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, the MBBI == MBB->begin() case is not required.

} else {
RS.enterBasicBlockEnd(*MBB);
RS.backward(std::prev(MBBI));
RS.backward(MBBI);
}
} else {
// The scratch register will be used at the start of the block.
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/Target/RISCV/RISCVMakeCompressible.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ static Register analyzeCompressibleUses(MachineInstr &FirstMI,

RegScavenger RS;
RS.enterBasicBlockEnd(MBB);
RS.backward(MIs.back()->getIterator());
RS.backward(std::next(MIs.back()->getIterator()));
return RS.scavengeRegisterBackwards(*RCToScavenge, FirstMI.getIterator(),
/*RestoreAfter=*/false, /*SPAdj=*/0,
/*AllowSpill=*/false);
Expand Down
2 changes: 1 addition & 1 deletion llvm/test/CodeGen/XCore/scavenging.ll
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,8 @@ declare void @g(ptr, ptr)
; CHECK: ldw r2, cp[[[INDEX4]]]
; r4 & r5 used by InsertSPConstInst() to emit STW_l3r instruction.
; CHECK: stw r0, r1[r2]
; CHECK: ldw r2, sp[0]
; CHECK: ldw r1, sp[1]
; CHECK: ldw r2, sp[0]
; CHECK: ldaw r0, sp[0]
; scavenge r2 using SR spill slot
; CHECK: stw r2, sp[1]
Expand Down