blob: a6ff8900a0349f61bf0c2b2a43550e695326fc0f [file] [edit]
# 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
...
# Cap: the producer in bb.0 dominates the multi-predecessor block bb.3, but the
# path to the redundant compare in bb.3 has more NF-convertible EFLAGS clobbers
# (7 IMULs on the bb.1 arm) than the conversion cap allows. Converting that many
# instructions to delete one compare is a net size regression, so the reuse is
# declined and the compare in bb.3 is kept.
---
name: too_many_conversions
tracksRegLiveness: true
body: |
; CHECK-LABEL: name: too_many_conversions
; 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: {{ $}}
; 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.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
JCC_1 %bb.2, 12, implicit $eflags
JMP_1 %bb.1
bb.1:
%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.3
bb.2:
bb.3:
CMP32ri %0, 2, implicit-def $eflags
$al = SETCCr 15, implicit $eflags
RET 0, $al
...
# Loop: the producer in bb.0 dominates the multi-predecessor block bb.1 (preds
# bb.0 and the bb.3 back-edge). The redundant compare in bb.1 is removed and the
# NF-convertible IMUL on the bb.2 path is rewritten. This exercises the backward
# walk over a cyclic CFG with a back-edge (the Visited set keeps it
# terminating), which the acyclic diamonds in optimize-compare-multipred.ll do
# not cover.
---
name: loop_backedge
tracksRegLiveness: true
body: |
; CHECK-LABEL: name: loop_backedge
; 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.4(0x40000000), %bb.2(0x40000000)
; CHECK-NEXT: liveins: $eflags
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: JCC_1 %bb.4, 4, implicit $eflags
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: bb.2:
; 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.3:
; CHECK-NEXT: successors: %bb.1(0x80000000)
; CHECK-NEXT: liveins: $eflags
; 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:
CMP32ri %0, 2, implicit-def $eflags
JCC_1 %bb.4, 4, implicit $eflags
bb.2:
%2:gr32 = nuw nsw IMUL32rr %0, %1, implicit-def dead $eflags
JMP_1 %bb.3
bb.3:
JMP_1 %bb.1
bb.4:
liveins: $eflags
$al = SETCCr 15, implicit $eflags
RET 0, $al
...
# The producer lives in bb.2, an immediate predecessor of the multi-predecessor
# block bb.3, but bb.3's other predecessor bb.1 reaches it without passing
# through bb.2, so bb.2 does not dominate bb.3. The backward walk reaches the
# entry block bb.0 (predecessor-less) without finding the producer on that path
# and bails, so the redundant compare in bb.3 is kept.
---
name: producer_in_nondominating_pred
tracksRegLiveness: true
body: |
; CHECK-LABEL: name: producer_in_nondominating_pred
; 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: JCC_1 %bb.2, 4, implicit undef $eflags
; CHECK-NEXT: JMP_1 %bb.1
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: bb.1:
; CHECK-NEXT: successors: %bb.3(0x80000000)
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: JMP_1 %bb.3
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: bb.2:
; CHECK-NEXT: successors: %bb.3(0x80000000)
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: CMP32ri [[COPY]], 2, implicit-def $eflags
; CHECK-NEXT: JMP_1 %bb.3
; 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
JCC_1 %bb.2, 4, implicit undef $eflags
JMP_1 %bb.1
bb.1:
JMP_1 %bb.3
bb.2:
CMP32ri %0, 2, implicit-def $eflags
JMP_1 %bb.3
bb.3:
CMP32ri %0, 2, implicit-def $eflags
$al = SETCCr 15, implicit $eflags
RET 0, $al
...
# The producer is duplicated on both diamond arms bb.1 and bb.2, so neither
# block alone dominates the multi-predecessor block bb.3. The backward walk
# finds a producer in two distinct blocks and bails, keeping the compare.
---
name: producer_in_two_blocks
tracksRegLiveness: true
body: |
; CHECK-LABEL: name: producer_in_two_blocks
; 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: JCC_1 %bb.2, 4, implicit undef $eflags
; CHECK-NEXT: JMP_1 %bb.1
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: bb.1:
; CHECK-NEXT: successors: %bb.3(0x80000000)
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: CMP32ri [[COPY]], 2, implicit-def $eflags
; CHECK-NEXT: JMP_1 %bb.3
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: bb.2:
; CHECK-NEXT: successors: %bb.3(0x80000000)
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: CMP32ri [[COPY]], 2, implicit-def $eflags
; CHECK-NEXT: JMP_1 %bb.3
; 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
JCC_1 %bb.2, 4, implicit undef $eflags
JMP_1 %bb.1
bb.1:
CMP32ri %0, 2, implicit-def $eflags
JMP_1 %bb.3
bb.2:
CMP32ri %0, 2, implicit-def $eflags
JMP_1 %bb.3
bb.3:
CMP32ri %0, 2, implicit-def $eflags
$al = SETCCr 15, implicit $eflags
RET 0, $al
...