[llvm] [X86][APX] Reuse EFLAGS across multi-predecessor blocks via NF in optimizeCompareInstr (PR #208184)
Phoebe Wang via llvm-commits
llvm-commits at lists.llvm.org
Mon Jul 13 22:52:00 PDT 2026
================
@@ -0,0 +1,353 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
+# RUN: llc -o - %s -mtriple=x86_64-- -run-pass peephole-opt -mattr=+nf | FileCheck %s
+
+# MIR-level coverage for the multi-predecessor EFLAGS reuse in
+# optimizeCompareInstr / findDominatingRedundantFlagInstr. These CFG shapes are
+# awkward to produce from IR (LICM hoists loop-invariant compares, the scheduler
+# repositions EFLAGS clobbers), so they are written directly as MIR.
+
+# A non-NF-convertible EFLAGS clobber in the dominating block that defines the
+# flags shadows the producer, so the redundant compare in bb.3 must be kept.
+---
+name: dom_shadow_clobber
+tracksRegLiveness: true
+body: |
+ ; CHECK-LABEL: name: dom_shadow_clobber
+ ; CHECK: bb.0:
+ ; CHECK-NEXT: successors: %bb.2(0x40000000), %bb.1(0x40000000)
+ ; 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: CMP32ri [[COPY1]], 7, implicit-def $eflags
+ ; CHECK-NEXT: JCC_1 %bb.2, 12, implicit $eflags
+ ; CHECK-NEXT: JMP_1 %bb.1
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: bb.1:
+ ; CHECK-NEXT: successors: %bb.3(0x80000000)
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[IMUL32rr:%[0-9]+]]:gr32 = nuw nsw IMUL32rr [[COPY]], [[COPY1]], implicit-def dead $eflags
+ ; CHECK-NEXT: JMP_1 %bb.3
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: bb.2:
+ ; CHECK-NEXT: successors: %bb.3(0x80000000)
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: bb.3:
+ ; CHECK-NEXT: CMP32ri [[COPY]], 2, implicit-def $eflags
+ ; 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
+ CMP32ri %1, 7, implicit-def $eflags
+ JCC_1 %bb.2, 12, implicit $eflags
+ JMP_1 %bb.1
+
+ bb.1:
+ %2:gr32 = nuw nsw IMUL32rr %0, %1, implicit-def dead $eflags
+ JMP_1 %bb.3
+
+ bb.2:
+
+ bb.3:
+ CMP32ri %0, 2, implicit-def $eflags
+ $al = SETCCr 15, implicit $eflags
+ RET 0, $al
+...
+
+# Same shape WITHOUT the shadow clobber: the producer in the dominating block is
+# found, the redundant compare in bb.3 is removed and the IMUL on the path is
+# rewritten to its NF variant. Positive control for dom_shadow_clobber.
+---
+name: dom_no_shadow
+tracksRegLiveness: true
+body: |
+ ; CHECK-LABEL: name: dom_no_shadow
+ ; CHECK: bb.0:
+ ; CHECK-NEXT: successors: %bb.2(0x40000000), %bb.1(0x40000000)
+ ; 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: JCC_1 %bb.2, 12, implicit $eflags
+ ; CHECK-NEXT: JMP_1 %bb.1
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: bb.1:
+ ; CHECK-NEXT: successors: %bb.3(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.3
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: bb.2:
+ ; CHECK-NEXT: successors: %bb.3(0x80000000)
+ ; CHECK-NEXT: liveins: $eflags
+ ; 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
+ JCC_1 %bb.2, 12, implicit $eflags
+ JMP_1 %bb.1
+
+ bb.1:
+ %2:gr32 = nuw nsw IMUL32rr %0, %1, implicit-def dead $eflags
+ JMP_1 %bb.3
+
+ bb.2:
+
+ bb.3:
+ CMP32ri %0, 2, implicit-def $eflags
+ $al = SETCCr 15, implicit $eflags
+ RET 0, $al
+...
+
+# Profitability: like dom_no_shadow, but bb.3 (the multi-predecessor block)
+# reaches the redundant compare in bb.4 through a single-predecessor chain that
+# itself has an NF-convertible clobber (the IMUL in bb.3). That clobber is on
+# the unconditional path to the compare, so converting it is pure added cost:
----------------
phoebewang wrote:
I don't get the point. The cost is code size. It doesn't matter it's conditional or unconditional path.
https://github.com/llvm/llvm-project/pull/208184
More information about the llvm-commits
mailing list