xref: /llvm-project/llvm/test/Transforms/GuardWidening/pr60234.ll (revision fa97f63ac63f27045a2bef1892b98300d9e33431)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt -passes=indvars,guard-widening -S < %s | FileCheck %s
3
4declare i32 @llvm.experimental.deoptimize.i32(...)
5
6; Make sure that guard widening does not turn loop-invariant condition
7; (that then gets optimized basing on this fact) into non-invariant.
8; https://github.com/llvm/llvm-project/issues/60234 explains how it causes
9; a miscompile.
10define i32 @test(i32 %start) {
11; CHECK-LABEL: @test(
12; CHECK-NEXT:  entry:
13; CHECK-NEXT:    [[WC1:%.*]] = call i1 @llvm.experimental.widenable.condition()
14; CHECK-NEXT:    br label [[LOOP:%.*]]
15; CHECK:       loop:
16; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
17; CHECK-NEXT:    br i1 [[WC1]], label [[GUARD_BLOCK:%.*]], label [[EXIT_BY_WC:%.*]]
18; CHECK:       exit_by_wc:
19; CHECK-NEXT:    [[IV_LCSSA:%.*]] = phi i32 [ [[START]], [[LOOP]] ]
20; CHECK-NEXT:    [[RVAL1:%.*]] = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"(i32 [[IV_LCSSA]]) ]
21; CHECK-NEXT:    ret i32 [[RVAL1]]
22; CHECK:       guard_block:
23; CHECK-NEXT:    [[START_PLUS_1:%.*]] = add i32 [[START]], 1
24; CHECK-NEXT:    [[COND:%.*]] = icmp ne i32 [[START_PLUS_1]], [[IV]]
25; CHECK-NEXT:    [[WC2:%.*]] = call i1 @llvm.experimental.widenable.condition()
26; CHECK-NEXT:    [[GUARD:%.*]] = and i1 [[COND]], [[WC2]]
27; CHECK-NEXT:    br i1 [[GUARD]], label [[BACKEDGE]], label [[FAILURE:%.*]]
28; CHECK:       backedge:
29; CHECK-NEXT:    call void @side_effect()
30; CHECK-NEXT:    [[IV_NEXT]] = add i32 [[IV]], 1
31; CHECK-NEXT:    br label [[LOOP]]
32; CHECK:       exit:
33; CHECK-NEXT:    ret i32 -1
34; CHECK:       failure:
35; CHECK-NEXT:    [[IV_LCSSA1:%.*]] = phi i32 [ [[IV]], [[GUARD_BLOCK]] ]
36; CHECK-NEXT:    [[RVAL2:%.*]] = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"(i32 [[IV_LCSSA1]]) ]
37; CHECK-NEXT:    ret i32 [[RVAL2]]
38;
39entry:
40  %wc1 = call i1 @llvm.experimental.widenable.condition()
41  br label %loop
42
43loop:
44  %iv = phi i32 [ %start, %entry ], [ %iv.next, %backedge ]
45  br i1 %wc1, label %guard_block, label %exit_by_wc
46
47exit_by_wc:
48  %rval1 = call i32(...) @llvm.experimental.deoptimize.i32() [ "deopt"(i32 %iv) ]
49  ret i32 %rval1
50
51guard_block:
52  %start_plus_1 = add i32 %start, 1
53  %cond = icmp ne i32 %start_plus_1, %iv
54  %wc2 = call i1 @llvm.experimental.widenable.condition()
55  %guard = and i1 %cond, %wc2
56  br i1 %guard, label %backedge, label %failure
57
58backedge:
59  call void @side_effect()
60  %iv.next = add i32 %iv, 1
61  br label %loop
62
63exit:
64  ret i32 -1
65
66failure:
67  %rval2 = call i32(...) @llvm.experimental.deoptimize.i32() [ "deopt"(i32 %iv) ]
68  ret i32 %rval2
69}
70
71; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(inaccessiblemem: readwrite)
72declare i1 @llvm.experimental.widenable.condition()
73
74declare void @side_effect()
75