[llvm] [CodeGen] PHIEliminationImpl::LowerPHINode: Fix assertion failure when all phi operands are undefined (PR #209013)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Jul 24 05:12:01 PDT 2026
https://github.com/rdevshp updated https://github.com/llvm/llvm-project/pull/209013
>From dbcf25d59d599c765703281a83d8a141ecb46493 Mon Sep 17 00:00:00 2001
From: rdevshp <rdevshp at gmail.com>
Date: Sun, 12 Jul 2026 11:52:37 +0000
Subject: [PATCH 1/2] [CodeGen] PHIEliminationImpl::LowerPHINode: Fix assertion
failure when all phi operands are undefined
IncomingReg is only set to a register when allPhiOperandsUndefined does not hold.
Changes PHIEliminationImpl::LowerPHINode to check IncomingReg before using it
for debug phi.
Fixes #206324
Assisted-by: Codex
---
llvm/lib/CodeGen/PHIElimination.cpp | 2 +-
.../InstrRef/undef-phi-through-regalloc.mir | 182 ++++++++++++++++++
2 files changed, 183 insertions(+), 1 deletion(-)
create mode 100644 llvm/test/DebugInfo/MIR/InstrRef/undef-phi-through-regalloc.mir
diff --git a/llvm/lib/CodeGen/PHIElimination.cpp b/llvm/lib/CodeGen/PHIElimination.cpp
index 403831f1c3503..c3f7d973843ea 100644
--- a/llvm/lib/CodeGen/PHIElimination.cpp
+++ b/llvm/lib/CodeGen/PHIElimination.cpp
@@ -422,7 +422,7 @@ void PHIEliminationImpl::LowerPHINode(MachineBasicBlock &MBB,
MBB, AfterPHIsIt, MPhi->getDebugLoc(), IncomingReg, DestReg);
}
- if (MPhi->peekDebugInstrNum()) {
+ if (MPhi->peekDebugInstrNum() && IncomingReg) {
// If referred to by debug-info, store where this PHI was.
MachineFunction *MF = MBB.getParent();
unsigned ID = MPhi->peekDebugInstrNum();
diff --git a/llvm/test/DebugInfo/MIR/InstrRef/undef-phi-through-regalloc.mir b/llvm/test/DebugInfo/MIR/InstrRef/undef-phi-through-regalloc.mir
new file mode 100644
index 0000000000000..79c3f08542584
--- /dev/null
+++ b/llvm/test/DebugInfo/MIR/InstrRef/undef-phi-through-regalloc.mir
@@ -0,0 +1,182 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 6
+# RUN: llc %s -o - -mtriple=x86_64-unknown-unknown \
+# RUN: -experimental-debug-variable-locations \
+# RUN: -run-pass=phi-node-elimination,livedebugvars,greedy,virtregrewriter \
+# RUN: | FileCheck %s
+#
+# This test checks phi-node-elimination does not create a debug phi
+# with invalid register reference
+# Original code fed to llc -stop-before...
+# target triple = "x86_64"
+#
+# define void @f(i1 %c) !dbg !5 {
+# e:
+# br label %l
+#
+# l:
+# %x = phi <1 x i1> [ undef, %e ], [ %y, %a ], [ undef, %b ]
+# #dbg_value(<1 x i1> %x, !DILocalVariable(scope: !5), !DIExpression(), !DILocation(scope: !5))
+# br i1 %c, label %a, label %b
+#
+# a:
+# %y = insertelement <1 x i1> %x, i1 undef, i64 0
+# br i1 %c, label %l, label %z
+#
+# b:
+# br i1 %c, label %l, label %z
+#
+# z:
+# %r = phi <1 x i1> [ %y, %a ], [ undef, %b ]
+# store <1 x i1> %r, ptr null
+# ret void
+# }
+#
+# !llvm.dbg.cu = !{!0}
+# !llvm.module.flags = !{!2}
+# !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !DIFile(filename: "x", directory: ""), emissionKind: FullDebug)
+# !2 = !{i32 2, !"Debug Info Version", i32 3}
+# !5 = distinct !DISubprogram(scope: !0, type: !DISubroutineType(types: !{null}), unit: !0, keyInstructions: true)
+
+--- |
+ ; ModuleID = 'prog.ll'
+ source_filename = "prog.ll"
+ 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"
+
+ define void @f(i1 %c) !dbg !3 {
+ e:
+ br label %l
+
+ l: ; preds = %b, %a, %e
+ %x = phi <1 x i1> [ undef, %e ], [ %y, %a ], [ undef, %b ]
+ #dbg_value(<1 x i1> %x, !6, !DIExpression(), !7)
+ br i1 %c, label %a, label %b
+
+ a: ; preds = %l
+ %y = insertelement <1 x i1> %x, i1 undef, i64 0
+ br i1 %c, label %l, label %z
+
+ b: ; preds = %l
+ br i1 %c, label %l, label %z
+
+ z: ; preds = %b, %a
+ %r = phi <1 x i1> [ %y, %a ], [ undef, %b ]
+ store <1 x i1> %r, ptr null, align 1
+ ret void
+ }
+
+ !llvm.dbg.cu = !{!0}
+ !llvm.module.flags = !{!2}
+
+ !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug)
+ !1 = !DIFile(filename: "x", directory: "")
+ !2 = !{i32 2, !"Debug Info Version", i32 3}
+ !3 = distinct !DISubprogram(scope: !0, type: !4, spFlags: DISPFlagDefinition, unit: !0, keyInstructions: true)
+ !4 = !DISubroutineType(types: !5)
+ !5 = !{null}
+ !6 = !DILocalVariable(scope: !3)
+ !7 = !DILocation(line: 0, scope: !3)
+...
+---
+name: f
+alignment: 1
+exposesReturnsTwice: false
+legalized: false
+regBankSelected: false
+selected: false
+failedISel: false
+tracksRegLiveness: true
+hasWinCFI: false
+noPhis: false
+isSSA: true
+noVRegs: false
+hasFakeUses: false
+callsEHReturn: false
+callsUnwindInit: false
+hasEHContTarget: false
+hasEHScopes: false
+hasEHFunclets: false
+isOutlined: false
+debugInstrRef: true
+failsVerification: false
+tracksDebugUserValues: false
+registers:
+ - { id: 0, class: gr8, preferred-register: '', flags: [ ] }
+ - { id: 1, class: gr8, preferred-register: '', flags: [ ] }
+ - { id: 2, class: gr8, preferred-register: '', flags: [ ] }
+ - { id: 3, class: gr32, preferred-register: '', flags: [ ] }
+ - { id: 4, class: gr8, preferred-register: '', flags: [ ] }
+ - { id: 5, class: gr8, preferred-register: '', flags: [ ] }
+ - { id: 6, class: gr8, preferred-register: '', flags: [ ] }
+ - { id: 7, class: gr8, preferred-register: '', flags: [ ] }
+liveins:
+ - { reg: '$edi', virtual-reg: '%3' }
+frameInfo:
+ isFrameAddressTaken: false
+ isReturnAddressTaken: false
+ hasStackMap: false
+ hasPatchPoint: false
+ stackSize: 0
+ offsetAdjustment: 0
+ maxAlignment: 1
+ adjustsStack: false
+ hasCalls: false
+ framePointerPolicy: none
+ stackProtector: ''
+ functionContext: ''
+ maxCallFrameSize: 4294967295
+ cvBytesOfCalleeSavedRegisters: 0
+ hasOpaqueSPAdjustment: false
+ hasVAStart: false
+ hasMustTailInVarArgFunc: false
+ hasTailCall: false
+ isCalleeSavedInfoValid: false
+ localFrameSize: 0
+fixedStack: []
+stack: []
+entry_values: []
+callSites: []
+debugValueSubstitutions: []
+constants: []
+machineFunctionInfo:
+ amxProgModel: None
+body: |
+ ; CHECK-LABEL: name: f
+ ; CHECK-NOT: DBG_PHI
+ ; CHECK: RET 0
+ bb.0.e:
+ successors: %bb.1(0x80000000)
+ liveins: $edi
+
+ %3:gr32 = COPY killed $edi
+ %4:gr8 = COPY killed %3.sub_8bit
+
+ bb.1.l:
+ successors: %bb.2(0x40000000), %bb.3(0x40000000)
+
+ %0:gr8 = PHI undef %5:gr8, %bb.0, undef %6:gr8, %bb.3, %0, %bb.2, debug-instr-number 1
+ DBG_INSTR_REF !6, !DIExpression(DW_OP_LLVM_arg, 0), dbg-instr-ref(1, 0), debug-location !7
+ TEST8ri %4, 1, implicit-def $eflags
+ JCC_1 %bb.3, 4, implicit $eflags
+ JMP_1 %bb.2
+
+ bb.2.a:
+ successors: %bb.1(0x7c000000), %bb.4(0x04000000)
+ liveins: $eflags
+
+ JCC_1 %bb.1, 5, implicit killed $eflags
+ JMP_1 %bb.4
+
+ bb.3.b:
+ successors: %bb.1(0x7c000000), %bb.4(0x04000000)
+ liveins: $eflags
+
+ JCC_1 %bb.1, 5, implicit killed $eflags
+ JMP_1 %bb.4
+
+ bb.4.z:
+ %2:gr8 = PHI undef %6:gr8, %bb.3, %0, %bb.2
+ %7:gr8 = AND8ri killed %2, 1, implicit-def dead $eflags
+ MOV8mr $noreg, 1, $noreg, 0, $noreg, killed %7 :: (store (s8) into `ptr null`)
+ RET 0
+...
>From 592929ca24f3d7ecbb5b6af26952ec900da18916 Mon Sep 17 00:00:00 2001
From: rdevshp <rdevshp at gmail.com>
Date: Fri, 24 Jul 2026 12:10:47 +0000
Subject: [PATCH 2/2] Minimize test case
---
.../InstrRef/undef-phi-through-regalloc.mir | 184 ++----------------
1 file changed, 21 insertions(+), 163 deletions(-)
diff --git a/llvm/test/DebugInfo/MIR/InstrRef/undef-phi-through-regalloc.mir b/llvm/test/DebugInfo/MIR/InstrRef/undef-phi-through-regalloc.mir
index 79c3f08542584..68c4589798078 100644
--- a/llvm/test/DebugInfo/MIR/InstrRef/undef-phi-through-regalloc.mir
+++ b/llvm/test/DebugInfo/MIR/InstrRef/undef-phi-through-regalloc.mir
@@ -6,177 +6,35 @@
#
# This test checks phi-node-elimination does not create a debug phi
# with invalid register reference
-# Original code fed to llc -stop-before...
-# target triple = "x86_64"
-#
-# define void @f(i1 %c) !dbg !5 {
-# e:
-# br label %l
-#
-# l:
-# %x = phi <1 x i1> [ undef, %e ], [ %y, %a ], [ undef, %b ]
-# #dbg_value(<1 x i1> %x, !DILocalVariable(scope: !5), !DIExpression(), !DILocation(scope: !5))
-# br i1 %c, label %a, label %b
-#
-# a:
-# %y = insertelement <1 x i1> %x, i1 undef, i64 0
-# br i1 %c, label %l, label %z
-#
-# b:
-# br i1 %c, label %l, label %z
-#
-# z:
-# %r = phi <1 x i1> [ %y, %a ], [ undef, %b ]
-# store <1 x i1> %r, ptr null
-# ret void
-# }
-#
-# !llvm.dbg.cu = !{!0}
-# !llvm.module.flags = !{!2}
-# !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !DIFile(filename: "x", directory: ""), emissionKind: FullDebug)
-# !2 = !{i32 2, !"Debug Info Version", i32 3}
-# !5 = distinct !DISubprogram(scope: !0, type: !DISubroutineType(types: !{null}), unit: !0, keyInstructions: true)
--- |
- ; ModuleID = 'prog.ll'
- source_filename = "prog.ll"
- 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"
-
- define void @f(i1 %c) !dbg !3 {
- e:
- br label %l
-
- l: ; preds = %b, %a, %e
- %x = phi <1 x i1> [ undef, %e ], [ %y, %a ], [ undef, %b ]
- #dbg_value(<1 x i1> %x, !6, !DIExpression(), !7)
- br i1 %c, label %a, label %b
-
- a: ; preds = %l
- %y = insertelement <1 x i1> %x, i1 undef, i64 0
- br i1 %c, label %l, label %z
-
- b: ; preds = %l
- br i1 %c, label %l, label %z
-
- z: ; preds = %b, %a
- %r = phi <1 x i1> [ %y, %a ], [ undef, %b ]
- store <1 x i1> %r, ptr null, align 1
+ define void @f() !dbg !2 {
ret void
}
!llvm.dbg.cu = !{!0}
- !llvm.module.flags = !{!2}
-
- !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug)
- !1 = !DIFile(filename: "x", directory: "")
- !2 = !{i32 2, !"Debug Info Version", i32 3}
- !3 = distinct !DISubprogram(scope: !0, type: !4, spFlags: DISPFlagDefinition, unit: !0, keyInstructions: true)
- !4 = !DISubroutineType(types: !5)
- !5 = !{null}
- !6 = !DILocalVariable(scope: !3)
- !7 = !DILocation(line: 0, scope: !3)
+ !llvm.module.flags = !{!1}
+ !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !DIFile(filename: "x", directory: ""), emissionKind: FullDebug)
+ !1 = !{i32 2, !"Debug Info Version", i32 3}
+ !2 = distinct !DISubprogram(scope: !0, type: !DISubroutineType(types: !{null}), unit: !0, retainedNodes: !{!6})
+ !6 = !DILocalVariable(scope: !2)
...
---
-name: f
-alignment: 1
-exposesReturnsTwice: false
-legalized: false
-regBankSelected: false
-selected: false
-failedISel: false
-tracksRegLiveness: true
-hasWinCFI: false
-noPhis: false
-isSSA: true
-noVRegs: false
-hasFakeUses: false
-callsEHReturn: false
-callsUnwindInit: false
-hasEHContTarget: false
-hasEHScopes: false
-hasEHFunclets: false
-isOutlined: false
-debugInstrRef: true
-failsVerification: false
-tracksDebugUserValues: false
-registers:
- - { id: 0, class: gr8, preferred-register: '', flags: [ ] }
- - { id: 1, class: gr8, preferred-register: '', flags: [ ] }
- - { id: 2, class: gr8, preferred-register: '', flags: [ ] }
- - { id: 3, class: gr32, preferred-register: '', flags: [ ] }
- - { id: 4, class: gr8, preferred-register: '', flags: [ ] }
- - { id: 5, class: gr8, preferred-register: '', flags: [ ] }
- - { id: 6, class: gr8, preferred-register: '', flags: [ ] }
- - { id: 7, class: gr8, preferred-register: '', flags: [ ] }
-liveins:
- - { reg: '$edi', virtual-reg: '%3' }
-frameInfo:
- isFrameAddressTaken: false
- isReturnAddressTaken: false
- hasStackMap: false
- hasPatchPoint: false
- stackSize: 0
- offsetAdjustment: 0
- maxAlignment: 1
- adjustsStack: false
- hasCalls: false
- framePointerPolicy: none
- stackProtector: ''
- functionContext: ''
- maxCallFrameSize: 4294967295
- cvBytesOfCalleeSavedRegisters: 0
- hasOpaqueSPAdjustment: false
- hasVAStart: false
- hasMustTailInVarArgFunc: false
- hasTailCall: false
- isCalleeSavedInfoValid: false
- localFrameSize: 0
-fixedStack: []
-stack: []
-entry_values: []
-callSites: []
-debugValueSubstitutions: []
-constants: []
-machineFunctionInfo:
- amxProgModel: None
-body: |
+name: f
+debugInstrRef: true
+body: |
; CHECK-LABEL: name: f
- ; CHECK-NOT: DBG_PHI
- ; CHECK: RET 0
- bb.0.e:
- successors: %bb.1(0x80000000)
- liveins: $edi
-
- %3:gr32 = COPY killed $edi
- %4:gr8 = COPY killed %3.sub_8bit
-
- bb.1.l:
- successors: %bb.2(0x40000000), %bb.3(0x40000000)
-
- %0:gr8 = PHI undef %5:gr8, %bb.0, undef %6:gr8, %bb.3, %0, %bb.2, debug-instr-number 1
- DBG_INSTR_REF !6, !DIExpression(DW_OP_LLVM_arg, 0), dbg-instr-ref(1, 0), debug-location !7
- TEST8ri %4, 1, implicit-def $eflags
- JCC_1 %bb.3, 4, implicit $eflags
- JMP_1 %bb.2
-
- bb.2.a:
- successors: %bb.1(0x7c000000), %bb.4(0x04000000)
- liveins: $eflags
-
- JCC_1 %bb.1, 5, implicit killed $eflags
- JMP_1 %bb.4
-
- bb.3.b:
- successors: %bb.1(0x7c000000), %bb.4(0x04000000)
- liveins: $eflags
-
- JCC_1 %bb.1, 5, implicit killed $eflags
- JMP_1 %bb.4
-
- bb.4.z:
- %2:gr8 = PHI undef %6:gr8, %bb.3, %0, %bb.2
- %7:gr8 = AND8ri killed %2, 1, implicit-def dead $eflags
- MOV8mr $noreg, 1, $noreg, 0, $noreg, killed %7 :: (store (s8) into `ptr null`)
+ ; CHECK: bb.0:
+ ; CHECK-NEXT: successors: %bb.1(0x80000000)
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: bb.1:
+ ; CHECK-NEXT: dead renamable $al = IMPLICIT_DEF
+ ; CHECK-NEXT: DBG_INSTR_REF !7, !DIExpression(), dbg-instr-ref(1, 0), debug-location !DILocation(line: 0, scope: !3)
+ ; CHECK-NEXT: RET 0
+ bb.0:
+ successors: %bb.1
+ bb.1:
+ %0:gr8 = PHI undef %0:gr8, %bb.0, debug-instr-number 1
+ DBG_INSTR_REF !6, !DIExpression(), dbg-instr-ref(1, 0), debug-location !DILocation(line: 0, scope: !2)
RET 0
...
More information about the llvm-commits
mailing list