From 0b5166a2a2e6e7a166518d56e14c877095fa01be Mon Sep 17 00:00:00 2001 From: Orlando Cazalet-Hyams Date: Thu, 27 Mar 2025 16:53:00 +0000 Subject: [PATCH 01/14] [KeyInstr][DwarfDebug] Add is_stmt emission support Interpret Key Instructions metadata to determine is_stmt placement. The lowest rank (highest precedent) instructions in each {InlinedAt, atomGroup} set are candidates for is_stmt. Only the last instruction in each set in a given block gets is_stmt. Calls always get is_stmt. --- llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp | 210 +++++++++++++++++- llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h | 9 + .../KeyInstructions/X86/dwarf-basic-ranks.ll | 68 ++++++ .../KeyInstructions/X86/dwarf-basic.ll | 62 ++++++ .../X86/dwarf-buoy-multi-key.mir | 78 +++++++ .../KeyInstructions/X86/dwarf-buoy.mir | 66 ++++++ .../KeyInstructions/X86/dwarf-calls.ll | 117 ++++++++++ .../KeyInstructions/X86/dwarf-ranks-blocks.ll | 65 ++++++ 8 files changed, 663 insertions(+), 12 deletions(-) create mode 100644 llvm/test/DebugInfo/KeyInstructions/X86/dwarf-basic-ranks.ll create mode 100644 llvm/test/DebugInfo/KeyInstructions/X86/dwarf-basic.ll create mode 100644 llvm/test/DebugInfo/KeyInstructions/X86/dwarf-buoy-multi-key.mir create mode 100644 llvm/test/DebugInfo/KeyInstructions/X86/dwarf-buoy.mir create mode 100644 llvm/test/DebugInfo/KeyInstructions/X86/dwarf-calls.ll create mode 100644 llvm/test/DebugInfo/KeyInstructions/X86/dwarf-ranks-blocks.ll diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp index b331854d1ee8f..792441607eec2 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -17,6 +17,7 @@ #include "DwarfExpression.h" #include "DwarfUnit.h" #include "llvm/ADT/APInt.h" +#include "llvm/ADT/ScopeExit.h" #include "llvm/ADT/Statistic.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/Twine.h" @@ -170,6 +171,9 @@ static cl::opt MinimizeAddrInV5Option( "Stuff")), cl::init(DwarfDebug::MinimizeAddrInV5::Default)); +static cl::opt KeyInstructionsAreStmts("dwarf-use-key-instructions", + cl::Hidden, cl::init(false)); + static constexpr unsigned ULEB128PadSize = 4; void DebugLocDwarfExpression::emitOp(uint8_t Op, const char *Comment) { @@ -2070,6 +2074,10 @@ void DwarfDebug::beginInstruction(const MachineInstr *MI) { unsigned LastAsmLine = Asm->OutStreamer->getContext().getCurrentDwarfLoc().getLine(); + bool IsKey = false; + if (KeyInstructionsAreStmts && DL && DL.getLine()) + IsKey = KeyInstructions.contains(MI); + if (!DL && MI == PrologEndLoc) { // In rare situations, we might want to place the end of the prologue // somewhere that doesn't have a source location already. It should be in @@ -2088,13 +2096,18 @@ void DwarfDebug::beginInstruction(const MachineInstr *MI) { // If we have an ongoing unspecified location, nothing to do here. if (!DL) return; - // We have an explicit location, same as the previous location. - // But we might be coming back to it after a line 0 record. - if ((LastAsmLine == 0 && DL.getLine() != 0) || Flags) { - // Reinstate the source location but not marked as a statement. - RecordSourceLine(DL, Flags); + + // Skip this if the instruction is Key, else we might accidentally miss an + // is_stmt. + if (!IsKey) { + // We have an explicit location, same as the previous location. + // But we might be coming back to it after a line 0 record. + if ((LastAsmLine == 0 && DL.getLine() != 0) || Flags) { + // Reinstate the source location but not marked as a statement. + RecordSourceLine(DL, Flags); + } + return; } - return; } if (!DL) { @@ -2141,11 +2154,17 @@ void DwarfDebug::beginInstruction(const MachineInstr *MI) { Flags |= DWARF2_FLAG_PROLOGUE_END | DWARF2_FLAG_IS_STMT; PrologEndLoc = nullptr; } - // If the line changed, we call that a new statement; unless we went to - // line 0 and came back, in which case it is not a new statement. - unsigned OldLine = PrevInstLoc ? PrevInstLoc.getLine() : LastAsmLine; - if (DL.getLine() && (DL.getLine() != OldLine || ForceIsStmt)) - Flags |= DWARF2_FLAG_IS_STMT; + + if (KeyInstructionsAreStmts) { + if (IsKey) + Flags |= DWARF2_FLAG_IS_STMT; + } else { + // If the line changed, we call that a new statement; unless we went to + // line 0 and came back, in which case it is not a new statement. + unsigned OldLine = PrevInstLoc ? PrevInstLoc.getLine() : LastAsmLine; + if (DL.getLine() && (DL.getLine() != OldLine || ForceIsStmt)) + Flags |= DWARF2_FLAG_IS_STMT; + } RecordSourceLine(DL, Flags); @@ -2338,6 +2357,170 @@ DwarfDebug::emitInitialLocDirective(const MachineFunction &MF, unsigned CUID) { return PrologEndLoc; } +void DwarfDebug::findKeyInstructions(const MachineFunction *MF) { + // New function - reset KeyInstructions. + KeyInstructions.clear(); + + // The current candidate is_stmt instructions for each source atom. + // Map {(InlinedAt, Group): (Rank, Instructions)}. + DenseMap, + std::pair>> + GroupCandidates; + + // For each instruction: + // * Skip insts without DebugLoc, AtomGroup or AtomRank, and line zeros. + // * Check if insts in this group have been seen already in GroupCandidates. + // * If this instr rank is equal, add this instruction to KeyInstructions. + // Remove existing instructions from KeyInstructions if they have the + // same parent. + // * If this instr rank is higher (lower precedence), ignore it. + // * If this instr rank is lower (higher precedence), erase existing + // instructions from KeyInstructions. Add this instr to KeyInstructions. + + for (auto &MBB : *MF) { + // Rather than apply is_stmt directly to Key Instructions, we "float" + // is_stmt up to the 1st instruction with the same line number in a + // contiguous block. That instruction is called the "buoy". The + // buoy gets reset if we encouner an instruction with an atom + // group. + const MachineInstr *Buoy = nullptr; + // The atom group number associated with Buoy which may be 0 if we haven't + // encountered an atom group yet in this blob of instructions with the same + // line number. + uint64_t BuoyAtom = 0; + + for (auto &MI : MBB) { + if (MI.isMetaInstruction()) + continue; + + if (!MI.getDebugLoc() || !MI.getDebugLoc().getLine()) + continue; + + // Reset the Buoy to this instruciton if it has a different line number. + if (!Buoy || + Buoy->getDebugLoc().getLine() != MI.getDebugLoc().getLine()) { + Buoy = &MI; + BuoyAtom = 0; + } + + // Call instructions are handled specially - we always mark them as key + // regardless of atom info. + const auto &TII = + *MI.getParent()->getParent()->getSubtarget().getInstrInfo(); + if (MI.isCall() || TII.isTailCall(MI)) { + assert(MI.getDebugLoc() && "Unexpectedly missing DL"); + + // Calls are always key. + KeyInstructions.insert(Buoy); + + uint64_t Group = MI.getDebugLoc()->getAtomGroup(); + uint8_t Rank = MI.getDebugLoc()->getAtomRank(); + if (Group && Rank) { + auto *InlinedAt = MI.getDebugLoc()->getInlinedAt(); + auto &[CandidateRank, CandidateInsts] = GroupCandidates[{InlinedAt, Group}]; + + // This looks similar to the non-call handling code, except that + // we don't put the call into CandidateInsts so that they can't be + // made un-key. As a result, we also have to take special care not + // to erase the is_stmt from the buoy, and prevent that happening + // in the future. + + if (CandidateRank == Rank) { + // We've seen other instructions in this group of this rank. Discard + // ones we've seen in this block, keep the others. + assert(!CandidateInsts.empty()); + SmallVector Insts; + Insts.reserve(CandidateInsts.size()); + for (auto &PrevInst : CandidateInsts) { + if (PrevInst->getParent() != MI.getParent()) + Insts.push_back(PrevInst); + else if (PrevInst != Buoy) + KeyInstructions.erase(PrevInst); + } + + if (Insts.empty()) { + CandidateInsts.clear(); + CandidateRank = 0; + } else { + CandidateInsts = std::move(Insts); + } + + } else if (CandidateRank > Rank) { + // We've seen other instructions in this group of lower precedence + // (higher rank). Discard them. + for (auto *Supplanted : CandidateInsts) { + // Don't erase the is_stmt we're using for this call. + if (Supplanted != Buoy) + KeyInstructions.erase(Supplanted); + } + CandidateInsts.clear(); + CandidateRank = 0; + } + } + + // Avoid floating any future is_stmts up to the call. + Buoy = nullptr; + continue; + } + + auto *InlinedAt = MI.getDebugLoc()->getInlinedAt(); + uint64_t Group = MI.getDebugLoc()->getAtomGroup(); + uint8_t Rank = MI.getDebugLoc()->getAtomRank(); + if (!Group || !Rank) + continue; + + // Don't let is_stmts float past instructions from different source atoms. + if (BuoyAtom && BuoyAtom != Group) { + Buoy = &MI; + BuoyAtom = MI.getDebugLoc()->getAtomGroup(); + } + + auto &[CandidateRank, CandidateInsts] = GroupCandidates[{InlinedAt, Group}]; + + if (CandidateRank == 0) { + // This is the first time we're seeing an instruction in this atom + // group. Add it to the map. + assert(CandidateInsts.empty()); + CandidateRank = Rank; + CandidateInsts.push_back(Buoy); + + } else if (CandidateRank == Rank) { + // We've seen other instructions in this group of this rank. Discard + // ones we've seen in this block, keep the others, add this one. + assert(!CandidateInsts.empty()); + SmallVector Insts; + Insts.reserve(CandidateInsts.size() + 1); + for (auto &PrevInst : CandidateInsts) { + if (PrevInst->getParent() != MI.getParent()) + Insts.push_back(PrevInst); + else + KeyInstructions.erase(PrevInst); + } + Insts.push_back(Buoy); + CandidateInsts = std::move(Insts); + + } else if (CandidateRank > Rank) { + // We've seen other instructions in this group of lower precedence + // (higher rank). Discard them, add this one. + assert(!CandidateInsts.empty()); + CandidateRank = Rank; + for (auto *Supplanted : CandidateInsts) + KeyInstructions.erase(Supplanted); + CandidateInsts = {Buoy}; + + } else { + // We've seen other instructions in this group with higher precedence + // (lower rank). Discard this one. + assert(Rank != 0 && CandidateRank < Rank && CandidateRank != 0); + continue; + } + KeyInstructions.insert(Buoy); + assert(!BuoyAtom || BuoyAtom == MI.getDebugLoc()->getAtomGroup()); + BuoyAtom = MI.getDebugLoc()->getAtomGroup(); + } + } +} + /// For the function \p MF, finds the set of instructions which may represent a /// change in line number from one or more of the preceding MBBs. Stores the /// resulting set of instructions, which should have is_stmt set, in @@ -2496,7 +2679,10 @@ void DwarfDebug::beginFunctionImpl(const MachineFunction *MF) { PrologEndLoc = emitInitialLocDirective( *MF, Asm->OutStreamer->getContext().getDwarfCompileUnitID()); - findForceIsStmtInstrs(MF); + if (KeyInstructionsAreStmts) + findKeyInstructions(MF); + else + findForceIsStmtInstrs(MF); } unsigned diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h index 58e6d39f76ae0..cd232a8e94ecf 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h @@ -464,6 +464,10 @@ class DwarfDebug : public DebugHandlerBase { }; private: + /// Instructions which should get is_stmt applied because they implement key + /// functionality for a source atom. + SmallDenseSet KeyInstructions; + /// Force the use of DW_AT_ranges even for single-entry range lists. MinimizeAddrInV5 MinimizeAddr = MinimizeAddrInV5::Disabled; @@ -701,6 +705,11 @@ class DwarfDebug : public DebugHandlerBase { void findForceIsStmtInstrs(const MachineFunction *MF); + /// Find instructions which should get is_stmt applied because they implement + /// key functionality for a source atom, store results in + /// DwarfDebug::KeyInstructions. + void findKeyInstructions(const MachineFunction *MF); + protected: /// Gather pre-function debug information. void beginFunctionImpl(const MachineFunction *MF) override; diff --git a/llvm/test/DebugInfo/KeyInstructions/X86/dwarf-basic-ranks.ll b/llvm/test/DebugInfo/KeyInstructions/X86/dwarf-basic-ranks.ll new file mode 100644 index 0000000000000..71ecf1dc41238 --- /dev/null +++ b/llvm/test/DebugInfo/KeyInstructions/X86/dwarf-basic-ranks.ll @@ -0,0 +1,68 @@ +; RUN: llc %s --filetype=obj -o - --dwarf-use-key-instructions \ +; RUN: | llvm-objdump -d - --no-show-raw-insn \ +; RUN: | FileCheck %s --check-prefix=OBJ + +; RUN: llc %s --filetype=obj -o - --dwarf-use-key-instructions \ +; RUN: | llvm-dwarfdump - --debug-line \ +; RUN: | FileCheck %s --check-prefix=DBG + +; OBJ: 0000000000000000 <_Z1fPiii>: +; OBJ-NEXT: 0: pushq %rbp +; OBJ-NEXT: 1: pushq %r14 +; OBJ-NEXT: 3: pushq %rbx +; OBJ-NEXT: 4: movl %edx, %ebx +; OBJ-NEXT: 6: movl %esi, %ebp +; OBJ-NEXT: 8: movq %rdi, %r14 +; OBJ-NEXT: b: callq 0x10 <_Z1fPiii+0x10> +; OBJ-NEXT: 10: addl %ebx, %ebp +; OBJ-NEXT: 12: movl %ebp, (%r14) +; OBJ-NEXT: 15: movl %ebp, %eax +; OBJ-NEXT: 17: popq %rbx +; OBJ-NEXT: 18: popq %r14 +; OBJ-NEXT: 1a: popq %rbp + +; DBG: Address Line Column File ISA Discriminator OpIndex Flags +; DBG-NEXT: ------------------ ------ ------ ------ --- ------------- ------- ------------- +; DBG-NEXT: 0x0000000000000000 3 0 0 0 0 0 is_stmt +; DBG-NEXT: 0x000000000000000b 4 0 0 0 0 0 is_stmt prologue_end +; DBG-NEXT: 0x0000000000000010 6 0 0 0 0 0 +; DBG-NEXT: 0x0000000000000012 5 0 0 0 0 0 is_stmt +; DBG-NEXT: 0x0000000000000015 7 0 0 0 0 0 is_stmt +; DBG-NEXT: 0x0000000000000017 7 0 0 0 0 0 epilogue_begin +; DBG-NEXT: 0x000000000000001c 7 0 0 0 0 0 end_sequence + +;; 1. [[gnu::nodebug]] void prologue_end(); +;; 2. +;; 3. int f(int *a, int b, int c) { +;; 4. prologue_end(); +;; 5. *a = +;; 6. b + c; +;; 7. return *a; +;; 8. } + +;; The add and store are in the same goup (1). The add (line 6) has lower +;; precedence (rank 2) so should not get is_stmt applied. +target triple = "x86_64-unknown-linux-gnu" + +define hidden noundef i32 @_Z1fPiii(ptr %a, i32 %b, i32 %c) local_unnamed_addr !dbg !11 { +entry: + tail call void @_Z12prologue_endv(), !dbg !DILocation(line: 4, scope: !11) + %add = add nsw i32 %c, %b, !dbg !DILocation(line: 6, scope: !11, atomGroup: 1, atomRank: 2) + store i32 %add, ptr %a, align 4, !dbg !DILocation(line: 5, scope: !11, atomGroup: 1, atomRank: 1) + ret i32 %add, !dbg !DILocation(line: 7, scope: !11, atomGroup: 2, atomRank: 1) +} + +declare void @_Z12prologue_endv() local_unnamed_addr #1 + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!2, !3} +!llvm.ident = !{!10} + +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_17, file: !1, producer: "clang version 19.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: LineTablesOnly, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "test.cpp", directory: "/") +!2 = !{i32 7, !"Dwarf Version", i32 5} +!3 = !{i32 2, !"Debug Info Version", i32 3} +!10 = !{!"clang version 19.0.0"} +!11 = distinct !DISubprogram(name: "f", scope: !1, file: !1, line: 3, type: !12, scopeLine: 3, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0) +!12 = !DISubroutineType(types: !13) +!13 = !{} diff --git a/llvm/test/DebugInfo/KeyInstructions/X86/dwarf-basic.ll b/llvm/test/DebugInfo/KeyInstructions/X86/dwarf-basic.ll new file mode 100644 index 0000000000000..e3b0184a837f8 --- /dev/null +++ b/llvm/test/DebugInfo/KeyInstructions/X86/dwarf-basic.ll @@ -0,0 +1,62 @@ +; RUN: llc %s --filetype=obj -o - --dwarf-use-key-instructions \ +; RUN: | llvm-objdump -d - --no-show-raw-insn \ +; RUN: | FileCheck %s --check-prefix=OBJ + +; RUN: llc %s --filetype=obj -o - --dwarf-use-key-instructions \ +; RUN: | llvm-dwarfdump - --debug-line \ +; RUN: | FileCheck %s --check-prefix=DBG + +; OBJ: 0000000000000000 <_Z1fi>: +; OBJ-NEXT: 0: leal 0x1(%rdi), %eax +; OBJ-NEXT: 3: retq +; OBJ: 0000000000000010 <_Z1gi>: +; OBJ-NEXT: 10: leal 0x1(%rdi), %eax +; OBJ-NEXT: 13: retq + +; DBG: Address Line Column File ISA Discriminator OpIndex Flags +; DBG-NEXT: ------------------ ------ ------ ------ --- ------------- ------- ------------- +; DBG-NEXT: 0x0000000000000000 2 0 0 0 0 0 is_stmt prologue_end +; DBG-NEXT: 0x0000000000000003 3 0 0 0 0 0 is_stmt +; DBG-NEXT: 0x0000000000000010 2 0 0 0 0 0 is_stmt prologue_end +; DBG-NEXT: 0x0000000000000013 6 0 0 0 0 0 is_stmt + +;; 1. int f(int a) { +;; 2. int x = a + 1; +;; 3. return x; +;; 4. } +;; 5. int g(int b) { +;; 6. return f(b); +;; 7. } +;; +;; Both functions contain 2 instructions in unique atom groups. In f we see +;; groups 1 and 3, and in g we see {!18, 1} and 1. All of these instructions +;; should get is_stmt. + +target triple = "x86_64-unknown-linux-gnu" + +define hidden noundef i32 @_Z1fi(i32 noundef %a) local_unnamed_addr !dbg !11 { +entry: + %add = add nsw i32 %a, 1, !dbg !DILocation(line: 2, scope: !11, atomGroup: 1, atomRank: 2) + ret i32 %add, !dbg !DILocation(line: 3, scope: !11, atomGroup: 3, atomRank: 1) +} + +define hidden noundef i32 @_Z1gi(i32 noundef %b) local_unnamed_addr !dbg !16 { +entry: + %add.i = add nsw i32 %b, 1, !dbg !DILocation(line: 2, scope: !11, inlinedAt: !18, atomGroup: 1, atomRank: 2) + ret i32 %add.i, !dbg !DILocation(line: 6, scope: !16, atomGroup: 1, atomRank: 1) +} + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!2, !3} +!llvm.ident = !{!10} + +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_17, file: !1, producer: "clang version 19.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: LineTablesOnly, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "test.cpp", directory: "/") +!2 = !{i32 7, !"Dwarf Version", i32 5} +!3 = !{i32 2, !"Debug Info Version", i32 3} +!10 = !{!"clang version 19.0.0"} +!11 = distinct !DISubprogram(name: "f", scope: !1, file: !1, line: 1, type: !12, scopeLine: 1, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0) +!12 = !DISubroutineType(types: !13) +!13 = !{} +!16 = distinct !DISubprogram(name: "g", scope: !1, file: !1, line: 5, type: !12, scopeLine: 5, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0) +!18 = distinct !DILocation(line: 6, scope: !16) diff --git a/llvm/test/DebugInfo/KeyInstructions/X86/dwarf-buoy-multi-key.mir b/llvm/test/DebugInfo/KeyInstructions/X86/dwarf-buoy-multi-key.mir new file mode 100644 index 0000000000000..c8459b4ced600 --- /dev/null +++ b/llvm/test/DebugInfo/KeyInstructions/X86/dwarf-buoy-multi-key.mir @@ -0,0 +1,78 @@ +# RUN: llc %s --start-after=livedebugvalues --dwarf-use-key-instructions --filetype=obj -o - \ +# RUN: | llvm-objdump -d - --no-show-raw-insn \ +# RUN: | FileCheck %s --check-prefix=OBJ + +# RUN: llc %s --start-after=livedebugvalues --dwarf-use-key-instructions --filetype=obj -o - \ +# RUN: | llvm-dwarfdump - --debug-line \ +# RUN: | FileCheck %s --check-prefix=DBG + +# OBJ: 0000000000000000 <_Z1fPiii>: +# OBJ-NEXT: 0: movl $0x0, %ebx +# OBJ-NEXT: 5: movl $0x1, %ebx +# OBJ-NEXT: a: movl $0x2, %ebx +# OBJ-NEXT: f: movl $0x3, %ebx +# OBJ-NEXT: 14: movl $0x4, %eax +# OBJ-NEXT: 19: movl $0x5, %eax +# OBJ-NEXT: 1e: movl $0x6, %eax +# OBJ-NEXT: 23: movl $0x7, %eax +# OBJ-NEXT: 28: retq + +# DBG: Address Line Column File ISA Discriminator OpIndex Flags +# DBG-NEXT: ------------------ ------ ------ ------ --- ------------- ------- ------------- +# DBG-NEXT: 0x0000000000000000 1 0 0 0 0 0 is_stmt prologue_end +# DBG-NEXT: 0x0000000000000005 2 0 0 0 0 0 is_stmt +# DBG-NEXT: 0x000000000000000a 2 0 0 0 0 0 +# DBG-NEXT: 0x000000000000000f 2 0 0 0 0 0 +# DBG-NEXT: 0x0000000000000014 2 0 0 0 0 0 +# DBG-NEXT: 0x0000000000000019 2 0 0 0 0 0 +# DBG-NEXT: 0x000000000000001e 2 0 0 0 0 0 is_stmt +# DBG-NEXT: 0x0000000000000023 2 0 0 0 0 0 is_stmt +# DBG-NEXT: 0x0000000000000029 2 0 0 0 0 0 is_stmt end_sequence + +## Check that interleaving atoms on the same line still produces reasonable +## is_stmt placement (the is_stmts want to "float up" to the first instruction +## in a contiguous set with the same line, but we don't let them float past +## other atom groups). + +--- | + target triple = "x86_64-unknown-linux-gnu" + + define hidden noundef i32 @_Z1fPiii(ptr %a, i32 %b, i32 %c, i1 %cond) local_unnamed_addr !dbg !5 { + entry: + ret i32 2 + } + + !llvm.dbg.cu = !{!0} + !llvm.module.flags = !{!2, !3} + !llvm.ident = !{!4} + + !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_17, file: !1, producer: "clang version 19.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: LineTablesOnly, splitDebugInlining: false, nameTableKind: None) + !1 = !DIFile(filename: "test.cpp", directory: "/") + !2 = !{i32 7, !"Dwarf Version", i32 5} + !3 = !{i32 2, !"Debug Info Version", i32 3} + !4 = !{!"clang version 19.0.0"} + !5 = distinct !DISubprogram(name: "f", scope: !1, file: !1, line: 1, type: !6, scopeLine: 1, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0) + !6 = !DISubroutineType(types: !7) + !7 = !{} + !8 = !DILocalVariable(name: "x", scope: !5, file: !1, line: 1, type: !7) + +... +--- +name: _Z1fPiii +alignment: 16 +body: | + bb.0.entry: + $ebx = MOV32ri 0, debug-location !DILocation(line: 1, scope: !5) + ;; is_stmt floats up here from mov 3. + $ebx = MOV32ri 1, debug-location !DILocation(line: 2, scope: !5, atomGroup: 1, atomRank: 1) + $ebx = MOV32ri 2, debug-location !DILocation(line: 2, scope: !5, atomGroup: 1, atomRank: 2) + $ebx = MOV32ri 3, debug-location !DILocation(line: 2, scope: !5, atomGroup: 1, atomRank: 1) + $eax = MOV32ri 4, debug-location !DILocation(line: 2, scope: !5) + $eax = MOV32ri 5, debug-location !DILocation(line: 2, scope: !5, atomGroup: 2, atomRank: 1) + ;; is_stmt for this group can't float higher due to atom group above. + $eax = MOV32ri 6, debug-location !DILocation(line: 2, scope: !5, atomGroup: 3, atomRank: 1) + ;; Same again. + $eax = MOV32ri 7, debug-location !DILocation(line: 2, scope: !5, atomGroup: 2, atomRank: 1) + RET64 $eax + +... diff --git a/llvm/test/DebugInfo/KeyInstructions/X86/dwarf-buoy.mir b/llvm/test/DebugInfo/KeyInstructions/X86/dwarf-buoy.mir new file mode 100644 index 0000000000000..3aff5e22326ec --- /dev/null +++ b/llvm/test/DebugInfo/KeyInstructions/X86/dwarf-buoy.mir @@ -0,0 +1,66 @@ +# RUN: llc %s --start-after=livedebugvalues --dwarf-use-key-instructions --filetype=obj -o - \ +# RUN: | llvm-objdump -d - --no-show-raw-insn \ +# RUN: | FileCheck %s --check-prefix=OBJ + +# RUN: llc %s --start-after=livedebugvalues --dwarf-use-key-instructions --filetype=obj -o - \ +# RUN: | llvm-dwarfdump - --debug-line \ +# RUN: | FileCheck %s --check-prefix=DBG + +# OBJ: 0000000000000000 <_Z1fPiii>: +# OBJ-NEXT: 0: movl $0x1, %ebx +# OBJ-NEXT: 5: movl $0x2, %eax +# OBJ-NEXT: a: movl $0x0, %eax +# OBJ-NEXT: f: movl $0x0, %eax +# OBJ-NEXT: 14: retq + +# DBG: Address Line Column File ISA Discriminator OpIndex Flags +# DBG-NEXT: ------------------ ------ ------ ------ --- ------------- ------- ------------- +# DBG-NEXT: 0x0000000000000000 1 0 0 0 0 0 is_stmt prologue_end +# DBG-NEXT: 0x0000000000000005 2 0 0 0 0 0 is_stmt +# DBG-NEXT: 0x000000000000000a 0 0 0 0 0 0 +# DBG-NEXT: 0x0000000000000014 2 0 0 0 0 0 +# DBG-NEXT: 0x0000000000000015 2 0 0 0 0 0 end_sequence + +## The `RET64` is the only key instruction. The `MOV32ri 2` has the same line +## number so the is_stmt should "float up" from the ret to the mov. Check this +## happens; check that the DBG_VALUE wedged between them with a different line +## number, the line zero, and missing DebugLoc, don't disrupt that; and check +## the is_stmt doesn't float too far up onto the `MOV32ri 1`. + +--- | + target triple = "x86_64-unknown-linux-gnu" + + define hidden noundef i32 @_Z1fPiii(ptr %a, i32 %b, i32 %c, i1 %cond) local_unnamed_addr !dbg !5 { + entry: + ret i32 2 + } + + !llvm.dbg.cu = !{!0} + !llvm.module.flags = !{!2, !3} + !llvm.ident = !{!4} + + !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_17, file: !1, producer: "clang version 19.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: LineTablesOnly, splitDebugInlining: false, nameTableKind: None) + !1 = !DIFile(filename: "test.cpp", directory: "/") + !2 = !{i32 7, !"Dwarf Version", i32 5} + !3 = !{i32 2, !"Debug Info Version", i32 3} + !4 = !{!"clang version 19.0.0"} + !5 = distinct !DISubprogram(name: "f", scope: !1, file: !1, line: 1, type: !6, scopeLine: 1, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0) + !6 = !DISubroutineType(types: !7) + !7 = !{} + !8 = !DILocalVariable(name: "x", scope: !5, file: !1, line: 1, type: !7) + +... +--- +name: _Z1fPiii +alignment: 16 +body: | + bb.0.entry: + + $ebx = MOV32ri 1, debug-location !DILocation(line: 1, scope: !5) + $eax = MOV32ri 2, debug-location !DILocation(line: 2, scope: !5) + $eax = MOV32ri 0, debug-location !DILocation(line: 0, scope: !5) + $eax = MOV32ri 0 + DBG_VALUE $noreg, $noreg, !8, !DIExpression(), debug-location !DILocation(line: 1, scope: !5) + RET64 $eax, debug-location !DILocation(line: 2, scope: !5, atomGroup: 1, atomRank: 2) + +... diff --git a/llvm/test/DebugInfo/KeyInstructions/X86/dwarf-calls.ll b/llvm/test/DebugInfo/KeyInstructions/X86/dwarf-calls.ll new file mode 100644 index 0000000000000..780374127707e --- /dev/null +++ b/llvm/test/DebugInfo/KeyInstructions/X86/dwarf-calls.ll @@ -0,0 +1,117 @@ +; RUN: llc %s --filetype=obj -o - --dwarf-use-key-instructions \ +; RUN: | llvm-objdump -d - --no-show-raw-insn \ +; RUN: | FileCheck %s --check-prefix=OBJ + +; RUN: llc %s --filetype=obj -o - --dwarf-use-key-instructions \ +; RUN: | llvm-dwarfdump - --debug-line \ +; RUN: | FileCheck %s --check-prefix=DBG + +; OBJ:0000000000000000 : +; OBJ-NEXT: 0: pushq %rbp +; OBJ-NEXT: 1: pushq %r14 +; OBJ-NEXT: 3: pushq %rbx +; OBJ-NEXT: 4: movq (%rip), %rax +; OBJ-NEXT: b: movl (%rax), %ebp +; OBJ-NEXT: d: callq 0x12 +; OBJ-NEXT: 12: callq 0x17 +; OBJ-NEXT: 17: movl %eax, %ebx +; OBJ-NEXT: 19: addl %ebp, %ebx +; OBJ-NEXT: 1b: movq (%rip), %r14 +; OBJ-NEXT: 22: movl $0x1, (%r14) +; OBJ-NEXT: 29: callq 0x2e +; OBJ-NEXT: 2e: movl $0x2, (%r14) +; OBJ-NEXT: 35: callq 0x3a +; OBJ-NEXT: 3a: movl $0x3, (%r14) +; OBJ-NEXT: 41: callq 0x46 +; OBJ-NEXT: 46: movl $0x4, (%r14) +; OBJ-NEXT: 4d: callq 0x52 +; OBJ-NEXT: 52: movl %ebx, %eax +; OBJ-NEXT: 54: popq %rbx +; OBJ-NEXT: 55: popq %r14 +; OBJ-NEXT: 57: popq %rbp +; OBJ-NEXT: 58: retq + +; DBG: Address Line Column File ISA Discriminator OpIndex Flags +; DBG-NEXT: ------------------ ------ ------ ------ --- ------------- ------- ------------- +; DBG-NEXT: 0x0000000000000000 1 0 0 0 0 0 is_stmt +; DBG-NEXT: 0x0000000000000004 2 0 0 0 0 0 is_stmt prologue_end + +;; Test A: +;; Check the 1st call (line 3) gets is_stmt despite having no atom group. +; DBG-NEXT: 0x000000000000000d 3 0 0 0 0 0 is_stmt + +;; Test B: +;; Check the 2nd call (line 4) gets is_stmt applied despite being part of group +;; 1 and having lower precedence than the add. Check that the add stil gets +;; is_stmt applied. +;; There are two is_stmt line 4 entries are is_stmt because we don't float +;; is_stmts up on the same line past other key instructions. The call is +;; key, so the add's is_stmt floats up to the movl on the same line, but +;; not past the call. +; DBG-NEXT: 0x0000000000000012 4 0 0 0 0 0 is_stmt +; DBG-NEXT: 0x0000000000000017 4 0 0 0 0 0 is_stmt +; DBG-NEXT: 0x0000000000000019 4 0 0 0 0 0 + +;; Test C: +;; Check that is_stmt floats up from the call to the store. +; DBG-NEXT: 0x000000000000001b 5 0 0 0 0 0 is_stmt +; DBG-NEXT: 0x0000000000000029 5 0 0 0 0 0 + +;; Test D: +;; Check the is_stmt is not applied to the lower ranking instruction. +; DBG-NEXT: 0x000000000000002e 6 0 0 0 0 0 +; DBG-NEXT: 0x0000000000000035 7 0 0 0 0 0 is_stmt + +;; Test E: +;; Check the is_stmt floats up to an instruction in the same group of the same +;; or lower precedence. +; DBG-NEXT: 0x000000000000003a 8 0 0 0 0 0 is_stmt +; DBG-NEXT: 0x0000000000000041 8 0 0 0 0 0 +; DBG-NEXT: 0x0000000000000046 9 0 0 0 0 0 is_stmt + +; DBG-NEXT: 0x0000000000000052 10 0 0 0 0 0 +; DBG-NEXT: 0x0000000000000054 10 0 0 0 0 0 epilogue_begin +; DBG-NEXT: 0x0000000000000059 10 0 0 0 0 0 end_sequence + +target triple = "x86_64-unknown-linux-gnu" + +@a = global i32 0 +@z = global i32 0 + +define hidden i32 @fun() local_unnamed_addr !dbg !11 { +entry: + %b = load i32, ptr @a, !dbg !DILocation(line: 2, scope: !11) +;; Test A: + tail call void @f(), !dbg !DILocation(line: 3, scope: !11) +;; Test B: + %x = tail call i32 @g(), !dbg !DILocation(line: 4, scope: !11, atomGroup: 1, atomRank: 2) + %y = add i32 %x, %b, !dbg !DILocation(line: 4, scope: !11, atomGroup: 1, atomRank: 1) +;; Test C: + store i32 1, ptr @z, !dbg !DILocation(line: 5, scope: !11, atomGroup: 2, atomRank: 2) + tail call void @f(), !dbg !DILocation(line: 5, scope: !11, atomGroup: 2, atomRank: 1) +;; Test D: + store i32 2, ptr @z, !dbg !DILocation(line: 6, scope: !11, atomGroup: 3, atomRank: 2) + tail call void @f(), !dbg !DILocation(line: 7, scope: !11, atomGroup: 3, atomRank: 1) +;; Test E: + store i32 3, ptr @z, !dbg !DILocation(line: 8, scope: !11, atomGroup: 4, atomRank: 2) + tail call void @f(), !dbg !DILocation(line: 8, scope: !11, atomGroup: 4, atomRank: 1) + store i32 4, ptr @z, !dbg !DILocation(line: 9, scope: !11, atomGroup: 5, atomRank: 1) + tail call void @f(), !dbg !DILocation(line: 9, scope: !11, atomGroup: 5, atomRank: 1) + ret i32 %y, !dbg !DILocation(line: 10, scope: !11) +} + +declare void @f() local_unnamed_addr +declare i32 @g() local_unnamed_addr + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!2, !3} +!llvm.ident = !{!10} + +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_17, file: !1, producer: "clang version 19.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: LineTablesOnly, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "test.cpp", directory: "/") +!2 = !{i32 7, !"Dwarf Version", i32 5} +!3 = !{i32 2, !"Debug Info Version", i32 3} +!10 = !{!"clang version 19.0.0"} +!11 = distinct !DISubprogram(name: "fun", scope: !1, file: !1, line: 1, type: !12, scopeLine: 1, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0) +!12 = !DISubroutineType(types: !13) +!13 = !{} diff --git a/llvm/test/DebugInfo/KeyInstructions/X86/dwarf-ranks-blocks.ll b/llvm/test/DebugInfo/KeyInstructions/X86/dwarf-ranks-blocks.ll new file mode 100644 index 0000000000000..cd840ecce07f5 --- /dev/null +++ b/llvm/test/DebugInfo/KeyInstructions/X86/dwarf-ranks-blocks.ll @@ -0,0 +1,65 @@ +; RUN: llc %s --filetype=obj -o - --dwarf-use-key-instructions \ +; RUN: | llvm-objdump -d - --no-show-raw-insn \ +; RUN: | FileCheck %s --check-prefix=OBJ + +; RUN: llc %s --filetype=obj -o - --dwarf-use-key-instructions \ +; RUN: | llvm-dwarfdump - --debug-line \ +; RUN: | FileCheck %s --check-prefix=DBG + +;; Hand written. The stores and add are in the same atom group. Check that, +;; despite each instruction belonging to a separate block, the stores (line 3) +;; get is_stmt (both rank 1) and the add (line 2) does not (it's rank 2). + +; OBJ: 16: addl %ebp, %ebx +; OBJ-NEXT: 18: testb $0x1, %r15b +; OBJ-NEXT: 1c: je 0x23 <_Z1fPiii+0x23> +; OBJ-NEXT: 1e: movl %ebx, (%r14) +; OBJ-NEXT: 21: jmp 0x26 <_Z1fPiii+0x26> +; OBJ-NEXT: 23: movl %ebp, (%r14) + +; DBG: Address Line Column File ISA Discriminator OpIndex Flags +; DBG-NEXT: ------------------ ------ ------ ------ --- ------------- ------- ------------- +; DBG-NEXT: 0x0000000000000000 1 0 0 0 0 0 is_stmt +; DBG-NEXT: 0x0000000000000011 1 0 0 0 0 0 is_stmt prologue_end +;; The add: no is_stmt +; DBG-NEXT: 0x0000000000000016 2 0 0 0 0 0 +; DBG-NEXT: 0x0000000000000018 1 0 0 0 0 0 +;; Both stores: is_stmt +; DBG-NEXT: 0x000000000000001e 3 0 0 0 0 0 is_stmt +; DBG-NEXT: 0x0000000000000023 3 0 0 0 0 0 is_stmt +; DBG-NEXT: 0x0000000000000026 1 0 0 0 0 0 +; DBG-NEXT: 0x0000000000000028 1 0 0 0 0 0 epilogue_begin +; DBG-NEXT: 0x0000000000000033 1 0 0 0 0 0 end_sequence + +target triple = "x86_64-unknown-linux-gnu" + +define hidden noundef i32 @_Z1fPiii(ptr %a, i32 %b, i32 %c, i1 %cond) local_unnamed_addr !dbg !11 { +entry: + tail call void @_Z12prologue_endv(), !dbg !DILocation(line: 1, scope: !11) + %add = add nsw i32 %c, %b, !dbg !DILocation(line: 2, scope: !11, atomGroup: 1, atomRank: 2) + br i1 %cond, label %bb1, label %bb2, !dbg !DILocation(line: 1, scope: !11) + +bb1: + store i32 %add, ptr %a, align 4, !dbg !DILocation(line: 3, scope: !11, atomGroup: 1, atomRank: 1) + ret i32 %add, !dbg !DILocation(line: 1, scope: !11) + +bb2: + store i32 %b, ptr %a, align 4, !dbg !DILocation(line: 3, scope: !11, atomGroup: 1, atomRank: 1) + store i32 %c, ptr %a, align 4, !dbg !DILocation(line: 3, scope: !11, atomGroup: 1, atomRank: 1) + ret i32 %add, !dbg !DILocation(line: 1, scope: !11) +} + +declare void @_Z12prologue_endv() local_unnamed_addr #1 + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!2, !3} +!llvm.ident = !{!10} + +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_17, file: !1, producer: "clang version 19.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: LineTablesOnly, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "test.cpp", directory: "/") +!2 = !{i32 7, !"Dwarf Version", i32 5} +!3 = !{i32 2, !"Debug Info Version", i32 3} +!10 = !{!"clang version 19.0.0"} +!11 = distinct !DISubprogram(name: "f", scope: !1, file: !1, line: 1, type: !12, scopeLine: 1, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0) +!12 = !DISubroutineType(types: !13) +!13 = !{} From 3b8ef1a64088d1f89840ae609de8e78e31bc0298 Mon Sep 17 00:00:00 2001 From: Orlando Cazalet-Hyams Date: Thu, 8 May 2025 15:24:26 +0100 Subject: [PATCH 02/14] format --- llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp index 792441607eec2..a1de323ec322d 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -2417,7 +2417,8 @@ void DwarfDebug::findKeyInstructions(const MachineFunction *MF) { uint8_t Rank = MI.getDebugLoc()->getAtomRank(); if (Group && Rank) { auto *InlinedAt = MI.getDebugLoc()->getInlinedAt(); - auto &[CandidateRank, CandidateInsts] = GroupCandidates[{InlinedAt, Group}]; + auto &[CandidateRank, CandidateInsts] = + GroupCandidates[{InlinedAt, Group}]; // This looks similar to the non-call handling code, except that // we don't put the call into CandidateInsts so that they can't be @@ -2475,7 +2476,8 @@ void DwarfDebug::findKeyInstructions(const MachineFunction *MF) { BuoyAtom = MI.getDebugLoc()->getAtomGroup(); } - auto &[CandidateRank, CandidateInsts] = GroupCandidates[{InlinedAt, Group}]; + auto &[CandidateRank, CandidateInsts] = + GroupCandidates[{InlinedAt, Group}]; if (CandidateRank == 0) { // This is the first time we're seeing an instruction in this atom From f9cca03779c1be0c27a504a18132a3d1be5e7275 Mon Sep 17 00:00:00 2001 From: Orlando Cazalet-Hyams Date: Thu, 8 May 2025 15:40:38 +0100 Subject: [PATCH 03/14] nits --- llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp | 90 ++++++++++--------- llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h | 6 +- .../KeyInstructions/X86/dwarf-calls.ll | 2 +- 3 files changed, 50 insertions(+), 48 deletions(-) diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp index a1de323ec322d..0703dff0cfeca 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -2357,7 +2357,7 @@ DwarfDebug::emitInitialLocDirective(const MachineFunction &MF, unsigned CUID) { return PrologEndLoc; } -void DwarfDebug::findKeyInstructions(const MachineFunction *MF) { +void DwarfDebug::computeKeyInstructions(const MachineFunction *MF) { // New function - reset KeyInstructions. KeyInstructions.clear(); @@ -2396,7 +2396,7 @@ void DwarfDebug::findKeyInstructions(const MachineFunction *MF) { if (!MI.getDebugLoc() || !MI.getDebugLoc().getLine()) continue; - // Reset the Buoy to this instruciton if it has a different line number. + // Reset the Buoy to this instruction if it has a different line number. if (!Buoy || Buoy->getDebugLoc().getLine() != MI.getDebugLoc().getLine()) { Buoy = &MI; @@ -2415,52 +2415,54 @@ void DwarfDebug::findKeyInstructions(const MachineFunction *MF) { uint64_t Group = MI.getDebugLoc()->getAtomGroup(); uint8_t Rank = MI.getDebugLoc()->getAtomRank(); - if (Group && Rank) { - auto *InlinedAt = MI.getDebugLoc()->getInlinedAt(); - auto &[CandidateRank, CandidateInsts] = - GroupCandidates[{InlinedAt, Group}]; - - // This looks similar to the non-call handling code, except that - // we don't put the call into CandidateInsts so that they can't be - // made un-key. As a result, we also have to take special care not - // to erase the is_stmt from the buoy, and prevent that happening - // in the future. - - if (CandidateRank == Rank) { - // We've seen other instructions in this group of this rank. Discard - // ones we've seen in this block, keep the others. - assert(!CandidateInsts.empty()); - SmallVector Insts; - Insts.reserve(CandidateInsts.size()); - for (auto &PrevInst : CandidateInsts) { - if (PrevInst->getParent() != MI.getParent()) - Insts.push_back(PrevInst); - else if (PrevInst != Buoy) - KeyInstructions.erase(PrevInst); - } - - if (Insts.empty()) { - CandidateInsts.clear(); - CandidateRank = 0; - } else { - CandidateInsts = std::move(Insts); - } - - } else if (CandidateRank > Rank) { - // We've seen other instructions in this group of lower precedence - // (higher rank). Discard them. - for (auto *Supplanted : CandidateInsts) { - // Don't erase the is_stmt we're using for this call. - if (Supplanted != Buoy) - KeyInstructions.erase(Supplanted); - } + if (!Group || !Rank) { + Buoy = nullptr; // Avoid floating any future is_stmts up to the call. + continue; + } + + auto *InlinedAt = MI.getDebugLoc()->getInlinedAt(); + auto &[CandidateRank, CandidateInsts] = + GroupCandidates[{InlinedAt, Group}]; + + // This looks similar to the non-call handling code, except that + // we don't put the call into CandidateInsts so that they can't be + // made un-key. As a result, we also have to take special care not + // to erase the is_stmt from the buoy, and prevent that happening + // in the future. + + if (CandidateRank == Rank) { + // We've seen other instructions in this group of this rank. Discard + // ones we've seen in this block, keep the others. + assert(!CandidateInsts.empty()); + SmallVector Insts; + Insts.reserve(CandidateInsts.size()); + for (auto &PrevInst : CandidateInsts) { + if (PrevInst->getParent() != MI.getParent()) + Insts.push_back(PrevInst); + else if (PrevInst != Buoy) + KeyInstructions.erase(PrevInst); + } + + if (Insts.empty()) { CandidateInsts.clear(); CandidateRank = 0; + } else { + CandidateInsts = std::move(Insts); + } + + } else if (CandidateRank > Rank) { + // We've seen other instructions in this group of lower precedence + // (higher rank). Discard them. + for (auto *Supplanted : CandidateInsts) { + // Don't erase the is_stmt we're using for this call. + if (Supplanted != Buoy) + KeyInstructions.erase(Supplanted); } + CandidateInsts.clear(); + CandidateRank = 0; } - // Avoid floating any future is_stmts up to the call. - Buoy = nullptr; + Buoy = nullptr; // Avoid floating any future is_stmts up to the call. continue; } @@ -2682,7 +2684,7 @@ void DwarfDebug::beginFunctionImpl(const MachineFunction *MF) { *MF, Asm->OutStreamer->getContext().getDwarfCompileUnitID()); if (KeyInstructionsAreStmts) - findKeyInstructions(MF); + computeKeyInstructions(MF); else findForceIsStmtInstrs(MF); } diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h index cd232a8e94ecf..89813dcf0fdab 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h @@ -705,10 +705,10 @@ class DwarfDebug : public DebugHandlerBase { void findForceIsStmtInstrs(const MachineFunction *MF); - /// Find instructions which should get is_stmt applied because they implement - /// key functionality for a source atom, store results in + /// Compute instructions which should get is_stmt applied because they + /// implement key functionality for a source location atom, store results in /// DwarfDebug::KeyInstructions. - void findKeyInstructions(const MachineFunction *MF); + void computeKeyInstructions(const MachineFunction *MF); protected: /// Gather pre-function debug information. diff --git a/llvm/test/DebugInfo/KeyInstructions/X86/dwarf-calls.ll b/llvm/test/DebugInfo/KeyInstructions/X86/dwarf-calls.ll index 780374127707e..6f3640a40932a 100644 --- a/llvm/test/DebugInfo/KeyInstructions/X86/dwarf-calls.ll +++ b/llvm/test/DebugInfo/KeyInstructions/X86/dwarf-calls.ll @@ -44,7 +44,7 @@ ;; Check the 2nd call (line 4) gets is_stmt applied despite being part of group ;; 1 and having lower precedence than the add. Check that the add stil gets ;; is_stmt applied. -;; There are two is_stmt line 4 entries are is_stmt because we don't float +;; There are two is_stmt line 4 entries because we don't float ;; is_stmts up on the same line past other key instructions. The call is ;; key, so the add's is_stmt floats up to the movl on the same line, but ;; not past the call. From 2fb14b5f9bfa4c7e1eeb8791aa70892de018e30b Mon Sep 17 00:00:00 2001 From: Orlando Cazalet-Hyams Date: Thu, 8 May 2025 18:23:14 +0100 Subject: [PATCH 04/14] defer insertion into KeyInstructions - simplifies code --- llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp | 25 +++++++--------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp index 0703dff0cfeca..f4c7a83eaa697 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -2410,7 +2410,9 @@ void DwarfDebug::computeKeyInstructions(const MachineFunction *MF) { if (MI.isCall() || TII.isTailCall(MI)) { assert(MI.getDebugLoc() && "Unexpectedly missing DL"); - // Calls are always key. + // Calls are always key. Put the buoy (may not be the call) into + // KeyInstructions directly rather than the candidate map to avoid it + // being erased (and we may not have a group number for the call). KeyInstructions.insert(Buoy); uint64_t Group = MI.getDebugLoc()->getAtomGroup(); @@ -2426,10 +2428,7 @@ void DwarfDebug::computeKeyInstructions(const MachineFunction *MF) { // This looks similar to the non-call handling code, except that // we don't put the call into CandidateInsts so that they can't be - // made un-key. As a result, we also have to take special care not - // to erase the is_stmt from the buoy, and prevent that happening - // in the future. - + // made un-key. if (CandidateRank == Rank) { // We've seen other instructions in this group of this rank. Discard // ones we've seen in this block, keep the others. @@ -2439,8 +2438,6 @@ void DwarfDebug::computeKeyInstructions(const MachineFunction *MF) { for (auto &PrevInst : CandidateInsts) { if (PrevInst->getParent() != MI.getParent()) Insts.push_back(PrevInst); - else if (PrevInst != Buoy) - KeyInstructions.erase(PrevInst); } if (Insts.empty()) { @@ -2453,11 +2450,6 @@ void DwarfDebug::computeKeyInstructions(const MachineFunction *MF) { } else if (CandidateRank > Rank) { // We've seen other instructions in this group of lower precedence // (higher rank). Discard them. - for (auto *Supplanted : CandidateInsts) { - // Don't erase the is_stmt we're using for this call. - if (Supplanted != Buoy) - KeyInstructions.erase(Supplanted); - } CandidateInsts.clear(); CandidateRank = 0; } @@ -2497,8 +2489,6 @@ void DwarfDebug::computeKeyInstructions(const MachineFunction *MF) { for (auto &PrevInst : CandidateInsts) { if (PrevInst->getParent() != MI.getParent()) Insts.push_back(PrevInst); - else - KeyInstructions.erase(PrevInst); } Insts.push_back(Buoy); CandidateInsts = std::move(Insts); @@ -2508,8 +2498,6 @@ void DwarfDebug::computeKeyInstructions(const MachineFunction *MF) { // (higher rank). Discard them, add this one. assert(!CandidateInsts.empty()); CandidateRank = Rank; - for (auto *Supplanted : CandidateInsts) - KeyInstructions.erase(Supplanted); CandidateInsts = {Buoy}; } else { @@ -2518,11 +2506,14 @@ void DwarfDebug::computeKeyInstructions(const MachineFunction *MF) { assert(Rank != 0 && CandidateRank < Rank && CandidateRank != 0); continue; } - KeyInstructions.insert(Buoy); assert(!BuoyAtom || BuoyAtom == MI.getDebugLoc()->getAtomGroup()); BuoyAtom = MI.getDebugLoc()->getAtomGroup(); } } + + for (const auto &[_, Insts] : GroupCandidates.values()) + for (auto *I : Insts) + KeyInstructions.insert(I); } /// For the function \p MF, finds the set of instructions which may represent a From 911905f9309dfbb302b89d8a13244daa6f83bf2b Mon Sep 17 00:00:00 2001 From: Orlando Cazalet-Hyams Date: Thu, 8 May 2025 18:44:56 +0100 Subject: [PATCH 05/14] simplfy by using use remove_if --- llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp | 29 +++++++--------------- 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp index f4c7a83eaa697..9f4301e217a3f 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -2433,19 +2433,12 @@ void DwarfDebug::computeKeyInstructions(const MachineFunction *MF) { // We've seen other instructions in this group of this rank. Discard // ones we've seen in this block, keep the others. assert(!CandidateInsts.empty()); - SmallVector Insts; - Insts.reserve(CandidateInsts.size()); - for (auto &PrevInst : CandidateInsts) { - if (PrevInst->getParent() != MI.getParent()) - Insts.push_back(PrevInst); - } - - if (Insts.empty()) { - CandidateInsts.clear(); + llvm::remove_if(CandidateInsts, [&MI](const MachineInstr *Candidate) { + return MI.getParent() == Candidate->getParent(); + }); + + if (CandidateInsts.empty()) CandidateRank = 0; - } else { - CandidateInsts = std::move(Insts); - } } else if (CandidateRank > Rank) { // We've seen other instructions in this group of lower precedence @@ -2484,14 +2477,10 @@ void DwarfDebug::computeKeyInstructions(const MachineFunction *MF) { // We've seen other instructions in this group of this rank. Discard // ones we've seen in this block, keep the others, add this one. assert(!CandidateInsts.empty()); - SmallVector Insts; - Insts.reserve(CandidateInsts.size() + 1); - for (auto &PrevInst : CandidateInsts) { - if (PrevInst->getParent() != MI.getParent()) - Insts.push_back(PrevInst); - } - Insts.push_back(Buoy); - CandidateInsts = std::move(Insts); + llvm::remove_if(CandidateInsts, [&MI](const MachineInstr *Candidate) { + return MI.getParent() == Candidate->getParent(); + }); + CandidateInsts.push_back(Buoy); } else if (CandidateRank > Rank) { // We've seen other instructions in this group of lower precedence From ed775f4c4a33f5a4168d304141ebd0bd5b3f42e0 Mon Sep 17 00:00:00 2001 From: Orlando Cazalet-Hyams Date: Thu, 8 May 2025 18:47:34 +0100 Subject: [PATCH 06/14] improve comments --- llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp index 9f4301e217a3f..cab3ca64f8c31 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -2370,12 +2370,14 @@ void DwarfDebug::computeKeyInstructions(const MachineFunction *MF) { // For each instruction: // * Skip insts without DebugLoc, AtomGroup or AtomRank, and line zeros. // * Check if insts in this group have been seen already in GroupCandidates. - // * If this instr rank is equal, add this instruction to KeyInstructions. - // Remove existing instructions from KeyInstructions if they have the + // * If this instr rank is equal, add this instruction to GroupCandidates. + // Remove existing instructions from GroupCandidates if they have the // same parent. // * If this instr rank is higher (lower precedence), ignore it. // * If this instr rank is lower (higher precedence), erase existing - // instructions from KeyInstructions. Add this instr to KeyInstructions. + // instructions from GroupCandidates and add this one. + // + // Then insert each GroupCandidates instruction into KeyInstructions. for (auto &MBB : *MF) { // Rather than apply is_stmt directly to Key Instructions, we "float" @@ -2400,7 +2402,7 @@ void DwarfDebug::computeKeyInstructions(const MachineFunction *MF) { if (!Buoy || Buoy->getDebugLoc().getLine() != MI.getDebugLoc().getLine()) { Buoy = &MI; - BuoyAtom = 0; + BuoyAtom = 0; // Set later when we know which atom the buoy is used by. } // Call instructions are handled specially - we always mark them as key From 2428132841bf0a747aa7a78ebeee497d0752e0b1 Mon Sep 17 00:00:00 2001 From: Orlando Cazalet-Hyams Date: Thu, 8 May 2025 19:04:00 +0100 Subject: [PATCH 07/14] simplify: sink common bits --- llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp index cab3ca64f8c31..b7aa6812e49f3 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -2472,8 +2472,6 @@ void DwarfDebug::computeKeyInstructions(const MachineFunction *MF) { // This is the first time we're seeing an instruction in this atom // group. Add it to the map. assert(CandidateInsts.empty()); - CandidateRank = Rank; - CandidateInsts.push_back(Buoy); } else if (CandidateRank == Rank) { // We've seen other instructions in this group of this rank. Discard @@ -2482,14 +2480,12 @@ void DwarfDebug::computeKeyInstructions(const MachineFunction *MF) { llvm::remove_if(CandidateInsts, [&MI](const MachineInstr *Candidate) { return MI.getParent() == Candidate->getParent(); }); - CandidateInsts.push_back(Buoy); } else if (CandidateRank > Rank) { // We've seen other instructions in this group of lower precedence // (higher rank). Discard them, add this one. assert(!CandidateInsts.empty()); - CandidateRank = Rank; - CandidateInsts = {Buoy}; + CandidateInsts.clear(); } else { // We've seen other instructions in this group with higher precedence @@ -2499,6 +2495,9 @@ void DwarfDebug::computeKeyInstructions(const MachineFunction *MF) { } assert(!BuoyAtom || BuoyAtom == MI.getDebugLoc()->getAtomGroup()); BuoyAtom = MI.getDebugLoc()->getAtomGroup(); + + CandidateInsts.push_back(Buoy); + CandidateRank = Rank; } } From 69938cf6919a6f23a49e098744e64a983cb2bfd8 Mon Sep 17 00:00:00 2001 From: Orlando Cazalet-Hyams Date: Thu, 8 May 2025 19:09:50 +0100 Subject: [PATCH 08/14] remove some now useless ctrl-flow, keeping asserts --- llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp index b7aa6812e49f3..260907e4cc711 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -2468,12 +2468,15 @@ void DwarfDebug::computeKeyInstructions(const MachineFunction *MF) { auto &[CandidateRank, CandidateInsts] = GroupCandidates[{InlinedAt, Group}]; - if (CandidateRank == 0) { - // This is the first time we're seeing an instruction in this atom - // group. Add it to the map. - assert(CandidateInsts.empty()); - - } else if (CandidateRank == Rank) { + // If CandidateRank is zero then CandidateInsts should be empty: there + // are no other candidates for this group yet. If CandidateRank is nonzero + // then CandidateInsts shouldn't be empty: we've got existing candidate + // instructions. + assert((CandidateRank == 0 && CandidateInsts.empty()) || + (CandidateRank != 0 && !CandidateInsts.empty())); + + assert(Rank && "expected nonzero rank"); + if (CandidateRank == Rank) { // We've seen other instructions in this group of this rank. Discard // ones we've seen in this block, keep the others, add this one. assert(!CandidateInsts.empty()); @@ -2487,12 +2490,13 @@ void DwarfDebug::computeKeyInstructions(const MachineFunction *MF) { assert(!CandidateInsts.empty()); CandidateInsts.clear(); - } else { + } else if (CandidateRank) { // We've seen other instructions in this group with higher precedence // (lower rank). Discard this one. assert(Rank != 0 && CandidateRank < Rank && CandidateRank != 0); continue; } + assert(!BuoyAtom || BuoyAtom == MI.getDebugLoc()->getAtomGroup()); BuoyAtom = MI.getDebugLoc()->getAtomGroup(); From 9854b9532944eafc3762edb6b522680ae5a58619 Mon Sep 17 00:00:00 2001 From: Orlando Cazalet-Hyams Date: Thu, 8 May 2025 19:15:39 +0100 Subject: [PATCH 09/14] simplify remaining ctrl-flow --- llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp | 32 ++++++++++------------ 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp index 260907e4cc711..5f2d7b465c399 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -2476,32 +2476,28 @@ void DwarfDebug::computeKeyInstructions(const MachineFunction *MF) { (CandidateRank != 0 && !CandidateInsts.empty())); assert(Rank && "expected nonzero rank"); - if (CandidateRank == Rank) { - // We've seen other instructions in this group of this rank. Discard - // ones we've seen in this block, keep the others, add this one. - assert(!CandidateInsts.empty()); + // If we've seen other instructions in this group with higher precedence + // (lower nonzero rank), don't add this one as a candidate. + if (CandidateRank && CandidateRank < Rank) + continue; + + // If we've seen other instructions in this group of the same rank, + // discard any from this block (keeping the others). Else if we've + // seen other instructions in this group of lower precedence (higher + // rank), discard them all. + if (CandidateRank == Rank) llvm::remove_if(CandidateInsts, [&MI](const MachineInstr *Candidate) { return MI.getParent() == Candidate->getParent(); }); - - } else if (CandidateRank > Rank) { - // We've seen other instructions in this group of lower precedence - // (higher rank). Discard them, add this one. - assert(!CandidateInsts.empty()); + else if (CandidateRank > Rank) CandidateInsts.clear(); - } else if (CandidateRank) { - // We've seen other instructions in this group with higher precedence - // (lower rank). Discard this one. - assert(Rank != 0 && CandidateRank < Rank && CandidateRank != 0); - continue; - } + // Add this candidate. + CandidateInsts.push_back(Buoy); + CandidateRank = Rank; assert(!BuoyAtom || BuoyAtom == MI.getDebugLoc()->getAtomGroup()); BuoyAtom = MI.getDebugLoc()->getAtomGroup(); - - CandidateInsts.push_back(Buoy); - CandidateRank = Rank; } } From 317d98b0b028ea293a01da56e8e3150f9cdb015a Mon Sep 17 00:00:00 2001 From: Orlando Cazalet-Hyams Date: Thu, 8 May 2025 19:21:47 +0100 Subject: [PATCH 10/14] simplify call handling --- llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp | 60 ++++++++-------------- 1 file changed, 21 insertions(+), 39 deletions(-) diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp index 5f2d7b465c399..9069def6b96ec 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -2409,7 +2409,8 @@ void DwarfDebug::computeKeyInstructions(const MachineFunction *MF) { // regardless of atom info. const auto &TII = *MI.getParent()->getParent()->getSubtarget().getInstrInfo(); - if (MI.isCall() || TII.isTailCall(MI)) { + bool IsCallLike = MI.isCall() || TII.isTailCall(MI); + if (IsCallLike) { assert(MI.getDebugLoc() && "Unexpectedly missing DL"); // Calls are always key. Put the buoy (may not be the call) into @@ -2417,40 +2418,13 @@ void DwarfDebug::computeKeyInstructions(const MachineFunction *MF) { // being erased (and we may not have a group number for the call). KeyInstructions.insert(Buoy); - uint64_t Group = MI.getDebugLoc()->getAtomGroup(); - uint8_t Rank = MI.getDebugLoc()->getAtomRank(); - if (!Group || !Rank) { - Buoy = nullptr; // Avoid floating any future is_stmts up to the call. - continue; - } - - auto *InlinedAt = MI.getDebugLoc()->getInlinedAt(); - auto &[CandidateRank, CandidateInsts] = - GroupCandidates[{InlinedAt, Group}]; - - // This looks similar to the non-call handling code, except that - // we don't put the call into CandidateInsts so that they can't be - // made un-key. - if (CandidateRank == Rank) { - // We've seen other instructions in this group of this rank. Discard - // ones we've seen in this block, keep the others. - assert(!CandidateInsts.empty()); - llvm::remove_if(CandidateInsts, [&MI](const MachineInstr *Candidate) { - return MI.getParent() == Candidate->getParent(); - }); - - if (CandidateInsts.empty()) - CandidateRank = 0; - - } else if (CandidateRank > Rank) { - // We've seen other instructions in this group of lower precedence - // (higher rank). Discard them. - CandidateInsts.clear(); - CandidateRank = 0; - } + // Avoid floating any future is_stmts up to the call. + Buoy = nullptr; + BuoyAtom = 0; - Buoy = nullptr; // Avoid floating any future is_stmts up to the call. - continue; + if (!MI.getDebugLoc()->getAtomGroup() || + !MI.getDebugLoc()->getAtomRank()) + continue; } auto *InlinedAt = MI.getDebugLoc()->getInlinedAt(); @@ -2492,12 +2466,20 @@ void DwarfDebug::computeKeyInstructions(const MachineFunction *MF) { else if (CandidateRank > Rank) CandidateInsts.clear(); - // Add this candidate. - CandidateInsts.push_back(Buoy); - CandidateRank = Rank; + if (Buoy) { + // Add this candidate. + CandidateInsts.push_back(Buoy); + CandidateRank = Rank; - assert(!BuoyAtom || BuoyAtom == MI.getDebugLoc()->getAtomGroup()); - BuoyAtom = MI.getDebugLoc()->getAtomGroup(); + assert(!BuoyAtom || BuoyAtom == MI.getDebugLoc()->getAtomGroup()); + BuoyAtom = MI.getDebugLoc()->getAtomGroup(); + } else { + // Don't add calls, because they've been dealt with already. This means + // CandidateInsts might now be empty - handle that. + assert(IsCallLike); + if (CandidateInsts.empty()) + CandidateRank = 0; + } } } From 80b8bb4ce6569c2d9ff9548b2ad505d2e8a19091 Mon Sep 17 00:00:00 2001 From: Orlando Cazalet-Hyams Date: Fri, 9 May 2025 12:16:41 +0100 Subject: [PATCH 11/14] Update llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp review nit, use `Group`, "Avoids the appearance that this could be different from the one earlier." Co-authored-by: Jeremy Morse --- llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp index 9069def6b96ec..fe6bdce228906 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -2436,7 +2436,7 @@ void DwarfDebug::computeKeyInstructions(const MachineFunction *MF) { // Don't let is_stmts float past instructions from different source atoms. if (BuoyAtom && BuoyAtom != Group) { Buoy = &MI; - BuoyAtom = MI.getDebugLoc()->getAtomGroup(); + BuoyAtom = Group; } auto &[CandidateRank, CandidateInsts] = From a1ae08ed1e7f08045657b61a51647287f1671bc4 Mon Sep 17 00:00:00 2001 From: Orlando Cazalet-Hyams Date: Fri, 9 May 2025 13:00:54 +0100 Subject: [PATCH 12/14] fix line entries not folding together properly --- llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp | 2 +- .../KeyInstructions/X86/dwarf-buoy-multi-key.mir | 5 +---- llvm/test/DebugInfo/KeyInstructions/X86/dwarf-calls.ll | 9 +++------ 3 files changed, 5 insertions(+), 11 deletions(-) diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp index fe6bdce228906..95cac03c446b4 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -2092,7 +2092,7 @@ void DwarfDebug::beginInstruction(const MachineInstr *MI) { (!PrevInstBB || PrevInstBB->getSectionID() == MI->getParent()->getSectionID()); bool ForceIsStmt = ForceIsStmtInstrs.contains(MI); - if (DL == PrevInstLoc && PrevInstInSameSection && !ForceIsStmt) { + if (PrevInstInSameSection && !ForceIsStmt && DL.isSameSourceLocation(PrevInstLoc)) { // If we have an ongoing unspecified location, nothing to do here. if (!DL) return; diff --git a/llvm/test/DebugInfo/KeyInstructions/X86/dwarf-buoy-multi-key.mir b/llvm/test/DebugInfo/KeyInstructions/X86/dwarf-buoy-multi-key.mir index c8459b4ced600..3b7d5850e7e83 100644 --- a/llvm/test/DebugInfo/KeyInstructions/X86/dwarf-buoy-multi-key.mir +++ b/llvm/test/DebugInfo/KeyInstructions/X86/dwarf-buoy-multi-key.mir @@ -21,10 +21,7 @@ # DBG-NEXT: ------------------ ------ ------ ------ --- ------------- ------- ------------- # DBG-NEXT: 0x0000000000000000 1 0 0 0 0 0 is_stmt prologue_end # DBG-NEXT: 0x0000000000000005 2 0 0 0 0 0 is_stmt -# DBG-NEXT: 0x000000000000000a 2 0 0 0 0 0 -# DBG-NEXT: 0x000000000000000f 2 0 0 0 0 0 -# DBG-NEXT: 0x0000000000000014 2 0 0 0 0 0 -# DBG-NEXT: 0x0000000000000019 2 0 0 0 0 0 +# DBG-NEXT: 0x0000000000000019 2 0 0 0 0 0 is_stmt # DBG-NEXT: 0x000000000000001e 2 0 0 0 0 0 is_stmt # DBG-NEXT: 0x0000000000000023 2 0 0 0 0 0 is_stmt # DBG-NEXT: 0x0000000000000029 2 0 0 0 0 0 is_stmt end_sequence diff --git a/llvm/test/DebugInfo/KeyInstructions/X86/dwarf-calls.ll b/llvm/test/DebugInfo/KeyInstructions/X86/dwarf-calls.ll index 6f3640a40932a..14dfa8a6a9ccb 100644 --- a/llvm/test/DebugInfo/KeyInstructions/X86/dwarf-calls.ll +++ b/llvm/test/DebugInfo/KeyInstructions/X86/dwarf-calls.ll @@ -50,23 +50,20 @@ ;; not past the call. ; DBG-NEXT: 0x0000000000000012 4 0 0 0 0 0 is_stmt ; DBG-NEXT: 0x0000000000000017 4 0 0 0 0 0 is_stmt -; DBG-NEXT: 0x0000000000000019 4 0 0 0 0 0 ;; Test C: -;; Check that is_stmt floats up from the call to the store. +;; Check that is_stmt floats up from the call (0x29) to the store (0x1b). ; DBG-NEXT: 0x000000000000001b 5 0 0 0 0 0 is_stmt -; DBG-NEXT: 0x0000000000000029 5 0 0 0 0 0 ;; Test D: -;; Check the is_stmt is not applied to the lower ranking instruction. +;; Check the is_stmt is not applied to the lower ranking instruction (0x2e). ; DBG-NEXT: 0x000000000000002e 6 0 0 0 0 0 ; DBG-NEXT: 0x0000000000000035 7 0 0 0 0 0 is_stmt ;; Test E: ;; Check the is_stmt floats up to an instruction in the same group of the same -;; or lower precedence. +;; or lower precedence (from call, 0x41, to `store 3`, 0x3a). ; DBG-NEXT: 0x000000000000003a 8 0 0 0 0 0 is_stmt -; DBG-NEXT: 0x0000000000000041 8 0 0 0 0 0 ; DBG-NEXT: 0x0000000000000046 9 0 0 0 0 0 is_stmt ; DBG-NEXT: 0x0000000000000052 10 0 0 0 0 0 From 8c67d683f23d88319e865605369803549ab3fae6 Mon Sep 17 00:00:00 2001 From: Orlando Cazalet-Hyams Date: Fri, 9 May 2025 13:06:11 +0100 Subject: [PATCH 13/14] shuffle input source comment around in tests --- .../KeyInstructions/X86/dwarf-basic-ranks.ll | 23 +++++++++--------- .../KeyInstructions/X86/dwarf-basic.ll | 24 +++++++++---------- 2 files changed, 24 insertions(+), 23 deletions(-) diff --git a/llvm/test/DebugInfo/KeyInstructions/X86/dwarf-basic-ranks.ll b/llvm/test/DebugInfo/KeyInstructions/X86/dwarf-basic-ranks.ll index 71ecf1dc41238..6988a6fb2ec3f 100644 --- a/llvm/test/DebugInfo/KeyInstructions/X86/dwarf-basic-ranks.ll +++ b/llvm/test/DebugInfo/KeyInstructions/X86/dwarf-basic-ranks.ll @@ -6,6 +6,18 @@ ; RUN: | llvm-dwarfdump - --debug-line \ ; RUN: | FileCheck %s --check-prefix=DBG +;; 1. [[gnu::nodebug]] void prologue_end(); +;; 2. +;; 3. int f(int *a, int b, int c) { +;; 4. prologue_end(); +;; 5. *a = +;; 6. b + c; +;; 7. return *a; +;; 8. } +;; +;; The add and store are in the same group (1). The add (line 6) has lower +;; precedence (rank 2) so should not get is_stmt applied. + ; OBJ: 0000000000000000 <_Z1fPiii>: ; OBJ-NEXT: 0: pushq %rbp ; OBJ-NEXT: 1: pushq %r14 @@ -31,17 +43,6 @@ ; DBG-NEXT: 0x0000000000000017 7 0 0 0 0 0 epilogue_begin ; DBG-NEXT: 0x000000000000001c 7 0 0 0 0 0 end_sequence -;; 1. [[gnu::nodebug]] void prologue_end(); -;; 2. -;; 3. int f(int *a, int b, int c) { -;; 4. prologue_end(); -;; 5. *a = -;; 6. b + c; -;; 7. return *a; -;; 8. } - -;; The add and store are in the same goup (1). The add (line 6) has lower -;; precedence (rank 2) so should not get is_stmt applied. target triple = "x86_64-unknown-linux-gnu" define hidden noundef i32 @_Z1fPiii(ptr %a, i32 %b, i32 %c) local_unnamed_addr !dbg !11 { diff --git a/llvm/test/DebugInfo/KeyInstructions/X86/dwarf-basic.ll b/llvm/test/DebugInfo/KeyInstructions/X86/dwarf-basic.ll index e3b0184a837f8..ba38bb2ffe903 100644 --- a/llvm/test/DebugInfo/KeyInstructions/X86/dwarf-basic.ll +++ b/llvm/test/DebugInfo/KeyInstructions/X86/dwarf-basic.ll @@ -6,6 +6,18 @@ ; RUN: | llvm-dwarfdump - --debug-line \ ; RUN: | FileCheck %s --check-prefix=DBG +;; 1. int f(int a) { +;; 2. int x = a + 1; +;; 3. return x; +;; 4. } +;; 5. int g(int b) { +;; 6. return f(b); +;; 7. } +;; +;; Both functions contain 2 instructions in unique atom groups. In f we see +;; groups 1 and 3, and in g we see {!18, 1} and 1. All of these instructions +;; should get is_stmt. + ; OBJ: 0000000000000000 <_Z1fi>: ; OBJ-NEXT: 0: leal 0x1(%rdi), %eax ; OBJ-NEXT: 3: retq @@ -20,18 +32,6 @@ ; DBG-NEXT: 0x0000000000000010 2 0 0 0 0 0 is_stmt prologue_end ; DBG-NEXT: 0x0000000000000013 6 0 0 0 0 0 is_stmt -;; 1. int f(int a) { -;; 2. int x = a + 1; -;; 3. return x; -;; 4. } -;; 5. int g(int b) { -;; 6. return f(b); -;; 7. } -;; -;; Both functions contain 2 instructions in unique atom groups. In f we see -;; groups 1 and 3, and in g we see {!18, 1} and 1. All of these instructions -;; should get is_stmt. - target triple = "x86_64-unknown-linux-gnu" define hidden noundef i32 @_Z1fi(i32 noundef %a) local_unnamed_addr !dbg !11 { From 4e1c4b4674cf4c1b3e9237c16378aa1efe236ed4 Mon Sep 17 00:00:00 2001 From: Orlando Cazalet-Hyams Date: Tue, 13 May 2025 17:17:02 +0100 Subject: [PATCH 14/14] set smallvector inline-elements size --- llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp index 95cac03c446b4..00a46e8a1f487 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -2363,8 +2363,10 @@ void DwarfDebug::computeKeyInstructions(const MachineFunction *MF) { // The current candidate is_stmt instructions for each source atom. // Map {(InlinedAt, Group): (Rank, Instructions)}. + // NOTE: Anecdotally, for a large C++ blob, 99% of the instruction + // SmallVectors contain 2 or fewer elements; use 2 inline elements. DenseMap, - std::pair>> + std::pair>> GroupCandidates; // For each instruction: