Skip to content

Commit 619b9e2

Browse files
committed
Spill/restore FP/BP around instructions in which they are clobbered
This patch fixes llvm#17204. If a base pointer is used in a function, and it is clobbered by an instruction (typically an inline asm), current register allocator can't handle this situation, so BP becomes garbage after those instructions. It can also occur to FP in theory. We can spill and reload FP/BP registers around those instructions. But normal spill/reload instructions also use FP/BP, so we can't spill them into normal spill slots, instead we spill them into the top of stack by using SP register.
1 parent 9c75a98 commit 619b9e2

File tree

10 files changed

+366
-0
lines changed

10 files changed

+366
-0
lines changed

llvm/include/llvm/CodeGen/MachineFrameInfo.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -599,6 +599,7 @@ class MachineFrameInfo {
599599
/// Return the alignment in bytes that this function must be aligned to,
600600
/// which is greater than the default stack alignment provided by the target.
601601
Align getMaxAlign() const { return MaxAlignment; }
602+
Align getStackAlignment() const { return StackAlignment; }
602603

603604
/// Make sure the function is at least Align bytes aligned.
604605
void ensureMaxAlignment(Align Alignment);

llvm/include/llvm/CodeGen/TargetFrameLowering.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,31 @@ class TargetFrameLowering {
466466
/// Return the frame base information to be encoded in the DWARF subprogram
467467
/// debug info.
468468
virtual DwarfFrameBase getDwarfFrameBase(const MachineFunction &MF) const;
469+
470+
/// Issue instructions to allocate stack space and spill FP and/or BP to stack
471+
/// using SP register.
472+
virtual void spillFPBPUsingSP(MachineFunction &MF,
473+
const MachineBasicBlock::iterator BeforeMI,
474+
bool SpillFP, bool SpillBP) const {
475+
report_fatal_error("spillFPBPUsingSP is not implemented for this target!");
476+
}
477+
478+
/// Issue instructions to restore FP and/or BP from stack using SP register,
479+
/// and free stack space.
480+
virtual void restoreFPBPUsingSP(MachineFunction &MF,
481+
const MachineBasicBlock::iterator AfterMI,
482+
bool SpillFP, bool SpillBP) const {
483+
report_fatal_error("restoreFPBPUsingSP is not implemented for this "
484+
"target!");
485+
}
486+
487+
// If MI uses fp/bp, but target can handle it, and doesn't want PEI to spill
488+
// it, this function should return true, and update MI so PEI will not check
489+
// any instructions from it and later.
490+
virtual bool skipSpillFPBP(MachineFunction &MF,
491+
MachineBasicBlock::reverse_iterator &MI) const {
492+
return false;
493+
}
469494
};
470495

471496
} // End llvm namespace

llvm/include/llvm/CodeGen/TargetRegisterInfo.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -963,6 +963,16 @@ class TargetRegisterInfo : public MCRegisterInfo {
963963
return false;
964964
}
965965

966+
/// Returns true if the target needs a base register.
967+
virtual bool hasBaseRegister(const MachineFunction &MF) const {
968+
return false;
969+
}
970+
971+
/// Returns the physical base register used to access stack object.
972+
virtual Register getBaseRegister(const MachineFunction &MF) const {
973+
return 0;
974+
}
975+
966976
/// Return true if target has reserved a spill slot in the stack frame of
967977
/// the given function for the specified register. e.g. On x86, if the frame
968978
/// register is required, the first fixed stack object is reserved as its

llvm/lib/CodeGen/PrologEpilogInserter.cpp

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,15 @@ using MBBVector = SmallVector<MachineBasicBlock *, 4>;
7777
STATISTIC(NumLeafFuncWithSpills, "Number of leaf functions with CSRs");
7878
STATISTIC(NumFuncSeen, "Number of functions seen in PEI");
7979

