Skip to content

Commit

Permalink
Spill/restore FP/BP around instructions in which they are clobbered (l…
Browse files Browse the repository at this point in the history
…lvm#81048)

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.
  • Loading branch information
weiguozhi authored and kstoimenov committed Aug 15, 2024
1 parent 7202bf6 commit 0ed0238
Show file tree
Hide file tree
Showing 17 changed files with 783 additions and 6 deletions.
4 changes: 4 additions & 0 deletions llvm/include/llvm/CodeGen/TargetFrameLowering.h
Original file line number Diff line number Diff line change
Expand Up @@ -475,6 +475,10 @@ class TargetFrameLowering {
/// debug info.
virtual DwarfFrameBase getDwarfFrameBase(const MachineFunction &MF) const;

/// If frame pointer or base pointer is clobbered by an instruction, we should
/// spill/restore it around that instruction.
virtual void spillFPBP(MachineFunction &MF) const {}

/// This method is called at the end of prolog/epilog code insertion, so
/// targets can emit remarks based on the final frame layout.
virtual void emitRemarks(const MachineFunction &MF,
Expand Down
33 changes: 27 additions & 6 deletions llvm/lib/CodeGen/CFIInstrInserter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "llvm/CodeGen/TargetInstrInfo.h"
#include "llvm/CodeGen/TargetSubtargetInfo.h"
#include "llvm/InitializePasses.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCDwarf.h"
using namespace llvm;

Expand Down Expand Up @@ -184,6 +185,10 @@ void CFIInstrInserter::calculateOutgoingCFAInfo(MBBCFAInfo &MBBInfo) {
unsigned NumRegs = TRI.getNumSupportedRegs(*MF);
BitVector CSRSaved(NumRegs), CSRRestored(NumRegs);

#ifndef NDEBUG
int RememberState = 0;
#endif

// Determine cfa offset and register set by the block.
for (MachineInstr &MI : *MBBInfo.MBB) {
if (MI.isCFIInstruction()) {
Expand Down Expand Up @@ -228,17 +233,25 @@ void CFIInstrInserter::calculateOutgoingCFAInfo(MBBCFAInfo &MBBInfo) {
case MCCFIInstruction::OpRememberState:
// TODO: Add support for handling cfi_remember_state.
#ifndef NDEBUG
report_fatal_error(
"Support for cfi_remember_state not implemented! Value of CFA "
"may be incorrect!\n");
// Currently we need cfi_remember_state and cfi_restore_state to be in
// the same BB, so it will not impact outgoing CFA.
++RememberState;
if (RememberState != 1)
MF->getContext().reportError(
SMLoc(),
"Support for cfi_remember_state not implemented! Value of CFA "
"may be incorrect!\n");
#endif
break;
case MCCFIInstruction::OpRestoreState:
// TODO: Add support for handling cfi_restore_state.
#ifndef NDEBUG
report_fatal_error(
"Support for cfi_restore_state not implemented! Value of CFA may "
"be incorrect!\n");
--RememberState;
if (RememberState != 0)
MF->getContext().reportError(
SMLoc(),
"Support for cfi_restore_state not implemented! Value of CFA may "
"be incorrect!\n");
#endif
break;
// Other CFI directives do not affect CFA value.
Expand All @@ -264,6 +277,14 @@ void CFIInstrInserter::calculateOutgoingCFAInfo(MBBCFAInfo &MBBInfo) {
}
}

#ifndef NDEBUG
if (RememberState != 0)
MF->getContext().reportError(
SMLoc(),
"Support for cfi_remember_state not implemented! Value of CFA may be "
"incorrect!\n");
#endif

MBBInfo.Processed = true;

// Update outgoing CFA info.
Expand Down
5 changes: 5 additions & 0 deletions llvm/lib/CodeGen/PrologEpilogInserter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,11 @@ bool PEI::runOnMachineFunction(MachineFunction &MF) {
FrameIndexVirtualScavenging = TRI->requiresFrameIndexScavenging(MF);
ORE = &getAnalysis<MachineOptimizationRemarkEmitterPass>().getORE();

// Spill frame pointer and/or base pointer registers if they are clobbered.
// It is placed before call frame instruction elimination so it will not mess
// with stack arguments.
TFI->spillFPBP(MF);

// Calculate the MaxCallFrameSize value for the function's frame
// information. Also eliminates call frame pseudo instructions.
calculateCallFrameInfo(MF);
Expand Down
Loading

0 comments on commit 0ed0238

Please sign in to comment.