Files
clang-p2996/llvm/test/Transforms/LoopDeletion/zero-btc.ll
Max Kazantsev de92287cf8 [LoopDeletion] Break backedge if we can prove that the loop is exited on 1st iteration (try 3)
This patch handles one particular case of one-iteration loops for which SCEV
cannot straightforwardly prove BECount = 1. The idea of the optimization is to
symbolically execute conditional branches on the 1st iteration, moving in topoligical
order, and only visiting blocks that may be reached on the first iteration. If we find out
that we never reach header via the latch, then the backedge can be broken.

This implementation uses InstSimplify. SCEV version was rejected due to high
compile time impact.

Differential Revision: https://reviews.llvm.org/D102615
Reviewed By: nikic
2021-06-18 17:31:57 +07:00

382 lines
10 KiB
LLVM

; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt < %s -loop-deletion -S | FileCheck %s
@G = external global i32
define void @test_trivial() {
; CHECK-LABEL: @test_trivial(
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: store i32 0, i32* @G, align 4
; CHECK-NEXT: br i1 false, label [[LOOP_LOOP_CRIT_EDGE:%.*]], label [[EXIT:%.*]]
; CHECK: loop.loop_crit_edge:
; CHECK-NEXT: unreachable
; CHECK: exit:
; CHECK-NEXT: ret void
;
entry:
br label %loop
loop:
store i32 0, i32* @G
br i1 false, label %loop, label %exit
exit:
ret void
}
define void @test_bottom_tested() {
; CHECK-LABEL: @test_bottom_tested(
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ]
; CHECK-NEXT: store i32 0, i32* @G, align 4
; CHECK-NEXT: [[IV_INC:%.*]] = add i32 [[IV]], 1
; CHECK-NEXT: [[BE_TAKEN:%.*]] = icmp ne i32 [[IV_INC]], 1
; CHECK-NEXT: br i1 [[BE_TAKEN]], label [[LOOP_LOOP_CRIT_EDGE:%.*]], label [[EXIT:%.*]]
; CHECK: loop.loop_crit_edge:
; CHECK-NEXT: unreachable
; CHECK: exit:
; CHECK-NEXT: ret void
;
entry:
br label %loop
loop:
%iv = phi i32 [ 0, %entry], [ %iv.inc, %loop ]
store i32 0, i32* @G
%iv.inc = add i32 %iv, 1
%be_taken = icmp ne i32 %iv.inc, 1
br i1 %be_taken, label %loop, label %exit
exit:
ret void
}
define void @test_early_exit() {
; CHECK-LABEL: @test_early_exit(
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ]
; CHECK-NEXT: store i32 0, i32* @G, align 4
; CHECK-NEXT: [[IV_INC:%.*]] = add i32 [[IV]], 1
; CHECK-NEXT: [[BE_TAKEN:%.*]] = icmp ne i32 [[IV_INC]], 1
; CHECK-NEXT: br i1 [[BE_TAKEN]], label [[LATCH:%.*]], label [[EXIT:%.*]]
; CHECK: latch:
; CHECK-NEXT: br label [[LATCH_SPLIT:%.*]]
; CHECK: latch.split:
; CHECK-NEXT: unreachable
; CHECK: exit:
; CHECK-NEXT: ret void
;
entry:
br label %loop
loop:
%iv = phi i32 [ 0, %entry], [ %iv.inc, %latch ]
store i32 0, i32* @G
%iv.inc = add i32 %iv, 1
%be_taken = icmp ne i32 %iv.inc, 1
br i1 %be_taken, label %latch, label %exit
latch:
br label %loop
exit:
ret void
}
define void @test_multi_exit1() {
; CHECK-LABEL: @test_multi_exit1(
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ]
; CHECK-NEXT: store i32 0, i32* @G, align 4
; CHECK-NEXT: [[IV_INC:%.*]] = add i32 [[IV]], 1
; CHECK-NEXT: [[BE_TAKEN:%.*]] = icmp ne i32 [[IV_INC]], 1
; CHECK-NEXT: br i1 [[BE_TAKEN]], label [[LATCH:%.*]], label [[EXIT:%.*]]
; CHECK: latch:
; CHECK-NEXT: store i32 1, i32* @G, align 4
; CHECK-NEXT: [[COND2:%.*]] = icmp ult i32 [[IV_INC]], 30
; CHECK-NEXT: br i1 [[COND2]], label [[LATCH_LOOP_CRIT_EDGE:%.*]], label [[EXIT]]
; CHECK: latch.loop_crit_edge:
; CHECK-NEXT: unreachable
; CHECK: exit:
; CHECK-NEXT: ret void
;
entry:
br label %loop
loop:
%iv = phi i32 [ 0, %entry], [ %iv.inc, %latch ]
store i32 0, i32* @G
%iv.inc = add i32 %iv, 1
%be_taken = icmp ne i32 %iv.inc, 1
br i1 %be_taken, label %latch, label %exit
latch:
store i32 1, i32* @G
%cond2 = icmp ult i32 %iv.inc, 30
br i1 %cond2, label %loop, label %exit
exit:
ret void
}
define void @test_multi_exit2() {
; CHECK-LABEL: @test_multi_exit2(
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: store i32 0, i32* @G, align 4
; CHECK-NEXT: br i1 true, label [[LATCH:%.*]], label [[EXIT:%.*]]
; CHECK: latch:
; CHECK-NEXT: store i32 1, i32* @G, align 4
; CHECK-NEXT: br i1 false, label [[LATCH_LOOP_CRIT_EDGE:%.*]], label [[EXIT]]
; CHECK: latch.loop_crit_edge:
; CHECK-NEXT: unreachable
; CHECK: exit:
; CHECK-NEXT: ret void
;
entry:
br label %loop
loop:
store i32 0, i32* @G
br i1 true, label %latch, label %exit
latch:
store i32 1, i32* @G
br i1 false, label %loop, label %exit
exit:
ret void
}
define void @test_multi_exit3(i1 %cond1) {
; CHECK-LABEL: @test_multi_exit3(
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ]
; CHECK-NEXT: store i32 0, i32* @G, align 4
; CHECK-NEXT: br i1 [[COND1:%.*]], label [[LATCH:%.*]], label [[EXIT:%.*]]
; CHECK: latch:
; CHECK-NEXT: store i32 1, i32* @G, align 4
; CHECK-NEXT: [[IV_INC:%.*]] = add i32 [[IV]], 1
; CHECK-NEXT: [[BE_TAKEN:%.*]] = icmp ne i32 [[IV_INC]], 1
; CHECK-NEXT: br i1 [[BE_TAKEN]], label [[LATCH_LOOP_CRIT_EDGE:%.*]], label [[EXIT]]
; CHECK: latch.loop_crit_edge:
; CHECK-NEXT: unreachable
; CHECK: exit:
; CHECK-NEXT: ret void
;
entry:
br label %loop
loop:
%iv = phi i32 [ 0, %entry], [ %iv.inc, %latch ]
store i32 0, i32* @G
br i1 %cond1, label %latch, label %exit
latch:
store i32 1, i32* @G
%iv.inc = add i32 %iv, 1
%be_taken = icmp ne i32 %iv.inc, 1
br i1 %be_taken, label %loop, label %exit
exit:
ret void
}
; Subtle - This is either zero btc, or infinite, thus, can't break
; backedge
define void @test_multi_exit4(i1 %cond1, i1 %cond2) {
; CHECK-LABEL: @test_multi_exit4(
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: store i32 0, i32* @G, align 4
; CHECK-NEXT: br i1 [[COND1:%.*]], label [[LATCH:%.*]], label [[EXIT:%.*]]
; CHECK: latch:
; CHECK-NEXT: store i32 1, i32* @G, align 4
; CHECK-NEXT: br i1 [[COND2:%.*]], label [[LOOP]], label [[EXIT]]
; CHECK: exit:
; CHECK-NEXT: ret void
;
entry:
br label %loop
loop:
store i32 0, i32* @G
br i1 %cond1, label %latch, label %exit
latch:
store i32 1, i32* @G
br i1 %cond2, label %loop, label %exit
exit:
ret void
}
; A simple case with multiple exit blocks
define void @test_multi_exit5() {
; CHECK-LABEL: @test_multi_exit5(
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: store i32 0, i32* @G, align 4
; CHECK-NEXT: br i1 true, label [[LATCH:%.*]], label [[EXIT1:%.*]]
; CHECK: latch:
; CHECK-NEXT: store i32 1, i32* @G, align 4
; CHECK-NEXT: br i1 false, label [[LATCH_LOOP_CRIT_EDGE:%.*]], label [[EXIT2:%.*]]
; CHECK: latch.loop_crit_edge:
; CHECK-NEXT: unreachable
; CHECK: exit1:
; CHECK-NEXT: ret void
; CHECK: exit2:
; CHECK-NEXT: ret void
;
entry:
br label %loop
loop:
store i32 0, i32* @G
br i1 true, label %latch, label %exit1
latch:
store i32 1, i32* @G
br i1 false, label %loop, label %exit2
exit1:
ret void
exit2:
ret void
}
define void @test_live_inner() {
; CHECK-LABEL: @test_live_inner(
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: store i32 0, i32* @G, align 4
; CHECK-NEXT: br label [[INNER:%.*]]
; CHECK: inner:
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[LOOP]] ], [ [[IV_INC:%.*]], [[INNER]] ]
; CHECK-NEXT: store i32 [[IV]], i32* @G, align 4
; CHECK-NEXT: [[IV_INC]] = add i32 [[IV]], 1
; CHECK-NEXT: [[CND:%.*]] = icmp ult i32 [[IV_INC]], 200
; CHECK-NEXT: br i1 [[CND]], label [[INNER]], label [[LATCH:%.*]]
; CHECK: latch:
; CHECK-NEXT: br i1 false, label [[LATCH_LOOP_CRIT_EDGE:%.*]], label [[EXIT:%.*]]
; CHECK: latch.loop_crit_edge:
; CHECK-NEXT: unreachable
; CHECK: exit:
; CHECK-NEXT: ret void
;
entry:
br label %loop
loop:
store i32 0, i32* @G
br label %inner
inner:
%iv = phi i32 [0, %loop], [%iv.inc, %inner]
store i32 %iv, i32* @G
%iv.inc = add i32 %iv, 1
%cnd = icmp ult i32 %iv.inc, 200
br i1 %cnd, label %inner, label %latch
latch:
br i1 false, label %loop, label %exit
exit:
ret void
}
define void @test_live_outer() {
; CHECK-LABEL: @test_live_outer(
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_INC:%.*]], [[LATCH:%.*]] ]
; CHECK-NEXT: br label [[INNER:%.*]]
; CHECK: inner:
; CHECK-NEXT: store i32 0, i32* @G, align 4
; CHECK-NEXT: br i1 false, label [[INNER_INNER_CRIT_EDGE:%.*]], label [[LATCH]]
; CHECK: inner.inner_crit_edge:
; CHECK-NEXT: unreachable
; CHECK: latch:
; CHECK-NEXT: store i32 [[IV]], i32* @G, align 4
; CHECK-NEXT: [[IV_INC]] = add i32 [[IV]], 1
; CHECK-NEXT: [[CND:%.*]] = icmp ult i32 [[IV_INC]], 200
; CHECK-NEXT: br i1 [[CND]], label [[LOOP]], label [[EXIT:%.*]]
; CHECK: exit:
; CHECK-NEXT: ret void
;
entry:
br label %loop
loop:
%iv = phi i32 [0, %entry], [%iv.inc, %latch]
br label %inner
inner:
store i32 0, i32* @G
br i1 false, label %inner, label %latch
latch:
store i32 %iv, i32* @G
%iv.inc = add i32 %iv, 1
%cnd = icmp ult i32 %iv.inc, 200
br i1 %cnd, label %loop, label %exit
exit:
ret void
}
; Key point is that inner_latch drops out of the outer loop when
; the inner loop is deleted, and thus the lcssa phi needs to be
; in the inner_latch block to preserve LCSSA. We either have to
; insert the LCSSA phi, or not break the inner backedge.
define void @loop_nest_lcssa() {
; CHECK-LABEL: @loop_nest_lcssa(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP0:%.*]] = add i32 1, 2
; CHECK-NEXT: br label [[OUTER_HEADER:%.*]]
; CHECK: outer_header:
; CHECK-NEXT: br label [[INNER_HEADER:%.*]]
; CHECK: inner_header:
; CHECK-NEXT: br i1 false, label [[INNER_LATCH:%.*]], label [[OUTER_LATCH:%.*]]
; CHECK: inner_latch:
; CHECK-NEXT: [[DOTLCSSA:%.*]] = phi i32 [ [[TMP0]], [[INNER_HEADER]] ]
; CHECK-NEXT: br i1 false, label [[INNER_LATCH_INNER_HEADER_CRIT_EDGE:%.*]], label [[LOOPEXIT:%.*]]
; CHECK: inner_latch.inner_header_crit_edge:
; CHECK-NEXT: unreachable
; CHECK: outer_latch:
; CHECK-NEXT: br label [[OUTER_HEADER]]
; CHECK: loopexit:
; CHECK-NEXT: [[DOTLCSSA32:%.*]] = phi i32 [ [[DOTLCSSA]], [[INNER_LATCH]] ]
; CHECK-NEXT: unreachable
;
entry:
br label %outer_header
outer_header:
%0 = add i32 1, 2
br label %inner_header
inner_header:
br i1 false, label %inner_latch, label %outer_latch
inner_latch:
br i1 false, label %inner_header, label %loopexit
outer_latch:
br label %outer_header
loopexit:
%.lcssa32 = phi i32 [ %0, %inner_latch ]
unreachable
}