From: Jeremy Morse Date: Mon, 29 Apr 2019 09:13:16 +0000 (+0000) Subject: [DebugInfo] Terminate more location-list ranges at the end of blocks X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=74e964e3d177d17ae2190f7a8b0fa8ce4225b6d0;p=llvm [DebugInfo] Terminate more location-list ranges at the end of blocks This patch fixes PR40795, where constant-valued variable locations can "leak" into blocks placed at higher addresses. The root of this is that DbgEntityHistoryCalculator terminates all register variable locations at the end of each block, but not constant-value variable locations. Fixing this requires constant-valued DBG_VALUE instructions to be broadcast into all blocks where the variable location remains valid, as documented in the LiveDebugValues section of SourceLevelDebugging.rst, and correct termination in DbgEntityHistoryCalculator. Differential Revision: https://reviews.llvm.org/D59431 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@359426 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/AsmPrinter/DbgEntityHistoryCalculator.cpp b/lib/CodeGen/AsmPrinter/DbgEntityHistoryCalculator.cpp index c006f3cc2ef..5601678734a 100644 --- a/lib/CodeGen/AsmPrinter/DbgEntityHistoryCalculator.cpp +++ b/lib/CodeGen/AsmPrinter/DbgEntityHistoryCalculator.cpp @@ -352,17 +352,43 @@ void llvm::calculateDbgEntityHistory(const MachineFunction *MF, } } - // Make sure locations for register-described variables are valid only - // until the end of the basic block (unless it's the last basic block, in - // which case let their liveness run off to the end of the function). + // Make sure locations for all variables are valid only until the end of + // the basic block (unless it's the last basic block, in which case let + // their liveness run off to the end of the function). if (!MBB.empty() && &MBB != &MF->back()) { - for (auto I = RegVars.begin(), E = RegVars.end(); I != E;) { - auto CurElem = I++; // CurElem can be erased below. - if (TRI->isVirtualRegister(CurElem->first) || - ChangingRegs.test(CurElem->first)) - clobberRegisterUses(RegVars, CurElem, DbgValues, LiveEntries, - MBB.back()); + // Iterate over all variables that have open debug values. + SmallSet RegsToClobber; + for (auto &Pair : LiveEntries) { + // Iterate over history entries for all open fragments. + SmallVector IdxesToRemove; + for (EntryIndex Idx : Pair.second) { + DbgValueHistoryMap::Entry &Ent = DbgValues.getEntry(Pair.first, Idx); + assert(Ent.isDbgValue() && !Ent.isClosed()); + const MachineInstr *DbgValue = Ent.getInstr(); + + // If this is a register or indirect DBG_VALUE, apply some futher + // tests to see if we should clobber it. Perform the clobbering + // later though, to keep LiveEntries iteration stable. + if (DbgValue->getOperand(0).isReg()) { + unsigned RegNo = DbgValue->getOperand(0).getReg(); + if (TRI->isVirtualRegister(RegNo) || ChangingRegs.test(RegNo)) + RegsToClobber.insert(RegNo); + } else { + // This is a constant, terminate it at end of the block. Store + // eliminated EntryIdx and delete later, for iteration stability. + EntryIndex ClobIdx = DbgValues.startClobber(Pair.first, MBB.back()); + DbgValues.getEntry(Pair.first, Idx).endEntry(ClobIdx); + IdxesToRemove.push_back(Idx); + } + } + + for (EntryIndex Idx : IdxesToRemove) + Pair.second.erase(Idx); } + + // Implement clobbering of registers at the end of BB. + for (unsigned Reg : RegsToClobber) + clobberRegisterUses(RegVars, Reg, DbgValues, LiveEntries, MBB.back()); } } } diff --git a/lib/CodeGen/LiveDebugValues.cpp b/lib/CodeGen/LiveDebugValues.cpp index 449f10c7ef7..e36694d2c5b 100644 --- a/lib/CodeGen/LiveDebugValues.cpp +++ b/lib/CodeGen/LiveDebugValues.cpp @@ -143,7 +143,8 @@ private: enum VarLocKind { InvalidKind = 0, RegisterKind, - SpillLocKind + SpillLocKind, + ImmediateKind } Kind = InvalidKind; /// The value location. Stored separately to avoid repeatedly @@ -152,6 +153,9 @@ private: uint64_t RegNo; SpillLoc SpillLocation; uint64_t Hash; + int64_t Immediate; + const ConstantFP *FPImm; + const ConstantInt *CImm; } Loc; VarLoc(const MachineInstr &MI, LexicalScopes &LS) @@ -164,6 +168,15 @@ private: if (int RegNo = isDbgValueDescribedByReg(MI)) { Kind = RegisterKind; Loc.RegNo = RegNo; + } else if (MI.getOperand(0).isImm()) { + Kind = ImmediateKind; + Loc.Immediate = MI.getOperand(0).getImm(); + } else if (MI.getOperand(0).isFPImm()) { + Kind = ImmediateKind; + Loc.FPImm = MI.getOperand(0).getFPImm(); + } else if (MI.getOperand(0).isCImm()) { + Kind = ImmediateKind; + Loc.CImm = MI.getOperand(0).getCImm(); } } @@ -178,6 +191,9 @@ private: Loc.SpillLocation = {SpillBase, SpillOffset}; } + // Is the Loc field a constant or constant object? + bool isConstant() const { return Kind == ImmediateKind; } + /// If this variable is described by a register, return it, /// otherwise return 0. unsigned isDescribedByReg() const { @@ -195,7 +211,8 @@ private: #endif bool operator==(const VarLoc &Other) const { - return Var == Other.Var && Loc.Hash == Other.Loc.Hash; + return Kind == Other.Kind && Var == Other.Var && + Loc.Hash == Other.Loc.Hash; } /// This operator guarantees that VarLocs are sorted by Variable first. @@ -408,11 +425,23 @@ void LiveDebugValues::transferDebugValue(const MachineInstr &MI, OpenRanges.erase(V); // Add the VarLoc to OpenRanges from this DBG_VALUE. - // TODO: Currently handles DBG_VALUE which has only reg as location. - if (isDbgValueDescribedByReg(MI)) { + unsigned ID; + if (isDbgValueDescribedByReg(MI) || MI.getOperand(0).isImm() || + MI.getOperand(0).isFPImm() || MI.getOperand(0).isCImm()) { + // Use normal VarLoc constructor for registers and immediates. VarLoc VL(MI, LS); - unsigned ID = VarLocIDs.insert(VL); + ID = VarLocIDs.insert(VL); + OpenRanges.insert(ID, VL.Var); + } else if (MI.hasOneMemOperand()) { + // It's a stack spill -- fetch spill base and offset. + VarLoc::SpillLoc SpillLocation = extractSpillBaseRegAndOffset(MI); + VarLoc VL(MI, SpillLocation.SpillBase, SpillLocation.SpillOffset, LS); + ID = VarLocIDs.insert(VL); OpenRanges.insert(ID, VL.Var); + } else { + // This must be an undefined location. We should leave OpenRanges closed. + assert(MI.getOperand(0).isReg() && MI.getOperand(0).getReg() == 0 && + "Unexpected non-undef DBG_VALUE encountered"); } } @@ -806,12 +835,19 @@ bool LiveDebugValues::join( // a new DBG_VALUE. process() will end this range however appropriate. const VarLoc &DiffIt = VarLocIDs[ID]; const MachineInstr *DMI = &DiffIt.MI; - MachineInstr *MI = - BuildMI(MBB, MBB.instr_begin(), DMI->getDebugLoc(), DMI->getDesc(), - DMI->isIndirectDebugValue(), DMI->getOperand(0).getReg(), - DMI->getDebugVariable(), DMI->getDebugExpression()); - if (DMI->isIndirectDebugValue()) - MI->getOperand(1).setImm(DMI->getOperand(1).getImm()); + MachineInstr *MI = nullptr; + if (DiffIt.isConstant()) { + MachineOperand MO(DMI->getOperand(0)); + MI = BuildMI(MBB, MBB.instr_begin(), DMI->getDebugLoc(), DMI->getDesc(), + false, MO, DMI->getDebugVariable(), + DMI->getDebugExpression()); + } else { + MI = BuildMI(MBB, MBB.instr_begin(), DMI->getDebugLoc(), DMI->getDesc(), + DMI->isIndirectDebugValue(), DMI->getOperand(0).getReg(), + DMI->getDebugVariable(), DMI->getDebugExpression()); + if (DMI->isIndirectDebugValue()) + MI->getOperand(1).setImm(DMI->getOperand(1).getImm()); + } LLVM_DEBUG(dbgs() << "Inserted: "; MI->dump();); ILS.set(ID); ++NumInserted; diff --git a/test/DebugInfo/COFF/pieces.ll b/test/DebugInfo/COFF/pieces.ll index b218f076fde..eebef3895d4 100644 --- a/test/DebugInfo/COFF/pieces.ll +++ b/test/DebugInfo/COFF/pieces.ll @@ -40,9 +40,10 @@ ; ASM: # %bb.2: # %for.body.preheader ; ASM: xorl %edi, %edi ; ASM: xorl %esi, %esi +; ASM: [[oy_ox_start:\.Ltmp[0-9]+]]: ; ASM: .p2align 4, 0x90 ; ASM: .LBB0_3: # %for.body -; ASM: [[oy_ox_start:\.Ltmp[0-9]+]]: +; ASM: #DEBUG_VALUE: loop_csr:o <- [DW_OP_LLVM_fragment 0 32] 0 ; ASM: #DEBUG_VALUE: loop_csr:o <- [DW_OP_LLVM_fragment 0 32] $edi ; ASM: #DEBUG_VALUE: loop_csr:o <- [DW_OP_LLVM_fragment 32 32] $esi ; ASM: .cv_loc 0 1 13 11 # t.c:13:11 @@ -59,13 +60,21 @@ ; ASM: #DEBUG_VALUE: loop_csr:o <- [DW_OP_LLVM_fragment 32 32] $esi ; ASM: cmpl n(%rip), %eax ; ASM: jl .LBB0_3 +; ASM: [[loopskip_start:\.Ltmp[0-9]+]]: +; ASM: #DEBUG_VALUE: loop_csr:o <- [DW_OP_LLVM_fragment 0 32] 0 +; ASM: xorl %esi, %esi +; ASM: xorl %edi, %edi ; ASM: [[oy_end:\.Ltmp[0-9]+]]: ; ASM: addl %edi, %esi ; ASM: movl %esi, %eax +; XXX FIXME: the debug value line after loopskip_start should be repeated +; because both fields of 'o' are zero flowing into this block. However, it +; appears livedebugvalues doesn't account for fragments. ; ASM-LABEL: pad_right: # @pad_right ; ASM: movq %rcx, %rax +; ASM: [[pad_right_tmp:\.Ltmp[0-9]+]]: ; ASM: #DEBUG_VALUE: pad_right:o <- [DW_OP_LLVM_fragment 32 32] $eax ; ASM: retq @@ -73,6 +82,7 @@ ; ASM-LABEL: pad_left: # @pad_left ; ASM: .cv_loc 2 1 24 3 # t.c:24:3 ; ASM: movq %rcx, %rax +; ASM: [[pad_left_tmp:\.Ltmp[0-9]+]]: ; ASM: #DEBUG_VALUE: pad_left:o <- [DW_OP_LLVM_fragment 0 32] $eax ; ASM: retq @@ -104,8 +114,8 @@ ; ASM: .asciz "o" ; ASM: .cv_def_range [[oy_ox_start]] [[ox_start]], "C\021\030\000\000\000\000\000\000\000" ; ASM: .cv_def_range [[oy_ox_start]] [[oy_start]], "C\021\027\000\000\000\004\000\000\000" -; ASM: .cv_def_range [[ox_start]] [[oy_end]], "C\021\030\000\000\000\000\000\000\000" -; ASM: .cv_def_range [[oy_start]] [[oy_end]], "C\021\027\000\000\000\004\000\000\000" +; ASM: .cv_def_range [[ox_start]] [[loopskip_start]], "C\021\030\000\000\000\000\000\000\000" +; ASM: .cv_def_range [[oy_start]] [[loopskip_start]], "C\021\027\000\000\000\004\000\000\000" ; OBJ-LABEL: GlobalProcIdSym { @@ -136,7 +146,7 @@ ; ASM: .asciz "pad_right" # Function name ; ASM: .short 4414 # Record kind: S_LOCAL ; ASM: .asciz "o" -; ASM: .cv_def_range .Ltmp8 .Ltmp8, "C\021\021\000\000\000\004\000\000\000" +; ASM: .cv_def_range [[pad_right_tmp]] [[pad_right_tmp]], "C\021\021\000\000\000\004\000\000\000" ; OBJ-LABEL: GlobalProcIdSym { ; OBJ: Kind: S_GPROC32_ID (0x1147) @@ -159,7 +169,7 @@ ; ASM: .asciz "pad_left" # Function name ; ASM: .short 4414 # Record kind: S_LOCAL ; ASM: .asciz "o" -; ASM: .cv_def_range .Ltmp10 .Ltmp10, "C\021\021\000\000\000\000\000\000\000" +; ASM: .cv_def_range [[pad_left_tmp]] [[pad_left_tmp]], "C\021\021\000\000\000\000\000\000\000" ; OBJ-LABEL: GlobalProcIdSym { ; OBJ: Kind: S_GPROC32_ID (0x1147) diff --git a/test/DebugInfo/MIR/AArch64/implicit-def-dead-scope.mir b/test/DebugInfo/MIR/AArch64/implicit-def-dead-scope.mir index 06db4150684..d2a8d4cd322 100644 --- a/test/DebugInfo/MIR/AArch64/implicit-def-dead-scope.mir +++ b/test/DebugInfo/MIR/AArch64/implicit-def-dead-scope.mir @@ -5,8 +5,10 @@ # encountering an IMPLICIT_DEF in its own lexical scope. # CHECK: .debug_info contents: -# CHECK: DW_TAG_formal_parameter -# CHECK: DW_AT_const_value [DW_FORM_udata] (0) +# CHECK: DW_TAG_formal_parameter +# CHECK: DW_AT_location [DW_FORM_sec_offset] +# CHECK-NEXT: DW_OP_lit0, DW_OP_stack_value +# CHECK-NEXT: DW_AT_abstract_origin {{.*}} "name" --- | ; ModuleID = 't.ll' source_filename = "t.ll" @@ -103,7 +105,7 @@ !15 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "v", file: !5, line: 97, size: 64, elements: !2, identifier: "_ZTS1v") !16 = !DISubroutineType(types: !2) !17 = !DISubprogram(name: "bv", linkageName: "_ZN1v2bvEv", scope: !15, file: !5, line: 98, type: !16, isLocal: false, isDefinition: false, scopeLine: 98, flags: DIFlagPrototyped, isOptimized: true) - !18 = !DILocalVariable(arg: 2, scope: !19, file: !5, line: 22, type: !21) + !18 = !DILocalVariable(name: "name", arg: 2, scope: !19, file: !5, line: 22, type: !21) !19 = distinct !DISubprogram(name: "m", linkageName: "_ZN1jILi6EN1a1fEE1mEj", scope: !11, file: !5, line: 22, type: !16, isLocal: false, isDefinition: true, scopeLine: 22, flags: DIFlagPrototyped, isOptimized: true, unit: !0, declaration: !20, retainedNodes: !2) !20 = !DISubprogram(name: "m", linkageName: "_ZN1jILi6EN1a1fEE1mEj", scope: !11, file: !5, line: 22, type: !16, isLocal: false, isDefinition: false, scopeLine: 22, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: true) !21 = !DIDerivedType(tag: DW_TAG_typedef, name: "h", file: !5, line: 10, baseType: !22) diff --git a/test/DebugInfo/X86/fission-ranges.ll b/test/DebugInfo/X86/fission-ranges.ll index 1a1dc22870a..b9a1675d608 100644 --- a/test/DebugInfo/X86/fission-ranges.ll +++ b/test/DebugInfo/X86/fission-ranges.ll @@ -15,6 +15,7 @@ ; CHECK-NEXT: DW_AT_GNU_addr_base [DW_FORM_sec_offset] (0x00000000) ; CHECK: .debug_info.dwo contents: +; CHECK: DW_AT_location [DW_FORM_sec_offset] ([[P:0x[0-9a-z]*]] ; CHECK: DW_AT_location [DW_FORM_sec_offset] ([[A:0x[0-9a-z]*]] ; CHECK: DW_AT_location [DW_FORM_sec_offset] ([[E:0x[0-9a-z]*]] ; CHECK: DW_AT_location [DW_FORM_sec_offset] ([[B:0x[0-9a-z]*]] @@ -27,24 +28,31 @@ ; Don't assume these locations are entirely correct - feel free to update them ; if they've changed due to a bugfix, change in register allocation, etc. +; CHECK: [[P]]: +; CHECK-NEXT: Addr idx 1 (w/ length 204): DW_OP_consts +1, DW_OP_stack_value ; CHECK: [[A]]: ; CHECK-NEXT: Addr idx 2 (w/ length 169): DW_OP_consts +0, DW_OP_stack_value -; CHECK-NEXT: Addr idx 3 (w/ length 25): DW_OP_reg0 RAX +; CHECK-NEXT: Addr idx 3 (w/ length 15): DW_OP_reg0 RAX +; CHECK-NEXT: Addr idx 4 (w/ length 6): DW_OP_breg7 RSP-8 +; CHECK-NEXT: Addr idx 5 (w/ length 4): DW_OP_reg0 RAX ; CHECK: [[E]]: -; CHECK-NEXT: Addr idx 4 (w/ length 19): DW_OP_reg0 RAX +; CHECK-NEXT: Addr idx 6 (w/ length 9): DW_OP_reg0 RAX +; CHECK-NEXT: Addr idx 7 (w/ length 98): DW_OP_breg7 RSP-44 ; CHECK: [[B]]: -; CHECK-NEXT: Addr idx 5 (w/ length 17): DW_OP_reg0 RAX +; CHECK-NEXT: Addr idx 8 (w/ length 15): DW_OP_reg0 RAX +; CHECK-NEXT: Addr idx 9 (w/ length 66): DW_OP_breg7 RSP-32 ; CHECK: [[D]]: -; CHECK-NEXT: Addr idx 6 (w/ length 17): DW_OP_reg0 RAX +; CHECK-NEXT: Addr idx 10 (w/ length 15): DW_OP_reg0 RAX +; CHECK-NEXT: Addr idx 11 (w/ length 42): DW_OP_breg7 RSP-20 ; Make sure we don't produce any relocations in any .dwo section (though in particular, debug_info.dwo) ; HDR-NOT: .rela.{{.*}}.dwo ; Make sure we have enough stuff in the debug_addr to cover the address indexes -; (6 is the last index in debug_loc.dwo, making 7 entries of 8 bytes each, 7 * 8 -; == 56 base 10 == 38 base 16) +; (11 is the last index in debug_loc.dwo, making 12 entries of 8 bytes each, +; 12 * 8 == 96 base 10 == 60 base 16) -; HDR: .debug_addr 00000038 +; HDR: .debug_addr 00000060 ; HDR-NOT: .rela.{{.*}}.dwo ; Check for the existence of a DWARF v5-style range list table in the .debug_rnglists diff --git a/test/DebugInfo/X86/live-debug-values-constprop.mir b/test/DebugInfo/X86/live-debug-values-constprop.mir new file mode 100644 index 00000000000..086f664e19a --- /dev/null +++ b/test/DebugInfo/X86/live-debug-values-constprop.mir @@ -0,0 +1,347 @@ +# RUN: llc %s -o - -run-pass=livedebugvalues -mtriple=x86_64-unknown-unknown | FileCheck %s --check-prefix=CHECK +# RUN: llc %s -o - -start-before=livedebugvalues -filetype=obj -mtriple=x86_64-unknown-unknown | llvm-dwarfdump - | FileCheck %s --check-prefix=RANGES +# Check that livedebugvalues does the right thing when register and constant +# DBG_VALUEs interact, and that their ranges are correctly terminated by the +# debug printing backend. +--- | + ; All these IR functions are duds, see the MIR below. + source_filename = "" + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + + define i32 @foo(i32* %bees, i32* %output) !dbg !4 { + entry: + br i1 undef, label %bb1, label %bb1 + bb1: + br label %bb3 + bb2: + br label %bb3 + bb3: + ret i32 0 + } + + define i32 @bar(i32* %bees, i32* %output) !dbg !40 { + entry: + br i1 undef, label %bb1, label %bb1 + bb1: + br label %bb3 + bb2: + br label %bb3 + bb3: + ret i32 0 + } + + define i32 @baz(i32* %bees, i32* %output) !dbg !80 { + entry: + br i1 undef, label %bb1, label %bb1 + bb1: + br label %bb3 + bb2: + br label %bb3 + bb3: + ret i32 0 + } + + define i32 @qux(i32* %bees, i32* %output) !dbg !120 { + entry: + br i1 undef, label %bb1, label %bb1 + bb1: + br label %bb3 + bb2: + br label %bb3 + bb3: + ret i32 0 + } + + ; Function Attrs: nounwind readnone speculatable + declare void @llvm.dbg.value(metadata, metadata, metadata) + + ; Function Attrs: nounwind readnone speculatable + declare void @llvm.dbg.declare(metadata, metadata, metadata) + + ; Function Attrs: nounwind + declare void @llvm.stackprotector(i8*, i8**) + + !llvm.module.flags = !{!0, !100} + !llvm.dbg.cu = !{!1} + + !100 = !{i32 2, !"Dwarf Version", i32 4} + !0 = !{i32 2, !"Debug Info Version", i32 3} + !1 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !2, producer: "beards", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug) + !2 = !DIFile(filename: "bees.cpp", directory: ".") + !3 = !DILocalVariable(name: "flannel", scope: !4, file: !2, line: 1, type: !16) + !4 = distinct !DISubprogram(name: "nope", scope: !2, file: !2, line: 1, spFlags: DISPFlagDefinition, unit: !1, retainedNodes: !13, type: !14, isDefinition: true) + !5 = !DILocation(line: 0, scope: !4) + !6 = !DILocation(line: 1, scope: !4) + !7 = !DILocation(line: 2, scope: !4) + !8 = !DILocation(line: 4, scope: !4) + !9 = !DILocation(line: 5, scope: !4) + !10 = !DILocation(line: 6, scope: !4) + !11 = !DILocation(line: 7, scope: !4) + !12 = !DILocation(line: 8, scope: !4) + !13 = !{!3} + !14 = !DISubroutineType(types: !15) + !15 = !{!16} + !16 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed) + !40 = distinct !DISubprogram(name: "bar", scope: !2, file: !2, line: 1, spFlags: DISPFlagDefinition, unit: !1, retainedNodes: !13, type: !14, isDefinition: true) + !41 = !DILocalVariable(name: "towel", scope: !40, file: !2, line: 1, type: !16) + !42 = !DILocation(line: 40, scope: !40) + !80 = distinct !DISubprogram(name: "baz", scope: !2, file: !2, line: 1, spFlags: DISPFlagDefinition, unit: !1, retainedNodes: !13, type: !14, isDefinition: true) + !81 = !DILocalVariable(name: "socks", scope: !80, file: !2, line: 1, type: !16) + !82 = !DILocation(line: 40, scope: !80) + !120 = distinct !DISubprogram(name: "qux", scope: !2, file: !2, line: 1, spFlags: DISPFlagDefinition, unit: !1, retainedNodes: !13, type: !14, isDefinition: true) + !121 = !DILocalVariable(name: "shoes", scope: !120, file: !2, line: 1, type: !16) + !122 = !DILocation(line: 40, scope: !120) + +... +--- +name: foo +alignment: 4 +tracksRegLiveness: true +registers: [] +liveins: + - { reg: '$rdi', virtual-reg: '' } +body: | + + ; Two DBG_VALUEs for eax merge into bb3, check that livedebugvalues propagates + ; the location. + ; CHECK-LABEL: name: foo + ; CHECK-LABEL: bb.1.bb1 + ; CHECK: $eax = MOV32rr + ; CHECK-NEXT: DBG_VALUE $eax + ; CHECK-NEXT: JMP_1 %bb.3 + ; CHECK-LABEL: bb.2.bb2 + ; CHECK: $eax = ADD32ri8 + ; CHECK-NEXT: DBG_VALUE $eax + ; CHECK-NEXT: JMP_1 %bb.3 + ; CHECK-LABEL: bb.3.bb3 + ; CHECK: DBG_VALUE $eax + ; Test for there being a location-list gap between bb1 and bb2, as the + ; variable does not have a location over the ADD32ri. The range should also + ; extend over the final bb. + ; RANGES-LABEL: DW_TAG_subprogram + ; RANGES: DW_AT_high_pc (0x[[NOPEHIGHPC:[0-9a-f]+]]) + ; RANGES-LABEL: DW_AT_name ("nope") + ; RANGES: DW_AT_location (0x{{[0-9a-f]+}} + ; RANGES-NEXT: [0x{{[0-9a-f]+}}, 0x[[NOPEADDR:[0-9a-f]+]]): DW_OP_reg0 RAX + ; RANGES-NEXT: [ + ; RANGES-NOT: 0x[[NOPEADDR]] + ; RANGES-SAME: , 0x[[NOPEHIGHPC]]): DW_OP_reg0 RAX + + bb.0.entry: + successors: %bb.1, %bb.2 + liveins: $rdi + + $ecx = XOR32rr undef $ecx, undef $ecx, implicit-def $eflags + JCC_1 %bb.1, 2, implicit killed $eflags + JMP_1 %bb.2 + + bb.1.bb1 (align 4): + successors: %bb.3 + liveins: $ecx, $rdi + + $eax = MOV32rr killed $ecx, implicit-def $rax + DBG_VALUE $eax, $noreg, !3, !DIExpression(), debug-location !8 + JMP_1 %bb.3 + + bb.2.bb2: + successors: %bb.3 + liveins: $rax + + $eax = ADD32ri8 $eax, 3, implicit-def dead $eflags, implicit killed $rax, implicit-def $rax + DBG_VALUE $eax, $noreg, !3, !DIExpression(), debug-location !8 + JMP_1 %bb.3 + + bb.3.bb3: + liveins: $rax + RETQ $eax, debug-location !9 + +... +--- +name: bar +alignment: 4 +tracksRegLiveness: true +registers: [] +liveins: + - { reg: '$rdi', virtual-reg: '' } +body: | + ; Two DBG_VALUEs, one for eax, the other for zero, merge into bb3. Check that + ; livedebugvalues does not propagate anything. + ; the location. + ; CHECK-LABEL: name: bar + ; CHECK-LABEL: bb.1.bb1 + ; CHECK: $eax = MOV32rr + ; CHECK-NEXT: DBG_VALUE 0 + ; CHECK-NEXT: JMP_1 %bb.3 + ; CHECK-LABEL: bb.2.bb2 + ; CHECK: $eax = ADD32ri8 + ; CHECK-NEXT: DBG_VALUE $eax + ; CHECK-NEXT: JMP_1 %bb.3 + ; CHECK-LABEL: bb.3.bb3 + ; CHECK-NOT: DBG_VALUE + ; Test for there being a location-list gap between bb1 and bb2, the variable + ; should not have a location over the ADD32ri. The range of the last entry + ; should not cover the last block. + ; RANGES-LABEL: DW_TAG_subprogram + ; RANGES: DW_AT_high_pc (0x[[BARHIGHPC:[0-9a-f]+]]) + ; RANGES-LABEL: DW_AT_name ("bar") + ; RANGES: DW_AT_location (0x{{[0-9a-f]+}} + ; RANGES-NEXT: [0x{{[0-9a-f]+}}, 0x[[BARADDR:[0-9a-f]+]]): DW_OP_consts +0, DW_OP_stack_value + ; RANGES-NEXT: [ + ; RANGES-NOT: 0x[[BARADDR]] + ; RANGES-NOT: 0x[[BARHIGHPC]] + ; RANGES-SAME: ): DW_OP_reg0 RAX + + bb.0.entry: + successors: %bb.1, %bb.2 + liveins: $rdi + + $ecx = XOR32rr undef $ecx, undef $ecx, implicit-def $eflags + JCC_1 %bb.1, 2, implicit killed $eflags + JMP_1 %bb.2 + + bb.1.bb1 (align 4): + successors: %bb.3 + liveins: $ecx, $rdi + + $eax = MOV32rr killed $ecx, implicit-def $rax + DBG_VALUE 0, $noreg, !41, !DIExpression(), debug-location !42 + JMP_1 %bb.3 + + bb.2.bb2: + successors: %bb.3 + liveins: $rax + + $eax = ADD32ri8 $eax, 3, implicit-def dead $eflags, implicit killed $rax, implicit-def $rax + DBG_VALUE $eax, $noreg, !41, !DIExpression(), debug-location !42 + JMP_1 %bb.3 + + bb.3.bb3: + liveins: $rax + RETQ $eax, debug-location !42 + +... +--- +name: baz +alignment: 4 +tracksRegLiveness: true +registers: [] +liveins: + - { reg: '$rdi', virtual-reg: '' } +body: | + ; Two DBG_VALUEs, one for zero, the other for eax, merge into bb3. Check that + ; livedebugvalues does not propagate anything. + ; the location. + ; CHECK-LABEL: name: baz + ; CHECK-LABEL: bb.1.bb1 + ; CHECK: $eax = MOV32rr + ; CHECK-NEXT: DBG_VALUE $eax + ; CHECK-NEXT: JMP_1 %bb.3 + ; CHECK-LABEL: bb.2.bb2 + ; CHECK: $eax = ADD32ri8 + ; CHECK-NEXT: DBG_VALUE 0 + ; CHECK-NEXT: JMP_1 %bb.3 + ; CHECK-LABEL: bb.3.bb3 + ; CHECK-NOT: DBG_VALUE + ; Test for there being a location-list gap between bb1 and bb2, the variable + ; should not have a location over the ADD32ri. The range of the last item + ; should not cover the last block. + ; RANGES-LABEL: DW_TAG_subprogram + ; RANGES: DW_AT_high_pc (0x[[BAZHIGHPC:[0-9a-f]+]]) + ; RANGES-LABEL: DW_AT_name ("baz") + ; RANGES: DW_AT_location (0x{{[0-9a-f]+}} + ; RANGES-NEXT: [0x{{[0-9a-f]+}}, 0x[[BAZADDR:[0-9a-f]+]]): DW_OP_reg0 RAX + ; RANGES-NEXT: [ + ; RANGES-NOT: 0x[[BAZADDR]] + ; RANGES-NOT: 0x[[BAZHIGHPC]] + ; RANGES-SAME: ): DW_OP_consts +0, DW_OP_stack_value + + bb.0.entry: + successors: %bb.1, %bb.2 + liveins: $rdi + + $ecx = XOR32rr undef $ecx, undef $ecx, implicit-def $eflags + JCC_1 %bb.1, 2, implicit killed $eflags + JMP_1 %bb.2 + + bb.1.bb1 (align 4): + successors: %bb.3 + liveins: $ecx, $rdi + + $eax = MOV32rr killed $ecx, implicit-def $rax + DBG_VALUE $eax, $noreg, !81, !DIExpression(), debug-location !82 + JMP_1 %bb.3 + + bb.2.bb2: + successors: %bb.3 + liveins: $rax + + $eax = ADD32ri8 $eax, 3, implicit-def dead $eflags, implicit killed $rax, implicit-def $rax + DBG_VALUE 0, $noreg, !81, !DIExpression(), debug-location !82 + JMP_1 %bb.3 + + bb.3.bb3: + liveins: $rax + RETQ $eax, debug-location !82 + +... +--- +name: qux +alignment: 4 +tracksRegLiveness: true +registers: [] +liveins: + - { reg: '$rdi', virtual-reg: '' } +body: | + ; Two DBG_VALUEs for zero merging into bb3, Check that livedebugvalues does + ; propagate the zero into the merging block. + ; CHECK-LABEL: name: qux + ; CHECK-LABEL: bb.1.bb1 + ; CHECK: $eax = MOV32rr + ; CHECK-NEXT: DBG_VALUE 0 + ; CHECK-NEXT: JMP_1 %bb.3 + ; CHECK-LABEL: bb.2.bb2 + ; CHECK: $eax = ADD32ri8 + ; CHECK-NEXT: DBG_VALUE 0 + ; CHECK-NEXT: JMP_1 %bb.3 + ; CHECK-LABEL: bb.3.bb3 + ; CHECK: DBG_VALUE 0 + ; Test for there being a location-list gap between bb1 and bb2, the variable + ; should not have a location over the ADD32ri. The final entry should cover + ; the final block. + ; RANGES-LABEL: DW_TAG_subprogram + ; RANGES: DW_AT_high_pc (0x[[QUXHIGHPC:[0-9a-f]+]]) + ; RANGES-LABEL: DW_AT_name ("qux") + ; RANGES: DW_AT_location (0x{{[0-9a-f]+}} + ; RANGES-NEXT: [0x{{[0-9a-f]+}}, 0x[[QUXADDR:[0-9a-f]+]]): DW_OP_consts +0, DW_OP_stack_value + ; RANGES-NOT: 0x[[QUXADDR]] + ; RANGES-NEXT: [0x{{[0-9a-f]+}}, 0x[[QUXHIGHPC]]): DW_OP_consts +0, DW_OP_stack_value + + bb.0.entry: + successors: %bb.1, %bb.2 + liveins: $rdi + + $ecx = XOR32rr undef $ecx, undef $ecx, implicit-def $eflags + JCC_1 %bb.1, 2, implicit killed $eflags + JMP_1 %bb.2 + + bb.1.bb1 (align 4): + successors: %bb.3 + liveins: $ecx, $rdi + + $eax = MOV32rr killed $ecx, implicit-def $rax + DBG_VALUE 0, $noreg, !121, !DIExpression(), debug-location !122 + JMP_1 %bb.3 + + bb.2.bb2: + successors: %bb.3 + liveins: $rax + + $eax = ADD32ri8 $eax, 3, implicit-def dead $eflags, implicit killed $rax, implicit-def $rax + DBG_VALUE 0, $noreg, !121, !DIExpression(), debug-location !122 + JMP_1 %bb.3 + + bb.3.bb3: + liveins: $rax + RETQ $eax, debug-location !122 + +...