diff --git a/llvm/test/Transforms/LoopDeletion/zero-btc.ll b/llvm/test/Transforms/LoopDeletion/zero-btc.ll new file mode 100644 index 00000000000000..b56e30e8f1be63 --- /dev/null +++ b/llvm/test/Transforms/LoopDeletion/zero-btc.ll @@ -0,0 +1,319 @@ +; 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]], label [[EXIT:%.*]] +; 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:%.*]] ], [ [[IV_INC:%.*]], [[LOOP]] ] +; 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]], label [[EXIT:%.*]] +; 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:%.*]] ], [ [[IV_INC:%.*]], [[LATCH:%.*]] ] +; 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 [[LOOP]] +; 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:%.*]] ], [ [[IV_INC:%.*]], [[LATCH:%.*]] ] +; 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 [[LOOP]], label [[EXIT]] +; 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 [[LOOP]], label [[EXIT]] +; 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 +} + +; TODO: SCEV seems not to recognize this as a zero btc loop +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:%.*]] ], [ [[IV_INC:%.*]], [[LATCH:%.*]] ] +; 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 [[LOOP]], label [[EXIT]] +; 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 [[LOOP]], label [[EXIT2:%.*]] +; 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 [[LOOP]], label [[EXIT:%.*]] +; 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]], label [[LATCH]] +; 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 +}