Index: llvm/include/llvm/CodeGen/TargetFrameLowering.h =================================================================== --- llvm/include/llvm/CodeGen/TargetFrameLowering.h +++ 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 {} Index: llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp =================================================================== --- llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -3067,18 +3067,32 @@ 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 { Index: llvm/lib/CodeGen/AsmPrinter/DwarfCFIException.cpp =================================================================== --- llvm/lib/CodeGen/AsmPrinter/DwarfCFIException.cpp +++ 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(); +} Index: llvm/lib/CodeGen/AsmPrinter/DwarfException.h =================================================================== --- llvm/lib/CodeGen/AsmPrinter/DwarfException.h +++ 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 { Index: llvm/lib/CodeGen/CFIInstrInserter.cpp =================================================================== --- llvm/lib/CodeGen/CFIInstrInserter.cpp +++ 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()) { Index: llvm/lib/Target/AArch64/AArch64FrameLowering.h =================================================================== --- llvm/lib/Target/AArch64/AArch64FrameLowering.h +++ 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, Index: llvm/lib/Target/X86/X86FrameLowering.h =================================================================== --- llvm/lib/Target/X86/X86FrameLowering.h +++ 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. Index: llvm/lib/Target/X86/X86FrameLowering.cpp =================================================================== --- llvm/lib/Target/X86/X86FrameLowering.cpp +++ llvm/lib/Target/X86/X86FrameLowering.cpp @@ -479,6 +479,29 @@ .addCFIIndex(CFIIndex); } +/// Emits Dwarf Info specifying offsets of callee saved registers and +/// frame pointer. +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 { Index: llvm/test/DebugInfo/X86/basic-block-sections-cfi-1.ll =================================================================== --- /dev/null +++ llvm/test/DebugInfo/X86/basic-block-sections-cfi-1.ll @@ -0,0 +1,71 @@ +; RUN: llc -O0 %s --basicblock-sections=all -mtriple=x86_64-unknown-linux-gnu -filetype=asm -o - | FileCheck --check-prefix=SECTIONS_CFI %s +; RUN: llc -O0 %s --basicblock-sections=all -mtriple=x86_64-unknown-linux-gnu -filetype=obj -o - | llvm-dwarfdump --debug-frame - | FileCheck --check-prefix=DEBUG_FRAME %s + +; void f1(); +; void f3(bool b) { +; if (b) +; f1(); +; } + + +; SECTIONS_CFI: _Z2f3b +; SECTIONS_CFI: .cfi_startproc +; SECTIONS_CFI: .cfi_def_cfa_offset +; SECTIONS_CFI: .cfi_def_cfa_register +; SECTIONS_CFI: .cfi_endproc + +; SECTIONS_CFI: _Z2f3b.1 +; SECTIONS_CFI-NEXT: .cfi_startproc +; SECTIONS_CFI-NEXT: .cfi_def_cfa +; SECTIONS_CFI-NEXT: .cfi_offset +; SECTIONS_CFI: .cfi_endproc + +; SECTIONS_CFI: _Z2f3b.2 +; SECTIONS_CFI-NEXT: .cfi_startproc +; SECTIONS_CFI-NEXT: .cfi_def_cfa +; SECTIONS_CFI-NEXT: .cfi_offset +; SECTIONS_CFI: .cfi_def_cfa +; SECTIONS_CFI: .cfi_endproc + +; There must be 1 CIE and 3 FDEs + +; DEBUG_FRAME: .debug_frame contents + +; DEBUG_FRAME: CIE +; DEBUG_FRAME: DW_CFA_def_cfa +; DEBUG_FRAME: DW_CFA_offset + +; DEBUG_FRAME: FDE cie= +; DEBUG_FRAME: DW_CFA_def_cfa_offset +; DEBUG_FRAME: DW_CFA_offset +; DEBUG_FRAME: DW_CFA_def_cfa_register + +; DEBUG_FRAME: FDE cie= +; DEBUG_FRAME: DW_CFA_def_cfa +; DEBUG_FRAME: DW_CFA_offset + +; DEBUG_FRAME: FDE cie= +; DEBUG_FRAME: DW_CFA_def_cfa +; DEBUG_FRAME: DW_CFA_offset + +; Function Attrs: noinline optnone uwtable +define dso_local void @_Z2f3b(i1 zeroext %b) #0 { +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() + +attributes #0 = { "frame-pointer"="all" } Index: llvm/test/DebugInfo/X86/basic-block-sections-cfiinstr-1.ll =================================================================== --- /dev/null +++ llvm/test/DebugInfo/X86/basic-block-sections-cfiinstr-1.ll @@ -0,0 +1,51 @@ +; This test checks if CFI instructions for callee saved registers are emitted +; correctly with basic block sections. +; RUN: llc -O3 %s -mtriple=x86_64-unknown-linux-gnu -filetype=asm --basicblock-sections=all -stop-after=cfi-instr-inserter -o - | FileCheck --check-prefix=CFI_INSTR %s + +; CFI_INSTR: _Z3foobiiiiii +; CFI_INSTR: bb.0.entry: +; CFI_INSTR: CFI_INSTRUCTION offset +; CFI_INSTR-NEXT: CFI_INSTRUCTION offset +; CFI_INSTR-NEXT: CFI_INSTRUCTION offset +; CFI_INSTR: bb.1.if.then (bbsections 1): +; CFI_INSTR: CFI_INSTRUCTION def_cfa $rsp +; CFI_INSTR-NEXT: CFI_INSTRUCTION offset +; CFI_INSTR-NEXT: CFI_INSTRUCTION offset +; CFI_INSTR-NEXT: CFI_INSTRUCTION offset +; CFI_INSTR: bb.2.if.end (bbsections 2): +; CFI_INSTR: CFI_INSTRUCTION def_cfa $rsp +; CFI_INSTR-NEXT: CFI_INSTRUCTION offset +; CFI_INSTR-NEXT: CFI_INSTRUCTION offset +; CFI_INSTR-NEXT: CFI_INSTRUCTION offset + +; Exhaust caller-saved parameter registers and force callee saved registers to +; be used. This tests that CFI directives for callee saved registers are +; generated with basic block sections. +; extern void f1(int, int, int); +; +; void foo(bool k, int p1, int p2, int p3, int p4, int p5, int p6) { +; // Using a conditional forces a basic block section. +; if (k) { +; // p1, p3 and p5 will use the same parameter registers as p2, p4 and p6 +; // respectively in making the calls below. This forces the need to stash +; // some of these values (already in the parameter registers) in callee +; // saved registers. +; f1(p1, p3, p5); +; f1(p2, p4, p6); +; } +; } + +define dso_local void @_Z3foobiiiiii(i1 zeroext %k, i32 %p1, i32 %p2, i32 %p3, i32 %p4, i32 %p5, i32 %p6) local_unnamed_addr { +entry: + br i1 %k, label %if.then, label %if.end + +if.then: ; preds = %entry + tail call void @_Z2f1iii(i32 %p1, i32 %p3, i32 %p5) + tail call void @_Z2f1iii(i32 %p2, i32 %p4, i32 %p6) + br label %if.end + +if.end: ; preds = %if.then, %entry + ret void +} + +declare dso_local void @_Z2f1iii(i32, i32, i32) local_unnamed_addr