| # 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 |
| ... |