| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py |
| ; RUN: opt -passes=guard-widening -S < %s | FileCheck %s |
| |
| declare i32 @llvm.experimental.deoptimize.i32(...) |
| |
| ; Make sure the two loop-invariant conditions can be widened together, |
| ; and the widening point is outside the loop. |
| define i32 @test_01(i32 %start, i32 %x) { |
| ; CHECK-LABEL: @test_01( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[START_GW_FR:%.*]] = freeze i32 [[START:%.*]] |
| ; CHECK-NEXT: [[X_GW_FR:%.*]] = freeze i32 [[X:%.*]] |
| ; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[START_GW_FR]], [[X_GW_FR]] |
| ; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 true, [[COND]] |
| ; CHECK-NEXT: [[WC1:%.*]] = call i1 @llvm.experimental.widenable.condition() |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START_GW_FR]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ] |
| ; CHECK-NEXT: [[TMP0:%.*]] = and i1 [[WIDE_CHK]], [[WC1]] |
| ; CHECK-NEXT: br i1 [[TMP0]], label [[GUARD_BLOCK:%.*]], label [[EXIT_BY_WC:%.*]] |
| ; CHECK: exit_by_wc: |
| ; CHECK-NEXT: [[RVAL1:%.*]] = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"(i32 [[IV]]) ] |
| ; CHECK-NEXT: ret i32 [[RVAL1]] |
| ; CHECK: guard_block: |
| ; CHECK-NEXT: [[WC2:%.*]] = call i1 @llvm.experimental.widenable.condition() |
| ; CHECK-NEXT: [[GUARD:%.*]] = and i1 [[COND]], [[WC2]] |
| ; CHECK-NEXT: br i1 true, label [[BACKEDGE]], label [[FAILURE:%.*]] |
| ; CHECK: backedge: |
| ; CHECK-NEXT: call void @side_effect() |
| ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 |
| ; CHECK-NEXT: br label [[LOOP]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret i32 -1 |
| ; CHECK: failure: |
| ; CHECK-NEXT: [[RVAL2:%.*]] = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"(i32 [[IV]]) ] |
| ; CHECK-NEXT: ret i32 [[RVAL2]] |
| ; |
| entry: |
| %cond = icmp eq i32 %start, %x |
| %wc1 = call i1 @llvm.experimental.widenable.condition() |
| br label %loop |
| |
| loop: |
| %iv = phi i32 [ %start, %entry ], [ %iv.next, %backedge ] |
| br i1 %wc1, label %guard_block, label %exit_by_wc |
| |
| exit_by_wc: |
| %rval1 = call i32(...) @llvm.experimental.deoptimize.i32() [ "deopt"(i32 %iv) ] |
| ret i32 %rval1 |
| |
| guard_block: |
| %wc2 = call i1 @llvm.experimental.widenable.condition() |
| %guard = and i1 %cond, %wc2 |
| br i1 %guard, label %backedge, label %failure |
| |
| backedge: |
| call void @side_effect() |
| %iv.next = add i32 %iv, 1 |
| br label %loop |
| |
| exit: |
| ret i32 -1 |
| |
| failure: |
| %rval2 = call i32(...) @llvm.experimental.deoptimize.i32() [ "deopt"(i32 %iv) ] |
| ret i32 %rval2 |
| } |
| |
| |
| ; Make sure the loop-variant condition is not widened into loop-invariant. |
| define i32 @test_02(i32 %start, i32 %x) { |
| ; CHECK-LABEL: @test_02( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[WC1:%.*]] = call i1 @llvm.experimental.widenable.condition() |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ] |
| ; CHECK-NEXT: br i1 [[WC1]], label [[GUARD_BLOCK:%.*]], label [[EXIT_BY_WC:%.*]] |
| ; CHECK: exit_by_wc: |
| ; CHECK-NEXT: [[RVAL1:%.*]] = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"(i32 [[IV]]) ] |
| ; CHECK-NEXT: ret i32 [[RVAL1]] |
| ; CHECK: guard_block: |
| ; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[IV]], [[X:%.*]] |
| ; CHECK-NEXT: [[WC2:%.*]] = call i1 @llvm.experimental.widenable.condition() |
| ; CHECK-NEXT: [[GUARD:%.*]] = and i1 [[COND]], [[WC2]] |
| ; CHECK-NEXT: br i1 [[GUARD]], label [[BACKEDGE]], label [[FAILURE:%.*]] |
| ; CHECK: backedge: |
| ; CHECK-NEXT: call void @side_effect() |
| ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 |
| ; CHECK-NEXT: br label [[LOOP]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret i32 -1 |
| ; CHECK: failure: |
| ; CHECK-NEXT: [[RVAL2:%.*]] = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"(i32 [[IV]]) ] |
| ; CHECK-NEXT: ret i32 [[RVAL2]] |
| ; |
| entry: |
| %wc1 = call i1 @llvm.experimental.widenable.condition() |
| br label %loop |
| |
| loop: |
| %iv = phi i32 [ %start, %entry ], [ %iv.next, %backedge ] |
| br i1 %wc1, label %guard_block, label %exit_by_wc |
| |
| exit_by_wc: |
| %rval1 = call i32(...) @llvm.experimental.deoptimize.i32() [ "deopt"(i32 %iv) ] |
| ret i32 %rval1 |
| |
| guard_block: |
| %cond = icmp eq i32 %iv, %x |
| %wc2 = call i1 @llvm.experimental.widenable.condition() |
| %guard = and i1 %cond, %wc2 |
| br i1 %guard, label %backedge, label %failure |
| |
| backedge: |
| call void @side_effect() |
| %iv.next = add i32 %iv, 1 |
| br label %loop |
| |
| exit: |
| ret i32 -1 |
| |
| failure: |
| %rval2 = call i32(...) @llvm.experimental.deoptimize.i32() [ "deopt"(i32 %iv) ] |
| ret i32 %rval2 |
| } |
| |
| ; Same as test_01, but the initial condition is not immediately WC. |
| define i32 @test_03(i32 %start, i32 %x, i1 %c) { |
| ; CHECK-LABEL: @test_03( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[START_GW_FR:%.*]] = freeze i32 [[START:%.*]] |
| ; CHECK-NEXT: [[X_GW_FR:%.*]] = freeze i32 [[X:%.*]] |
| ; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[START_GW_FR]], [[X_GW_FR]] |
| ; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[C:%.*]], [[COND]] |
| ; CHECK-NEXT: [[WC1:%.*]] = call i1 @llvm.experimental.widenable.condition() |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START_GW_FR]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ] |
| ; CHECK-NEXT: [[INVARIANT:%.*]] = and i1 [[WIDE_CHK]], [[WC1]] |
| ; CHECK-NEXT: br i1 [[INVARIANT]], label [[GUARD_BLOCK:%.*]], label [[EXIT_BY_WC:%.*]] |
| ; CHECK: exit_by_wc: |
| ; CHECK-NEXT: [[RVAL1:%.*]] = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"(i32 [[IV]]) ] |
| ; CHECK-NEXT: ret i32 [[RVAL1]] |
| ; CHECK: guard_block: |
| ; CHECK-NEXT: [[WC2:%.*]] = call i1 @llvm.experimental.widenable.condition() |
| ; CHECK-NEXT: [[GUARD:%.*]] = and i1 [[COND]], [[WC2]] |
| ; CHECK-NEXT: br i1 true, label [[BACKEDGE]], label [[FAILURE:%.*]] |
| ; CHECK: backedge: |
| ; CHECK-NEXT: call void @side_effect() |
| ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 |
| ; CHECK-NEXT: br label [[LOOP]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret i32 -1 |
| ; CHECK: failure: |
| ; CHECK-NEXT: [[RVAL2:%.*]] = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"(i32 [[IV]]) ] |
| ; CHECK-NEXT: ret i32 [[RVAL2]] |
| ; CHECK: early_failure: |
| ; CHECK-NEXT: [[RVAL3:%.*]] = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"(i32 [[X_GW_FR]]) ] |
| ; CHECK-NEXT: ret i32 [[RVAL3]] |
| ; |
| entry: |
| %cond = icmp eq i32 %start, %x |
| %wc1 = call i1 @llvm.experimental.widenable.condition() |
| %invariant = and i1 %c, %wc1 |
| br label %loop |
| |
| loop: |
| %iv = phi i32 [ %start, %entry ], [ %iv.next, %backedge ] |
| br i1 %invariant, label %guard_block, label %exit_by_wc |
| |
| exit_by_wc: |
| %rval1 = call i32(...) @llvm.experimental.deoptimize.i32() [ "deopt"(i32 %iv) ] |
| ret i32 %rval1 |
| |
| guard_block: |
| %wc2 = call i1 @llvm.experimental.widenable.condition() |
| %guard = and i1 %cond, %wc2 |
| br i1 %guard, label %backedge, label %failure |
| |
| backedge: |
| call void @side_effect() |
| %iv.next = add i32 %iv, 1 |
| br label %loop |
| |
| exit: |
| ret i32 -1 |
| |
| failure: |
| %rval2 = call i32(...) @llvm.experimental.deoptimize.i32() [ "deopt"(i32 %iv) ] |
| ret i32 %rval2 |
| |
| early_failure: |
| %rval3 = call i32(...) @llvm.experimental.deoptimize.i32() [ "deopt"(i32 %x) ] |
| ret i32 %rval3 |
| } |
| |
| ; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(inaccessiblemem: readwrite) |
| declare i1 @llvm.experimental.widenable.condition() |
| |
| declare void @side_effect() |