diff --git a/llvm/include/llvm/CodeGen/TargetFrameLowering.h b/llvm/include/llvm/CodeGen/TargetFrameLowering.h --- a/llvm/include/llvm/CodeGen/TargetFrameLowering.h +++ b/llvm/include/llvm/CodeGen/TargetFrameLowering.h @@ -202,6 +202,17 @@ virtual void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const = 0; + /// With basic block sections, emit callee saved frame moves for basic blocks + /// that are in a different section. + virtual void + emitCalleeSavedFrameMoves(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI) const {} + + virtual void emitCalleeSavedFrameMoves(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + const DebugLoc &DL, + bool IsPrologue) const {} + /// Replace a StackProbe stub (if any) with the actual probe code inline virtual void inlineStackProbe(MachineFunction &MF, MachineBasicBlock &PrologueMBB) const {} diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -3067,18 +3067,30 @@ if (isVerbose() && MBB.hasLabelMustBeEmitted()) { OutStreamer->AddComment("Label of block must be emitted"); } + auto *BBSymbol = MBB.getSymbol(); // Switch to a new section if this basic block must begin a section. if (MBB.isBeginSection()) { OutStreamer->SwitchSection( getObjFileLowering().getSectionForMachineBasicBlock(MF->getFunction(), MBB, TM)); - CurrentSectionBeginSym = MBB.getSymbol(); + CurrentSectionBeginSym = BBSymbol; } - OutStreamer->emitLabel(MBB.getSymbol()); + OutStreamer->emitLabel(BBSymbol); + // With BB sections, each basic block must handle CFI information on its own + // if it begins a section. + if (MBB.isBeginSection()) + for (const HandlerInfo &HI : Handlers) + HI.Handler->beginBasicBlock(MBB); } } -void AsmPrinter::emitBasicBlockEnd(const MachineBasicBlock &MBB) {} +void AsmPrinter::emitBasicBlockEnd(const MachineBasicBlock &MBB) { + // Check if CFI information needs to be updated for this MBB with basic block + // sections. + if (MBB.isEndSection()) + for (const HandlerInfo &HI : Handlers) + HI.Handler->endBasicBlock(MBB); +} void AsmPrinter::emitVisibility(MCSymbol *Sym, unsigned Visibility, bool IsDefinition) const { diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfCFIException.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfCFIException.cpp --- a/llvm/lib/CodeGen/AsmPrinter/DwarfCFIException.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfCFIException.cpp @@ -47,7 +47,7 @@ } void DwarfCFIExceptionBase::endFragment() { - if (shouldEmitCFI) + if (shouldEmitCFI && !Asm->MF->hasBBSections()) Asm->OutStreamer->emitCFIEndProc(); } @@ -172,3 +172,12 @@ emitExceptionTable(); } + +void DwarfCFIException::beginBasicBlock(const MachineBasicBlock &MBB) { + beginFragment(&MBB, getExceptionSym); +} + +void DwarfCFIException::endBasicBlock(const MachineBasicBlock &MBB) { + if (shouldEmitCFI) + Asm->OutStreamer->emitCFIEndProc(); +} diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfException.h b/llvm/lib/CodeGen/AsmPrinter/DwarfException.h --- a/llvm/lib/CodeGen/AsmPrinter/DwarfException.h +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfException.h @@ -66,6 +66,9 @@ void beginFragment(const MachineBasicBlock *MBB, ExceptionSymbolProvider ESP) override; + + void beginBasicBlock(const MachineBasicBlock &MBB) override; + void endBasicBlock(const MachineBasicBlock &MBB) override; }; class LLVM_LIBRARY_VISIBILITY ARMException : public DwarfCFIExceptionBase { diff --git a/llvm/lib/CodeGen/CFIInstrInserter.cpp b/llvm/lib/CodeGen/CFIInstrInserter.cpp --- a/llvm/lib/CodeGen/CFIInstrInserter.cpp +++ b/llvm/lib/CodeGen/CFIInstrInserter.cpp @@ -303,28 +303,31 @@ auto MBBI = MBBInfo.MBB->begin(); DebugLoc DL = MBBInfo.MBB->findDebugLoc(MBBI); - if (PrevMBBInfo->OutgoingCFAOffset != MBBInfo.IncomingCFAOffset) { + // If the current MBB will be placed in a unique section, a full DefCfa + // must be emitted. + const bool ForceFullCFA = MBB.isBeginSection(); + + if ((PrevMBBInfo->OutgoingCFAOffset != MBBInfo.IncomingCFAOffset && + PrevMBBInfo->OutgoingCFARegister != MBBInfo.IncomingCFARegister) || + ForceFullCFA) { // If both outgoing offset and register of a previous block don't match - // incoming offset and register of this block, add a def_cfa instruction - // with the correct offset and register for this block. - if (PrevMBBInfo->OutgoingCFARegister != MBBInfo.IncomingCFARegister) { - unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::cfiDefCfa( - nullptr, MBBInfo.IncomingCFARegister, getCorrectCFAOffset(&MBB))); - BuildMI(*MBBInfo.MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) - .addCFIIndex(CFIIndex); - // If outgoing offset of a previous block doesn't match incoming offset - // of this block, add a def_cfa_offset instruction with the correct - // offset for this block. - } else { - unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::cfiDefCfaOffset( - nullptr, getCorrectCFAOffset(&MBB))); - BuildMI(*MBBInfo.MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) - .addCFIIndex(CFIIndex); - } + // incoming offset and register of this block, or if this block begins a + // section, add a def_cfa instruction with the correct offset and + // register for this block. + unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::cfiDefCfa( + nullptr, MBBInfo.IncomingCFARegister, getCorrectCFAOffset(&MBB))); + BuildMI(*MBBInfo.MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) + .addCFIIndex(CFIIndex); + InsertedCFIInstr = true; + } else if (PrevMBBInfo->OutgoingCFAOffset != MBBInfo.IncomingCFAOffset) { + // If outgoing offset of a previous block doesn't match incoming offset + // of this block, add a def_cfa_offset instruction with the correct + // offset for this block. + unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::cfiDefCfaOffset( + nullptr, getCorrectCFAOffset(&MBB))); + BuildMI(*MBBInfo.MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) + .addCFIIndex(CFIIndex); InsertedCFIInstr = true; - // If outgoing register of a previous block doesn't match incoming - // register of this block, add a def_cfa_register instruction with the - // correct register for this block. } else if (PrevMBBInfo->OutgoingCFARegister != MBBInfo.IncomingCFARegister) { unsigned CFIIndex = @@ -335,6 +338,14 @@ InsertedCFIInstr = true; } + if (ForceFullCFA) { + MF.getSubtarget().getFrameLowering()->emitCalleeSavedFrameMoves( + *MBBInfo.MBB, MBBI); + InsertedCFIInstr = true; + PrevMBBInfo = &MBBInfo; + continue; + } + BitVector SetDifference = PrevMBBInfo->OutgoingCSRSaved; SetDifference.reset(MBBInfo.IncomingCSRSaved); for (int Reg : SetDifference.set_bits()) { diff --git a/llvm/lib/Target/AArch64/AArch64FrameLowering.h b/llvm/lib/Target/AArch64/AArch64FrameLowering.h --- a/llvm/lib/Target/AArch64/AArch64FrameLowering.h +++ b/llvm/lib/Target/AArch64/AArch64FrameLowering.h @@ -24,8 +24,9 @@ : TargetFrameLowering(StackGrowsDown, Align(16), 0, Align(16), true /*StackRealignable*/) {} - void emitCalleeSavedFrameMoves(MachineBasicBlock &MBB, - MachineBasicBlock::iterator MBBI) const; + void + emitCalleeSavedFrameMoves(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI) const override; MachineBasicBlock::iterator eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB, diff --git a/llvm/lib/Target/X86/X86FrameLowering.h b/llvm/lib/Target/X86/X86FrameLowering.h --- a/llvm/lib/Target/X86/X86FrameLowering.h +++ b/llvm/lib/Target/X86/X86FrameLowering.h @@ -58,9 +58,14 @@ void inlineStackProbe(MachineFunction &MF, MachineBasicBlock &PrologMBB) const override; + void + emitCalleeSavedFrameMoves(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI) const override; + void emitCalleeSavedFrameMoves(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, - const DebugLoc &DL, bool IsPrologue) const; + const DebugLoc &DL, + bool IsPrologue) const override; /// emitProlog/emitEpilog - These methods insert prolog and epilog code into /// the function. diff --git a/llvm/lib/Target/X86/X86FrameLowering.cpp b/llvm/lib/Target/X86/X86FrameLowering.cpp --- a/llvm/lib/Target/X86/X86FrameLowering.cpp +++ b/llvm/lib/Target/X86/X86FrameLowering.cpp @@ -479,6 +479,29 @@ .addCFIIndex(CFIIndex); } +/// Emits Dwarf Info specifying offsets of callee saved registers and +/// frame pointer. This is called only when basic block sections are enabled. +void X86FrameLowering::emitCalleeSavedFrameMoves( + MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI) const { + MachineFunction &MF = *MBB.getParent(); + if (!hasFP(MF)) { + emitCalleeSavedFrameMoves(MBB, MBBI, DebugLoc{}, true); + return; + } + const MachineModuleInfo &MMI = MF.getMMI(); + const MCRegisterInfo *MRI = MMI.getContext().getRegisterInfo(); + const unsigned FramePtr = TRI->getFrameRegister(MF); + const unsigned MachineFramePtr = + STI.isTarget64BitILP32() ? unsigned(getX86SubSuperRegister(FramePtr, 64)) + : FramePtr; + unsigned DwarfReg = MRI->getDwarfRegNum(MachineFramePtr, true); + // Offset = space for return address + size of the frame pointer itself. + unsigned Offset = (Is64Bit ? 8 : 4) + (Uses64BitFramePtr ? 8 : 4); + BuildCFI(MBB, MBBI, DebugLoc{}, + MCCFIInstruction::createOffset(nullptr, DwarfReg, -Offset)); + emitCalleeSavedFrameMoves(MBB, MBBI, DebugLoc{}, true); +} + void X86FrameLowering::emitCalleeSavedFrameMoves( MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, const DebugLoc &DL, bool IsPrologue) const { diff --git a/llvm/test/CodeGen/X86/cfi-basic-block-sections-1.ll b/llvm/test/CodeGen/X86/cfi-basic-block-sections-1.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/X86/cfi-basic-block-sections-1.ll @@ -0,0 +1,86 @@ +; RUN: llc -O0 %s --basicblock-sections=all -mtriple=x86_64 -filetype=asm --frame-pointer=all -o - | FileCheck --check-prefix=SECTIONS_CFI %s +; RUN: llc -O0 %s --basicblock-sections=all -mtriple=x86_64 -filetype=asm --frame-pointer=none -o - | FileCheck --check-prefix=SECTIONS_NOFP_CFI %s +; RUN: llc -O0 %s --basicblock-sections=all -mtriple=x86_64 -filetype=obj --frame-pointer=all -o - | llvm-dwarfdump --eh-frame - | FileCheck --check-prefix=EH_FRAME %s + +;; void f1(); +;; void f3(bool b) { +;; if (b) +;; f1(); +;; } + + +; SECTIONS_CFI: _Z2f3b: +; SECTIONS_CFI: .cfi_startproc +; SECTIONS_CFI: .cfi_def_cfa_offset 16 +; SECTIONS_CFI: .cfi_offset %rbp, -16 +; SECTIONS_CFI: .cfi_def_cfa_register %rbp +; SECTIONS_CFI: .cfi_endproc + +; SECTIONS_CFI: _Z2f3b.1: +; SECTIONS_CFI-NEXT: .cfi_startproc +; SECTIONS_CFI-NEXT: .cfi_def_cfa %rbp, 16 +; SECTIONS_CFI-NEXT: .cfi_offset %rbp, -16 +; SECTIONS_CFI: .cfi_endproc + +; SECTIONS_CFI: _Z2f3b.2: +; SECTIONS_CFI-NEXT: .cfi_startproc +; SECTIONS_CFI-NEXT: .cfi_def_cfa %rbp, 16 +; SECTIONS_CFI-NEXT: .cfi_offset %rbp, -16 +; SECTIONS_CFI: .cfi_def_cfa +; SECTIONS_CFI: .cfi_endproc + + +; SECTIONS_NOFP_CFI: _Z2f3b: +; SECTIONS_NOFP_CFI: .cfi_startproc +; SECTIONS_NOFP_CFI: .cfi_def_cfa_offset 16 +; SECTIONS_NOFP_CFI: .cfi_endproc + +; SECTIONS_NOFP_CFI: _Z2f3b.1: +; SECTIONS_NOFP_CFI-NEXT: .cfi_startproc +; SECTIONS_NOFP_CFI-NEXT: .cfi_def_cfa %rsp, 16 +; SECTIONS_NOFP_CFI: .cfi_endproc + +; SECTIONS_NOFP_CFI: _Z2f3b.2: +; SECTIONS_NOFP_CFI-NEXT: .cfi_startproc +; SECTIONS_NOFP_CFI-NEXT: .cfi_def_cfa %rsp, 16 +; SECTIONS_NOFP_CFI: .cfi_endproc + + +;; There must be 1 CIE and 3 FDEs. + +; EH_FRAME: CIE +; EH_FRAME: DW_CFA_def_cfa +; EH_FRAME: DW_CFA_offset + +; EH_FRAME: FDE cie= +; EH_FRAME: DW_CFA_def_cfa_offset +; EH_FRAME: DW_CFA_offset +; EH_FRAME: DW_CFA_def_cfa_register + +; EH_FRAME: FDE cie= +; EH_FRAME: DW_CFA_def_cfa +; EH_FRAME: DW_CFA_offset + +; EH_FRAME: FDE cie= +; EH_FRAME: DW_CFA_def_cfa +; EH_FRAME: DW_CFA_offset + +; Function Attrs: noinline optnone uwtable +define dso_local void @_Z2f3b(i1 zeroext %b) { +entry: + %b.addr = alloca i8, align 1 + %frombool = zext i1 %b to i8 + store i8 %frombool, i8* %b.addr, align 1 + %0 = load i8, i8* %b.addr, align 1 + %tobool = trunc i8 %0 to i1 + br i1 %tobool, label %if.then, label %if.end + +if.then: ; preds = %entry + call void @_Z2f1v() + br label %if.end + +if.end: ; preds = %if.then, %entry + ret void +} + +declare dso_local void @_Z2f1v() diff --git a/llvm/test/CodeGen/X86/cfi-inserter-basic-block-sections-callee-save-registers.ll b/llvm/test/CodeGen/X86/cfi-inserter-basic-block-sections-callee-save-registers.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/X86/cfi-inserter-basic-block-sections-callee-save-registers.ll @@ -0,0 +1,53 @@ +;; This test checks if CFI instructions for all callee saved registers are emitted +;; correctly with basic block sections. +; RUN: llc %s -mtriple=x86_64 -filetype=asm --basicblock-sections=all --frame-pointer=all -o - | FileCheck --check-prefix=SECTIONS_CFI %s + +; SECTIONS_CFI: _Z3foob: +; SECTIONS_CFI: .cfi_offset %rbp, -16 +; SECTIONS_CFI: .cfi_offset [[RA:%r.+]], -56 +; SECTIONS_CFI-NEXT: .cfi_offset [[RB:%r.+]], -48 +; SECTIONS_CFI-NEXT: .cfi_offset [[RC:%r.+]], -40 +; SECTIONS_CFI-NEXT: .cfi_offset [[RD:%r.+]], -32 +; SECTIONS_CFI-NEXT: .cfi_offset [[RE:%r.+]], -24 + +; SECTIONS_CFI: _Z3foob.1: +; SECTIONS_CFI: .cfi_offset %rbp, -16 +; SECTIONS_CFI: .cfi_offset [[RA]], -56 +; SECTIONS_CFI-NEXT: .cfi_offset [[RB]], -48 +; SECTIONS_CFI-NEXT: .cfi_offset [[RC]], -40 +; SECTIONS_CFI-NEXT: .cfi_offset [[RD]], -32 +; SECTIONS_CFI-NEXT: .cfi_offset [[RE]], -24 + +; SECTIONS_CFI: _Z3foob.2: +; SECTIONS_CFI: .cfi_offset %rbp, -16 +; SECTIONS_CFI: .cfi_offset [[RA]], -56 +; SECTIONS_CFI-NEXT: .cfi_offset [[RB]], -48 +; SECTIONS_CFI-NEXT: .cfi_offset [[RC]], -40 +; SECTIONS_CFI-NEXT: .cfi_offset [[RD]], -32 +; SECTIONS_CFI-NEXT: .cfi_offset [[RE]], -24 + + +;; void foo(bool b) { +;; if (b) // adds a basic block +;; // clobber all callee-save registers to force them to be callee-saved and to +;; // be described by cfi_offset directives. +;; asm("nop" ::: "r12", "r13", "r14", "r15", "rbx"); +;; } + +define dso_local void @_Z3foob(i1 zeroext %b) { +entry: + %b.addr = alloca i8, align 1 + %frombool = zext i1 %b to i8 + store i8 %frombool, i8* %b.addr, align 1 + %0 = load i8, i8* %b.addr, align 1 + %tobool = trunc i8 %0 to i1 + br i1 %tobool, label %if.then, label %if.end + +if.then: ; preds = %entry + call void asm sideeffect "nop", "~{r12},~{r13},~{r14},~{r15},~{rbx},~{dirflag},~{fpsr},~{flags}"() #1, !srcloc !2 + br label %if.end + +if.end: ; preds = %if.then, %entry + ret void +} +!2 = !{i32 38}