Index: llvm/lib/CodeGen/AsmPrinter/DebugLocEntry.h =================================================================== --- llvm/lib/CodeGen/AsmPrinter/DebugLocEntry.h +++ llvm/lib/CodeGen/AsmPrinter/DebugLocEntry.h @@ -9,6 +9,7 @@ #ifndef LLVM_LIB_CODEGEN_ASMPRINTER_DEBUGLOCENTRY_H #define LLVM_LIB_CODEGEN_ASMPRINTER_DEBUGLOCENTRY_H +#include "AddressPool.h" #include "DebugLocStream.h" #include "llvm/Config/llvm-config.h" #include "llvm/IR/Constants.h" @@ -90,9 +91,9 @@ /// This struct describes location entries emitted in the .debug_loc /// section. class DebugLocEntry { - /// Begin and end symbols for the address range that this location is valid. - const MCSymbol *Begin; - const MCSymbol *End; + /// Beginning and end for the address range that this location is valid. + SymbolWithOffset Begin; + SymbolWithOffset End; /// A nonempty list of locations/constants belonging to this entry, /// sorted by offset. @@ -102,7 +103,7 @@ /// Create a location list entry for the range [\p Begin, \p End). /// /// \param Vals One or more values describing (parts of) the variable. - DebugLocEntry(const MCSymbol *Begin, const MCSymbol *End, + DebugLocEntry(const SymbolWithOffset &Begin, const SymbolWithOffset &End, ArrayRef Vals) : Begin(Begin), End(End) { addValues(Vals); @@ -121,8 +122,8 @@ return false; } - const MCSymbol *getBeginSym() const { return Begin; } - const MCSymbol *getEndSym() const { return End; } + SymbolWithOffset getBeginAddr() const { return Begin; } + SymbolWithOffset getEndAddr() const { return End; } ArrayRef getValues() const { return Values; } void addValues(ArrayRef Vals) { Values.append(Vals.begin(), Vals.end()); Index: llvm/lib/CodeGen/AsmPrinter/DebugLocStream.h =================================================================== --- llvm/lib/CodeGen/AsmPrinter/DebugLocStream.h +++ llvm/lib/CodeGen/AsmPrinter/DebugLocStream.h @@ -9,6 +9,7 @@ #ifndef LLVM_LIB_CODEGEN_ASMPRINTER_DEBUGLOCSTREAM_H #define LLVM_LIB_CODEGEN_ASMPRINTER_DEBUGLOCSTREAM_H +#include "AddressPool.h" #include "ByteStreamer.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallVector.h" @@ -38,8 +39,8 @@ : CU(CU), EntryOffset(EntryOffset) {} }; struct Entry { - const MCSymbol *Begin; - const MCSymbol *End; + SymbolWithOffset Begin; + SymbolWithOffset End; size_t ByteOffset; size_t CommentOffset; }; @@ -88,8 +89,8 @@ /// /// Until the next call, bytes added to the stream will be added to this /// entry. - void startEntry(const MCSymbol *BeginSym, const MCSymbol *EndSym) { - Entries.push_back({BeginSym, EndSym, DWARFBytes.size(), Comments.size()}); + void startEntry(const SymbolWithOffset &Begin, const SymbolWithOffset &End) { + Entries.push_back({Begin, End, DWARFBytes.size(), Comments.size()}); } /// Finalize a .debug_loc entry, deleting if it's empty. @@ -172,7 +173,8 @@ DebugLocStream &Locs; public: - EntryBuilder(ListBuilder &List, const MCSymbol *Begin, const MCSymbol *End) + EntryBuilder(ListBuilder &List, const SymbolWithOffset &Begin, + const SymbolWithOffset &End) : Locs(List.getLocs()) { Locs.startEntry(Begin, End); } Index: llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h =================================================================== --- llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h +++ llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h @@ -381,6 +381,10 @@ /// a monolithic sequence of string offsets. bool UseSegmentedStringOffsetsTable; + /// Whether to emit trimmed location list entries around calls for variables + /// that are described by call-clobbered registers. + bool TrimCallClobberedEntries; + /// Separated Dwarf Variables /// In general these will all be for bits that are left in the /// original object file, rather than things that are meant Index: llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp =================================================================== --- llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -388,6 +388,13 @@ // a monolithic string offsets table without any header. UseSegmentedStringOffsetsTable = DwarfVersion >= 5; + // GDB does not have knowledge about which registers that are caller-saved. + // Due to that we must emit shorter location list entries around calls for + // variables that are described by such registers, as those variables + // otherwise could be printed with incorrect register values when performing + // virtual unwinding (e.g. when printing backtraces). + TrimCallClobberedEntries = tuneForGDB(); + Asm->OutStreamer->getContext().setDwarfVersion(DwarfVersion); } @@ -1322,6 +1329,36 @@ return false; } +/// Returns true if the given value is described by a register that is +/// clobbered by a call. +static bool isCallClobberedRegValue(const DbgValueLoc &Value, + const MachineFunction *MF) { + if (!Value.isLocation() || !Value.getLoc().isReg()) + return false; + // Entry values are not clobbered by calls. + if (Value.getExpression()->isEntryValue()) + return false; + const TargetRegisterInfo &TRI = *MF->getSubtarget().getRegisterInfo(); + return !TRI.isCalleeSavedPhysReg(Value.getLoc().getReg(), *MF); +} + +/// Attempt to coalesce the ranges of the last two otherwise identical +/// DebugLocEntries. +static void +attemptMergeLastTwoEntries(SmallVectorImpl &DebugLoc) { + auto CurEntry = DebugLoc.rbegin(); + LLVM_DEBUG({ + dbgs() << CurEntry->getValues().size() << " Values:\n"; + for (auto &Value : CurEntry->getValues()) + Value.dump(); + dbgs() << "-----\n"; + }); + + auto PrevEntry = std::next(CurEntry); + if (PrevEntry != DebugLoc.rend() && PrevEntry->MergeRanges(*CurEntry)) + DebugLoc.pop_back(); +} + /// Build the location list for all DBG_VALUEs in the function that /// describe the same variable. The resulting DebugLocEntries will have /// strict monotonically increasing begin addresses and will never @@ -1431,24 +1468,56 @@ continue; } + SymbolWithOffset StartAddr{StartLabel, 0}; + SymbolWithOffset EndAddr{EndLabel, 0}; + SmallVector Values; for (auto &R : OpenRanges) Values.push_back(R.second); - DebugLoc.emplace_back(StartLabel, EndLabel, Values); - - // Attempt to coalesce the ranges of two otherwise identical - // DebugLocEntries. - auto CurEntry = DebugLoc.rbegin(); - LLVM_DEBUG({ - dbgs() << CurEntry->getValues().size() << " Values:\n"; - for (auto &Value : CurEntry->getValues()) - Value.dump(); - dbgs() << "-----\n"; - }); - auto PrevEntry = std::next(CurEntry); - if (PrevEntry != DebugLoc.rend() && PrevEntry->MergeRanges(*CurEntry)) - DebugLoc.pop_back(); + bool NextEntryIsClobberingCall = std::next(EI) != Entries.end() && + std::next(EI)->isClobber() && + std::next(EI)->getInstr()->isCall(); + + if (TrimCallClobberedEntries && NextEntryIsClobberingCall) { + // If the range ends at a call, and any of the values are described by + // call-clobbered registers, then create two location list entries; one + // for the range [Begin, End-1) where all values are included, and one + // for the range [End-1,End) where all call-clobbered fragments have been + // removed. + // + // When performing virtual unwinding, consumers such as GDB and LLDB + // subtract one byte from the return address to get the right scope of + // the call. We utilize that fact here to stop consumers that don't have + // explicit knowledge of caller-saved registers from considering entries + // expressed in those registers as valid when unwinding. GCC behaves in + // the same way. + + const MachineFunction *MF = Instr->getParent()->getParent(); + auto CallClobberedIt = partition(Values, [MF](DbgValueLoc R) { + return !isCallClobberedRegValue(R, MF); + }); + + // If any values are call-clobbered, then create a location list entry + // for the range [Begin, End-1]. + if (CallClobberedIt != Values.end()) { + SymbolWithOffset MidAddr{EndLabel, -1}; + DebugLoc.emplace_back(StartAddr, MidAddr, Values); + attemptMergeLastTwoEntries(DebugLoc); + + // If all values are call-clobbered, then do not create a location list + // entry for the range [End-1, End). + if (CallClobberedIt == Values.begin()) + continue; + StartAddr = MidAddr; + + // Remove all values that are call-clobbered. + Values.erase(CallClobberedIt, Values.end()); + } + } + + DebugLoc.emplace_back(StartAddr, EndAddr, Values); + attemptMergeLastTwoEntries(DebugLoc); } return DebugLoc.size() == 1 && isSafeForSingleLocation && @@ -2194,8 +2263,8 @@ DwarfCompileUnit &TheCU) { assert(!Values.empty() && "location list entries without values are redundant"); - assert(Begin != End && "unexpected location list entry with empty range"); - DebugLocStream::EntryBuilder Entry(List, Begin, End); + assert(!(Begin == End) && "unexpected location list entry with empty range"); + DebugLocStream::EntryBuilder Entry(List, getBeginAddr(), getEndAddr()); BufferByteStreamer Streamer = Entry.getStreamer(); DebugLocDwarfExpression DwarfExpr(AP.getDwarfVersion(), Streamer, TheCU); const DbgValueLoc &Value = Values[0]; @@ -2293,6 +2362,71 @@ return TableEnd; } +/// Create an expression for the given symbol + offset. +static const MCExpr *getSymWithOffsetExpr(SymbolWithOffset SymWithOffs, + AsmPrinter *Asm) { + const MCSymbolRefExpr *SymRef = MCSymbolRefExpr::create( + SymWithOffs.Symbol, Asm->OutStreamer->getContext()); + + if (SymWithOffs.Offset == 0) + return SymRef; + + const auto Offset = MCConstantExpr::create(abs(SymWithOffs.Offset), + Asm->OutStreamer->getContext()); + auto Op = SymWithOffs.Offset < 0 ? MCBinaryExpr::Sub : MCBinaryExpr::Add; + return MCBinaryExpr::create(Op, SymRef, Offset, + Asm->OutStreamer->getContext()); +} + +/// Emit the offsetted symbol. +static void emitSymWithOffset(SymbolWithOffset SymWithOffs, unsigned char Size, + AsmPrinter *Asm) { + if (SymWithOffs.Offset == 0) { + Asm->OutStreamer->EmitSymbolValue(SymWithOffs.Symbol, Size); + return; + } + + auto Expr = getSymWithOffsetExpr(SymWithOffs, Asm); + Asm->OutStreamer->EmitValue(Expr, Size); +} + +/// Create an expression for the difference between the two offsetted symbols. +static const MCExpr *getSymWithOffsetDifference(SymbolWithOffset End, + SymbolWithOffset Begin, + AsmPrinter *Asm) { + auto EndExpr = getSymWithOffsetExpr(End, Asm); + auto BeginExpr = getSymWithOffsetExpr(Begin, Asm); + + return MCBinaryExpr::createSub(EndExpr, BeginExpr, + Asm->OutStreamer->getContext()); +} + +/// Emit the difference between the two offsetted symbols. +static void emitSymWithOffsetDifference(SymbolWithOffset End, + SymbolWithOffset Begin, + unsigned char Size, AsmPrinter *Asm) { + if (End.Offset == 0 && Begin.Offset == 0) { + Asm->EmitLabelDifference(End.Symbol, Begin.Symbol, Size); + return; + } + + const MCExpr *Diff = getSymWithOffsetDifference(End, Begin, Asm); + Asm->OutStreamer->EmitValue(Diff, Size); +} + +/// Emit the difference between the two offsetted symbols in ULEB128. +static void emitSymWithOffsetDifferenceULEB128(SymbolWithOffset End, + SymbolWithOffset Begin, + AsmPrinter *Asm) { + if (End.Offset == 0 && Begin.Offset == 0) { + Asm->EmitLabelDifferenceAsULEB128(End.Symbol, Begin.Symbol); + return; + } + + const MCExpr *Diff = getSymWithOffsetDifference(End, Begin, Asm); + Asm->OutStreamer->EmitULEB128Value(Diff); +} + // Emit locations into the .debug_loc/.debug_rnglists section. void DwarfDebug::emitDebugLoc() { if (DebugLocs.getLists().empty()) @@ -2315,9 +2449,9 @@ Asm->OutStreamer->EmitLabel(List.Label); const DwarfCompileUnit *CU = List.CU; - const MCSymbol *Base = CU->getBaseAddress(); + SymbolWithOffset Base{CU->getBaseAddress(), 0}; for (const auto &Entry : DebugLocs.getEntries(List)) { - if (Base) { + if (Base.Symbol) { // Set up the range. This range is relative to the entry point of the // compile unit. This is a hard coded 0 for low_pc when we're emitting // ranges, or the DW_AT_low_pc on the compile unit otherwise. @@ -2325,12 +2459,12 @@ Asm->OutStreamer->AddComment("DW_LLE_offset_pair"); Asm->OutStreamer->EmitIntValue(dwarf::DW_LLE_offset_pair, 1); Asm->OutStreamer->AddComment(" starting offset"); - Asm->EmitLabelDifferenceAsULEB128(Entry.Begin, Base); + emitSymWithOffsetDifferenceULEB128(Entry.Begin, Base, Asm); Asm->OutStreamer->AddComment(" ending offset"); - Asm->EmitLabelDifferenceAsULEB128(Entry.End, Base); + emitSymWithOffsetDifferenceULEB128(Entry.End, Base, Asm); } else { - Asm->EmitLabelDifference(Entry.Begin, Base, Size); - Asm->EmitLabelDifference(Entry.End, Base, Size); + emitSymWithOffsetDifference(Entry.Begin, Base, Size, Asm); + emitSymWithOffsetDifference(Entry.End, Base, Size, Asm); } emitDebugLocEntryLocation(Entry, CU); @@ -2348,10 +2482,10 @@ Asm->OutStreamer->AddComment(" start idx"); Asm->EmitULEB128(AddrPool.getIndex(Entry.Begin)); Asm->OutStreamer->AddComment(" length"); - Asm->EmitLabelDifferenceAsULEB128(Entry.End, Entry.Begin); + emitSymWithOffsetDifferenceULEB128(Entry.End, Entry.Begin, Asm); } else { - Asm->OutStreamer->EmitSymbolValue(Entry.Begin, Size); - Asm->OutStreamer->EmitSymbolValue(Entry.End, Size); + emitSymWithOffset(Entry.Begin, Size, Asm); + emitSymWithOffset(Entry.End, Size, Asm); } emitDebugLocEntryLocation(Entry, CU); @@ -2388,7 +2522,7 @@ Asm->emitInt8(dwarf::DW_LLE_startx_length); unsigned idx = AddrPool.getIndex(Entry.Begin); Asm->EmitULEB128(idx); - Asm->EmitLabelDifference(Entry.End, Entry.Begin, 4); + emitSymWithOffsetDifference(Entry.End, Entry.Begin, 4, Asm); emitDebugLocEntryLocation(Entry, List.CU); } Index: llvm/test/DebugInfo/MIR/ARM/param-reg-const-mix.mir =================================================================== --- llvm/test/DebugInfo/MIR/ARM/param-reg-const-mix.mir +++ llvm/test/DebugInfo/MIR/ARM/param-reg-const-mix.mir @@ -91,6 +91,6 @@ # terminate the non-overlapping fragment that is described by $r1. # CHECK: DW_AT_location (0x00000000 -# CHECK-NEXT: [0x00000008, 0x00000010): DW_OP_reg4 R4, DW_OP_piece 0x4, DW_OP_reg1 R1, DW_OP_piece 0x4 -# CHECK-NEXT: [0x00000010, 0x00000024): DW_OP_reg4 R4, DW_OP_piece 0x4) +# CHECK-NEXT: [0x00000008, 0x0000000f): DW_OP_reg4 R4, DW_OP_piece 0x4, DW_OP_reg1 R1, DW_OP_piece 0x4 +# CHECK-NEXT: [0x0000000f, 0x00000024): DW_OP_reg4 R4, DW_OP_piece 0x4) # CHECK-NEXT: DW_AT_name ("p1") Index: llvm/test/DebugInfo/MIR/X86/call-clobbered-entry-value.mir =================================================================== --- /dev/null +++ llvm/test/DebugInfo/MIR/X86/call-clobbered-entry-value.mir @@ -0,0 +1,109 @@ +# RUN: %llc_dwarf -start-after=livedebugvalues -debug-entry-values -filetype=obj %s -o - | llvm-dwarfdump - | FileCheck %s + +# Verify that the entry value in param's location list is not considered +# clobbered by the call to bar(). + +# Reproducer based on the following C file: +# +# extern void bar(int); +# extern int global; +# void foo(int param) { +# if (global) +# bar(1); +# } +# +# Compiled using -O2 -g -Xclang -femit-debug-entry-values. + +--- | + target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" + target triple = "x86_64" + + @global = external dso_local local_unnamed_addr global i32, align 4 + + ; Function Attrs: nounwind + define dso_local void @foo(i32 %param) local_unnamed_addr #0 !dbg !12 { + entry: + call void @llvm.dbg.value(metadata i32 %param, metadata !14, metadata !DIExpression()), !dbg !15 + %0 = load i32, i32* @global, align 4, !dbg !16 + %tobool = icmp eq i32 %0, 0, !dbg !16 + br i1 %tobool, label %if.end, label %if.then, !dbg !18 + + if.then: ; preds = %entry + tail call void @bar(i32 1), !dbg !19 + ret void, !dbg !20 + + if.end: ; preds = %entry + ret void, !dbg !20 + } + + declare !dbg !4 dso_local void @bar(i32) local_unnamed_addr + + ; Function Attrs: nounwind readnone speculatable willreturn + declare void @llvm.dbg.value(metadata, metadata, metadata) + + attributes #0 = { "frame-pointer"="all" } + + !llvm.dbg.cu = !{!0} + !llvm.module.flags = !{!8, !9, !10} + !llvm.ident = !{!11} + + !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, nameTableKind: None) + !1 = !DIFile(filename: "x86.c", directory: "/") + !2 = !{} + !3 = !{!4} + !4 = !DISubprogram(name: "bar", scope: !1, file: !1, line: 1, type: !5, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !2) + !5 = !DISubroutineType(types: !6) + !6 = !{null, !7} + !7 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) + !8 = !{i32 2, !"Dwarf Version", i32 4} + !9 = !{i32 2, !"Debug Info Version", i32 3} + !10 = !{i32 1, !"wchar_size", i32 4} + !11 = !{!"clang version 10.0.0"} + !12 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 3, type: !5, scopeLine: 3, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !13) + !13 = !{!14} + !14 = !DILocalVariable(name: "param", arg: 1, scope: !12, file: !1, line: 3, type: !7, flags: DIFlagArgumentNotModified) + !15 = !DILocation(line: 0, scope: !12) + !16 = !DILocation(line: 4, scope: !17) + !17 = distinct !DILexicalBlock(scope: !12, file: !1, line: 4) + !18 = !DILocation(line: 4, scope: !12) + !19 = !DILocation(line: 5, scope: !17) + !20 = !DILocation(line: 6, scope: !12) + +... +--- +name: foo +tracksRegLiveness: true +callSites: + - { bb: 1, offset: 5, fwdArgRegs: + - { arg: 0, reg: '$edi' } } +body: | + bb.0.entry: + successors: %bb.1(0x30000000), %bb.2(0x50000000) + + DBG_VALUE $edi, $noreg, !14, !DIExpression(), debug-location !15 + frame-setup PUSH64r killed $rbp, implicit-def $rsp, implicit $rsp + CFI_INSTRUCTION def_cfa_offset 16 + CFI_INSTRUCTION offset $rbp, -16 + $rbp = frame-setup MOV64rr $rsp + CFI_INSTRUCTION def_cfa_register $rbp + CMP32mi8 $rip, 1, $noreg, @global, $noreg, 0, implicit-def $eflags, debug-location !16 :: (dereferenceable load 4 from @global) + JCC_1 %bb.1, 4, implicit $eflags, debug-location !18 + + bb.2.if.then: + DBG_VALUE $edi, $noreg, !14, !DIExpression(), debug-location !15 + $edi = MOV32ri 1, debug-location !19 + DBG_VALUE $edi, $noreg, !14, !DIExpression(DW_OP_entry_value, 1), debug-location !15 + $rbp = frame-destroy POP64r implicit-def $rsp, implicit $rsp, debug-location !19 + CFI_INSTRUCTION def_cfa $rsp, 8, debug-location !19 + TAILJMPd64 @bar, csr_64, implicit $rsp, implicit $ssp, implicit $rsp, implicit $ssp, implicit killed $edi, debug-location !19 + + bb.1.if.end: + DBG_VALUE $edi, $noreg, !14, !DIExpression(), debug-location !15 + $rbp = frame-destroy POP64r implicit-def $rsp, implicit $rsp, debug-location !20 + CFI_INSTRUCTION def_cfa $rsp, 8, debug-location !20 + RETQ debug-location !20 + +... + +# CHECK: {{0x[0-9a-f]*}}, [[END:0x[0-9a-f]*]]): DW_OP_GNU_entry_value(DW_OP_reg5 RDI), DW_OP_stack_value +# CHECK-NEXT: [[END]], {{0x[0-9a-f]*}}): DW_OP_reg5 RDI) Index: llvm/test/DebugInfo/MIR/X86/call-clobbered-split.mir =================================================================== --- /dev/null +++ llvm/test/DebugInfo/MIR/X86/call-clobbered-split.mir @@ -0,0 +1,124 @@ +# RUN: %llc_dwarf -start-after=livedebugvalues -march=x86-64 -split-dwarf-file=foo.dwo -filetype=asm %s -o - | FileCheck %s + +# Reproducer based on the following C file: +# +# extern void fn2(int *); +# +# void fn1() { +# int data[] = {1, 2}; +# int *ptrs[] = {0, &data[1]}; +# fn2(ptrs[1]); +# ptrs[1] = 0; +# } +# +# Compiled using -O1 -g -gsplit-dwarf. + +--- | + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + target triple = "x86_64-unknown-linux-gnu" + + ; Function Attrs: nounwind uwtable + define void @fn1() !dbg !6 { + entry: + unreachable + } + + declare void @fn2(i32*) + + ; Function Attrs: nounwind readnone speculatable + declare void @llvm.dbg.value(metadata, metadata, metadata) #0 + + attributes #0 = { nounwind readnone speculatable } + + !llvm.dbg.cu = !{!0} + !llvm.module.flags = !{!3, !4} + !llvm.ident = !{!5} + + !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: GNU) + !1 = !DIFile(filename: "foo.c", directory: "/") + !2 = !{} + !3 = !{i32 2, !"Dwarf Version", i32 5} + !4 = !{i32 2, !"Debug Info Version", i32 3} + !5 = !{!"clang version 9.0.0"} + !6 = distinct !DISubprogram(name: "fn1", scope: !1, file: !1, line: 3, type: !7, scopeLine: 3, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !9) + !7 = !DISubroutineType(types: !8) + !8 = !{null} + !9 = !{!10} + !10 = !DILocalVariable(name: "ptrs", scope: !6, file: !1, line: 5, type: !11) + !11 = !DICompositeType(tag: DW_TAG_array_type, baseType: !12, size: 128, elements: !14) + !12 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !13, size: 64) + !13 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) + !14 = !{!15} + !15 = !DISubrange(count: 2) + !16 = !DILocation(line: 4, scope: !6) + !17 = !DILocation(line: 5, scope: !6) + !18 = !DILocation(line: 6, scope: !6) + !19 = !DILocation(line: 8, scope: !6) + +... +--- +name: fn1 +tracksRegLiveness: true +body: | + bb.0.entry: + frame-setup PUSH64r undef $rax, implicit-def $rsp, implicit $rsp + renamable $rax = MOV64ri 8589934593 + MOV64mr $rsp, 1, $noreg, 0, $noreg, killed renamable $rax, debug-location !16 + renamable $rdi = LEA64r $rsp, 1, $noreg, 4, $noreg, debug-location !17 + DBG_VALUE 0, $noreg, !10, !DIExpression(DW_OP_LLVM_fragment, 0, 64), debug-location !17 + DBG_VALUE $rdi, $noreg, !10, !DIExpression(DW_OP_LLVM_fragment, 64, 64), debug-location !17 + CALL64pcrel32 @fn2, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp, debug-location !18 + DBG_VALUE 0, $noreg, !10, !DIExpression(DW_OP_LLVM_fragment, 64, 64), debug-location !17 + $rax = frame-destroy POP64r implicit-def $rsp, implicit $rsp, debug-location !19 + RETQ debug-location !19 + +... + +# In this case a location list entry that starts one byte into the call to +# fn2() will be created, which describes the non-clobbered constant fragment. +# Verify that the entry's beginning address, that is, the label after the call +# offseted by one byte, is correctly emitted in the address table. + +# CHECK: callq fn2 +# CHECK-NEXT: .Ltmp2 +# CHECK-NEXT: DEBUG_VALUE + +# CHECK: .Ldebug_loc0: +# CHECK-NEXT: .byte 3 +# CHECK-NEXT: .byte 1 +# CHECK-NEXT: .long (.Ltmp2-1)-.Ltmp1 +# CHECK-NEXT: .byte 7 # Loc expr size +# CHECK-NEXT: .byte 48 # DW_OP_lit0 +# CHECK-NEXT: .byte 159 # DW_OP_stack_value +# CHECK-NEXT: .byte 147 # DW_OP_piece +# CHECK-NEXT: .byte 8 # 8 +# CHECK-NEXT: .byte 85 # DW_OP_reg5 +# CHECK-NEXT: .byte 147 # DW_OP_piece +# CHECK-NEXT: .byte 8 # 8 +# CHECK-NEXT: .byte 3 +# CHECK-NEXT: .byte 2 +# CHECK-NEXT: .long .Ltmp2-(.Ltmp2-1) +# CHECK-NEXT: .byte 4 # Loc expr size +# CHECK-NEXT: .byte 48 # DW_OP_lit0 +# CHECK-NEXT: .byte 159 # DW_OP_stack_value +# CHECK-NEXT: .byte 147 # DW_OP_piece +# CHECK-NEXT: .byte 8 # 8 +# CHECK-NEXT: .byte 3 +# CHECK-NEXT: .byte 3 +# CHECK-NEXT: .long .Lfunc_end0-.Ltmp2 +# CHECK-NEXT: .byte 8 # Loc expr size +# CHECK-NEXT: .byte 48 # DW_OP_lit0 +# CHECK-NEXT: .byte 159 # DW_OP_stack_value +# CHECK-NEXT: .byte 147 # DW_OP_piece +# CHECK-NEXT: .byte 8 # 8 +# CHECK-NEXT: .byte 48 # DW_OP_lit0 +# CHECK-NEXT: .byte 159 # DW_OP_stack_value +# CHECK-NEXT: .byte 147 # DW_OP_piece +# CHECK-NEXT: .byte 8 # 8 +# CHECK-NEXT: .byte 0 + +# CHECK: .Laddr_table_base0: +# CHECK-NEXT: .quad .Lfunc_begin0 +# CHECK-NEXT: .quad .Ltmp1 +# CHECK-NEXT: .quad .Ltmp2-1 +# CHECK-NEXT: .quad .Ltmp2 Index: llvm/test/DebugInfo/MIR/X86/call-clobbered-values.mir =================================================================== --- /dev/null +++ llvm/test/DebugInfo/MIR/X86/call-clobbered-values.mir @@ -0,0 +1,263 @@ +# RUN: %llc_dwarf -start-after=livedebugvalues -march=x86-64 -dwarf-version=4 -filetype=obj %s -o - | llvm-dwarfdump - | FileCheck %s +# RUN: %llc_dwarf -start-after=livedebugvalues -march=x86-64 -dwarf-version=5 -filetype=obj %s -o - | llvm-dwarfdump - | FileCheck %s +# +# Reproducer based on the following C file: +# +# typedef struct { long a; long b; long c; } S; +# extern long ext(long, long, long); +# +# long mix(long p1, long p2, long p3) { +# S s1 = {p1, p2, p3}; +# s1.c = ext(s1.a, s1.b, s1.c); +# return s1.b + s1.c; +# } +# +# long all_preserved(long p1, long p2, long p3) { +# S s2 = {p1, p2, p3}; +# ext(s2.a, s2.b, s2.c); +# return s2.a + s2.b + s2.c; +# } +# +# long no_preserved(long p1, long p2, long p3) { +# S s3 = {p1, p2, p3}; +# ext(s3.a, s3.b, s3.c); +# return 0; +# } +# +# long non_reg_loc(long p1, long p2) { +# S s4 = {p1, 123, p2}; +# s4.a = ext(s4.a, s4.b, s4.c); +# return s4.a + s4.b; +# } +# +# Compiled using -O1 -g. + +--- | + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + target triple = "x86_64-unknown-linux-gnu" + + declare i64 @ext(i64, i64, i64) + + ; Function Attrs: nounwind uwtable + define i64 @mix(i64 %p1, i64 %p2, i64 %p3) !dbg !6 { + entry: + unreachable + } + + ; Function Attrs: nounwind uwtable + define i64 @all_preserved(i64 %p1, i64 %p2, i64 %p3) !dbg !21 { + entry: + unreachable + } + + ; Function Attrs: nounwind uwtable + define i64 @no_preserved(i64 %p1, i64 %p2, i64 %p3) !dbg !27 { + entry: + unreachable + } + + ; Function Attrs: nounwind uwtable + define i64 @non_reg_loc(i64 %p1, i64 %p2) !dbg !33 { + entry: + unreachable + } + + ; Function Attrs: nounwind readnone speculatable + declare void @llvm.dbg.value(metadata, metadata, metadata) #0 + + attributes #0 = { nounwind readnone speculatable } + + !llvm.dbg.cu = !{!0} + !llvm.module.flags = !{!3, !4} + !llvm.ident = !{!5} + + !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None) + !1 = !DIFile(filename: "test.c", directory: "/") + !2 = !{} + !3 = !{i32 2, !"Dwarf Version", i32 4} + !4 = !{i32 2, !"Debug Info Version", i32 3} + !5 = !{!"clang version 9.0.0"} + !6 = distinct !DISubprogram(name: "mix", scope: !1, file: !1, line: 8, type: !7, scopeLine: 8, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !10) + !7 = !DISubroutineType(types: !8) + !8 = !{!9, !9, !9, !9} + !9 = !DIBasicType(name: "long int", size: 64, encoding: DW_ATE_signed) + !10 = !{!11} + !11 = !DILocalVariable(name: "s1", scope: !6, file: !1, line: 9, type: !12) + !12 = !DIDerivedType(tag: DW_TAG_typedef, name: "S", file: !1, line: 1, baseType: !13) + !13 = distinct !DICompositeType(tag: DW_TAG_structure_type, file: !1, line: 1, size: 192, elements: !14) + !14 = !{!15, !16, !17} + !15 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !13, file: !1, line: 1, baseType: !9, size: 64) + !16 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !13, file: !1, line: 1, baseType: !9, size: 64, offset: 64) + !17 = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: !13, file: !1, line: 1, baseType: !9, size: 64, offset: 128) + !18 = !DILocation(line: 9, scope: !6) + !19 = !DILocation(line: 10, scope: !6) + !20 = !DILocation(line: 11, scope: !6) + !21 = distinct !DISubprogram(name: "all_preserved", scope: !1, file: !1, line: 16, type: !7, scopeLine: 16, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !22) + !22 = !{!23} + !23 = !DILocalVariable(name: "s2", scope: !21, file: !1, line: 17, type: !12) + !24 = !DILocation(line: 17, scope: !21) + !25 = !DILocation(line: 18, scope: !21) + !26 = !DILocation(line: 19, scope: !21) + !27 = distinct !DISubprogram(name: "no_preserved", scope: !1, file: !1, line: 23, type: !7, scopeLine: 23, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !28) + !28 = !{!29} + !29 = !DILocalVariable(name: "s3", scope: !27, file: !1, line: 24, type: !12) + !30 = !DILocation(line: 24, scope: !27) + !31 = !DILocation(line: 25, scope: !27) + !32 = !DILocation(line: 26, scope: !27) + !33 = distinct !DISubprogram(name: "non_reg_loc", scope: !1, file: !1, line: 30, type: !34, scopeLine: 30, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !36) + !34 = !DISubroutineType(types: !35) + !35 = !{!9, !9, !9} + !36 = !{!37} + !37 = !DILocalVariable(name: "s4", scope: !33, file: !1, line: 31, type: !12) + !38 = !DILocation(line: 31, scope: !33) + !39 = !DILocation(line: 32, scope: !33) + !40 = !DILocation(line: 33, scope: !33) + +... +--- +name: mix +tracksRegLiveness: true +body: | + bb.0.entry: + liveins: $rdi, $rdx, $rsi, $rbx + + frame-setup PUSH64r killed $rbx, implicit-def $rsp, implicit $rsp + DBG_VALUE $rdi, $noreg, !11, !DIExpression(DW_OP_LLVM_fragment, 0, 64), debug-location !18 + DBG_VALUE $rsi, $noreg, !11, !DIExpression(DW_OP_LLVM_fragment, 64, 64), debug-location !18 + DBG_VALUE $rdx, $noreg, !11, !DIExpression(DW_OP_LLVM_fragment, 128, 64), debug-location !18 + $rbx = MOV64rr $rsi + DBG_VALUE $rbx, $noreg, !11, !DIExpression(DW_OP_LLVM_fragment, 64, 64), debug-location !18 + CALL64pcrel32 @ext, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit $rsi, implicit $rdx, implicit-def $rsp, implicit-def $ssp, implicit-def $rax, debug-location !19 + DBG_VALUE $rax, $noreg, !11, !DIExpression(DW_OP_LLVM_fragment, 128, 64), debug-location !18 + renamable $rax = nsw ADD64rr killed renamable $rax, killed renamable $rbx, implicit-def dead $eflags, debug-location !20 + $rbx = frame-destroy POP64r implicit-def $rsp, implicit $rsp, debug-location !20 + RETQ $rax, debug-location !20 + +... + +# In this case the variable is described by both caller-saved registers and +# callee-saved registers at the time of the call, so verify that two ranges, +# one for [..., return_address - 1), and for [return_address - 1, ...), where +# the latter only contains the callee-saved fragments, are emitted for the +# call. +# +# The return address of the call to ext() is 0x9 in this case. + +# CHECK: DW_AT_location +# CHECK-NEXT: [0x0000000000000001, 0x0000000000000004): DW_OP_reg5 RDI, DW_OP_piece 0x8, DW_OP_reg4 RSI, DW_OP_piece 0x8, DW_OP_reg1 RDX, DW_OP_piece 0x8 +# CHECK-NEXT: [0x0000000000000004, 0x0000000000000008): DW_OP_reg5 RDI, DW_OP_piece 0x8, DW_OP_reg3 RBX, DW_OP_piece 0x8, DW_OP_reg1 RDX, DW_OP_piece 0x8 +# CHECK-NEXT: [0x0000000000000008, 0x0000000000000009): DW_OP_piece 0x8, DW_OP_reg3 RBX, DW_OP_piece 0x8 +# CHECK-NEXT: [0x0000000000000009, 0x000000000000000c): DW_OP_piece 0x8, DW_OP_reg3 RBX, DW_OP_piece 0x8, DW_OP_reg0 RAX, DW_OP_piece 0x8 +# CHECK-NEXT: [0x000000000000000c, 0x000000000000000d): DW_OP_piece 0x8, DW_OP_reg3 RBX, DW_OP_piece 0x8) +# CHECK-NEXT: DW_AT_name ("s1") + +--- +name: all_preserved +tracksRegLiveness: true +body: | + bb.0.entry: + liveins: $rdi, $rdx, $rsi, $r15, $r14, $rbx + + frame-setup PUSH64r killed $r15, implicit-def $rsp, implicit $rsp + frame-setup PUSH64r killed $r14, implicit-def $rsp, implicit $rsp + frame-setup PUSH64r killed $rbx, implicit-def $rsp, implicit $rsp + DBG_VALUE $rdi, $noreg, !23, !DIExpression(DW_OP_LLVM_fragment, 0, 64), debug-location !24 + DBG_VALUE $rsi, $noreg, !23, !DIExpression(DW_OP_LLVM_fragment, 64, 64), debug-location !24 + DBG_VALUE $rdx, $noreg, !23, !DIExpression(DW_OP_LLVM_fragment, 128, 64), debug-location !24 + $r14 = MOV64rr $rdx + $r15 = MOV64rr $rsi + $rbx = MOV64rr $rdi + DBG_VALUE $r14, $noreg, !23, !DIExpression(DW_OP_LLVM_fragment, 128, 64), debug-location !24 + DBG_VALUE $r15, $noreg, !23, !DIExpression(DW_OP_LLVM_fragment, 64, 64), debug-location !24 + DBG_VALUE $rbx, $noreg, !23, !DIExpression(DW_OP_LLVM_fragment, 0, 64), debug-location !24 + CALL64pcrel32 @ext, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit $rsi, implicit $rdx, implicit-def $rsp, implicit-def $ssp, implicit-def dead $rax, debug-location !25 + renamable $rax = LEA64r killed renamable $r15, 1, killed renamable $rbx, 0, $noreg, debug-location !26 + renamable $rax = nsw ADD64rr killed renamable $rax, killed renamable $r14, implicit-def dead $eflags, debug-location !26 + $rbx = frame-destroy POP64r implicit-def $rsp, implicit $rsp, debug-location !26 + $r14 = frame-destroy POP64r implicit-def $rsp, implicit $rsp, debug-location !26 + $r15 = frame-destroy POP64r implicit-def $rsp, implicit $rsp, debug-location !26 + RETQ $rax, debug-location !26 + +... + +# In this case the variable is only described by callee-saved registers at the +# time of the call, so verify that a single location list entry spans the call. + +# CHECK: DW_AT_location +# CHECK-NEXT: [0x0000000000000015, 0x000000000000001e): DW_OP_reg5 RDI, DW_OP_piece 0x8, DW_OP_reg4 RSI, DW_OP_piece 0x8, DW_OP_reg1 RDX, DW_OP_piece 0x8 +# CHECK-NEXT: [0x000000000000001e, 0x000000000000002b): DW_OP_reg3 RBX, DW_OP_piece 0x8, DW_OP_reg15 R15, DW_OP_piece 0x8, DW_OP_reg14 R14, DW_OP_piece 0x8 +# CHECK-NEXT: [0x000000000000002b, 0x000000000000002d): DW_OP_piece 0x8, DW_OP_reg15 R15, DW_OP_piece 0x8, DW_OP_reg14 R14, DW_OP_piece 0x8 +# CHECK-NEXT: [0x000000000000002d, 0x000000000000002f): DW_OP_piece 0x8, DW_OP_reg15 R15, DW_OP_piece 0x8) +# CHECK-NEXT: DW_AT_name ("s2") + +--- +name: no_preserved +tracksRegLiveness: true +body: | + bb.0.entry: + liveins: $rdi, $rdx, $rsi + + frame-setup PUSH64r undef $rax, implicit-def $rsp, implicit $rsp + DBG_VALUE $rdi, $noreg, !29, !DIExpression(DW_OP_LLVM_fragment, 0, 64), debug-location !30 + DBG_VALUE $rsi, $noreg, !29, !DIExpression(DW_OP_LLVM_fragment, 64, 64), debug-location !30 + DBG_VALUE $rdx, $noreg, !29, !DIExpression(DW_OP_LLVM_fragment, 128, 64), debug-location !30 + CALL64pcrel32 @ext, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit $rsi, implicit $rdx, implicit-def $rsp, implicit-def $ssp, implicit-def dead $rax, debug-location !31 + DBG_VALUE 0, $noreg, !29, !DIExpression(DW_OP_LLVM_fragment, 0, 64), debug-location !30 + dead $eax = XOR32rr undef $eax, undef $eax, implicit-def dead $eflags, implicit-def $rax, debug-location !32 + $rcx = frame-destroy POP64r implicit-def $rsp, implicit $rsp, debug-location !32 + RETQ killed $rax, debug-location !32 + +... + +# In this case the variable is only described by caller-saved registers at the +# time of the call, so verify that a call-clobbered location list entry [..., +# return_address - 1) is emitted for the call, but that no location list entry +# is emitted. +# +# Please note that I have purposely added a "DBG_VALUE 0" in the MIR directly +# after the call to be able to see the one byte gap in the location list. +# +# The return address of the call to ext() is 0x36 in this case. + +# CHECK: DW_AT_location +# CHECK-NEXT: [0x0000000000000031, 0x0000000000000035): DW_OP_reg5 RDI, DW_OP_piece 0x8, DW_OP_reg4 RSI, DW_OP_piece 0x8, DW_OP_reg1 RDX, DW_OP_piece 0x8 +# CHECK-NEXT: [0x0000000000000036, 0x000000000000003a): DW_OP_lit0, DW_OP_stack_value, DW_OP_piece 0x8) +# CHECK-NEXT: DW_AT_name ("s3") + +--- +name: non_reg_loc +tracksRegLiveness: true +body: | + bb.0.entry: + liveins: $rdi, $rsi + + frame-setup PUSH64r undef $rax, implicit-def $rsp, implicit $rsp + DBG_VALUE $rdi, $noreg, !37, !DIExpression(DW_OP_LLVM_fragment, 0, 64), debug-location !38 + DBG_VALUE $rsi, $noreg, !37, !DIExpression(DW_OP_LLVM_fragment, 128, 64), debug-location !38 + $rdx = MOV64rr $rsi + DBG_VALUE 123, $noreg, !37, !DIExpression(DW_OP_LLVM_fragment, 64, 64), debug-location !38 + DBG_VALUE $rdx, $noreg, !37, !DIExpression(DW_OP_LLVM_fragment, 128, 64), debug-location !38 + DBG_VALUE $rdi, $noreg, !37, !DIExpression(DW_OP_LLVM_fragment, 0, 64), debug-location !38 + $esi = MOV32ri 123, implicit-def $rsi, debug-location !39 + DBG_VALUE $rdx, $noreg, !37, !DIExpression(DW_OP_LLVM_fragment, 128, 64), debug-location !38 + DBG_VALUE $rdi, $noreg, !37, !DIExpression(DW_OP_LLVM_fragment, 0, 64), debug-location !38 + CALL64pcrel32 @ext, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit $rsi, implicit $rdx, implicit-def $rsp, implicit-def $ssp, implicit-def $rax, debug-location !39 + DBG_VALUE $rax, $noreg, !37, !DIExpression(DW_OP_LLVM_fragment, 0, 64), debug-location !38 + renamable $rax = nsw ADD64ri8 killed renamable $rax, 123, implicit-def dead $eflags, debug-location !40 + $rcx = frame-destroy POP64r implicit-def $rsp, implicit $rsp, debug-location !40 + RETQ $rax, debug-location !40 + +... + +# Verify that constant fragments are not removed from the location list entry +# for the range [return_address - 1, ...). +# +# The return address of the call to ext() is 0x4e in this case. + +# CHECK: DW_AT_location +# CHECK-NEXT: [0x0000000000000041, 0x0000000000000044): DW_OP_reg5 RDI, DW_OP_piece 0x8, DW_OP_piece 0x8, DW_OP_reg4 RSI, DW_OP_piece 0x8 +# CHECK-NEXT: [0x0000000000000044, 0x000000000000004d): DW_OP_reg5 RDI, DW_OP_piece 0x8, DW_OP_constu 0x7b, DW_OP_stack_value, DW_OP_piece 0x8, DW_OP_reg1 RDX, DW_OP_piece 0x8 +# CHECK-NEXT: [0x000000000000004d, 0x000000000000004e): DW_OP_piece 0x8, DW_OP_constu 0x7b, DW_OP_stack_value, DW_OP_piece 0x8 +# CHECK-NEXT: [0x000000000000004e, 0x0000000000000052): DW_OP_reg0 RAX, DW_OP_piece 0x8, DW_OP_constu 0x7b, DW_OP_stack_value, DW_OP_piece 0x8 +# CHECK-NEXT: [0x0000000000000052, 0x0000000000000054): DW_OP_piece 0x8, DW_OP_constu 0x7b, DW_OP_stack_value, DW_OP_piece 0x8) +# CHECK-NEXT: DW_AT_name ("s4") Index: llvm/test/DebugInfo/MIR/X86/clobbered-fragments.mir =================================================================== --- llvm/test/DebugInfo/MIR/X86/clobbered-fragments.mir +++ llvm/test/DebugInfo/MIR/X86/clobbered-fragments.mir @@ -158,7 +158,7 @@ # CHECK: .Ldebug_loc0: # CHECK-NEXT: .quad .Ltmp1-.Lfunc_begin0 -# CHECK-NEXT: .quad .Ltmp2-.Lfunc_begin0 +# CHECK-NEXT: .quad (.Ltmp2-1)-.Lfunc_begin0 # CHECK-NEXT: .short 14 # Loc expr size # CHECK-NEXT: .byte 85 # super-register DW_OP_reg5 # CHECK-NEXT: .byte 147 # DW_OP_piece @@ -174,7 +174,7 @@ # CHECK-NEXT: .byte 159 # DW_OP_stack_value # CHECK-NEXT: .byte 147 # DW_OP_piece # CHECK-NEXT: .byte 4 # 4 -# CHECK-NEXT: .quad .Ltmp2-.Lfunc_begin0 +# CHECK-NEXT: .quad (.Ltmp2-1)-.Lfunc_begin0 # CHECK-NEXT: .quad .Lfunc_end0-.Lfunc_begin0 # CHECK-NEXT: .short 13 # Loc expr size # CHECK-NEXT: .byte 147 # DW_OP_piece @@ -217,7 +217,7 @@ # CHECK-NEXT: .byte 147 # DW_OP_piece # CHECK-NEXT: .byte 4 # 4 # CHECK-NEXT: .quad .Ltmp6-.Lfunc_begin0 -# CHECK-NEXT: .quad .Ltmp7-.Lfunc_begin0 +# CHECK-NEXT: .quad (.Ltmp7-1)-.Lfunc_begin0 # CHECK-NEXT: .short 9 # Loc expr size # CHECK-NEXT: .byte 83 # super-register DW_OP_reg3 # CHECK-NEXT: .byte 147 # DW_OP_piece @@ -228,7 +228,7 @@ # CHECK-NEXT: .byte 81 # super-register DW_OP_reg1 # CHECK-NEXT: .byte 147 # DW_OP_piece # CHECK-NEXT: .byte 4 # 4 -# CHECK-NEXT: .quad .Ltmp7-.Lfunc_begin0 +# CHECK-NEXT: .quad (.Ltmp7-1)-.Lfunc_begin0 # CHECK-NEXT: .quad .Ltmp8-.Lfunc_begin0 # CHECK-NEXT: .short 3 # Loc expr size # CHECK-NEXT: .byte 83 # super-register DW_OP_reg3 Index: llvm/test/DebugInfo/X86/dbg-value-regmask-clobber.ll =================================================================== --- llvm/test/DebugInfo/X86/dbg-value-regmask-clobber.ll +++ llvm/test/DebugInfo/X86/dbg-value-regmask-clobber.ll @@ -15,7 +15,7 @@ ; argc is the first debug location. ; ASM: .Ldebug_loc1: ; ASM-NEXT: .quad .Lfunc_begin0-.Lfunc_begin0 -; ASM-NEXT: .quad [[argc_range_end]]-.Lfunc_begin0 +; ASM-NEXT: .quad ([[argc_range_end]]-1)-.Lfunc_begin0 ; ASM-NEXT: .short 1 # Loc expr size ; ASM-NEXT: .byte 82 # super-register DW_OP_reg2 @@ -23,7 +23,7 @@ ; DWARF: .debug_info contents: ; DWARF: DW_TAG_formal_parameter ; DWARF-NEXT: DW_AT_location [DW_FORM_sec_offset] ({{0x.*}} -; DWARF-NEXT: [0x0000000000000000, 0x0000000000000013): DW_OP_reg2 RCX) +; DWARF-NEXT: [0x0000000000000000, 0x0000000000000012): DW_OP_reg2 RCX) ; DWARF-NEXT: DW_AT_name [DW_FORM_strp] {{.*}} "argc" ; ModuleID = 't.cpp' Index: llvm/test/DebugInfo/X86/loclists-dwp.ll =================================================================== --- llvm/test/DebugInfo/X86/loclists-dwp.ll +++ llvm/test/DebugInfo/X86/loclists-dwp.ll @@ -19,7 +19,7 @@ ; void b(int i) { asm("" : : : "rdi"); } ; CHECK: DW_AT_location [DW_FORM_sec_offset] (0x00000000 -; CHECK-NEXT: Addr idx 0 (w/ length 6): DW_OP_reg5 RDI) +; CHECK-NEXT: Addr idx 0 (w/ length 5): DW_OP_reg5 RDI) ; CHECK: DW_AT_location [DW_FORM_sec_offset] (0x00000000 ; CHECK-NEXT: Addr idx 0 (w/ length 0): DW_OP_reg5 RDI) Index: llvm/test/tools/llvm-dwarfdump/X86/locstats.ll =================================================================== --- llvm/test/tools/llvm-dwarfdump/X86/locstats.ll +++ llvm/test/tools/llvm-dwarfdump/X86/locstats.ll @@ -3,10 +3,10 @@ ; ; CHECK: "entry value scope bytes covered":5 ; CHECK: "formal params scope bytes total":20 -; CHECK: "formal params scope bytes covered":20 +; CHECK: "formal params scope bytes covered":19 ; CHECK: "formal params entry value scope bytes covered":5 ; CHECK: "vars scope bytes total":78 -; CHECK: "vars scope bytes covered":60 +; CHECK: "vars scope bytes covered":58 ; CHECK: "vars entry value scope bytes covered":0 ; CHECK: "total variables procesed by location statistics":6 ; CHECK: "variables with 0% of its scope covered":1 @@ -19,8 +19,8 @@ ; CHECK: "variables with 60-69% of its scope covered":0 ; CHECK: "variables with 70-79% of its scope covered":0 ; CHECK: "variables with 80-89% of its scope covered":1 -; CHECK: "variables with 90-99% of its scope covered":0 -; CHECK: "variables with 100% of its scope covered":3 +; CHECK: "variables with 90-99% of its scope covered":1 +; CHECK: "variables with 100% of its scope covered":2 ; CHECK: "variables (excluding the debug entry values) with 0% of its scope covered":1 ; CHECK: "variables (excluding the debug entry values) with 1-9% of its scope covered":0 ; CHECK: "variables (excluding the debug entry values) with 10-19% of its scope covered":0 @@ -31,8 +31,8 @@ ; CHECK: "variables (excluding the debug entry values) with 60-69% of its scope covered":0 ; CHECK: "variables (excluding the debug entry values) with 70-79% of its scope covered":0 ; CHECK: "variables (excluding the debug entry values) with 80-89% of its scope covered":1 -; CHECK: "variables (excluding the debug entry values) with 90-99% of its scope covered":0 -; CHECK: "variables (excluding the debug entry values) with 100% of its scope covered":2 +; CHECK: "variables (excluding the debug entry values) with 90-99% of its scope covered":1 +; CHECK: "variables (excluding the debug entry values) with 100% of its scope covered":1 ; CHECK: "total params procesed by location statistics":2 ; CHECK: "params with 0% of its scope covered":0 ; CHECK: "params with 1-9% of its scope covered":0 @@ -44,8 +44,8 @@ ; CHECK: "params with 60-69% of its scope covered":0 ; CHECK: "params with 70-79% of its scope covered":0 ; CHECK: "params with 80-89% of its scope covered":0 -; CHECK: "params with 90-99% of its scope covered":0 -; CHECK: "params with 100% of its scope covered":2 +; CHECK: "params with 90-99% of its scope covered":1 +; CHECK: "params with 100% of its scope covered":1 ; CHECK: "params (excluding the debug entry values) with 0% of its scope covered":0 ; CHECK: "params (excluding the debug entry values) with 1-9% of its scope covered":0 ; CHECK: "params (excluding the debug entry values) with 10-19% of its scope covered":0 @@ -56,8 +56,8 @@ ; CHECK: "params (excluding the debug entry values) with 60-69% of its scope covered":0 ; CHECK: "params (excluding the debug entry values) with 70-79% of its scope covered":0 ; CHECK: "params (excluding the debug entry values) with 80-89% of its scope covered":0 -; CHECK: "params (excluding the debug entry values) with 90-99% of its scope covered":0 -; CHECK: "params (excluding the debug entry values) with 100% of its scope covered":1 +; CHECK: "params (excluding the debug entry values) with 90-99% of its scope covered":1 +; CHECK: "params (excluding the debug entry values) with 100% of its scope covered":0 ; CHECK: "total vars procesed by location statistics":4 ; CHECK: "vars with 0% of its scope covered":1 ; CHECK: "vars with 1-9% of its scope covered":0