[llvm] [X86][APX] Fix EFLAGS reuse across cycles (PR #223613)
Feng Zou via llvm-commits
llvm-commits at lists.llvm.org
Tue Sep 15 00:24:44 PDT 2026
https://github.com/fzou1 created https://github.com/llvm/llvm-project/pull/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.
>From bdb8e8ee267c9b54708fb120470c34accb0858d9 Mon Sep 17 00:00:00 2001
From: Feng Zou <feng.zou at intel.com>
Date: Mon, 14 Sep 2026 11:21:09 +0800
Subject: [PATCH] [X86][APX] Fix EFLAGS reuse across cycles in
findDominatingRedundantFlagInstr
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.
---
llvm/lib/Target/X86/X86InstrInfo.cpp | 46 ++-
.../X86/apx/optimize-compare-multipred.mir | 320 ++++++++++++++++++
2 files changed, 360 insertions(+), 6 deletions(-)
diff --git a/llvm/lib/Target/X86/X86InstrInfo.cpp b/llvm/lib/Target/X86/X86InstrInfo.cpp
index ca864d02b3399..16966bed1f531 100644
--- a/llvm/lib/Target/X86/X86InstrInfo.cpp
+++ b/llvm/lib/Target/X86/X86InstrInfo.cpp
@@ -5355,19 +5355,53 @@ MachineInstr *X86InstrInfo::findDominatingRedundantFlagInstr(
// bailing on any other clobber (it would shadow the producer's flags from
// 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.
+ // Both scans stage clobbers in Pending and only commit on success. The
+ // predecessor walk seeds Visited with MultiPredMBB so it doesn't re-scan
+ // the single-predecessor chain the caller already staged.
+ //
+ // If CmpMBB is on a CFG cycle, the region below CmpInstr executes on the
+ // back-edge before the next iteration's CmpInstr and is scanned by neither
+ // the caller nor the predecessor walk. Handle it here: 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 + below-scan + predecessor walk) 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();
+ auto IsCmpMBBOnCycle = [&] {
+ SmallPtrSet<MachineBasicBlock *, 8> Seen;
+ SmallVector<MachineBasicBlock *, 8> Stack(CmpMBB->succ_begin(),
+ CmpMBB->succ_end());
+ while (!Stack.empty()) {
+ MachineBasicBlock *Succ = Stack.pop_back_val();
+ if (Succ == CmpMBB)
+ return true;
+ if (!Seen.insert(Succ).second)
+ continue;
+ Stack.append(Succ->succ_begin(), Succ->succ_end());
+ }
+ return false;
+ };
+ if (IsCmpMBBOnCycle()) {
+ 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));
+ }
+ }
+
SmallPtrSet<MachineBasicBlock *, 8> Visited;
SmallVector<MachineBasicBlock *, 8> Worklist;
Visited.insert(MultiPredMBB);
diff --git a/llvm/test/CodeGen/X86/apx/optimize-compare-multipred.mir b/llvm/test/CodeGen/X86/apx/optimize-compare-multipred.mir
index a6ff8900a0349..9dcbf7358771e 100644
--- a/llvm/test/CodeGen/X86/apx/optimize-compare-multipred.mir
+++ b/llvm/test/CodeGen/X86/apx/optimize-compare-multipred.mir
@@ -352,3 +352,323 @@ 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 upfront
+# below-CmpInstr scan 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 upfront below-CmpInstr
+# scan 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 upfront below-CmpInstr scan stages the IMUL, the backward walk finds
+# bb.0's producer, 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