[llvm] [X86] Don't assert on EFLAGS copies in unreachable blocks (PR #203208)

via llvm-commits llvm-commits at lists.llvm.org
Thu Jun 11 02:20:10 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-x86

Author: Paweł Bylica (chfast)

<details>
<summary>Changes</summary>

X86FlagsCopyLowering collects the EFLAGS copies to lower using a ReversePostOrderTraversal, which only visits blocks reachable from the entry. Its end-of-pass verification, however, iterated over every block in the function, so an EFLAGS copy left in an unreachable block (e.g. produced by ISel for an always-taken branch whose other edge is dead) tripped the "Unlowered EFLAGS copy!" assertion.

Such copies are harmless: the unreachable block is removed by the unreachable-block elimination pass that runs right after this one, before register allocation, so the copy never reaches a pass that cannot handle it. Restrict the verification to reachable blocks (depth_first from the entry) to match the set of blocks actually processed.

Found via fuzzing (llvm-isel-fuzzer).

---
Full diff: https://github.com/llvm/llvm-project/pull/203208.diff


2 Files Affected:

- (modified) llvm/lib/Target/X86/X86FlagsCopyLowering.cpp (+3-2) 
- (added) llvm/test/CodeGen/X86/flags-copy-lowering-unreachable.mir (+29) 


``````````diff
diff --git a/llvm/lib/Target/X86/X86FlagsCopyLowering.cpp b/llvm/lib/Target/X86/X86FlagsCopyLowering.cpp
index 93c7571d5c37f..36b17cab03ee9 100644
--- a/llvm/lib/Target/X86/X86FlagsCopyLowering.cpp
+++ b/llvm/lib/Target/X86/X86FlagsCopyLowering.cpp
@@ -708,8 +708,9 @@ bool X86FlagsCopyLoweringImpl::runOnMachineFunction(MachineFunction &MF) {
   }
 
 #ifndef NDEBUG
-  for (MachineBasicBlock &MBB : MF)
-    for (MachineInstr &MI : MBB)
+  // Check reachable blocks for unlowered EFLAGS copies.
+  for (MachineBasicBlock *MBB : depth_first(&MF))
+    for (MachineInstr &MI : *MBB)
       if (MI.getOpcode() == TargetOpcode::COPY &&
           (MI.getOperand(0).getReg() == X86::EFLAGS ||
            MI.getOperand(1).getReg() == X86::EFLAGS)) {
diff --git a/llvm/test/CodeGen/X86/flags-copy-lowering-unreachable.mir b/llvm/test/CodeGen/X86/flags-copy-lowering-unreachable.mir
new file mode 100644
index 0000000000000..1854e95d60856
--- /dev/null
+++ b/llvm/test/CodeGen/X86/flags-copy-lowering-unreachable.mir
@@ -0,0 +1,29 @@
+# RUN: llc -mtriple=x86_64-- -run-pass=x86-flags-copy-lowering -verify-machineinstrs -o - %s | FileCheck %s
+#
+# An EFLAGS copy stranded in a block that is unreachable from the entry must
+# not trip the "Unlowered EFLAGS copy!" assertion. The pass collects copies to
+# lower with a reverse-post-order traversal, which only visits reachable
+# blocks, so such copies are intentionally left in place (a later pass removes
+# the unreachable block). The verification at the end of the pass must use the
+# same notion of reachability.
+---
+name:            stranded_eflags_copy
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    RET 0
+
+  ; bb.1 has no predecessors, so it is unreachable from bb.0. The save/recheck
+  ; EFLAGS copies below are left untouched rather than crashing the pass.
+  bb.1:
+    ; CHECK-LABEL: bb.1:
+    ; CHECK: %1:gr64 = COPY $eflags
+    ; CHECK: $eflags = COPY %1
+    %0:gr64 = IMPLICIT_DEF
+    TEST64rr %0, %0, implicit-def $eflags
+    %1:gr64 = COPY $eflags
+    TEST64rr %0, %0, implicit-def $eflags
+    $eflags = COPY %1
+    SETCCm $noreg, 1, $noreg, 0, $noreg, 4, implicit $eflags :: (store (s8) into `ptr null`)
+    RET 0
+...

``````````

</details>


https://github.com/llvm/llvm-project/pull/203208


More information about the llvm-commits mailing list