[llvm] f28f0ba - [X86][APX] Fix EFLAGS reuse across cycles (#223613)

via llvm-commits llvm-commits at lists.llvm.org
Sun Sep 20 04:57:49 PDT 2026


Author: Feng Zou
Date: 2026-09-20T19:57:44+08:00
New Revision: f28f0baf480125fd1a0b70c39c316778e3794b13

URL: https://github.com/llvm/llvm-project/commit/f28f0baf480125fd1a0b70c39c316778e3794b13
DIFF: https://github.com/llvm/llvm-project/commit/f28f0baf480125fd1a0b70c39c316778e3794b13.diff

LOG: [X86][APX] Fix EFLAGS reuse across cycles (#223613)

optimizeCompareInstr's multi-predecessor NF reuse (added in
ab39c491430e) did not scan the below-CmpInstr region of CmpMBB when
CmpMBB was on a CFG cycle: that region is on the back-edge path but is
scanned by neither the caller nor the helper's predecessor walk. A
non-NF-convertible EFLAGS clobber there (e.g. an unrelated CMP feeding a
JCC, as in the reproducer below with VUCOMISS/CTEST/COPY-\$eflags) still
let the helper delete the redundant compare and mark \$eflags live-in on
CmpMBB. That broke the reused EFLAGS on iteration 2+ and tripped
X86FlagsCopyLowering's SuccMBB == TestMBB self-loop check with a fatal
report_fatal_error when a preexisting COPY \$eflags save/restore sat in
the cycle.

Reproducer: https://godbolt.org/z/s58j5zxqd

Detect CmpMBB on a cycle via a forward-reachability BFS on its
successors and, when so, scan from just after CmpInstr to the block's
end: bail on any non-NF-convertible EFLAGS clobber, stage NF-convertible
ones. The rest of the helper is unchanged.

Tests exercise the bail paths (selfloop_shadow_below,
twoblock_cycle_shadow_below, threeblock_cycle_shadow_below,
selfloop_nfconvertible_below_cap), the positive stage-and-succeed path
(selfloop_nfconvertible_below), and the CmpMBB-not-on-cycle skip path
(multipred_above_cmpmbb).

Fixes: https://github.com/llvm/llvm-project/issues/223282

Assisted by Claude Code.

Added: 
    

Modified: 
    llvm/lib/Target/X86/X86InstrInfo.cpp
    llvm/test/CodeGen/X86/apx/optimize-compare-multipred.mir

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/X86/X86InstrInfo.cpp b/llvm/lib/Target/X86/X86InstrInfo.cpp
index f57658ae5e20e..09a8ae6107020 100644
--- a/llvm/lib/Target/X86/X86InstrInfo.cpp
+++ b/llvm/lib/Target/X86/X86InstrInfo.cpp
@@ -5367,24 +5367,42 @@ MachineInstr *X86InstrInfo::findDominatingRedundantFlagInstr(
   // CmpInstr).
   //
   // Clobbers are staged in Pending and committed only on success. Visited
-  // (seeded with MultiPredMBB) stops the walk from revisiting a block or
-  // re-entering the single-predecessor chain, so none is collected twice.
+  // is seeded with the caller's single-predecessor chain (CmpMBB through
+  // MultiPredMBB) so the walk doesn't re-scan blocks the caller already
+  // staged. The walk doubles as a cycle detector: a predecessor equal to
+  // CmpMBB is a back-edge from CmpMBB's successors into the walked region,
+  // which means CmpMBB is on a CFG cycle. In that case the region below
+  // CmpInstr executes on the back-edge before the next iteration's CmpInstr
+  // and must be checked too: bail on any non-NF-convertible EFLAGS clobber,
+  // stage NF-convertible ones.
   //
   // Each NF conversion trades a compact legacy/EVEX-compressed encoding for a
   // wider EVEX (often NDD three-operand) one, growing code size, while the
   // reuse only removes a single compare. Cap the total number of conversions
-  // (those the caller already collected on the single-predecessor chain plus
-  // those the walk stages) so the reuse cannot bloat code just to delete one
-  // compare.
+  // (caller chain + predecessor walk + below-scan) so the reuse cannot bloat
+  // code just to delete one compare.
   MachineInstr *Sub = nullptr;
   MachineBasicBlock *SubMBB = nullptr;
   SmallVector<std::pair<MachineInstr *, unsigned>, 4> Pending;
+
+  MachineBasicBlock *CmpMBB = CmpInstr.getParent();
   SmallPtrSet<MachineBasicBlock *, 8> Visited;
   SmallVector<MachineBasicBlock *, 8> Worklist;
+  for (MachineBasicBlock *MBB = CmpMBB; MBB != MultiPredMBB;
+       MBB = MBB->getSinglePredecessor())
+    Visited.insert(MBB);
   Visited.insert(MultiPredMBB);
-  for (MachineBasicBlock *Pred : MultiPredMBB->predecessors())
+
+  bool CmpMBBOnCycle = false;
+  auto TryPush = [&](MachineBasicBlock *Pred) {
+    if (Pred == CmpMBB)
+      CmpMBBOnCycle = true;
     if (Visited.insert(Pred).second)
       Worklist.push_back(Pred);
+  };
+
+  for (MachineBasicBlock *Pred : MultiPredMBB->predecessors())
+    TryPush(Pred);
   while (!Worklist.empty()) {
     MachineBasicBlock *MBB = Worklist.pop_back_val();
     MachineInstr *Producer = nullptr;
@@ -5415,8 +5433,7 @@ MachineInstr *X86InstrInfo::findDominatingRedundantFlagInstr(
     if (MBB->pred_empty())
       return nullptr;
     for (MachineBasicBlock *Pred : MBB->predecessors())
-      if (Visited.insert(Pred).second)
-        Worklist.push_back(Pred);
+      TryPush(Pred);
   }
   if (!Sub)
     return nullptr;
@@ -5430,6 +5447,22 @@ MachineInstr *X86InstrInfo::findDominatingRedundantFlagInstr(
   if (IsSwapped || ImmDelta != 0)
     return nullptr;
 
+  // If CmpMBB is on a CFG cycle, its below-CmpInstr region is on the back-edge
+  // path and must also be free of non-NF-convertible EFLAGS clobbers.
+  if (CmpMBBOnCycle) {
+    for (MachineInstr &Inst : make_range(
+             std::next(MachineBasicBlock::iterator(CmpInstr)), CmpMBB->end())) {
+      if (!Inst.modifiesRegister(X86::EFLAGS, TRI))
+        continue;
+      unsigned NewOpc = X86::getNFVariantIfClobberRemovable(Inst, TRI);
+      if (!NewOpc)
+        return nullptr;
+      if (InstsToUpdate.size() + Pending.size() >= MaxNFConversions)
+        return nullptr;
+      Pending.push_back(std::make_pair(&Inst, NewOpc));
+    }
+  }
+
   InstsToUpdate.append(Pending.begin(), Pending.end());
   return Sub;
 }

diff  --git a/llvm/test/CodeGen/X86/apx/optimize-compare-multipred.mir b/llvm/test/CodeGen/X86/apx/optimize-compare-multipred.mir
index a6ff8900a0349..c8d5c1dd5dfb5 100644
--- a/llvm/test/CodeGen/X86/apx/optimize-compare-multipred.mir
+++ b/llvm/test/CodeGen/X86/apx/optimize-compare-multipred.mir
@@ -352,3 +352,326 @@ body: |
     $al = SETCCr 15, implicit $eflags
     RET 0, $al
 ...
+
+# Self-loop: bb.1 is its own predecessor. A live CMP below the redundant
+# compare in bb.1 shadows bb.0's producer on iteration 2+. The below-CmpInstr
+# scan (triggered when the walk detects CmpMBB is on a cycle) spots the
+# clobber and keeps the compare.
+---
+name: selfloop_shadow_below
+tracksRegLiveness: true
+body: |
+  ; CHECK-LABEL: name: selfloop_shadow_below
+  ; CHECK: bb.0:
+  ; CHECK-NEXT:   successors: %bb.1(0x80000000)
+  ; CHECK-NEXT:   liveins: $edi, $esi
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:gr32 = COPY $edi
+  ; CHECK-NEXT:   [[COPY1:%[0-9]+]]:gr32 = COPY $esi
+  ; CHECK-NEXT:   CMP32ri [[COPY]], 2, implicit-def $eflags
+  ; CHECK-NEXT:   JMP_1 %bb.1
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.1:
+  ; CHECK-NEXT:   successors: %bb.1(0x40000000), %bb.2(0x40000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   CMP32ri [[COPY]], 2, implicit-def $eflags
+  ; CHECK-NEXT:   CMP32ri [[COPY1]], 5, implicit-def $eflags
+  ; CHECK-NEXT:   JCC_1 %bb.1, 5, implicit $eflags
+  ; CHECK-NEXT:   JMP_1 %bb.2
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.2:
+  ; CHECK-NEXT:   liveins: $eflags
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   $al = SETCCr 15, implicit $eflags
+  ; CHECK-NEXT:   RET 0, $al
+  bb.0:
+    liveins: $edi, $esi
+    %0:gr32 = COPY $edi
+    %1:gr32 = COPY $esi
+    CMP32ri %0, 2, implicit-def $eflags
+    JMP_1 %bb.1
+
+  bb.1:
+    CMP32ri %0, 2, implicit-def $eflags
+    CMP32ri %1, 5, implicit-def $eflags
+    JCC_1 %bb.1, 5, implicit $eflags
+    JMP_1 %bb.2
+
+  bb.2:
+    liveins: $eflags
+    $al = SETCCr 15, implicit $eflags
+    RET 0, $al
+...
+
+# Two-block cycle bb.1 -> bb.2 -> bb.1. A live CMP below the redundant compare
+# in bb.1 shadows bb.0's producer on the back-edge. The below-CmpInstr scan
+# (triggered when the walk detects CmpMBB is on a cycle) spots the clobber and
+# keeps the compare. Guards against a self-loop-only cycle check that would
+# miss this shape.
+---
+name: twoblock_cycle_shadow_below
+tracksRegLiveness: true
+body: |
+  ; CHECK-LABEL: name: twoblock_cycle_shadow_below
+  ; CHECK: bb.0:
+  ; CHECK-NEXT:   successors: %bb.1(0x80000000)
+  ; CHECK-NEXT:   liveins: $edi, $esi
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:gr32 = COPY $edi
+  ; CHECK-NEXT:   [[COPY1:%[0-9]+]]:gr32 = COPY $esi
+  ; CHECK-NEXT:   CMP32ri [[COPY]], 2, implicit-def $eflags
+  ; CHECK-NEXT:   JMP_1 %bb.1
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.1:
+  ; CHECK-NEXT:   successors: %bb.2(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   CMP32ri [[COPY]], 2, implicit-def $eflags
+  ; CHECK-NEXT:   CMP32ri [[COPY1]], 5, implicit-def $eflags
+  ; CHECK-NEXT:   JMP_1 %bb.2
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.2:
+  ; CHECK-NEXT:   successors: %bb.1(0x40000000), %bb.3(0x40000000)
+  ; CHECK-NEXT:   liveins: $eflags
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   JCC_1 %bb.1, 5, implicit $eflags
+  ; CHECK-NEXT:   JMP_1 %bb.3
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.3:
+  ; CHECK-NEXT:   liveins: $eflags
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   $al = SETCCr 15, implicit $eflags
+  ; CHECK-NEXT:   RET 0, $al
+  bb.0:
+    liveins: $edi, $esi
+    %0:gr32 = COPY $edi
+    %1:gr32 = COPY $esi
+    CMP32ri %0, 2, implicit-def $eflags
+    JMP_1 %bb.1
+
+  bb.1:
+    CMP32ri %0, 2, implicit-def $eflags
+    CMP32ri %1, 5, implicit-def $eflags
+    JMP_1 %bb.2
+
+  bb.2:
+    liveins: $eflags
+    JCC_1 %bb.1, 5, implicit $eflags
+    JMP_1 %bb.3
+
+  bb.3:
+    liveins: $eflags
+    $al = SETCCr 15, implicit $eflags
+    RET 0, $al
+...
+
+# Self-loop where the below-CmpInstr region holds an NF-convertible dead clobber.
+# The backward walk finds bb.0's producer and detects the cycle back-edge into
+# MultiPredMBB; the below-CmpInstr scan then stages the IMUL, and the reuse
+# succeeds: the redundant compare is removed and the IMUL is rewritten to its
+# NF variant. Exercises the positive path of the new scan (the shadow_below
+# cases only exercise the bail path).
+---
+name: selfloop_nfconvertible_below
+tracksRegLiveness: true
+body: |
+  ; CHECK-LABEL: name: selfloop_nfconvertible_below
+  ; CHECK: bb.0:
+  ; CHECK-NEXT:   successors: %bb.1(0x80000000)
+  ; CHECK-NEXT:   liveins: $edi, $esi
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:gr32 = COPY $edi
+  ; CHECK-NEXT:   [[COPY1:%[0-9]+]]:gr32 = COPY $esi
+  ; CHECK-NEXT:   CMP32ri [[COPY]], 2, implicit-def $eflags
+  ; CHECK-NEXT:   JMP_1 %bb.1
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.1:
+  ; CHECK-NEXT:   successors: %bb.1(0x80000000)
+  ; CHECK-NEXT:   liveins: $eflags
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[IMUL32rr_NF:%[0-9]+]]:gr32 = nuw nsw IMUL32rr_NF [[COPY]], [[COPY1]]
+  ; CHECK-NEXT:   JMP_1 %bb.1
+  bb.0:
+    liveins: $edi, $esi
+    %0:gr32 = COPY $edi
+    %1:gr32 = COPY $esi
+    CMP32ri %0, 2, implicit-def $eflags
+    JMP_1 %bb.1
+
+  bb.1:
+    CMP32ri %0, 2, implicit-def $eflags
+    %2:gr32 = nuw nsw IMUL32rr %0, %1, implicit-def dead $eflags
+    JMP_1 %bb.1
+...
+
+# Multi-predecessor block sits above CmpMBB in the caller's single-predecessor
+# chain: bb.3 (CmpMBB) <- bb.2 <- bb.1 (MultiPredMBB, self-loop). bb.3 has no
+# back-edge so the below-CmpInstr scan is skipped; the walk finds bb.0's
+# producer through bb.1's non-self predecessor. Guards against a regression
+# where a revisit of MultiPredMBB would double-scan the caller's chain.
+---
+name: multipred_above_cmpmbb
+tracksRegLiveness: true
+body: |
+  ; CHECK-LABEL: name: multipred_above_cmpmbb
+  ; CHECK: bb.0:
+  ; CHECK-NEXT:   successors: %bb.1(0x80000000)
+  ; CHECK-NEXT:   liveins: $edi, $esi
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:gr32 = COPY $edi
+  ; CHECK-NEXT:   [[COPY1:%[0-9]+]]:gr32 = COPY $esi
+  ; CHECK-NEXT:   CMP32ri [[COPY]], 2, implicit-def $eflags
+  ; CHECK-NEXT:   JMP_1 %bb.1
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.1:
+  ; CHECK-NEXT:   successors: %bb.1(0x40000000), %bb.2(0x40000000)
+  ; CHECK-NEXT:   liveins: $eflags
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[IMUL32rr_NF:%[0-9]+]]:gr32 = nuw nsw IMUL32rr_NF [[COPY]], [[COPY1]]
+  ; CHECK-NEXT:   JCC_1 %bb.1, 5, implicit undef $eflags
+  ; CHECK-NEXT:   JMP_1 %bb.2
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.2:
+  ; CHECK-NEXT:   successors: %bb.3(0x80000000)
+  ; CHECK-NEXT:   liveins: $eflags
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   JMP_1 %bb.3
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.3:
+  ; CHECK-NEXT:   liveins: $eflags
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   $al = SETCCr 15, implicit $eflags
+  ; CHECK-NEXT:   RET 0, $al
+  bb.0:
+    liveins: $edi, $esi
+    %0:gr32 = COPY $edi
+    %1:gr32 = COPY $esi
+    CMP32ri %0, 2, implicit-def $eflags
+    JMP_1 %bb.1
+
+  bb.1:
+    %2:gr32 = nuw nsw IMUL32rr %0, %1, implicit-def dead $eflags
+    JCC_1 %bb.1, 5, implicit undef $eflags
+    JMP_1 %bb.2
+
+  bb.2:
+    JMP_1 %bb.3
+
+  bb.3:
+    CMP32ri %0, 2, implicit-def $eflags
+    $al = SETCCr 15, implicit $eflags
+    RET 0, $al
+...
+
+# Three-block cycle bb.2 (CmpMBB) -> bb.3 -> bb.1 (MultiPredMBB) -> bb.2.
+# Exercises the below-CmpInstr scan when MultiPredMBB is a distinct block on
+# the cycle.
+---
+name: threeblock_cycle_shadow_below
+tracksRegLiveness: true
+body: |
+  ; CHECK-LABEL: name: threeblock_cycle_shadow_below
+  ; CHECK: bb.0:
+  ; CHECK-NEXT:   successors: %bb.1(0x80000000)
+  ; CHECK-NEXT:   liveins: $edi, $esi
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:gr32 = COPY $edi
+  ; CHECK-NEXT:   [[COPY1:%[0-9]+]]:gr32 = COPY $esi
+  ; CHECK-NEXT:   CMP32ri [[COPY]], 2, implicit-def $eflags
+  ; CHECK-NEXT:   JMP_1 %bb.1
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.1:
+  ; CHECK-NEXT:   successors: %bb.2(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   JMP_1 %bb.2
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.2:
+  ; CHECK-NEXT:   successors: %bb.4(0x40000000), %bb.3(0x40000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   CMP32ri [[COPY]], 2, implicit-def $eflags
+  ; CHECK-NEXT:   CMP32ri [[COPY1]], 5, implicit-def $eflags
+  ; CHECK-NEXT:   JCC_1 %bb.4, 5, implicit $eflags
+  ; CHECK-NEXT:   JMP_1 %bb.3
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.3:
+  ; CHECK-NEXT:   successors: %bb.1(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   JMP_1 %bb.1
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.4:
+  ; CHECK-NEXT:   liveins: $eflags
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   $al = SETCCr 15, implicit $eflags
+  ; CHECK-NEXT:   RET 0, $al
+  bb.0:
+    liveins: $edi, $esi
+    %0:gr32 = COPY $edi
+    %1:gr32 = COPY $esi
+    CMP32ri %0, 2, implicit-def $eflags
+    JMP_1 %bb.1
+
+  bb.1:
+    JMP_1 %bb.2
+
+  bb.2:
+    CMP32ri %0, 2, implicit-def $eflags
+    CMP32ri %1, 5, implicit-def $eflags
+    JCC_1 %bb.4, 5, implicit $eflags
+    JMP_1 %bb.3
+
+  bb.3:
+    JMP_1 %bb.1
+
+  bb.4:
+    liveins: $eflags
+    $al = SETCCr 15, implicit $eflags
+    RET 0, $al
+...
+
+# Self-loop where the below-CmpInstr region holds 7 NF-convertible dead clobbers,
+# exceeding the default MaxNFConversions cap of 6. The below-scan declines
+# staging and the redundant compare is kept. Exercises the cap-bail branch of
+# the below-scan.
+---
+name: selfloop_nfconvertible_below_cap
+tracksRegLiveness: true
+body: |
+  ; CHECK-LABEL: name: selfloop_nfconvertible_below_cap
+  ; CHECK: bb.0:
+  ; CHECK-NEXT:   successors: %bb.1(0x80000000)
+  ; CHECK-NEXT:   liveins: $edi, $esi
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:gr32 = COPY $edi
+  ; CHECK-NEXT:   [[COPY1:%[0-9]+]]:gr32 = COPY $esi
+  ; CHECK-NEXT:   CMP32ri [[COPY]], 2, implicit-def $eflags
+  ; CHECK-NEXT:   JMP_1 %bb.1
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.1:
+  ; CHECK-NEXT:   successors: %bb.1(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   CMP32ri [[COPY]], 2, implicit-def $eflags
+  ; CHECK-NEXT:   [[IMUL32rr:%[0-9]+]]:gr32 = nuw nsw IMUL32rr [[COPY]], [[COPY1]], implicit-def dead $eflags
+  ; CHECK-NEXT:   [[IMUL32rr1:%[0-9]+]]:gr32 = nuw nsw IMUL32rr [[IMUL32rr]], [[COPY1]], implicit-def dead $eflags
+  ; CHECK-NEXT:   [[IMUL32rr2:%[0-9]+]]:gr32 = nuw nsw IMUL32rr [[IMUL32rr1]], [[COPY1]], implicit-def dead $eflags
+  ; CHECK-NEXT:   [[IMUL32rr3:%[0-9]+]]:gr32 = nuw nsw IMUL32rr [[IMUL32rr2]], [[COPY1]], implicit-def dead $eflags
+  ; CHECK-NEXT:   [[IMUL32rr4:%[0-9]+]]:gr32 = nuw nsw IMUL32rr [[IMUL32rr3]], [[COPY1]], implicit-def dead $eflags
+  ; CHECK-NEXT:   [[IMUL32rr5:%[0-9]+]]:gr32 = nuw nsw IMUL32rr [[IMUL32rr4]], [[COPY1]], implicit-def dead $eflags
+  ; CHECK-NEXT:   [[IMUL32rr6:%[0-9]+]]:gr32 = nuw nsw IMUL32rr [[IMUL32rr5]], [[COPY1]], implicit-def dead $eflags
+  ; CHECK-NEXT:   JMP_1 %bb.1
+  bb.0:
+    liveins: $edi, $esi
+    %0:gr32 = COPY $edi
+    %1:gr32 = COPY $esi
+    CMP32ri %0, 2, implicit-def $eflags
+    JMP_1 %bb.1
+
+  bb.1:
+    CMP32ri %0, 2, implicit-def $eflags
+    %2:gr32 = nuw nsw IMUL32rr %0, %1, implicit-def dead $eflags
+    %3:gr32 = nuw nsw IMUL32rr %2, %1, implicit-def dead $eflags
+    %4:gr32 = nuw nsw IMUL32rr %3, %1, implicit-def dead $eflags
+    %5:gr32 = nuw nsw IMUL32rr %4, %1, implicit-def dead $eflags
+    %6:gr32 = nuw nsw IMUL32rr %5, %1, implicit-def dead $eflags
+    %7:gr32 = nuw nsw IMUL32rr %6, %1, implicit-def dead $eflags
+    %8:gr32 = nuw nsw IMUL32rr %7, %1, implicit-def dead $eflags
+    JMP_1 %bb.1
+...


        


More information about the llvm-commits mailing list