80+
static cl::opt<bool> SpillClobberedFP(
81+
"spill-clobbered-fp",
82+
cl::desc("Spill clobbered fp register to stack."),
83+
cl::init(false), cl::Hidden);
84+
85+
static cl::opt<bool> SpillClobberedBP(
86+
"spill-clobbered-bp",
87+
cl::desc("Spill clobbered bp register to stack."),
88+
cl::init(true), cl::Hidden);
8089

8190
namespace {
8291

@@ -122,6 +131,7 @@ class PEI : public MachineFunctionPass {
122131
void calculateCallFrameInfo(MachineFunction &MF);
123132
void calculateSaveRestoreBlocks(MachineFunction &MF);
124133
void spillCalleeSavedRegs(MachineFunction &MF);
134+
void spillFrameBasePointer(MachineFunction &MF);
125135

126136
void calculateFrameObjectOffsets(MachineFunction &MF);
127137
void replaceFrameIndices(MachineFunction &MF);
@@ -228,6 +238,9 @@ bool PEI::runOnMachineFunction(MachineFunction &MF) {
228238
FrameIndexVirtualScavenging = TRI->requiresFrameIndexScavenging(MF);
229239
ORE = &getAnalysis<MachineOptimizationRemarkEmitterPass>().getORE();
230240

241+
// Handle FP and BP spilling and restoring, for instructions that need it.
242+
spillFrameBasePointer(MF);
243+
231244
// Calculate the MaxCallFrameSize and AdjustsStack variables for the
232245
// function's frame information. Also eliminates call frame pseudo
233246
// instructions.
@@ -1587,3 +1600,114 @@ void PEI::replaceFrameIndices(MachineBasicBlock *BB, MachineFunction &MF,
15871600
++I;
15881601
}
15891602
}
1603+
1604+
static bool accessFrameBasePointer(const MachineInstr &MI, Register FP,
1605+
Register BP, bool &AccessFP, bool &AccessBP,
1606+
const TargetRegisterInfo *TRI) {
1607+
AccessFP = AccessBP = false;
1608+
if (FP) {
1609+
if (MI.findRegisterUseOperandIdx(FP, false, TRI) != -1 ||
1610+
MI.findRegisterDefOperandIdx(FP, false, true, TRI) != -1)
1611+
AccessFP = true;
1612+
}
1613+
if (BP) {
1614+
if (MI.findRegisterUseOperandIdx(BP, false, TRI) != -1 ||
1615+
MI.findRegisterDefOperandIdx(BP, false, true, TRI) != -1)
1616+
AccessBP = true;
1617+
}
1618+
return AccessFP || AccessBP;
1619+
}
1620+
1621+
/// If a function uses base pointer and the base pointer is clobbered by inline
1622+
/// asm, RA doesn't detect this case, and after the inline asm, the base pointer
1623+
/// cotains garbage value.
1624+
/// For example if a 32b x86 function uses base pointer esi, and esi is
1625+
/// clobbered by following inline asm
1626+
/// asm("rep movsb" : "+D"(ptr), "+S"(x), "+c"(c)::"memory");
1627+
/// We need to save esi before the asm and restore it after the asm.
1628+
///
1629+
/// The problem can also occur to frame pointer if there is a function call, and
1630+
/// the callee uses a different calling convention and clobbers the fp.
1631+
///
1632+
/// Because normal frame objects (spill slots) are accessed through fp/bp
1633+
/// register, so we can't spill fp/bp to normal spill slots.
1634+
///
1635+
/// FIXME: There are 2 possible enhancements:
1636+
/// 1. In many cases there are different physical registers not clobbered by
1637+
/// inline asm, we can use one of them as base pointer. Or use a virtual
1638+
/// register as base pointer and let RA allocate a physical register to it.
1639+
/// 2. If there is no other instructions access stack with fp/bp from the
1640+
/// inline asm to the epilog, we can skip the save and restore operations.
1641+
void PEI::spillFrameBasePointer(MachineFunction &MF) {
1642+
Register FP, BP;
1643+
const TargetFrameLowering &TFI = *MF.getSubtarget().getFrameLowering();
1644+
const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo();
1645+
if (TFI.hasFP(MF) && SpillClobberedFP)
1646+
FP = TRI->getFrameRegister(MF);
1647+
if (TRI->hasBaseRegister(MF) && SpillClobberedBP)
1648+
BP = TRI->getBaseRegister(MF);
1649+
1650+
for (MachineBasicBlock &MBB : MF) {
1651+
auto MI = MBB.rbegin(), ME = MBB.rend();
1652+
while (MI != ME) {
1653+
// Skip frame setup/destroy instructions.
1654+
// Skip instructions handled by target.
1655+
if (MI->getFlag(MachineInstr::MIFlag::FrameSetup) ||
1656+
MI->getFlag(MachineInstr::MIFlag::FrameDestroy) ||
1657+
TFI.skipSpillFPBP(MF, MI)) {
1658+
++MI;
1659+
continue;
1660+
}
1661+
1662+
bool AccessFP, AccessBP;
1663+
// Check if fp or bp is used in MI.
1664+
if (!accessFrameBasePointer(*MI, FP, BP, AccessFP, AccessBP, TRI)) {
1665+
++MI;
1666+
continue;
1667+
}
1668+
1669+
// Look for the range [Start, Stop] in which fp or bp is defined and used.
1670+
bool FPLive = false, BPLive = false;
1671+
bool SpillFP = false, SpillBP = false;
1672+
auto Start = MI, Stop = MI;
1673+
do {
1674+
SpillFP |= AccessFP;
1675+
SpillBP |= AccessBP;
1676+
1677+
// Maintain FPLive and BPLive.
1678+
if (FPLive && MI->findRegisterDefOperandIdx(FP, false, true, TRI) != -1)
1679+
FPLive = false;
1680+
if (FP && MI->findRegisterUseOperandIdx(FP, false, TRI) != -1)
1681+
FPLive = true;
1682+
if (BPLive && MI->findRegisterDefOperandIdx(BP, false, true, TRI) != -1)
1683+
BPLive = false;
1684+
if (BP && MI->findRegisterUseOperandIdx(BP, false, TRI) != -1)
1685+
BPLive = true;
1686+
1687+
Start = MI++;
1688+
} while ((MI != ME) && (FPLive || BPLive ||
1689+
accessFrameBasePointer(*MI, FP, BP, AccessFP, AccessBP, TRI)));
1690+
1691+
// If the bp is clobbered by a call, we should save and restore outside of
1692+
// the frame setup instructions.
1693+
if (Stop->isCall()) {
1694+
const TargetInstrInfo &TII = *MF.getSubtarget().getInstrInfo();
1695+
auto FrameSetup = std::next(Start);
1696+
while (FrameSetup != ME && !TII.isFrameSetup(*FrameSetup) &&
1697+
!FrameSetup->isCall())
1698+
++FrameSetup;
1699+
if (FrameSetup != ME && TII.isFrameSetup(*FrameSetup)) {
1700+
while (!TII.isFrameInstr(*Stop))
1701+
--Stop;
1702+
Start = FrameSetup;
1703+
MI = Start;
1704+
++MI;
1705+
}
1706+
}
1707+
1708+
// Call target functions to spill and restore FP and BP registers.
1709+
TFI.spillFPBPUsingSP(MF, &(*Start), SpillFP, SpillBP);
1710+
TFI.restoreFPBPUsingSP(MF, &(*Stop), SpillFP, SpillBP);
1711+
}
1712+
}
1713+
}

llvm/lib/Target/X86/X86FrameLowering.cpp

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4178,3 +4178,114 @@ void X86FrameLowering::restoreWinEHStackPointersInParent(
41784178
/*RestoreSP=*/IsSEH);
41794179
}
41804180
}
4181+
4182+
static int computeSPAdjust4SpillFPBP(MachineFunction &MF,
4183+
const TargetRegisterClass *RC,
4184+
unsigned SpillRegNum) {
4185+
const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo();
4186+
unsigned AllocSize = TRI->getSpillSize(*RC) * SpillRegNum;
4187+
Align StackAlign = MF.getFrameInfo().getStackAlignment();
4188+
unsigned AlignedSize = alignTo(AllocSize, StackAlign);
4189+
return AlignedSize - AllocSize;
4190+
}
4191+
4192+
void X86FrameLowering::spillFPBPUsingSP(
4193+
MachineFunction &MF, MachineBasicBlock::iterator BeforeMI,
4194+
bool SpillFP, bool SpillBP) const {
4195+
const TargetRegisterClass *RC;
4196+
unsigned RegNum = 0;
4197+
MachineBasicBlock *MBB = BeforeMI->getParent();
4198+
DebugLoc DL = BeforeMI->getDebugLoc();
4199+
4200+
// Spill FP.
4201+
if (SpillFP) {
4202+
Register FP = TRI->getFrameRegister(MF);
4203+
if (STI.isTarget64BitILP32())
4204+
FP = Register(getX86SubSuperRegister(FP, 64));
4205+
RC = TRI->getMinimalPhysRegClass(FP);
4206+
++RegNum;
4207+
4208+
BuildMI(*MBB, BeforeMI, DL,
4209+
TII.get(getPUSHOpcode(MF.getSubtarget<X86Subtarget>())))
4210+
.addReg(FP);
4211+
}
4212+
4213+
// Spill BP.
4214+
if (SpillBP) {
4215+
Register BP = TRI->getBaseRegister(MF);
4216+
if (STI.isTarget64BitILP32())
4217+
BP = Register(getX86SubSuperRegister(BP, 64));
4218+
RC = TRI->getMinimalPhysRegClass(BP);
4219+
++RegNum;
4220+
4221+
BuildMI(*MBB, BeforeMI, DL,
4222+
TII.get(getPUSHOpcode(MF.getSubtarget<X86Subtarget>())))
4223+
.addReg(BP);
4224+
}
4225+
4226+
// Make sure SP is aligned.
4227+
int SPAdjust = computeSPAdjust4SpillFPBP(MF, RC, RegNum);
4228+
if (SPAdjust)
4229+
emitSPUpdate(*MBB, BeforeMI, DL, -SPAdjust, false);
4230+
}
4231+
4232+
void X86FrameLowering::restoreFPBPUsingSP(
4233+
MachineFunction &MF, MachineBasicBlock::iterator AfterMI,
4234+
bool SpillFP, bool SpillBP) const {
4235+
Register FP, BP;
4236+
const TargetRegisterClass *RC;
4237+
unsigned RegNum = 0;
4238+
if (SpillFP) {
4239+
FP = TRI->getFrameRegister(MF);
4240+
if (STI.isTarget64BitILP32())
4241+
FP = Register(getX86SubSuperRegister(FP, 64));
4242+
RC = TRI->getMinimalPhysRegClass(FP);
4243+
++RegNum;
4244+
}
4245+
if (SpillBP) {
4246+
BP = TRI->getBaseRegister(MF);
4247+
if (STI.isTarget64BitILP32())
4248+
BP = Register(getX86SubSuperRegister(BP, 64));
4249+
RC = TRI->getMinimalPhysRegClass(BP);
4250+
++RegNum;
4251+
}
4252+
4253+
// Adjust SP so it points to spilled FP or BP.
4254+
MachineBasicBlock *MBB = AfterMI->getParent();
4255+
MachineBasicBlock::iterator Pos = std::next(AfterMI);
4256+
DebugLoc DL = AfterMI->getDebugLoc();
4257+
int SPAdjust = computeSPAdjust4SpillFPBP(MF, RC, RegNum);
4258+
if (SPAdjust)
4259+
emitSPUpdate(*MBB, Pos, DL, SPAdjust, false);
4260+
4261+
// Restore BP.
4262+
if (SpillBP) {
4263+
BuildMI(*MBB, Pos, DL,
4264+
TII.get(getPOPOpcode(MF.getSubtarget<X86Subtarget>())), BP);
4265+
}
4266+
4267+
// Restore FP.
4268+
if (SpillFP) {
4269+
BuildMI(*MBB, Pos, DL,
4270+
TII.get(getPOPOpcode(MF.getSubtarget<X86Subtarget>())), FP);
4271+
}
4272+
}
4273+
4274+
bool X86FrameLowering::skipSpillFPBP(
4275+
MachineFunction &MF, MachineBasicBlock::reverse_iterator &MI) const {
4276+
if (MI->getOpcode() == X86::LCMPXCHG16B_SAVE_RBX) {
4277+
// The pseudo instruction LCMPXCHG16B_SAVE_RBX is generated in the form
4278+
// SaveRbx = COPY RBX
4279+
// SaveRbx = LCMPXCHG16B_SAVE_RBX ..., SaveRbx, implicit-def rbx
4280+
// And later LCMPXCHG16B_SAVE_RBX is expanded to restore RBX from SaveRbx.
4281+
// We should skip this instruction sequence.
4282+
int FI;
4283+
unsigned Reg;
4284+
while (!(MI->getOpcode() == TargetOpcode::COPY &&
4285+
MI->getOperand(1).getReg() == X86::RBX) &&
4286+
!((Reg = TII.isStoreToStackSlot(*MI, FI)) && Reg == X86::RBX))
4287+
++MI;
4288+
return true;
4289+
}
4290+
return false;
4291+
}

