[llvm] Spill/restore FP/BP around instructions in which they are clobbered (PR #81048)
via llvm-commits
llvm-commits at lists.llvm.org
Mon May 20 04:01:03 PDT 2024
================
@@ -1587,3 +1600,115 @@ void PEI::replaceFrameIndices(MachineBasicBlock *BB, MachineFunction &MF,
++I;
}
}
+
+static bool accessFrameBasePointer(const MachineInstr &MI, Register FP,
+ Register BP, bool &AccessFP, bool &AccessBP,
+ const TargetRegisterInfo *TRI) {
+ AccessFP = AccessBP = false;
+ if (FP) {
+ if (MI.findRegisterUseOperandIdx(FP, TRI, false) != -1 ||
+ MI.findRegisterDefOperandIdx(FP, TRI, false, true) != -1)
+ AccessFP = true;
+ }
+ if (BP) {
+ if (MI.findRegisterUseOperandIdx(BP, TRI, false) != -1 ||
+ MI.findRegisterDefOperandIdx(BP, TRI, false, true) != -1)
+ AccessBP = true;
+ }
+ return AccessFP || AccessBP;
+}
+
+/// If a function uses base pointer and the base pointer is clobbered by inline
+/// asm, RA doesn't detect this case, and after the inline asm, the base pointer
+/// cotains garbage value.
+/// For example if a 32b x86 function uses base pointer esi, and esi is
+/// clobbered by following inline asm
+/// asm("rep movsb" : "+D"(ptr), "+S"(x), "+c"(c)::"memory");
+/// We need to save esi before the asm and restore it after the asm.
+///
+/// The problem can also occur to frame pointer if there is a function call, and
+/// the callee uses a different calling convention and clobbers the fp.
+///
+/// Because normal frame objects (spill slots) are accessed through fp/bp
+/// register, so we can't spill fp/bp to normal spill slots.
+///
+/// FIXME: There are 2 possible enhancements:
+/// 1. In many cases there are different physical registers not clobbered by
+/// inline asm, we can use one of them as base pointer. Or use a virtual
+/// register as base pointer and let RA allocate a physical register to it.
+/// 2. If there is no other instructions access stack with fp/bp from the
+/// inline asm to the epilog, we can skip the save and restore operations.
+void PEI::spillFrameBasePointer(MachineFunction &MF) {
+ Register FP, BP;
+ const TargetFrameLowering &TFI = *MF.getSubtarget().getFrameLowering();
+ const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo();
+ if (TFI.hasFP(MF) && SpillClobberedFP)
+ FP = TRI->getFrameRegister(MF);
+ if (TRI->hasBaseRegister(MF) && SpillClobberedBP)
+ BP = TRI->getBaseRegister(MF);
+
+ for (MachineBasicBlock &MBB : MF) {
+ auto MI = MBB.rbegin(), ME = MBB.rend();
+ while (MI != ME) {
+ // Skip frame setup/destroy instructions.
+ // Skip instructions handled by target.
+ if (MI->getFlag(MachineInstr::MIFlag::FrameSetup) ||
+ MI->getFlag(MachineInstr::MIFlag::FrameDestroy) ||
+ TFI.skipSpillFPBP(MF, MI)) {
+ ++MI;
+ continue;
+ }
+
+ bool AccessFP, AccessBP;
+ // Check if fp or bp is used in MI.
+ if (!accessFrameBasePointer(*MI, FP, BP, AccessFP, AccessBP, TRI)) {
+ ++MI;
+ continue;
+ }
+
+ // Look for the range [Start, Stop] in which fp or bp is defined and used.
+ bool FPLive = false, BPLive = false;
+ bool SpillFP = false, SpillBP = false;
+ auto Start = MI, Stop = MI;
+ do {
+ SpillFP |= AccessFP;
+ SpillBP |= AccessBP;
+
+ // Maintain FPLive and BPLive.
+ if (FPLive && MI->findRegisterDefOperandIdx(FP, TRI, false, true) != -1)
+ FPLive = false;
+ if (FP && MI->findRegisterUseOperandIdx(FP, TRI, false) != -1)
+ FPLive = true;
+ if (BPLive && MI->findRegisterDefOperandIdx(BP, TRI, false, true) != -1)
+ BPLive = false;
+ if (BP && MI->findRegisterUseOperandIdx(BP, TRI, false) != -1)
+ BPLive = true;
+
+ Start = MI++;
+ } while ((MI != ME) &&
+ (FPLive || BPLive ||
+ accessFrameBasePointer(*MI, FP, BP, AccessFP, AccessBP, TRI)));
+
+ // If the bp is clobbered by a call, we should save and restore outside of
+ // the frame setup instructions.
+ if (Stop->isCall()) {
+ const TargetInstrInfo &TII = *MF.getSubtarget().getInstrInfo();
+ auto FrameSetup = std::next(Start);
+ while (FrameSetup != ME && !TII.isFrameSetup(*FrameSetup) &&
----------------
zmodem wrote:
Hmm, this is hard to follow. Maybe some comments would help. We're walking backwards from the instruction before Start towards the start of the BB, looking for the first frame setup or call instruction? And then we go to the instruction before that?
https://github.com/llvm/llvm-project/pull/81048
More information about the llvm-commits
mailing list