diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp index 05d3d18aa9557..073eb355491a7 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -2053,11 +2053,36 @@ void DwarfDebug::beginInstruction(const MachineInstr *MI) { if (NoDebug) return; + auto RecordLineZero = [&]() { + // Preserve the file and column numbers, if we can, to save space in + // the encoded line table. + // Do not update PrevInstLoc, it remembers the last non-0 line. + const MDNode *Scope = nullptr; + unsigned Column = 0; + if (PrevInstLoc) { + Scope = PrevInstLoc.getScope(); + Column = PrevInstLoc.getCol(); + } + recordSourceLine(/*Line=*/0, Column, Scope, /*Flags=*/0); + }; + + // When we emit a line-0 record, we don't update PrevInstLoc; so look at + // the last line number actually emitted, to see if it was line 0. + unsigned LastAsmLine = + Asm->OutStreamer->getContext().getCurrentDwarfLoc().getLine(); + // Check if source location changes, but ignore DBG_VALUE and CFI locations. // If the instruction is part of the function frame setup code, do not emit // any line record, as there is no correspondence with any user code. - if (MI->isMetaInstruction() || MI->getFlag(MachineInstr::FrameSetup)) + if (MI->isMetaInstruction()) + return; + if (MI->getFlag(MachineInstr::FrameSetup)) { + // Prevent a loc from the previous block leaking into frame setup instrs. + if (LastAsmLine && PrevInstBB && PrevInstBB != MI->getParent()) + RecordLineZero(); return; + } + const DebugLoc &DL = MI->getDebugLoc(); unsigned Flags = 0; @@ -2080,11 +2105,6 @@ void DwarfDebug::beginInstruction(const MachineInstr *MI) { LocationString); }; - // When we emit a line-0 record, we don't update PrevInstLoc; so look at - // the last line number actually emitted, to see if it was line 0. - unsigned LastAsmLine = - Asm->OutStreamer->getContext().getCurrentDwarfLoc().getLine(); - // There may be a mixture of scopes using and not using Key Instructions. // Not-Key-Instructions functions inlined into Key Instructions functions // should use not-key is_stmt handling. Key Instructions functions inlined @@ -2150,18 +2170,8 @@ void DwarfDebug::beginInstruction(const MachineInstr *MI) { // - Instruction is at the top of a block; we don't want to inherit the // location from the physically previous (maybe unrelated) block. if (UnknownLocations == Enable || PrevLabel || - (PrevInstBB && PrevInstBB != MI->getParent())) { - // Preserve the file and column numbers, if we can, to save space in - // the encoded line table. - // Do not update PrevInstLoc, it remembers the last non-0 line. - const MDNode *Scope = nullptr; - unsigned Column = 0; - if (PrevInstLoc) { - Scope = PrevInstLoc.getScope(); - Column = PrevInstLoc.getCol(); - } - recordSourceLine(/*Line=*/0, Column, Scope, /*Flags=*/0); - } + (PrevInstBB && PrevInstBB != MI->getParent())) + RecordLineZero(); return; } diff --git a/llvm/test/DebugInfo/X86/shrink-wrap-frame-setup-no-loc.mir b/llvm/test/DebugInfo/X86/shrink-wrap-frame-setup-no-loc.mir new file mode 100644 index 0000000000000..a6d9f96c4a592 --- /dev/null +++ b/llvm/test/DebugInfo/X86/shrink-wrap-frame-setup-no-loc.mir @@ -0,0 +1,139 @@ +# RUN: %llc_dwarf %s -o - -mtriple=x86_64-unknown-unknown | FileCheck %s + +## Check the line number from the ret above `.LBB0_1` doesn't leak onto the +## frame setup instructions in the `.LBB0_1` block; `pushq %rax` should +## explicitly get set to line zero. + +# CHECK: loop: +# CHECK-NEXT: .Lfunc_begin0: +# CHECK-NEXT: .cfi_startproc +# CHECK-NEXT: # %bb.0: +# CHECK-NEXT: .file 1 "/" "test.c" +# CHECK-NEXT: .loc 1 5 16 prologue_end # test.c:5:16 +# CHECK-NEXT: testq %rax, %rax +# CHECK-NEXT: je .LBB0_1 +# CHECK-NEXT: # %bb.2: +# CHECK-NEXT: .loc 1 5 16 # test.c:5:16 +# CHECK-NEXT: retq +# CHECK-NEXT: .LBB0_1: +# -- Check the .loc below sets the current location to line 0. +# CHECK-NEXT: .loc 1 0 16 is_stmt 0 # test.c:0:16 +# CHECK-NEXT: pushq %rax +# CHECK-NEXT: .cfi_def_cfa_offset 16 +# CHECK-NEXT: addq $8, %rsp +# CHECK-NEXT: .cfi_def_cfa_offset 8 +# CHECK-NEXT: .loc 1 5 16 is_stmt 1 # test.c:5:16 +# CHECK-NEXT: retq + +--- | + source_filename = "reduced.ll" + target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128" + target triple = "x86_64-unknown-unknown" + + define void @loop(i64 %i) !dbg !4 { + entry: + %cmp.not = icmp eq i64 %i, 0, !dbg !7 + br i1 %cmp.not, label %for.body, label %for.end + + for.body: ; preds = %entry + %puts10 = tail call i32 null(ptr null) + %inc = add i64 0, 0 + br label %for.end + + for.end: ; preds = %for.body, %entry + ret void + } + + !llvm.dbg.cu = !{!0} + !llvm.module.flags = !{!3} + + !0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "clang version 22.0.0git", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, globals: !2, splitDebugInlining: false, nameTableKind: None) + !1 = !DIFile(filename: "test.c", directory: "/") + !2 = !{} + !3 = !{i32 2, !"Debug Info Version", i32 3} + !4 = distinct !DISubprogram(name: "loop", scope: !1, file: !1, line: 4, type: !5, scopeLine: 4, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !2, keyInstructions: true) + !5 = !DISubroutineType(types: !6) + !6 = !{null} + !7 = !DILocation(line: 5, column: 16, scope: !8, atomGroup: 720, atomRank: 2) + !8 = distinct !DILexicalBlock(scope: !4, file: !1, line: 5, column: 9) +... +--- +name: loop +alignment: 16 +exposesReturnsTwice: false +legalized: false +regBankSelected: false +selected: false +failedISel: false +tracksRegLiveness: true +hasWinCFI: false +noPhis: false +isSSA: true +noVRegs: false +hasFakeUses: false +callsEHReturn: false +callsUnwindInit: false +hasEHContTarget: false +hasEHScopes: false +hasEHFunclets: false +isOutlined: false +debugInstrRef: false +failsVerification: false +tracksDebugUserValues: false +registers: + - { id: 0, class: gr64, preferred-register: '', flags: [ ] } + - { id: 1, class: gr32, preferred-register: '', flags: [ ] } + - { id: 2, class: gr64, preferred-register: '', flags: [ ] } + - { id: 3, class: gr32, preferred-register: '', flags: [ ] } + - { id: 4, class: gr64, preferred-register: '', flags: [ ] } + - { id: 5, class: gr32, preferred-register: '', flags: [ ] } + - { id: 6, class: gr32, preferred-register: '', flags: [ ] } + - { id: 7, class: gr64, preferred-register: '', flags: [ ] } +liveins: [] +frameInfo: + isFrameAddressTaken: false + isReturnAddressTaken: false + hasStackMap: false + hasPatchPoint: false + stackSize: 0 + offsetAdjustment: 0 + maxAlignment: 1 + adjustsStack: false + hasCalls: true + stackProtector: '' + functionContext: '' + maxCallFrameSize: 4294967295 + cvBytesOfCalleeSavedRegisters: 0 + hasOpaqueSPAdjustment: false + hasVAStart: false + hasMustTailInVarArgFunc: false + hasTailCall: false + isCalleeSavedInfoValid: false + localFrameSize: 0 +fixedStack: [] +stack: [] +entry_values: [] +callSites: [] +debugValueSubstitutions: [] +constants: [] +machineFunctionInfo: + amxProgModel: None +body: | + bb.0: + successors: %bb.1(0x30000000), %bb.2(0x50000000) + liveins: $rdi + + %7:gr64 = IMPLICIT_DEF + TEST64rr undef %7, undef %7, implicit-def $eflags, debug-location !7 + JCC_1 %bb.2, 5, implicit $eflags + JMP_1 %bb.1 + + bb.1: + successors: %bb.2(0x80000000) + + ADJCALLSTACKDOWN64 0, 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp + ADJCALLSTACKUP64 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp + + bb.2: + RET 0, debug-location !7 +...