llvm/lib/Target/X86/X86FrameLowering.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,20 @@ class X86FrameLowering : public TargetFrameLowering {
103103
MutableArrayRef<CalleeSavedInfo> CSI,
104104
const TargetRegisterInfo *TRI) const override;
105105

106+
void
107+
spillFPBPUsingSP(MachineFunction &MF,
108+
const MachineBasicBlock::iterator BeforeMI,
109+
bool SpillFP, bool SpillBP) const override;
110+
111+
void
112+
restoreFPBPUsingSP(MachineFunction &MF,
113+
const MachineBasicBlock::iterator AfterMI,
114+
bool SpillFP, bool SpillBP) const override;
115+
116+
bool
117+
skipSpillFPBP(MachineFunction &MF,
118+
MachineBasicBlock::reverse_iterator &MI) const override;
119+
106120
bool hasFP(const MachineFunction &MF) const override;
107121
bool hasReservedCallFrame(const MachineFunction &MF) const override;
108122
bool canSimplifyCallFramePseudos(const MachineFunction &MF) const override;

llvm/lib/Target/X86/X86RegisterInfo.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,9 @@ class X86RegisterInfo final : public X86GenRegisterInfo {
133133
void adjustStackMapLiveOutMask(uint32_t *Mask) const override;
134134

135135
bool hasBasePointer(const MachineFunction &MF) const;
136+
bool hasBaseRegister(const MachineFunction &MF) const override {
137+
return hasBasePointer(MF);
138+
}
136139

137140
bool canRealignStack(const MachineFunction &MF) const override;
138141

@@ -164,6 +167,9 @@ class X86RegisterInfo final : public X86GenRegisterInfo {
164167
unsigned getPtrSizedStackRegister(const MachineFunction &MF) const;
165168
Register getStackRegister() const { return StackPtr; }
166169
Register getBaseRegister() const { return BasePtr; }
170+
Register getBaseRegister(const MachineFunction &MF) const override {
171+
return BasePtr;
172+
}
167173
/// Returns physical register used as frame pointer.
168174
/// This will always returns the frame pointer register, contrary to
169175
/// getFrameRegister() which returns the "base pointer" in situations

0 commit comments

Comments
 (0)