diff --git a/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp b/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp index fdf50188fbcd8..a8143bd8f4273 100644 --- a/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp +++ b/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp @@ -359,6 +359,7 @@ class TransferTracker { SmallVector ResolvedDbgOps; bool IsValueValid = true; unsigned LastUseBeforeDef = 0; + bool DbgLocAvailableAndIsEntryVal = false; // If every value used by the incoming DbgValue is available at block // entry, ResolvedDbgOps will contain the machine locations/constants for @@ -412,6 +413,8 @@ class TransferTracker { // live range. LocIdx M = ValuesPreferredLoc->second.getLoc(); ResolvedDbgOps.push_back(M); + if (Value.Properties.DIExpr->isEntryValue()) + DbgLocAvailableAndIsEntryVal = true; } // If we cannot produce a valid value for the LiveIn value within this @@ -425,6 +428,16 @@ class TransferTracker { return; } + auto &[Var, DILoc] = DVMap.lookupDVID(VarID); + PendingDbgValues.push_back( + std::make_pair(VarID, &*MTracker->emitLoc(ResolvedDbgOps, Var, DILoc, + Value.Properties))); + + // If the location is available at block entry and is an entry value, skip + // tracking and recording thr transfer. + if (DbgLocAvailableAndIsEntryVal) + return; + // The LiveIn value is available at block entry, begin tracking and record // the transfer. for (const ResolvedDbgOp &Op : ResolvedDbgOps) @@ -434,10 +447,6 @@ class TransferTracker { auto Result = ActiveVLocs.insert(std::make_pair(VarID, NewValue)); if (!Result.second) Result.first->second = NewValue; - auto &[Var, DILoc] = DVMap.lookupDVID(VarID); - PendingDbgValues.push_back( - std::make_pair(VarID, &*MTracker->emitLoc(ResolvedDbgOps, Var, DILoc, - Value.Properties))); } /// Load object with live-in variable values. \p mlocs contains the live-in @@ -668,6 +677,16 @@ class TransferTracker { auto &[Var, DILoc] = DVMap.lookupDVID(VarID); + // If the expression is a DW_OP_entry_value, emit the variable location + // as-is. + if (DIExpr->isEntryValue()) { + Register Reg = MTracker->LocIdxToLocID[Num.getLoc()]; + MachineOperand MO = MachineOperand::CreateReg(Reg, false); + PendingDbgValues.push_back(std::make_pair( + VarID, &*emitMOLoc(MO, Var, {DIExpr, Prop.Indirect, false}))); + return true; + } + // Is the variable appropriate for entry values (i.e., is a parameter). if (!isEntryValueVariable(Var, DIExpr)) return false; @@ -694,7 +713,7 @@ class TransferTracker { DebugVariableID VarID = DVMap.getDVID(Var); // Ignore non-register locations, we don't transfer those. - if (MI.isUndefDebugValue() || + if (MI.isUndefDebugValue() || MI.getDebugExpression()->isEntryValue() || all_of(MI.debug_operands(), [](const MachineOperand &MO) { return !MO.isReg(); })) { auto It = ActiveVLocs.find(VarID); diff --git a/llvm/test/DebugInfo/MIR/AArch64/entry_value_gets_propagated_aarch64.mir b/llvm/test/DebugInfo/MIR/AArch64/entry_value_gets_propagated_aarch64.mir new file mode 100644 index 0000000000000..7366ba4de64f4 --- /dev/null +++ b/llvm/test/DebugInfo/MIR/AArch64/entry_value_gets_propagated_aarch64.mir @@ -0,0 +1,84 @@ +# RUN: llc --run-pass=livedebugvalues -o - %s | FileCheck %s --implicit-check-not=DBG_VALUE +# REQUIRES: aarch64-registered-target + +# This test covers the scenario where a DBG_VALUE created prior to LiveDebugValues has an entry-value expression. +# It ensures that a clobbered stack copy doesn't crash if used as an entry-value because entry-values can't be clobbered. + +--- | + target triple = "aarch64-" + define i32 @baz(i32 swiftasync %arg1, i32 noundef %arg2, i1 %cond) !dbg !4 { + br i1 %cond, label %if.then, label %if.else, !dbg !14 + if.then: ; preds = %0 + %call = call i32 @foo(i32 noundef %arg1), !dbg !15 + br label %if.end, !dbg !18 + if.else: ; preds = %0 + %call1 = call i32 @foo(i32 noundef %arg2), !dbg !19 + br label %if.end + if.end: ; preds = %if.else, %if.then + %temp.0 = phi i32 [ %call, %if.then ], [ %call1, %if.else ], !dbg !21 + ret i32 %temp.0, !dbg !22 + } + declare i32 @foo(i32) + !llvm.dbg.cu = !{!0} + !llvm.module.flags = !{!2, !3} + !0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "ha", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug) + !1 = !DIFile(filename: "test.c", directory: "hah") + !2 = !{i32 7, !"Dwarf Version", i32 4} + !3 = !{i32 2, !"Debug Info Version", i32 3} + !4 = distinct !DISubprogram(name: "baz", scope: !1, file: !1, line: 3, type: !5, scopeLine: 3, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !8) + !5 = !DISubroutineType(types: !6) + !6 = !{!7, !7, !7, !7} + !7 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) + !8 = !{!9, !10, !11, !12} + !9 = !DILocalVariable(name: "arg1", arg: 1, scope: !4, file: !1, line: 3, type: !7) + !10 = !DILocalVariable(name: "arg2", arg: 2, scope: !4, file: !1, line: 3, type: !7) + !11 = !DILocalVariable(name: "cond", arg: 3, scope: !4, file: !1, line: 3, type: !7) + !12 = !DILocalVariable(name: "local", scope: !4, file: !1, line: 4, type: !7) + !13 = !DILocation(line: 0, scope: !4) + !14 = !DILocation(line: 7, column: 7, scope: !4) + !15 = !DILocation(line: 8, column: 12, scope: !16) + !16 = distinct !DILexicalBlock(scope: !17, file: !1, line: 7, column: 13) + !17 = distinct !DILexicalBlock(scope: !4, file: !1, line: 7, column: 7) + !18 = !DILocation(line: 9, column: 3, scope: !16) + !19 = !DILocation(line: 10, column: 12, scope: !20) + !20 = distinct !DILexicalBlock(scope: !17, file: !1, line: 9, column: 10) + !21 = !DILocation(line: 0, scope: !17) + !22 = !DILocation(line: 13, column: 3, scope: !4) +name: baz +debugInstrRef: true +stack: + - { id: 1, name: '', type: spill-slot, offset: -24, size: 4, alignment: 4, + debug-info-variable: '', debug-info-expression: '', debug-info-location: '' } +body: | + bb.0 (%ir-block.0): + DBG_VALUE $w1, $noreg, !12, !DIExpression(DW_OP_LLVM_entry_value, 1), debug-location !13 + + bb.1.if.then: + $w0 = LDRWui $sp, 2 + BL @foo, csr_darwin_aarch64_aapcs, implicit-def dead $lr, implicit $sp, implicit killed $w0, implicit-def $w0, debug-location !15 + $w1 = MOVi32imm 0 + + bb.2.if.else: + $w0 = LDRWui $sp, 3 + BL @foo, csr_darwin_aarch64_aapcs, implicit-def dead $lr, implicit $sp, implicit killed $w0, implicit-def $w0, debug-location !19 + STRWui killed $w0, $sp, 1 + B %bb.3 + + bb.3.if.end: + $w0 = LDRWui $sp, 1 + $fp, $lr = frame-destroy LDPXi $sp, 2, debug-location !22 + $sp = frame-destroy ADDXri $sp, 32, 0, debug-location !22 + RET undef $lr, implicit killed $w0, debug-location !22 + +# CHECK-LABEL: bb.0 +# CHECK: DBG_VALUE $w1, {{.*}}, !DIExpression(DW_OP_LLVM_entry_value, 1) +# CHECK-LABEL: bb.1.if.then: +# CHECK: DBG_VALUE $w1, {{.*}}, !DIExpression(DW_OP_LLVM_entry_value, 1) +# CHECK-NEXT: $w0 = LDRWui $sp, 2 +# CHECK-NEXT: BL @foo +# CHECK-NEXT: $w1 = MOVi32imm 0 +# CHECK-NOT: DBG_VALUE $w1, {{.*}}, !DIExpression(DW_OP_LLVM_entry_value, 1) +# CHECK-LABEL: bb.2.if.else: +# CHECK: DBG_VALUE $w1, {{.*}}, !DIExpression(DW_OP_LLVM_entry_value, 1) +# CHECK-LABEL: bb.3.if.end: +# CHECK: DBG_VALUE $w1, {{.*}}, !DIExpression(DW_OP_LLVM_entry_value, 1) \ No newline at end of file diff --git a/llvm/test/DebugInfo/MIR/X86/entry_value_clobbered_stack_copy.mir b/llvm/test/DebugInfo/MIR/X86/entry_value_clobbered_stack_copy.mir new file mode 100644 index 0000000000000..8fe3f7b75a765 --- /dev/null +++ b/llvm/test/DebugInfo/MIR/X86/entry_value_clobbered_stack_copy.mir @@ -0,0 +1,52 @@ +# RUN: llc --run-pass=livedebugvalues -o - %s | FileCheck %s +# REQUIRES: x86-registered-target + +# This test covers the scenario that saves a register on the stack, uses this register as an entry value DBG_VALUE location, and then clobbers it. + +--- | + target triple = "x86_64-" + define void @foo(ptr swiftasync %0) !dbg !4 { + call void @llvm.dbg.value(metadata ptr %0, metadata !9, metadata !DIExpression(DW_OP_LLVM_entry_value, 1)), !dbg !17 + ret void + } + declare void @llvm.dbg.value(metadata, metadata, metadata) + + !llvm.module.flags = !{!0} + !llvm.dbg.cu = !{!1} + + !0 = !{i32 2, !"Debug Info Version", i32 3} + !1 = distinct !DICompileUnit(language: DW_LANG_Swift, file: !2, producer: "blah", isOptimized: true, flags: "blah", runtimeVersion: 5, emissionKind: FullDebug) + !2 = !DIFile(filename: "blah", directory: "blah") + !3 = !{} + !4 = distinct !DISubprogram(name: "blah", linkageName: "blah", scope: !2, file: !2, line: 284, type: !7, unit: !1) + !7 = !DISubroutineType(types: !3) + !9 = !DILocalVariable(name: "self", arg: 3, scope: !4, file: !2, line: 328, type: !12, flags: DIFlagArtificial) + !12 = !DICompositeType(tag: DW_TAG_structure_type, name: "blah", scope: !2, file: !2, size: 64, elements: !3) + !17 = !DILocation(line: 328, column: 17, scope: !4) + +... +--- +name: foo +alignment: 16 +debugInstrRef: true +tracksDebugUserValues: true +liveins: + - { reg: '$r14', virtual-reg: '' } +stack: + - { id: 0, name: '', type: spill-slot, offset: -64, size: 8, alignment: 8, + stack-id: default, callee-saved-register: '', callee-saved-restored: true, + debug-info-variable: '', debug-info-expression: '', debug-info-location: '' } +body: | + bb.0: + liveins: $r14 + ; Put a copy of r14 on the stack. + MOV64mr $rbp, 1, $noreg, -48, $noreg, $r14 :: (store (s64) into %stack.0) + DBG_VALUE $r14, $noreg, !9, !DIExpression(DW_OP_LLVM_entry_value, 1), debug-location !17 + MOV64mi32 $noreg, 1, $noreg, 0, $noreg, 0, debug-location !17 :: (store (s64) into `ptr null`) + $r14 = MOV64rr killed $r13 + ; Clobber $r14 + RETI64 24 +# CHECK: bb.0: +# CHECK: MOV64mr $rbp, 1, $noreg, -48, $noreg, $r14 +# CHECK-NEXT: DBG_VALUE $r14, {{.*}}, !DIExpression(DW_OP_LLVM_entry_value, 1) +# CHECK-NOT: DBG_VALUE diff --git a/llvm/test/DebugInfo/MIR/X86/entry_value_gets_propagated_X86.mir b/llvm/test/DebugInfo/MIR/X86/entry_value_gets_propagated_X86.mir new file mode 100644 index 0000000000000..4e8863064c4fc --- /dev/null +++ b/llvm/test/DebugInfo/MIR/X86/entry_value_gets_propagated_X86.mir @@ -0,0 +1,98 @@ +# RUN: llc --run-pass=livedebugvalues -o - %s | FileCheck %s --implicit-check-not=DBG_VALUE +# REQUIRES: x86-registered-target + +# This test covers the scenario where a DBG_VALUE created prior to LiveDebugValues has an entry-value expression. +# It ensures that a clobbered stack copy doesn't crash if used as an entry-value because entry-values can't be clobbered. + +--- | + target triple = "x86_64-" + + define i32 @baz(i32 swiftasync %arg1, i32 noundef %arg2, i1 %cond) !dbg !9 { + tail call void @llvm.dbg.value(metadata i32 %arg1, metadata !17, metadata !DIExpression(DW_OP_LLVM_entry_value, 1)), !dbg !19 + br i1 %cond, label %if.then, label %if.else, !dbg !22 + if.then: + %call = call i32 @foo(i32 noundef %arg1), !dbg !23 + br label %if.end, !dbg !25 + if.else: + %call1 = call i32 @foo(i32 noundef %arg2), !dbg !26 + br label %if.end + if.end: + %temp.0 = phi i32 [ %call, %if.then ], [ %call1, %if.else ], !dbg !28 + ret i32 %temp.0, !dbg !29 + } + + declare i32 @foo(i32) + declare void @llvm.dbg.value(metadata, metadata, metadata) + + !llvm.dbg.cu = !{!0} + !llvm.module.flags = !{!2, !3} + + !0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "ha", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug) + !1 = !DIFile(filename: "test.c", directory: "hah") + !2 = !{i32 7, !"Dwarf Version", i32 4} + !3 = !{i32 2, !"Debug Info Version", i32 3} + !9 = distinct !DISubprogram(name: "baz", scope: !1, file: !1, line: 3, type: !10, scopeLine: 3, unit: !0, retainedNodes: !13) + !10 = !DISubroutineType(types: !11) + !11 = !{!12, !12, !12, !12} + !12 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) + !13 = !{!14, !15, !16, !17} + !14 = !DILocalVariable(name: "arg1", arg: 1, scope: !9, file: !1, line: 3, type: !12) + !15 = !DILocalVariable(name: "arg2", arg: 2, scope: !9, file: !1, line: 3, type: !12) + !16 = !DILocalVariable(name: "cond", arg: 3, scope: !9, file: !1, line: 3, type: !12) + !17 = !DILocalVariable(name: "local", scope: !9, file: !1, line: 4, type: !12) + !19 = !DILocation(line: 0, scope: !9) + !20 = !DILocation(line: 7, column: 7, scope: !21) + !21 = distinct !DILexicalBlock(scope: !9, file: !1, line: 7, column: 7) + !22 = !DILocation(line: 7, column: 7, scope: !9) + !23 = !DILocation(line: 8, column: 12, scope: !24) + !24 = distinct !DILexicalBlock(scope: !21, file: !1, line: 7, column: 13) + !25 = !DILocation(line: 9, column: 3, scope: !24) + !26 = !DILocation(line: 10, column: 12, scope: !27) + !27 = distinct !DILexicalBlock(scope: !21, file: !1, line: 9, column: 10) + !28 = !DILocation(line: 0, scope: !21) + !29 = !DILocation(line: 13, column: 3, scope: !9) + +... +--- +name: baz +alignment: 16 +debugInstrRef: true +tracksDebugUserValues: true +liveins: + - { reg: '$r14', virtual-reg: '' } + - { reg: '$edi', virtual-reg: '' } + - { reg: '$esi', virtual-reg: '' } + - { reg: '$edx', virtual-reg: '' } +body: | + bb.0: + successors: %bb.2(0x40000000), %bb.1(0x40000000) + liveins: $r14, $edi, $edx, $esi + DBG_VALUE $r14, $noreg, !14, !DIExpression(DW_OP_LLVM_entry_value, 1), debug-location !19 + CMP32ri killed renamable $edx, 0, implicit-def $eflags, debug-location !20 + JCC_1 %bb.2, 4, implicit killed $eflags, debug-location !22 + bb.1.if.then: + successors: %bb.3(0x80000000) + liveins: $edi, $r13 + CALL64pcrel32 @foo, csr_64, implicit $rsp, implicit $ssp, implicit $edi, implicit-def $eax, debug-location !23 + $r14 = MOV64ri 0, debug-location !20 + JMP_1 %bb.3, debug-location !25 + bb.2.if.else: + successors: %bb.3(0x80000000) + liveins: $esi, $r13 + $edi = MOV32rr killed $esi, debug-location !26 + CALL64pcrel32 @foo, csr_64, implicit $rsp, implicit $ssp, implicit $edi, implicit-def $eax, debug-location !26 + bb.3.if.end: + liveins: $eax + $rbp = frame-destroy POP64r implicit-def $rsp, implicit $rsp, debug-location !29 + RET64 implicit $eax, debug-location !29 +# CHECK-LABEL: bb.0: +# CHECK: DBG_VALUE $r14, {{.*}}, !DIExpression(DW_OP_LLVM_entry_value, 1) +# CHECK-LABEL: bb.1.if.then: +# CHECK: DBG_VALUE $r14, {{.*}}, !DIExpression(DW_OP_LLVM_entry_value, 1) +# CHECK-NEXT: CALL64pcrel32 @foo +# CHECK-NEXT: $r14 = MOV64ri 0 +# CHECK-NOT: DBG_VALUE $r14, {{.*}}, !DIExpression(DW_OP_LLVM_entry_value, 1) +# CHECK-LABEL: bb.2.if.else: +# CHECK: DBG_VALUE $r14, {{.*}}, !DIExpression(DW_OP_LLVM_entry_value, 1) +# CHECK-LABEL: bb.3.if.end: +# CHECK: DBG_VALUE $r14, {{.*}}, !DIExpression(DW_OP_LLVM_entry_value, 1)