[llvm] [X86] Ignore debug instructions in FixupLEAs search distance (PR #222871)

Yongqiang Tian via llvm-commits llvm-commits at lists.llvm.org
Fri Sep 11 00:38:03 PDT 2026


https://github.com/yqtian-se created https://github.com/llvm/llvm-project/pull/222871

## Summary

`FixupLEAsImpl::searchALUInst` currently counts every `MachineInstr` against
its bounded LEA-to-ALU search distance. Debug instructions can therefore
exhaust the search budget and make enabling debug information change the
ordinary optimization result.

Iterate over `instructionsWithoutDebug` while passing
`/*SkipPseudoOp=*/false`, so only debug instructions are excluded and pseudo
probes retain their existing behavior. Add a generated MIR regression test
covering both the legacy and new pass managers.

## Testing

- `llvm-lit -v llvm/test/CodeGen/X86/lea-fixup-debug-instrs.mir llvm/test/CodeGen/X86/leaFixup32.mir llvm/test/CodeGen/X86/leaFixup64.mir`
- `ninja check-llvm-codegen-x86`
- The original C reproducer produces byte-identical `.text` with `-O2 -g0` and `-O2 -g` after the patch.

Fixes #222868

AI disclosure: This patch was developed with OpenAI Codex 5.6 Sol and
co-reviewed by Claude and Yongqiang Tian.


>From 7c201f3e27d56c8718f822bedb928521e7b95abe Mon Sep 17 00:00:00 2001
From: Yongqiang Tian <yqtian668 at gmail.com>
Date: Fri, 11 Sep 2026 07:36:46 +0000
Subject: [PATCH] [X86] Ignore debug instructions in FixupLEAs search distance

FixupLEAs searches a bounded number of MachineInstrs for an ADD or SUB
consumer. Debug instructions currently consume this budget and can make
enabling debug information change the optimization decision.

Use instructionsWithoutDebug while retaining pseudo probes in the search, and
add a MIR regression test for both the legacy and new pass managers.

Fixes #222868

Assisted-by: OpenAI Codex 5.6 Sol
Assisted-by: Claude (review)
---
 llvm/lib/Target/X86/X86FixupLEAs.cpp          | 21 +++++-----
 .../CodeGen/X86/lea-fixup-debug-instrs.mir    | 41 +++++++++++++++++++
 2 files changed, 51 insertions(+), 11 deletions(-)
 create mode 100644 llvm/test/CodeGen/X86/lea-fixup-debug-instrs.mir

diff --git a/llvm/lib/Target/X86/X86FixupLEAs.cpp b/llvm/lib/Target/X86/X86FixupLEAs.cpp
index 5c9c74e64aa73..30443f9923c1a 100644
--- a/llvm/lib/Target/X86/X86FixupLEAs.cpp
+++ b/llvm/lib/Target/X86/X86FixupLEAs.cpp
@@ -414,43 +414,43 @@ FixupLEAsImpl::searchALUInst(MachineBasicBlock::iterator &I,
                              MachineBasicBlock &MBB) const {
   const int InstrDistanceThreshold = 5;
   int InstrDistance = 1;
-  MachineBasicBlock::iterator CurInst = std::next(I);
 
   unsigned LEAOpcode = I->getOpcode();
   unsigned AddOpcode = getADDrrFromLEA(LEAOpcode);
   unsigned SubOpcode = getSUBrrFromLEA(LEAOpcode);
   Register DestReg = I->getOperand(0).getReg();
 
-  while (CurInst != MBB.end()) {
-    if (CurInst->isCall() || CurInst->isInlineAsm())
+  for (MachineInstr &CurInst : instructionsWithoutDebug(
+           std::next(I), MBB.end(), /*SkipPseudoOp=*/false)) {
+    if (CurInst.isCall() || CurInst.isInlineAsm())
       break;
     if (InstrDistance > InstrDistanceThreshold)
       break;
 
     // Check if the lea dest register is used in an add/sub instruction only.
-    for (unsigned I = 0, E = CurInst->getNumOperands(); I != E; ++I) {
-      MachineOperand &Opnd = CurInst->getOperand(I);
+    for (unsigned I = 0, E = CurInst.getNumOperands(); I != E; ++I) {
+      MachineOperand &Opnd = CurInst.getOperand(I);
       if (Opnd.isReg()) {
         if (Opnd.getReg() == DestReg) {
           if (Opnd.isDef() || !Opnd.isKill())
             return MachineBasicBlock::iterator();
 
-          unsigned AluOpcode = CurInst->getOpcode();
+          unsigned AluOpcode = CurInst.getOpcode();
           if (AluOpcode != AddOpcode && AluOpcode != SubOpcode)
             return MachineBasicBlock::iterator();
 
-          MachineOperand &Opnd2 = CurInst->getOperand(3 - I);
-          MachineOperand AluDest = CurInst->getOperand(0);
+          MachineOperand &Opnd2 = CurInst.getOperand(3 - I);
+          MachineOperand AluDest = CurInst.getOperand(0);
           if (Opnd2.getReg() != AluDest.getReg())
             return MachineBasicBlock::iterator();
 
           // X - (Y + Z) may generate different flags than (X - Y) - Z when
           // there is overflow. So we can't change the alu instruction if the
           // flags register is live.
-          if (!CurInst->registerDefIsDead(X86::EFLAGS, TRI))
+          if (!CurInst.registerDefIsDead(X86::EFLAGS, TRI))
             return MachineBasicBlock::iterator();
 
-          return CurInst;
+          return CurInst.getIterator();
         }
         if (TRI->regsOverlap(DestReg, Opnd.getReg()))
           return MachineBasicBlock::iterator();
@@ -458,7 +458,6 @@ FixupLEAsImpl::searchALUInst(MachineBasicBlock::iterator &I,
     }
 
     InstrDistance++;
-    ++CurInst;
   }
   return MachineBasicBlock::iterator();
 }
diff --git a/llvm/test/CodeGen/X86/lea-fixup-debug-instrs.mir b/llvm/test/CodeGen/X86/lea-fixup-debug-instrs.mir
new file mode 100644
index 0000000000000..83e8619b401d9
--- /dev/null
+++ b/llvm/test/CodeGen/X86/lea-fixup-debug-instrs.mir
@@ -0,0 +1,41 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 6
+# RUN: llc -mtriple=x86_64-unknown-linux-gnu -mcpu=corei7-avx -run-pass=x86-fixup-leas -verify-machineinstrs -o - %s | FileCheck %s
+# RUN: llc -mtriple=x86_64-unknown-linux-gnu -mcpu=corei7-avx -passes="require<profile-summary>,function(machine-function(x86-fixup-leas))" -verify-machineinstrs -o - %s | FileCheck %s
+
+--- |
+  define i64 @debug_instrs_do_not_count(i64 %a, i64 %b) {
+  entry:
+    ret i64 0
+  }
+...
+---
+name:            debug_instrs_do_not_count
+tracksRegLiveness: true
+liveins:
+  - { reg: '$rax' }
+  - { reg: '$rdi' }
+  - { reg: '$rsi' }
+body:             |
+  bb.0.entry:
+    liveins: $rax, $rdi, $rsi
+
+    ; CHECK-LABEL: name: debug_instrs_do_not_count
+    ; CHECK: liveins: $rax, $rdi, $rsi
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: DBG_VALUE 0, $noreg
+    ; CHECK-NEXT: DBG_VALUE 0, $noreg
+    ; CHECK-NEXT: NOOP
+    ; CHECK-NEXT: NOOP
+    ; CHECK-NEXT: NOOP
+    ; CHECK-NEXT: $rax = ADD64rr killed $rax, $rdi, implicit-def dead $eflags
+    ; CHECK-NEXT: $rax = ADD64rr killed $rax, $rsi, implicit-def dead $eflags
+    ; CHECK-NEXT: RET64 $rax
+    renamable $rcx = LEA64r killed renamable $rdi, 1, killed renamable $rsi, 0, $noreg
+    DBG_VALUE 0, $noreg
+    DBG_VALUE 0, $noreg
+    NOOP
+    NOOP
+    NOOP
+    renamable $rax = ADD64rr killed renamable $rax, killed renamable $rcx, implicit-def dead $eflags
+    RET64 $rax
+...



More information about the llvm-commits mailing list