From 7017717259d8f504a6de59b31d86492650aa988d Mon Sep 17 00:00:00 2001 From: Guozhi Wei Date: Mon, 6 May 2024 13:48:07 -0700 Subject: [PATCH] Add unwinding information when FP is changed. --- llvm/lib/CodeGen/CFIInstrInserter.cpp | 29 ++++++++--- llvm/lib/CodeGen/PrologEpilogInserter.cpp | 35 +++++++------- llvm/lib/Target/X86/X86FrameLowering.cpp | 56 +++++++++++++++++++--- llvm/lib/Target/X86/X86FrameLowering.h | 19 ++++---- llvm/test/CodeGen/X86/clobber_frame_ptr.ll | 3 ++ 5 files changed, 102 insertions(+), 40 deletions(-) diff --git a/llvm/lib/CodeGen/CFIInstrInserter.cpp b/llvm/lib/CodeGen/CFIInstrInserter.cpp index 87b062a16df1d2b..bdea542acfd6536 100644 --- a/llvm/lib/CodeGen/CFIInstrInserter.cpp +++ b/llvm/lib/CodeGen/CFIInstrInserter.cpp @@ -184,6 +184,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()) { @@ -228,17 +232,23 @@ 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) + report_fatal_error( + "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) + report_fatal_error( + "Support for cfi_restore_state not implemented! Value of CFA may " + "be incorrect!\n"); #endif break; // Other CFI directives do not affect CFA value. @@ -263,6 +273,13 @@ void CFIInstrInserter::calculateOutgoingCFAInfo(MBBCFAInfo &MBBInfo) { } } +#ifndef NDEBUG + if (RememberState != 0) + report_fatal_error( + "Support for cfi_remember_state not implemented! Value of CFA " + "may be incorrect!\n"); +#endif + MBBInfo.Processed = true; // Update outgoing CFA info. diff --git a/llvm/lib/CodeGen/PrologEpilogInserter.cpp b/llvm/lib/CodeGen/PrologEpilogInserter.cpp index 040a3f4f9518630..7ff30a9b335e0ff 100644 --- a/llvm/lib/CodeGen/PrologEpilogInserter.cpp +++ b/llvm/lib/CodeGen/PrologEpilogInserter.cpp @@ -77,15 +77,15 @@ using MBBVector = SmallVector; STATISTIC(NumLeafFuncWithSpills, "Number of leaf functions with CSRs"); STATISTIC(NumFuncSeen, "Number of functions seen in PEI"); -static cl::opt SpillClobberedFP( - "spill-clobbered-fp", - cl::desc("Spill clobbered fp register to stack."), - cl::init(false), cl::Hidden); +static cl::opt + SpillClobberedFP("spill-clobbered-fp", + cl::desc("Spill clobbered fp register to stack."), + cl::init(false), cl::Hidden); -static cl::opt SpillClobberedBP( - "spill-clobbered-bp", - cl::desc("Spill clobbered bp register to stack."), - cl::init(true), cl::Hidden); +static cl::opt + SpillClobberedBP("spill-clobbered-bp", + cl::desc("Spill clobbered bp register to stack."), + cl::init(true), cl::Hidden); namespace { @@ -1606,13 +1606,13 @@ static bool accessFrameBasePointer(const MachineInstr &MI, Register FP, const TargetRegisterInfo *TRI) { AccessFP = AccessBP = false; if (FP) { - if (MI.findRegisterUseOperandIdx(FP, false, TRI) != -1 || - MI.findRegisterDefOperandIdx(FP, false, true, TRI) != -1) + if (MI.findRegisterUseOperandIdx(FP, TRI, false) != -1 || + MI.findRegisterDefOperandIdx(FP, TRI, false, true) != -1) AccessFP = true; } if (BP) { - if (MI.findRegisterUseOperandIdx(BP, false, TRI) != -1 || - MI.findRegisterDefOperandIdx(BP, false, true, TRI) != -1) + if (MI.findRegisterUseOperandIdx(BP, TRI, false) != -1 || + MI.findRegisterDefOperandIdx(BP, TRI, false, true) != -1) AccessBP = true; } return AccessFP || AccessBP; @@ -1675,17 +1675,18 @@ void PEI::spillFrameBasePointer(MachineFunction &MF) { SpillBP |= AccessBP; // Maintain FPLive and BPLive. - if (FPLive && MI->findRegisterDefOperandIdx(FP, false, true, TRI) != -1) + if (FPLive && MI->findRegisterDefOperandIdx(FP, TRI, false, true) != -1) FPLive = false; - if (FP && MI->findRegisterUseOperandIdx(FP, false, TRI) != -1) + if (FP && MI->findRegisterUseOperandIdx(FP, TRI, false) != -1) FPLive = true; - if (BPLive && MI->findRegisterDefOperandIdx(BP, false, true, TRI) != -1) + if (BPLive && MI->findRegisterDefOperandIdx(BP, TRI, false, true) != -1) BPLive = false; - if (BP && MI->findRegisterUseOperandIdx(BP, false, TRI) != -1) + if (BP && MI->findRegisterUseOperandIdx(BP, TRI, false) != -1) BPLive = true; Start = MI++; - } while ((MI != ME) && (FPLive || BPLive || + } 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 diff --git a/llvm/lib/Target/X86/X86FrameLowering.cpp b/llvm/lib/Target/X86/X86FrameLowering.cpp index 1fe874623bede64..c2132c48983f9ad 100644 --- a/llvm/lib/Target/X86/X86FrameLowering.cpp +++ b/llvm/lib/Target/X86/X86FrameLowering.cpp @@ -4189,9 +4189,9 @@ static int computeSPAdjust4SpillFPBP(MachineFunction &MF, return AlignedSize - AllocSize; } -void X86FrameLowering::spillFPBPUsingSP( - MachineFunction &MF, MachineBasicBlock::iterator BeforeMI, - bool SpillFP, bool SpillBP) const { +void X86FrameLowering::spillFPBPUsingSP(MachineFunction &MF, + MachineBasicBlock::iterator BeforeMI, + bool SpillFP, bool SpillBP) const { const TargetRegisterClass *RC; unsigned RegNum = 0; MachineBasicBlock *MBB = BeforeMI->getParent(); @@ -4227,11 +4227,46 @@ void X86FrameLowering::spillFPBPUsingSP( int SPAdjust = computeSPAdjust4SpillFPBP(MF, RC, RegNum); if (SPAdjust) emitSPUpdate(*MBB, BeforeMI, DL, -SPAdjust, false); + + // Emit unwinding information. + if (SpillFP && needsDwarfCFI(MF)) { + // Emit .cfi_remember_state to remember old frame. + unsigned CFIIndex = + MF.addFrameInst(MCCFIInstruction::createRememberState(nullptr)); + BuildMI(*MBB, BeforeMI, DL, TII.get(TargetOpcode::CFI_INSTRUCTION)) + .addCFIIndex(CFIIndex); + + // Setup new CFA value with DW_CFA_def_cfa_expression: + // DW_OP_breg7+offset, DW_OP_deref, DW_OP_consts 16, DW_OP_plus + SmallString<64> CfaExpr; + uint8_t buffer[16]; + int Offset = SPAdjust; + if (SpillBP) + Offset += TRI->getSpillSize(*RC); + Register StackPtr = TRI->getStackRegister(); + if (STI.isTarget64BitILP32()) + StackPtr = Register(getX86SubSuperRegister(StackPtr, 64)); + unsigned DwarfStackPtr = TRI->getDwarfRegNum(StackPtr, true); + CfaExpr.push_back((uint8_t)(dwarf::DW_OP_breg0 + DwarfStackPtr)); + CfaExpr.append(buffer, buffer + encodeSLEB128(Offset, buffer)); + CfaExpr.push_back(dwarf::DW_OP_deref); + CfaExpr.push_back(dwarf::DW_OP_consts); + CfaExpr.append(buffer, buffer + encodeSLEB128(SlotSize * 2, buffer)); + CfaExpr.push_back((uint8_t)dwarf::DW_OP_plus); + + SmallString<64> DefCfaExpr; + DefCfaExpr.push_back(dwarf::DW_CFA_def_cfa_expression); + DefCfaExpr.append(buffer, buffer + encodeSLEB128(CfaExpr.size(), buffer)); + DefCfaExpr.append(CfaExpr.str()); + BuildCFI(*MBB, BeforeMI, DL, + MCCFIInstruction::createEscape(nullptr, DefCfaExpr.str()), + MachineInstr::FrameSetup); + } } -void X86FrameLowering::restoreFPBPUsingSP( - MachineFunction &MF, MachineBasicBlock::iterator AfterMI, - bool SpillFP, bool SpillBP) const { +void X86FrameLowering::restoreFPBPUsingSP(MachineFunction &MF, + MachineBasicBlock::iterator AfterMI, + bool SpillFP, bool SpillBP) const { Register FP, BP; const TargetRegisterClass *RC; unsigned RegNum = 0; @@ -4268,6 +4303,15 @@ void X86FrameLowering::restoreFPBPUsingSP( if (SpillFP) { BuildMI(*MBB, Pos, DL, TII.get(getPOPOpcode(MF.getSubtarget())), FP); + + // Emit unwinding information. + if (needsDwarfCFI(MF)) { + // Restore original frame with .cfi_restore_state. + unsigned CFIIndex = + MF.addFrameInst(MCCFIInstruction::createRestoreState(nullptr)); + BuildMI(*MBB, Pos, DL, TII.get(TargetOpcode::CFI_INSTRUCTION)) + .addCFIIndex(CFIIndex); + } } } diff --git a/llvm/lib/Target/X86/X86FrameLowering.h b/llvm/lib/Target/X86/X86FrameLowering.h index 0d77933363ce4f5..0c83fa43f265df9 100644 --- a/llvm/lib/Target/X86/X86FrameLowering.h +++ b/llvm/lib/Target/X86/X86FrameLowering.h @@ -103,19 +103,16 @@ class X86FrameLowering : public TargetFrameLowering { MutableArrayRef CSI, const TargetRegisterInfo *TRI) const override; - void - spillFPBPUsingSP(MachineFunction &MF, - const MachineBasicBlock::iterator BeforeMI, - bool SpillFP, bool SpillBP) const override; + void spillFPBPUsingSP(MachineFunction &MF, + const MachineBasicBlock::iterator BeforeMI, + bool SpillFP, bool SpillBP) const override; - void - restoreFPBPUsingSP(MachineFunction &MF, - const MachineBasicBlock::iterator AfterMI, - bool SpillFP, bool SpillBP) const override; + void restoreFPBPUsingSP(MachineFunction &MF, + const MachineBasicBlock::iterator AfterMI, + bool SpillFP, bool SpillBP) const override; - bool - skipSpillFPBP(MachineFunction &MF, - MachineBasicBlock::reverse_iterator &MI) const override; + bool skipSpillFPBP(MachineFunction &MF, + MachineBasicBlock::reverse_iterator &MI) const override; bool hasFP(const MachineFunction &MF) const override; bool hasReservedCallFrame(const MachineFunction &MF) const override; diff --git a/llvm/test/CodeGen/X86/clobber_frame_ptr.ll b/llvm/test/CodeGen/X86/clobber_frame_ptr.ll index 591676bf3f15cd8..81403e5a64549bd 100644 --- a/llvm/test/CodeGen/X86/clobber_frame_ptr.ll +++ b/llvm/test/CodeGen/X86/clobber_frame_ptr.ll @@ -30,11 +30,14 @@ define i32 @foo(i32 %0, i32 %1) { ; CHECK-NEXT: # kill: def $edi killed $edi def $rdi ; CHECK-NEXT: pushq %rbp ; CHECK-NEXT: pushq %rax +; CHECK-NEXT: .cfi_remember_state +; CHECK-NEXT: .cfi_escape 0x0f, 0x06, 0x77, 0x08, 0x06, 0x11, 0x10, 0x22 # ; CHECK-NEXT: movl %esi, %ebp ; CHECK-NEXT: movq %rdi, %r13 ; CHECK-NEXT: callq external@PLT ; CHECK-NEXT: addq $8, %rsp ; CHECK-NEXT: popq %rbp +; CHECK-NEXT: .cfi_restore_state ; CHECK-NEXT: leaq -40(%rbp), %rsp ; CHECK-NEXT: popq %rbx ; CHECK-NEXT: popq %r12