[llvm] [AMDGPU][LiveDebugValues] Do not join debug values whose operand counts disagree (PR #221929)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Sep 8 02:08:55 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-debuginfo
Author: Teja Alaghari (TejaX-Alaghari)
<details>
<summary>Changes</summary>
Currently, `DbgValueProperties::isJoinable()` decides whether two values could be joined by comparing their `DIExpressions` only. That was safe when location-operand count was taken from the expression. In instruction-referencing `LiveDebugValues`, `NumLocOps` is taken from the `MachineInstr` (`getNumDebugOperands()`), so two values can share an expression and still differ in operand count.
Joining pairs location operands by index. When the counts disagreed, `pickVPHILoc` indexed past the shorter list and hit `assert(Index < OpCount)` in `DbgValue::getDbgOpID`.
This change makes `isJoinable()` return `false` unless `NumLocOps` **also agrees**. The merge block then gets no location for that variable, which is correct.
---
Full diff: https://github.com/llvm/llvm-project/pull/221929.diff
2 Files Affected:
- (modified) llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.h (+18-7)
- (added) llvm/test/DebugInfo/MIR/InstrRef/expr-operand-count-mismatch.mir (+91)
``````````diff
diff --git a/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.h b/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.h
index 184f07cb9fdf8..d73697fe5b4fc 100644
--- a/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.h
+++ b/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.h
@@ -299,8 +299,12 @@ class SpillLocationNo {
/// the value, and Boolean of whether or not it's indirect.
class DbgValueProperties {
public:
- DbgValueProperties(const DIExpression *DIExpr, bool Indirect, bool IsVariadic)
- : DIExpr(DIExpr), Indirect(Indirect), IsVariadic(IsVariadic) {}
+ DbgValueProperties(const DIExpression *DIExpr, bool Indirect, bool IsVariadic,
+ std::optional<unsigned> NumLocOps = std::nullopt)
+ : DIExpr(DIExpr), Indirect(Indirect), IsVariadic(IsVariadic),
+ NumLocOps(NumLocOps
+ ? *NumLocOps
+ : (IsVariadic ? DIExpr->getNumLocationOperands() : 1)) {}
/// Extract properties from an existing DBG_VALUE instruction.
DbgValueProperties(const MachineInstr &MI) {
@@ -310,29 +314,36 @@ class DbgValueProperties {
IsVariadic = MI.isDebugValueList();
DIExpr = MI.getDebugExpression();
Indirect = MI.isDebugOffsetImm();
+ NumLocOps = MI.getNumDebugOperands();
}
bool isJoinable(const DbgValueProperties &Other) const {
+ // Joining pairs location operands by index, so the operand counts must
+ // agree. Equal expressions do not imply equal counts, because the same
+ // DIExpression can appear on MachineInstrs with different numbers of
+ // debug operands.
+ if (NumLocOps != Other.NumLocOps)
+ return false;
return DIExpression::isEqualExpression(DIExpr, Indirect, Other.DIExpr,
Other.Indirect);
}
bool operator==(const DbgValueProperties &Other) const {
- return std::tie(DIExpr, Indirect, IsVariadic) ==
- std::tie(Other.DIExpr, Other.Indirect, Other.IsVariadic);
+ return std::tie(DIExpr, Indirect, IsVariadic, NumLocOps) ==
+ std::tie(Other.DIExpr, Other.Indirect, Other.IsVariadic,
+ Other.NumLocOps);
}
bool operator!=(const DbgValueProperties &Other) const {
return !(*this == Other);
}
- unsigned getLocationOpCount() const {
- return IsVariadic ? DIExpr->getNumLocationOperands() : 1;
- }
+ unsigned getLocationOpCount() const { return NumLocOps; }
const DIExpression *DIExpr;
bool Indirect;
bool IsVariadic;
+ unsigned NumLocOps;
};
/// TODO: Might pack better if we changed this to a Struct of Arrays, since
diff --git a/llvm/test/DebugInfo/MIR/InstrRef/expr-operand-count-mismatch.mir b/llvm/test/DebugInfo/MIR/InstrRef/expr-operand-count-mismatch.mir
new file mode 100644
index 0000000000000..13f436084d4d4
--- /dev/null
+++ b/llvm/test/DebugInfo/MIR/InstrRef/expr-operand-count-mismatch.mir
@@ -0,0 +1,91 @@
+# RUN: llc %s -o - -experimental-debug-variable-locations=true \
+# RUN: -run-pass=livedebugvalues | FileCheck %s
+#
+## Two debug values for the same variable can carry identical expressions
+## while having different numbers of location operands.
+##
+## LiveDebugValues joins values by pairing their location operands up by index,
+## and used to decide two values were joinable by comparing expressions alone.
+## When the counts disagreed it read past the end of the shorter value's
+## operand list. Check that we no longer do so, and that no location is
+## propagated into the join block, where the two counts disagree.
+#
+# CHECK: ![[VAR:[0-9]+]] = !DILocalVariable(name: "x"
+#
+# CHECK-LABEL: bb.0.entry:
+# CHECK: DBG_VALUE_LIST ![[VAR]], !DIExpression(), $noreg, $noreg, debug-location
+#
+# CHECK-LABEL: bb.1.then:
+# CHECK: DBG_VALUE_LIST ![[VAR]], !DIExpression(), $edi, $edi, debug-location
+# CHECK: DBG_VALUE_LIST ![[VAR]], !DIExpression(), $edi, debug-location
+#
+# CHECK-LABEL: bb.2.exit:
+# CHECK-NOT: DBG_VALUE
+
+--- |
+ target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+ target triple = "x86_64-unknown-unknown"
+
+ define i32 @f(i32 %a, i1 %c) !dbg !4 {
+ entry:
+ %v = add i32 %a, 1, !dbg !7
+ #dbg_value(!DIArgList(i32 %v, i32 %v), !8, !DIExpression(), !7)
+ br i1 %c, label %exit, label %then
+
+ then: ; preds = %entry
+ #dbg_value(i32 %v, !8, !DIExpression(), !7)
+ %t = mul i32 %v, 3, !dbg !7
+ br label %exit
+
+ exit: ; preds = %then, %entry
+ %p = phi i32 [ %t, %then ], [ 0, %entry ], !dbg !7
+ ret i32 %p, !dbg !7
+ }
+
+ !llvm.dbg.cu = !{!0}
+ !llvm.module.flags = !{!3}
+
+ !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "hand-written", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
+ !1 = !DIFile(filename: "min.c", directory: "/")
+ !2 = !{}
+ !3 = !{i32 2, !"Debug Info Version", i32 3}
+ !4 = distinct !DISubprogram(name: "f", scope: !1, file: !1, line: 1, type: !5, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !2)
+ !5 = distinct !DISubroutineType(types: !6)
+ !6 = !{null}
+ !7 = !DILocation(line: 1, column: 1, scope: !4)
+ !8 = !DILocalVariable(name: "x", scope: !4, file: !1, line: 1, type: !9)
+ !9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+...
+---
+name: f
+alignment: 1
+tracksRegLiveness: true
+debugInstrRef: true
+tracksDebugUserValues: true
+liveins:
+ - { reg: '$edi', virtual-reg: '' }
+ - { reg: '$esi', virtual-reg: '' }
+body: |
+ bb.0.entry:
+ successors: %bb.2(0x40000000), %bb.1(0x40000000)
+ liveins: $edi, $esi
+
+ renamable $edi = KILL $edi, implicit-def $rdi
+ DBG_INSTR_REF !8, !DIExpression(), dbg-instr-ref(1, 0), dbg-instr-ref(1, 0), debug-location !7
+ renamable $eax = XOR32rr undef $eax, undef $eax, implicit-def dead $eflags
+ TEST8ri renamable $sil, 1, implicit-def $eflags, implicit killed $esi
+ JCC_1 %bb.2, 5, implicit $eflags
+
+ bb.1.then:
+ successors: %bb.2(0x80000000)
+ liveins: $rdi
+
+ renamable $edi = INC32r renamable $edi, implicit-def dead $eflags, implicit killed $rdi, implicit-def $rdi, debug-instr-number 1, debug-location !7
+ DBG_INSTR_REF !8, !DIExpression(), dbg-instr-ref(1, 0), debug-location !7
+ renamable $eax = LEA64_32r killed renamable $rdi, 2, renamable $rdi, 0, $noreg, debug-location !7
+
+ bb.2.exit:
+ liveins: $eax
+
+ RET64 $eax, debug-location !7
+...
``````````
</details>
https://github.com/llvm/llvm-project/pull/221929
More information about the llvm-commits
mailing list