1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt -S -make-guards-explicit -basic-aa -licm < %s        | FileCheck %s
3; RUN: opt -S -aa-pipeline=basic-aa -passes='require<opt-remark-emit>,make-guards-explicit,loop-mssa(licm)' < %s | FileCheck %s
4
5declare void @llvm.experimental.guard(i1,...)
6declare void @maythrow()
7
8; Make sure that we do not hoist widenable_cond out of loop.
9define void @hoist_widenable_cond(i1 %cond, i32 %N, i32 %M) {
10; CHECK-LABEL: @hoist_widenable_cond(
11; CHECK-NEXT:  entry:
12; CHECK-NEXT:    [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition()
13; CHECK-NEXT:    br label [[LOOP:%.*]]
14; CHECK:       loop:
15; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[GUARDED:%.*]] ]
16; CHECK-NEXT:    [[GUARD_COND:%.*]] = icmp slt i32 [[IV]], [[N:%.*]]
17; CHECK-NEXT:    [[EXIPLICIT_GUARD_COND:%.*]] = and i1 [[GUARD_COND]], [[WIDENABLE_COND]]
18; CHECK-NEXT:    br i1 [[EXIPLICIT_GUARD_COND]], label [[GUARDED]], label [[DEOPT:%.*]], !prof !0
19; CHECK:       deopt:
20; CHECK-NEXT:    call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
21; CHECK-NEXT:    ret void
22; CHECK:       guarded:
23; CHECK-NEXT:    [[LOOP_COND:%.*]] = icmp slt i32 [[IV]], [[M:%.*]]
24; CHECK-NEXT:    [[IV_NEXT]] = add i32 [[IV]], 1
25; CHECK-NEXT:    br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
26; CHECK:       exit:
27; CHECK-NEXT:    ret void
28;
29entry:
30  br label %loop
31
32loop:
33  %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]
34  %guard_cond = icmp slt i32 %iv, %N
35  call void(i1, ...) @llvm.experimental.guard(i1 %guard_cond) [ "deopt"() ]
36  %loop_cond = icmp slt i32 %iv, %M
37  %iv.next = add i32 %iv, 1
38  br i1 %loop_cond, label %loop, label %exit
39
40exit:
41  ret void
42}
43
44define void @hoist_widenable_cond_speculate(i1 %cond, i32 %N, i32 %M) {
45; CHECK-LABEL: @hoist_widenable_cond_speculate(
46; CHECK-NEXT:  entry:
47; CHECK-NEXT:    [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition()
48; CHECK-NEXT:    br label [[LOOP:%.*]]
49; CHECK:       loop:
50; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[GUARDED:%.*]] ]
51; CHECK-NEXT:    [[GUARD_COND:%.*]] = icmp slt i32 [[IV]], [[N:%.*]]
52; CHECK-NEXT:    call void @maythrow()
53; CHECK-NEXT:    [[EXIPLICIT_GUARD_COND:%.*]] = and i1 [[GUARD_COND]], [[WIDENABLE_COND]]
54; CHECK-NEXT:    br i1 [[EXIPLICIT_GUARD_COND]], label [[GUARDED]], label [[DEOPT:%.*]], !prof !0
55; CHECK:       deopt:
56; CHECK-NEXT:    call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
57; CHECK-NEXT:    ret void
58; CHECK:       guarded:
59; CHECK-NEXT:    [[LOOP_COND:%.*]] = icmp slt i32 [[IV]], [[M:%.*]]
60; CHECK-NEXT:    [[IV_NEXT]] = add i32 [[IV]], 1
61; CHECK-NEXT:    br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
62; CHECK:       exit:
63; CHECK-NEXT:    ret void
64;
65entry:
66  br label %loop
67
68loop:
69  %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]
70  %guard_cond = icmp slt i32 %iv, %N
71  call void @maythrow()
72  call void(i1, ...) @llvm.experimental.guard(i1 %guard_cond) [ "deopt"() ]
73  %loop_cond = icmp slt i32 %iv, %M
74  %iv.next = add i32 %iv, 1
75  br i1 %loop_cond, label %loop, label %exit
76
77exit:
78  ret void
79}
80
81
82define void @hoist_invariant_load(i1 %cond, i32* %np, i32 %M) {
83; CHECK-LABEL: @hoist_invariant_load(
84; CHECK-NEXT:  entry:
85; CHECK-NEXT:    [[N:%.*]] = load i32, i32* [[NP:%.*]]
86; CHECK-NEXT:    [[WIDENABLE_COND:%.*]] = call i1 @llvm.experimental.widenable.condition()
87; CHECK-NEXT:    br label [[LOOP:%.*]]
88; CHECK:       loop:
89; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[GUARDED:%.*]] ]
90; CHECK-NEXT:    [[GUARD_COND:%.*]] = icmp slt i32 [[IV]], [[N]]
91; CHECK-NEXT:    [[EXIPLICIT_GUARD_COND:%.*]] = and i1 [[GUARD_COND]], [[WIDENABLE_COND]]
92; CHECK-NEXT:    br i1 [[EXIPLICIT_GUARD_COND]], label [[GUARDED]], label [[DEOPT:%.*]], !prof !0
93; CHECK:       deopt:
94; CHECK-NEXT:    call void (...) @llvm.experimental.deoptimize.isVoid() [ "deopt"() ]
95; CHECK-NEXT:    ret void
96; CHECK:       guarded:
97; CHECK-NEXT:    [[LOOP_COND:%.*]] = icmp slt i32 [[IV]], [[M:%.*]]
98; CHECK-NEXT:    [[IV_NEXT]] = add i32 [[IV]], 1
99; CHECK-NEXT:    br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]
100; CHECK:       exit:
101; CHECK-NEXT:    ret void
102;
103entry:
104  br label %loop
105
106loop:
107  %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]
108  %N = load i32, i32* %np
109  %guard_cond = icmp slt i32 %iv, %N
110  call void(i1, ...) @llvm.experimental.guard(i1 %guard_cond) [ "deopt"() ]
111  %loop_cond = icmp slt i32 %iv, %M
112  %iv.next = add i32 %iv, 1
113  br i1 %loop_cond, label %loop, label %exit
114
115exit:
116  ret void
117}
118