xref: /llvm-project/llvm/test/Transforms/GuardWidening/loop_invariant_widenable_condition.ll (revision 0b5bb6923f09ebc257ebed4ace1d8b6b113b2bf5)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt -passes=guard-widening -S < %s | FileCheck %s
3
4declare i32 @llvm.experimental.deoptimize.i32(...)
5
6; Make sure the two loop-invariant conditions can be widened together,
7; and the widening point is outside the loop.
8define i32 @test_01(i32 %start, i32 %x) {
9; CHECK-LABEL: @test_01(
10; CHECK-NEXT:  entry:
11; CHECK-NEXT:    [[START_GW_FR:%.*]] = freeze i32 [[START:%.*]]
12; CHECK-NEXT:    [[X_GW_FR:%.*]] = freeze i32 [[X:%.*]]
13; CHECK-NEXT:    [[COND:%.*]] = icmp eq i32 [[START_GW_FR]], [[X_GW_FR]]
14; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 true, [[COND]]
15; CHECK-NEXT:    [[WC1:%.*]] = call i1 @llvm.experimental.widenable.condition()
16; CHECK-NEXT:    br label [[LOOP:%.*]]
17; CHECK:       loop:
18; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ [[START_GW_FR]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
19; CHECK-NEXT:    [[TMP0:%.*]] = and i1 [[WIDE_CHK]], [[WC1]]
20; CHECK-NEXT:    br i1 [[TMP0]], label [[GUARD_BLOCK:%.*]], label [[EXIT_BY_WC:%.*]]
21; CHECK:       exit_by_wc:
22; CHECK-NEXT:    [[RVAL1:%.*]] = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"(i32 [[IV]]) ]
23; CHECK-NEXT:    ret i32 [[RVAL1]]
24; CHECK:       guard_block:
25; CHECK-NEXT:    [[WC2:%.*]] = call i1 @llvm.experimental.widenable.condition()
26; CHECK-NEXT:    [[GUARD:%.*]] = and i1 [[COND]], [[WC2]]
27; CHECK-NEXT:    br i1 true, 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:    [[RVAL2:%.*]] = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"(i32 [[IV]]) ]
36; CHECK-NEXT:    ret i32 [[RVAL2]]
37;
38entry:
39  %cond = icmp eq i32 %start, %x
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  %wc2 = call i1 @llvm.experimental.widenable.condition()
53  %guard = and i1 %cond, %wc2
54  br i1 %guard, label %backedge, label %failure
55
56backedge:
57  call void @side_effect()
58  %iv.next = add i32 %iv, 1
59  br label %loop
60
61exit:
62  ret i32 -1
63
64failure:
65  %rval2 = call i32(...) @llvm.experimental.deoptimize.i32() [ "deopt"(i32 %iv) ]
66  ret i32 %rval2
67}
68
69
70; Make sure the loop-variant condition is not widened into loop-invariant.
71define i32 @test_02(i32 %start, i32 %x) {
72; CHECK-LABEL: @test_02(
73; CHECK-NEXT:  entry:
74; CHECK-NEXT:    [[WC1:%.*]] = call i1 @llvm.experimental.widenable.condition()
75; CHECK-NEXT:    br label [[LOOP:%.*]]
76; CHECK:       loop:
77; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
78; CHECK-NEXT:    br i1 [[WC1]], label [[GUARD_BLOCK:%.*]], label [[EXIT_BY_WC:%.*]]
79; CHECK:       exit_by_wc:
80; CHECK-NEXT:    [[RVAL1:%.*]] = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"(i32 [[IV]]) ]
81; CHECK-NEXT:    ret i32 [[RVAL1]]
82; CHECK:       guard_block:
83; CHECK-NEXT:    [[COND:%.*]] = icmp eq i32 [[IV]], [[X:%.*]]
84; CHECK-NEXT:    [[WC2:%.*]] = call i1 @llvm.experimental.widenable.condition()
85; CHECK-NEXT:    [[GUARD:%.*]] = and i1 [[COND]], [[WC2]]
86; CHECK-NEXT:    br i1 [[GUARD]], label [[BACKEDGE]], label [[FAILURE:%.*]]
87; CHECK:       backedge:
88; CHECK-NEXT:    call void @side_effect()
89; CHECK-NEXT:    [[IV_NEXT]] = add i32 [[IV]], 1
90; CHECK-NEXT:    br label [[LOOP]]
91; CHECK:       exit:
92; CHECK-NEXT:    ret i32 -1
93; CHECK:       failure:
94; CHECK-NEXT:    [[RVAL2:%.*]] = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"(i32 [[IV]]) ]
95; CHECK-NEXT:    ret i32 [[RVAL2]]
96;
97entry:
98  %wc1 = call i1 @llvm.experimental.widenable.condition()
99  br label %loop
100
101loop:
102  %iv = phi i32 [ %start, %entry ], [ %iv.next, %backedge ]
103  br i1 %wc1, label %guard_block, label %exit_by_wc
104
105exit_by_wc:
106  %rval1 = call i32(...) @llvm.experimental.deoptimize.i32() [ "deopt"(i32 %iv) ]
107  ret i32 %rval1
108
109guard_block:
110  %cond = icmp eq i32 %iv, %x
111  %wc2 = call i1 @llvm.experimental.widenable.condition()
112  %guard = and i1 %cond, %wc2
113  br i1 %guard, label %backedge, label %failure
114
115backedge:
116  call void @side_effect()
117  %iv.next = add i32 %iv, 1
118  br label %loop
119
120exit:
121  ret i32 -1
122
123failure:
124  %rval2 = call i32(...) @llvm.experimental.deoptimize.i32() [ "deopt"(i32 %iv) ]
125  ret i32 %rval2
126}
127
128; Same as test_01, but the initial condition is not immediately WC.
129define i32 @test_03(i32 %start, i32 %x, i1 %c) {
130; CHECK-LABEL: @test_03(
131; CHECK-NEXT:  entry:
132; CHECK-NEXT:    [[START_GW_FR:%.*]] = freeze i32 [[START:%.*]]
133; CHECK-NEXT:    [[X_GW_FR:%.*]] = freeze i32 [[X:%.*]]
134; CHECK-NEXT:    [[COND:%.*]] = icmp eq i32 [[START_GW_FR]], [[X_GW_FR]]
135; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[C:%.*]], [[COND]]
136; CHECK-NEXT:    [[WC1:%.*]] = call i1 @llvm.experimental.widenable.condition()
137; CHECK-NEXT:    br label [[LOOP:%.*]]
138; CHECK:       loop:
139; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ [[START_GW_FR]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
140; CHECK-NEXT:    [[INVARIANT:%.*]] = and i1 [[WIDE_CHK]], [[WC1]]
141; CHECK-NEXT:    br i1 [[INVARIANT]], label [[GUARD_BLOCK:%.*]], label [[EXIT_BY_WC:%.*]]
142; CHECK:       exit_by_wc:
143; CHECK-NEXT:    [[RVAL1:%.*]] = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"(i32 [[IV]]) ]
144; CHECK-NEXT:    ret i32 [[RVAL1]]
145; CHECK:       guard_block:
146; CHECK-NEXT:    [[WC2:%.*]] = call i1 @llvm.experimental.widenable.condition()
147; CHECK-NEXT:    [[GUARD:%.*]] = and i1 [[COND]], [[WC2]]
148; CHECK-NEXT:    br i1 true, label [[BACKEDGE]], label [[FAILURE:%.*]]
149; CHECK:       backedge:
150; CHECK-NEXT:    call void @side_effect()
151; CHECK-NEXT:    [[IV_NEXT]] = add i32 [[IV]], 1
152; CHECK-NEXT:    br label [[LOOP]]
153; CHECK:       exit:
154; CHECK-NEXT:    ret i32 -1
155; CHECK:       failure:
156; CHECK-NEXT:    [[RVAL2:%.*]] = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"(i32 [[IV]]) ]
157; CHECK-NEXT:    ret i32 [[RVAL2]]
158; CHECK:       early_failure:
159; CHECK-NEXT:    [[RVAL3:%.*]] = call i32 (...) @llvm.experimental.deoptimize.i32() [ "deopt"(i32 [[X_GW_FR]]) ]
160; CHECK-NEXT:    ret i32 [[RVAL3]]
161;
162entry:
163  %cond = icmp eq i32 %start, %x
164  %wc1 = call i1 @llvm.experimental.widenable.condition()
165  %invariant = and i1 %c, %wc1
166  br label %loop
167
168loop:
169  %iv = phi i32 [ %start, %entry ], [ %iv.next, %backedge ]
170  br i1 %invariant, label %guard_block, label %exit_by_wc
171
172exit_by_wc:
173  %rval1 = call i32(...) @llvm.experimental.deoptimize.i32() [ "deopt"(i32 %iv) ]
174  ret i32 %rval1
175
176guard_block:
177  %wc2 = call i1 @llvm.experimental.widenable.condition()
178  %guard = and i1 %cond, %wc2
179  br i1 %guard, label %backedge, label %failure
180
181backedge:
182  call void @side_effect()
183  %iv.next = add i32 %iv, 1
184  br label %loop
185
186exit:
187  ret i32 -1
188
189failure:
190  %rval2 = call i32(...) @llvm.experimental.deoptimize.i32() [ "deopt"(i32 %iv) ]
191  ret i32 %rval2
192
193early_failure:
194  %rval3 = call i32(...) @llvm.experimental.deoptimize.i32() [ "deopt"(i32 %x) ]
195  ret i32 %rval3
196}
197
198; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(inaccessiblemem: readwrite)
199declare i1 @llvm.experimental.widenable.condition()
200
201declare void @side_effect()
202