[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