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 @@ -3068,18 +3068,34 @@ 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(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); + } } - OutStreamer->emitLabel(MBB.getSymbol()); } } -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,12 @@ InsertedCFIInstr = true; } + if (ForceFullCFA) { + MF.getSubtarget().getFrameLowering()->emitCalleeSavedFrameMoves( + *MBBInfo.MBB, MBBI); + InsertedCFIInstr = true; + } + 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 { + emitCalleeSavedFrameMoves(MBB, MBBI, DebugLoc{}, true); + + MachineFunction &MF = *MBB.getParent(); + if (!hasFP(MF)) + 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)); +} + 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,65 @@ +; 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: _Z7computeb10structparmS_iii +; CFI_INSTR: bb.0 +; CFI_INSTR: bb.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 +; 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 in the computation. This tests that CFI directives for callee saved +; registers are generated with basic block sections. +; typedef struct { +; int v[4]; +; } structparm; +; +; int compute(bool k, structparm p, structparm q, int pa, int pb, int pc) { +; int result = p.v[1]; +; if (k) +; result = p.v[0] * p.v[1] + p.v[2] / p.v[3] - q.v[0] * q.v[1] + q.v[2] / q.v[3] * pa + pb / pc; +; return result; +; } + + +define dso_local i32 @_Z7computeb10structparmS_iii(i1 zeroext %k, i64 %p.coerce0, i64 %p.coerce1, i64 %q.coerce0, i64 %q.coerce1, i32 %pa, i32 %pb, i32 %pc) local_unnamed_addr { +entry: + %p.sroa.2.0.extract.shift = lshr i64 %p.coerce0, 32 + %p.sroa.2.0.extract.trunc = trunc i64 %p.sroa.2.0.extract.shift to i32 + br i1 %k, label %if.then, label %if.end + +if.then: ; preds = %entry + %q.sroa.5.8.extract.shift = lshr i64 %q.coerce1, 32 + %q.sroa.5.8.extract.trunc = trunc i64 %q.sroa.5.8.extract.shift to i32 + %q.sroa.3.8.extract.trunc = trunc i64 %q.coerce1 to i32 + %q.sroa.2.0.extract.shift = lshr i64 %q.coerce0, 32 + %q.sroa.2.0.extract.trunc = trunc i64 %q.sroa.2.0.extract.shift to i32 + %q.sroa.0.0.extract.trunc = trunc i64 %q.coerce0 to i32 + %p.sroa.6.8.extract.shift = lshr i64 %p.coerce1, 32 + %p.sroa.6.8.extract.trunc = trunc i64 %p.sroa.6.8.extract.shift to i32 + %p.sroa.4.8.extract.trunc = trunc i64 %p.coerce1 to i32 + %p.sroa.0.0.extract.trunc = trunc i64 %p.coerce0 to i32 + %mul = mul nsw i32 %p.sroa.2.0.extract.trunc, %p.sroa.0.0.extract.trunc + %div = sdiv i32 %p.sroa.4.8.extract.trunc, %p.sroa.6.8.extract.trunc + %mul13 = mul nsw i32 %q.sroa.2.0.extract.trunc, %q.sroa.0.0.extract.trunc + %div18 = sdiv i32 %q.sroa.3.8.extract.trunc, %q.sroa.5.8.extract.trunc + %mul19 = mul nsw i32 %div18, %pa + %div21 = sdiv i32 %pb, %pc + %add = sub i32 %mul, %mul13 + %sub = add i32 %add, %div + %add20 = add i32 %sub, %mul19 + %add22 = add i32 %add20, %div21 + br label %if.end + +if.end: ; preds = %if.then, %entry + %result.0 = phi i32 [ %add22, %if.then ], [ %p.sroa.2.0.extract.trunc, %entry ] + ret i32 %result.0 +}