| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py |
| ; RUN: opt -passes=indvars,guard-widening -S < %s | FileCheck %s |
| |
| declare i32 @llvm.experimental.deoptimize.i32(...) |
| |
| ; Make sure that guard widening does not turn loop-invariant condition |
| ; (that then gets optimized basing on this fact) into non-invariant. |
| ; https://github.com/llvm/llvm-project/issues/60234 explains how it causes |
| ; a miscompile. |
| define i32 @test(i32 %start) { |
| ; CHECK-LABEL: @test( |
| ; 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: [[IV_LCSSA:%.*]] = phi i32 [ [[START]], [[LOOP]] ] |
| ; CHECK-NEXT: [[RVAL1:%.*]] = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"(i32 [[IV_LCSSA]]) ] |
| ; CHECK-NEXT: ret i32 [[RVAL1]] |
| ; CHECK: guard_block: |
| ; CHECK-NEXT: [[START_PLUS_1:%.*]] = add i32 [[START]], 1 |
| ; CHECK-NEXT: [[COND:%.*]] = icmp ne i32 [[START_PLUS_1]], [[IV]] |
| ; 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: [[IV_LCSSA1:%.*]] = phi i32 [ [[IV]], [[GUARD_BLOCK]] ] |
| ; CHECK-NEXT: [[RVAL2:%.*]] = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"(i32 [[IV_LCSSA1]]) ] |
| ; 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: |
| %start_plus_1 = add i32 %start, 1 |
| %cond = icmp ne i32 %start_plus_1, %iv |
| %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 |
| } |
| |
| ; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(inaccessiblemem: readwrite) |
| declare i1 @llvm.experimental.widenable.condition() |
| |
| declare void @side_effect() |