[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