Update PEI's virtual-register-based scavenging to support multiple simultaneous mappings
The previous algorithm could not deal properly with scavenging multiple virtual registers because it kept only one live virtual -> physical mapping (and iterated through operands in order). Now we don't maintain a current mapping, but rather use replaceRegWith to completely remove the virtual register as soon as the mapping is established. In order to allow the register scavenger to return a physical register killed by an instruction for definition by that same instruction, we now call RS->forward(I) prior to eliminating virtual registers defined in I. This requires a minor update to forward to ignore virtual registers. These new features will be tested in forthcoming commits. llvm-svn: 178058
This commit is contained in:
parent
7c0788b2d9
commit
4e05788cc3
|
@ -94,8 +94,11 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
/// skipTo - Move the internal MBB iterator but do not update register states.
|
/// skipTo - Move the internal MBB iterator but do not update register states.
|
||||||
///
|
void skipTo(MachineBasicBlock::iterator I) {
|
||||||
void skipTo(MachineBasicBlock::iterator I) { MBBI = I; }
|
if (I == MachineBasicBlock::iterator(NULL))
|
||||||
|
Tracking = false;
|
||||||
|
MBBI = I;
|
||||||
|
}
|
||||||
|
|
||||||
/// getRegsUsed - return all registers currently in use in used.
|
/// getRegsUsed - return all registers currently in use in used.
|
||||||
void getRegsUsed(BitVector &used, bool includeReserved);
|
void getRegsUsed(BitVector &used, bool includeReserved);
|
||||||
|
|
|
@ -55,7 +55,6 @@ INITIALIZE_PASS_END(PEI, "prologepilog",
|
||||||
"Prologue/Epilogue Insertion & Frame Finalization",
|
"Prologue/Epilogue Insertion & Frame Finalization",
|
||||||
false, false)
|
false, false)
|
||||||
|
|
||||||
STATISTIC(NumVirtualFrameRegs, "Number of virtual frame regs encountered");
|
|
||||||
STATISTIC(NumScavengedRegs, "Number of frame index regs scavenged");
|
STATISTIC(NumScavengedRegs, "Number of frame index regs scavenged");
|
||||||
STATISTIC(NumBytesStackSpace,
|
STATISTIC(NumBytesStackSpace,
|
||||||
"Number of bytes used for stack in all functions");
|
"Number of bytes used for stack in all functions");
|
||||||
|
@ -820,14 +819,20 @@ void PEI::scavengeFrameVirtualRegs(MachineFunction &Fn) {
|
||||||
E = Fn.end(); BB != E; ++BB) {
|
E = Fn.end(); BB != E; ++BB) {
|
||||||
RS->enterBasicBlock(BB);
|
RS->enterBasicBlock(BB);
|
||||||
|
|
||||||
unsigned VirtReg = 0;
|
|
||||||
unsigned ScratchReg = 0;
|
|
||||||
int SPAdj = 0;
|
int SPAdj = 0;
|
||||||
|
|
||||||
// The instruction stream may change in the loop, so check BB->end()
|
// The instruction stream may change in the loop, so check BB->end()
|
||||||
// directly.
|
// directly.
|
||||||
for (MachineBasicBlock::iterator I = BB->begin(); I != BB->end(); ) {
|
for (MachineBasicBlock::iterator I = BB->begin(); I != BB->end(); ) {
|
||||||
MachineInstr *MI = I;
|
MachineInstr *MI = I;
|
||||||
|
MachineBasicBlock::iterator J = llvm::next(I);
|
||||||
|
|
||||||
|
// RS should process this instruction before we might scavenge at this
|
||||||
|
// location. This is because we might be replacing a virtual register
|
||||||
|
// defined by this instruction, and if so, registers killed by this
|
||||||
|
// instruction are available, and defined registers are not.
|
||||||
|
RS->forward(I);
|
||||||
|
|
||||||
for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
|
for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
|
||||||
if (MI->getOperand(i).isReg()) {
|
if (MI->getOperand(i).isReg()) {
|
||||||
MachineOperand &MO = MI->getOperand(i);
|
MachineOperand &MO = MI->getOperand(i);
|
||||||
|
@ -837,29 +842,37 @@ void PEI::scavengeFrameVirtualRegs(MachineFunction &Fn) {
|
||||||
if (!TargetRegisterInfo::isVirtualRegister(Reg))
|
if (!TargetRegisterInfo::isVirtualRegister(Reg))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
++NumVirtualFrameRegs;
|
// When we first encounter a new virtual register, it
|
||||||
|
// must be a definition.
|
||||||
|
assert(MI->getOperand(i).isDef() &&
|
||||||
|
"frame index virtual missing def!");
|
||||||
|
// Scavenge a new scratch register
|
||||||
|
const TargetRegisterClass *RC = Fn.getRegInfo().getRegClass(Reg);
|
||||||
|
unsigned ScratchReg = RS->scavengeRegister(RC, J, SPAdj);
|
||||||
|
|
||||||
|
++NumScavengedRegs;
|
||||||
|
|
||||||
// Have we already allocated a scratch register for this virtual?
|
|
||||||
if (Reg != VirtReg) {
|
|
||||||
// When we first encounter a new virtual register, it
|
|
||||||
// must be a definition.
|
|
||||||
assert(MI->getOperand(i).isDef() &&
|
|
||||||
"frame index virtual missing def!");
|
|
||||||
// Scavenge a new scratch register
|
|
||||||
VirtReg = Reg;
|
|
||||||
const TargetRegisterClass *RC = Fn.getRegInfo().getRegClass(Reg);
|
|
||||||
ScratchReg = RS->scavengeRegister(RC, I, SPAdj);
|
|
||||||
++NumScavengedRegs;
|
|
||||||
}
|
|
||||||
// Replace this reference to the virtual register with the
|
// Replace this reference to the virtual register with the
|
||||||
// scratch register.
|
// scratch register.
|
||||||
assert (ScratchReg && "Missing scratch register!");
|
assert (ScratchReg && "Missing scratch register!");
|
||||||
MI->getOperand(i).setReg(ScratchReg);
|
Fn.getRegInfo().replaceRegWith(Reg, ScratchReg);
|
||||||
|
|
||||||
|
// Because this instruction was processed by the RS before this
|
||||||
|
// register was allocated, make sure that the RS now records the
|
||||||
|
// register as being used.
|
||||||
|
RS->setUsed(ScratchReg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RS->forward(I);
|
|
||||||
++I;
|
// If the scavenger needed to use one of its spill slots, the
|
||||||
|
// spill code will have been inserted in between I and J. This is a
|
||||||
|
// problem because we need the spill code before I: Move I to just
|
||||||
|
// prior to J.
|
||||||
|
if (I != llvm::prior(J)) {
|
||||||
|
BB->splice(J, BB, I++);
|
||||||
|
RS->skipTo(I == BB->begin() ? NULL : llvm::prior(I));
|
||||||
|
} else
|
||||||
|
++I;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -150,7 +150,7 @@ void RegScavenger::forward() {
|
||||||
if (!MO.isReg())
|
if (!MO.isReg())
|
||||||
continue;
|
continue;
|
||||||
unsigned Reg = MO.getReg();
|
unsigned Reg = MO.getReg();
|
||||||
if (!Reg || isReserved(Reg))
|
if (!Reg || TargetRegisterInfo::isVirtualRegister(Reg) || isReserved(Reg))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (MO.isUse()) {
|
if (MO.isUse()) {
|
||||||
|
@ -175,7 +175,7 @@ void RegScavenger::forward() {
|
||||||
if (!MO.isReg())
|
if (!MO.isReg())
|
||||||
continue;
|
continue;
|
||||||
unsigned Reg = MO.getReg();
|
unsigned Reg = MO.getReg();
|
||||||
if (!Reg || isReserved(Reg))
|
if (!Reg || TargetRegisterInfo::isVirtualRegister(Reg) || isReserved(Reg))
|
||||||
continue;
|
continue;
|
||||||
if (MO.isUse()) {
|
if (MO.isUse()) {
|
||||||
if (MO.isUndef())
|
if (MO.isUndef())
|
||||||
|
|
|
@ -71,8 +71,8 @@ define void @test_variadic_alloca(i64 %n, ...) {
|
||||||
; CHECK: sub sp, sp, #208
|
; CHECK: sub sp, sp, #208
|
||||||
; CHECK: stp x29, x30, [sp, #192]
|
; CHECK: stp x29, x30, [sp, #192]
|
||||||
; CHECK: add x29, sp, #192
|
; CHECK: add x29, sp, #192
|
||||||
; CHECK: sub x9, x29, #192
|
; CHECK: sub [[TMP:x[0-9]+]], x29, #192
|
||||||
; CHECK: add x8, x9, #0
|
; CHECK: add x8, [[TMP]], #0
|
||||||
; CHECK: str q7, [x8, #112]
|
; CHECK: str q7, [x8, #112]
|
||||||
; [...]
|
; [...]
|
||||||
; CHECK: str q1, [x8, #16]
|
; CHECK: str q1, [x8, #16]
|
||||||
|
@ -131,4 +131,4 @@ define void @test_scoped_alloca(i64 %n) {
|
||||||
; CHECK: mov sp, [[SAVED_SP]]
|
; CHECK: mov sp, [[SAVED_SP]]
|
||||||
|
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue