]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - test/Transforms/JumpThreading/guards.ll
Vendor import of llvm trunk r321414:
[FreeBSD/FreeBSD.git] / test / Transforms / JumpThreading / guards.ll
1 ; RUN: opt < %s -jump-threading -dce -S | FileCheck %s
2
3 declare void @llvm.experimental.guard(i1, ...)
4
5 declare i32 @f1()
6 declare i32 @f2()
7
8 define i32 @branch_implies_guard(i32 %a) {
9 ; CHECK-LABEL: @branch_implies_guard(
10   %cond = icmp slt i32 %a, 10
11   br i1 %cond, label %T1, label %F1
12
13 T1:
14 ; CHECK:       T1.split
15 ; CHECK:         %v1 = call i32 @f1()
16 ; CHECK-NEXT:    %retVal
17 ; CHECK-NEXT:    br label %Merge
18   %v1 = call i32 @f1()
19   br label %Merge
20
21 F1:
22 ; CHECK:       F1.split
23 ; CHECK:         %v2 = call i32 @f2()
24 ; CHECK-NEXT:    %retVal
25 ; CHECK-NEXT:    %condGuard
26 ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 %condGuard
27 ; CHECK-NEXT:    br label %Merge
28   %v2 = call i32 @f2()
29   br label %Merge
30
31 Merge:
32 ; CHECK:       Merge
33 ; CHECK-NOT:     call void(i1, ...) @llvm.experimental.guard(
34   %retPhi = phi i32 [ %v1, %T1 ], [ %v2, %F1 ]
35   %retVal = add i32 %retPhi, 10
36   %condGuard = icmp slt i32 %a, 20
37   call void(i1, ...) @llvm.experimental.guard(i1 %condGuard) [ "deopt"() ]
38   ret i32 %retVal
39 }
40
41 define i32 @not_branch_implies_guard(i32 %a) {
42 ; CHECK-LABEL: @not_branch_implies_guard(
43   %cond = icmp slt i32 %a, 20
44   br i1 %cond, label %T1, label %F1
45
46 T1:
47 ; CHECK:       T1.split:
48 ; CHECK-NEXT:    %v1 = call i32 @f1()
49 ; CHECK-NEXT:    %retVal
50 ; CHECK-NEXT:    %condGuard
51 ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 %condGuard
52 ; CHECK-NEXT:    br label %Merge
53   %v1 = call i32 @f1()
54   br label %Merge
55
56 F1:
57 ; CHECK:       F1.split:
58 ; CHECK-NEXT:   %v2 = call i32 @f2()
59 ; CHECK-NEXT:   %retVal
60 ; CHECK-NEXT:   br label %Merge
61   %v2 = call i32 @f2()
62   br label %Merge
63
64 Merge:
65 ; CHECK:       Merge
66 ; CHECK-NOT:     call void(i1, ...) @llvm.experimental.guard(
67   %retPhi = phi i32 [ %v1, %T1 ], [ %v2, %F1 ]
68   %retVal = add i32 %retPhi, 10
69   %condGuard = icmp sgt i32 %a, 10
70   call void(i1, ...) @llvm.experimental.guard(i1 %condGuard) [ "deopt"() ]
71   ret i32 %retVal
72 }
73
74 define i32 @branch_overlaps_guard(i32 %a) {
75 ; CHECK-LABEL: @branch_overlaps_guard(
76   %cond = icmp slt i32 %a, 20
77   br i1 %cond, label %T1, label %F1
78
79 T1:
80 ; CHECK:        T1:
81 ; CHECK-NEXT:      %v1 = call i32 @f1()
82 ; CHECK-NEXT:      br label %Merge
83   %v1 = call i32 @f1()
84   br label %Merge
85
86 F1:
87 ; CHECK:        F1:
88 ; CHECK-NEXT:     %v2 = call i32 @f2()
89 ; CHECK-NEXT:     br label %Merge
90   %v2 = call i32 @f2()
91   br label %Merge
92
93 Merge:
94 ; CHECK:       Merge
95 ; CHECK:         %condGuard = icmp slt i32 %a, 10
96 ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 %condGuard) [ "deopt"() ]
97   %retPhi = phi i32 [ %v1, %T1 ], [ %v2, %F1 ]
98   %retVal = add i32 %retPhi, 10
99   %condGuard = icmp slt i32 %a, 10
100   call void(i1, ...) @llvm.experimental.guard(i1 %condGuard) [ "deopt"() ]
101   ret i32 %retVal
102 }
103
104 define i32 @branch_doesnt_overlap_guard(i32 %a) {
105 ; CHECK-LABEL: @branch_doesnt_overlap_guard(
106   %cond = icmp slt i32 %a, 10
107   br i1 %cond, label %T1, label %F1
108
109 T1:
110 ; CHECK:        T1:
111 ; CHECK-NEXT:      %v1 = call i32 @f1()
112 ; CHECK-NEXT:      br label %Merge
113   %v1 = call i32 @f1()
114   br label %Merge
115
116 F1:
117 ; CHECK:        F1:
118 ; CHECK-NEXT:     %v2 = call i32 @f2()
119 ; CHECK-NEXT:     br label %Merge
120   %v2 = call i32 @f2()
121   br label %Merge
122
123 Merge:
124 ; CHECK:       Merge
125 ; CHECK:         %condGuard = icmp sgt i32 %a, 20
126 ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 %condGuard) [ "deopt"() ]
127   %retPhi = phi i32 [ %v1, %T1 ], [ %v2, %F1 ]
128   %retVal = add i32 %retPhi, 10
129   %condGuard = icmp sgt i32 %a, 20
130   call void(i1, ...) @llvm.experimental.guard(i1 %condGuard) [ "deopt"() ]
131   ret i32 %retVal
132 }
133
134 define i32 @not_a_diamond1(i32 %a, i1 %cond1) {
135 ; CHECK-LABEL: @not_a_diamond1(
136   br i1 %cond1, label %Pred, label %Exit
137
138 Pred:
139 ; CHECK:       Pred:
140 ; CHECK-NEXT:    switch i32 %a, label %Exit
141   switch i32 %a, label %Exit [
142     i32 10, label %Merge
143     i32 20, label %Merge
144   ]
145
146 Merge:
147 ; CHECK:       Merge:
148 ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 %cond1) [ "deopt"() ]
149 ; CHECK-NEXT:    br label %Exit
150   call void(i1, ...) @llvm.experimental.guard(i1 %cond1) [ "deopt"() ]
151   br label %Exit
152
153 Exit:
154 ; CHECK:       Exit:
155 ; CHECK-NEXT:    ret i32 %a
156   ret i32 %a
157 }
158
159 define void @not_a_diamond2(i32 %a, i1 %cond1) {
160 ; CHECK-LABEL: @not_a_diamond2(
161   br label %Parent
162
163 Merge:
164   call void(i1, ...) @llvm.experimental.guard(i1 %cond1)[ "deopt"() ]
165   ret void
166
167 Pred:
168 ; CHECK-NEXT:  Pred:
169 ; CHECK-NEXT:    switch i32 %a, label %Exit
170   switch i32 %a, label %Exit [
171     i32 10, label %Merge
172     i32 20, label %Merge
173   ]
174
175 Parent:
176   br label %Pred
177
178 Exit:
179 ; CHECK:       Merge:
180 ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 %cond1) [ "deopt"() ]
181 ; CHECK-NEXT:    ret void
182   ret void
183 }
184
185 declare void @never_called(i1)
186
187 ; LVI uses guard to identify value of %c2 in branch as true, we cannot replace that
188 ; guard with guard(true & c1).
189 define void @dont_fold_guard(i8* %addr, i32 %i, i32 %length) {
190 ; CHECK-LABEL: dont_fold_guard
191 ; CHECK: %wide.chk = and i1 %c1, %c2
192 ; CHECK-NEXT: experimental.guard(i1 %wide.chk)
193 ; CHECK-NEXT: call void @never_called(i1 true)
194 ; CHECK-NEXT: ret void
195   %c1 = icmp ult i32 %i, %length
196   %c2 = icmp eq i32 %i, 0
197   %wide.chk = and i1 %c1, %c2
198   call void(i1, ...) @llvm.experimental.guard(i1 %wide.chk) [ "deopt"() ]
199   br i1 %c2, label %BB1, label %BB2
200
201 BB1:
202   call void @never_called(i1 %c2)
203   ret void
204
205 BB2:
206   ret void
207 }
208
209 declare void @dummy(i1) nounwind argmemonly
210 ; same as dont_fold_guard1 but there's a use immediately after guard and before
211 ; branch. We can fold that use.
212 define void @dont_fold_guard2(i8* %addr, i32 %i, i32 %length) {
213 ; CHECK-LABEL: dont_fold_guard2
214 ; CHECK: %wide.chk = and i1 %c1, %c2
215 ; CHECK-NEXT: experimental.guard(i1 %wide.chk)
216 ; CHECK-NEXT: dummy(i1 true)
217 ; CHECK-NEXT: call void @never_called(i1 true)
218 ; CHECK-NEXT: ret void
219   %c1 = icmp ult i32 %i, %length
220   %c2 = icmp eq i32 %i, 0
221   %wide.chk = and i1 %c1, %c2
222   call void(i1, ...) @llvm.experimental.guard(i1 %wide.chk) [ "deopt"() ]
223   call void @dummy(i1 %c2)
224   br i1 %c2, label %BB1, label %BB2
225
226 BB1:
227   call void @never_called(i1 %c2)
228   ret void
229
230 BB2:
231   ret void
232 }
233
234 ; same as dont_fold_guard1 but condition %cmp is not an instruction.
235 ; We cannot fold the guard under any circumstance.
236 ; FIXME: We can merge unreachableBB2 into not_zero.
237 define void @dont_fold_guard3(i8* %addr, i1 %cmp, i32 %i, i32 %length) {
238 ; CHECK-LABEL: dont_fold_guard3
239 ; CHECK: guard(i1 %cmp)
240   call void(i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ]
241   br i1 %cmp, label %BB1, label %BB2
242
243 BB1:
244   call void @never_called(i1 %cmp)
245   ret void
246
247 BB2:
248   ret void
249 }
250
251 declare void @f(i1)
252 ; Same as dont_fold_guard1 but use switch instead of branch.
253 ; triggers source code `ProcessThreadableEdges`.
254 define void @dont_fold_guard4(i1 %cmp1, i32 %i) nounwind {
255 ; CHECK-LABEL: dont_fold_guard4 
256 ; CHECK-LABEL: L2:
257 ; CHECK-NEXT: %cmp = icmp eq i32 %i, 0 
258 ; CHECK-NEXT: guard(i1 %cmp)
259 ; CHECK-NEXT: dummy(i1 true)
260 ; CHECK-NEXT: @f(i1 true)
261 ; CHECK-NEXT: ret void
262 entry:
263   br i1 %cmp1, label %L0, label %L3 
264 L0:
265   %cmp = icmp eq i32 %i, 0
266   call void(i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ]
267   call void @dummy(i1 %cmp)
268   switch i1 %cmp, label %L3 [
269     i1 false, label %L1
270     i1 true, label %L2
271     ]
272
273 L1:
274   ret void
275 L2:
276   call void @f(i1 %cmp)
277   ret void
278 L3:
279   ret void
280 }
281
282 ; Make sure that we don't PRE a non-speculable load across a guard.
283 define void @unsafe_pre_across_guard(i8* %p, i1 %load.is.valid) {
284
285 ; CHECK-LABEL: @unsafe_pre_across_guard(
286 ; CHECK-NOT:   loaded.pr
287 ; CHECK:       entry:
288 ; CHECK-NEXT:    br label %loop
289 ; CHECK:       loop:
290 ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 %load.is.valid) [ "deopt"() ]
291 ; CHECK-NEXT:    %loaded = load i8, i8* %p
292 ; CHECK-NEXT:    %continue = icmp eq i8 %loaded, 0
293 ; CHECK-NEXT:    br i1 %continue, label %exit, label %loop
294 entry:
295   br label %loop
296
297 loop:                                             ; preds = %loop, %entry
298   call void (i1, ...) @llvm.experimental.guard(i1 %load.is.valid) [ "deopt"() ]
299   %loaded = load i8, i8* %p
300   %continue = icmp eq i8 %loaded, 0
301   br i1 %continue, label %exit, label %loop
302
303 exit:                                             ; preds = %loop
304   ret void
305 }
306
307 ; Make sure that we can safely PRE a speculable load across a guard.
308 define void @safe_pre_across_guard(i8* noalias nocapture readonly dereferenceable(8) %p, i1 %load.is.valid) {
309
310 ; CHECK-LABEL: @safe_pre_across_guard(
311 ; CHECK:       entry:
312 ; CHECK-NEXT:    %loaded.pr = load i8, i8* %p
313 ; CHECK-NEXT:    br label %loop
314 ; CHECK:       loop:
315 ; CHECK-NEXT:    %loaded = phi i8 [ %loaded, %loop ], [ %loaded.pr, %entry ]
316 ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 %load.is.valid) [ "deopt"() ]
317 ; CHECK-NEXT:    %continue = icmp eq i8 %loaded, 0
318 ; CHECK-NEXT:    br i1 %continue, label %exit, label %loop
319
320 entry:
321   br label %loop
322
323 loop:                                             ; preds = %loop, %entry
324   call void (i1, ...) @llvm.experimental.guard(i1 %load.is.valid) [ "deopt"() ]
325   %loaded = load i8, i8* %p
326   %continue = icmp eq i8 %loaded, 0
327   br i1 %continue, label %exit, label %loop
328
329 exit:                                             ; preds = %loop
330   ret void
331 }
332
333 ; Make sure that we don't PRE a non-speculable load across a call which may
334 ; alias with the load.
335 define void @unsafe_pre_across_call(i8* %p) {
336
337 ; CHECK-LABEL: @unsafe_pre_across_call(
338 ; CHECK-NOT:   loaded.pr
339 ; CHECK:       entry:
340 ; CHECK-NEXT:    br label %loop
341 ; CHECK:       loop:
342 ; CHECK-NEXT:    call i32 @f1()
343 ; CHECK-NEXT:    %loaded = load i8, i8* %p
344 ; CHECK-NEXT:    %continue = icmp eq i8 %loaded, 0
345 ; CHECK-NEXT:    br i1 %continue, label %exit, label %loop
346 entry:
347   br label %loop
348
349 loop:                                             ; preds = %loop, %entry
350   call i32 @f1()
351   %loaded = load i8, i8* %p
352   %continue = icmp eq i8 %loaded, 0
353   br i1 %continue, label %exit, label %loop
354
355 exit:                                             ; preds = %loop
356   ret void
357 }
358
359 ; Make sure that we can safely PRE a speculable load across a call.
360 define void @safe_pre_across_call(i8* noalias nocapture readonly dereferenceable(8) %p) {
361
362 ; CHECK-LABEL: @safe_pre_across_call(
363 ; CHECK:       entry:
364 ; CHECK-NEXT:    %loaded.pr = load i8, i8* %p
365 ; CHECK-NEXT:    br label %loop
366 ; CHECK:       loop:
367 ; CHECK-NEXT:    %loaded = phi i8 [ %loaded, %loop ], [ %loaded.pr, %entry ]
368 ; CHECK-NEXT:    call i32 @f1()
369 ; CHECK-NEXT:    %continue = icmp eq i8 %loaded, 0
370 ; CHECK-NEXT:    br i1 %continue, label %exit, label %loop
371
372 entry:
373   br label %loop
374
375 loop:                                             ; preds = %loop, %entry
376   call i32 @f1()
377   %loaded = load i8, i8* %p
378   %continue = icmp eq i8 %loaded, 0
379   br i1 %continue, label %exit, label %loop
380
381 exit:                                             ; preds = %loop
382   ret void
383 }