blob: c760283f9e5271da951e781fb787ae5cb297a4eb [file] [log] [blame]
Sanjoy Das8b859c22017-02-17 04:21:14 +00001; RUN: opt < %s -jump-threading -dce -S | FileCheck %s
2
3declare void @llvm.experimental.guard(i1, ...)
4
5declare i32 @f1()
6declare i32 @f2()
7
8define 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
13T1:
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
21F1:
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
31Merge:
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
41define 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
46T1:
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
56F1:
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
64Merge:
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
74define 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
79T1:
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
86F1:
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
93Merge:
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
104define 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
109T1:
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
116F1:
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
123Merge:
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
134define i32 @not_a_diamond1(i32 %a, i1 %cond1) {
135; CHECK-LABEL: @not_a_diamond1(
136 br i1 %cond1, label %Pred, label %Exit
137
138Pred:
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
146Merge:
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
153Exit:
154; CHECK: Exit:
155; CHECK-NEXT: ret i32 %a
156 ret i32 %a
157}
158
159define void @not_a_diamond2(i32 %a, i1 %cond1) {
160; CHECK-LABEL: @not_a_diamond2(
161 br label %Parent
162
163Merge:
164 call void(i1, ...) @llvm.experimental.guard(i1 %cond1)[ "deopt"() ]
165 ret void
166
167Pred:
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
175Parent:
176 br label %Pred
177
178Exit:
179; CHECK: Merge:
180; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 %cond1) [ "deopt"() ]
181; CHECK-NEXT: ret void
182 ret void
183}
Anna Thomas7bca5912017-05-18 13:12:18 +0000184
Anna Thomasc07d5542017-05-23 13:36:25 +0000185declare void @never_called(i1)
Anna Thomas7bca5912017-05-18 13:12:18 +0000186
Anna Thomasc07d5542017-05-23 13:36:25 +0000187; LVI uses guard to identify value of %c2 in branch as true, we cannot replace that
188; guard with guard(true & c1).
Anna Thomas7bca5912017-05-18 13:12:18 +0000189define void @dont_fold_guard(i8* %addr, i32 %i, i32 %length) {
190; CHECK-LABEL: dont_fold_guard
Anna Thomasc07d5542017-05-23 13:36:25 +0000191; 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
Anna Thomas7bca5912017-05-18 13:12:18 +0000195 %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"() ]
Anna Thomasc07d5542017-05-23 13:36:25 +0000199 br i1 %c2, label %BB1, label %BB2
Anna Thomas7bca5912017-05-18 13:12:18 +0000200
Anna Thomasc07d5542017-05-23 13:36:25 +0000201BB1:
202 call void @never_called(i1 %c2)
Anna Thomas7bca5912017-05-18 13:12:18 +0000203 ret void
204
Anna Thomasc07d5542017-05-23 13:36:25 +0000205BB2:
Anna Thomas7bca5912017-05-18 13:12:18 +0000206 ret void
207}
208
Anna Thomasc07d5542017-05-23 13:36:25 +0000209declare 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.
212define 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
226BB1:
227 call void @never_called(i1 %c2)
228 ret void
229
230BB2:
231 ret void
232}
Anna Thomas7bca5912017-05-18 13:12:18 +0000233
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.
Anna Thomasc07d5542017-05-23 13:36:25 +0000237define void @dont_fold_guard3(i8* %addr, i1 %cmp, i32 %i, i32 %length) {
238; CHECK-LABEL: dont_fold_guard3
Anna Thomas7bca5912017-05-18 13:12:18 +0000239; CHECK: guard(i1 %cmp)
Anna Thomas7bca5912017-05-18 13:12:18 +0000240 call void(i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ]
Anna Thomasc07d5542017-05-23 13:36:25 +0000241 br i1 %cmp, label %BB1, label %BB2
Anna Thomas7bca5912017-05-18 13:12:18 +0000242
Anna Thomasc07d5542017-05-23 13:36:25 +0000243BB1:
244 call void @never_called(i1 %cmp)
Anna Thomas7bca5912017-05-18 13:12:18 +0000245 ret void
246
Anna Thomasc07d5542017-05-23 13:36:25 +0000247BB2:
Anna Thomas7bca5912017-05-18 13:12:18 +0000248 ret void
249}
250
Anna Thomasc07d5542017-05-23 13:36:25 +0000251declare void @f(i1)
Anna Thomas7bca5912017-05-18 13:12:18 +0000252; Same as dont_fold_guard1 but use switch instead of branch.
253; triggers source code `ProcessThreadableEdges`.
Anna Thomasc07d5542017-05-23 13:36:25 +0000254define void @dont_fold_guard4(i1 %cmp1, i32 %i) nounwind {
255; CHECK-LABEL: dont_fold_guard4
Anna Thomas7bca5912017-05-18 13:12:18 +0000256; CHECK-LABEL: L2:
257; CHECK-NEXT: %cmp = icmp eq i32 %i, 0
258; CHECK-NEXT: guard(i1 %cmp)
Anna Thomasc07d5542017-05-23 13:36:25 +0000259; CHECK-NEXT: dummy(i1 true)
260; CHECK-NEXT: @f(i1 true)
Anna Thomas7bca5912017-05-18 13:12:18 +0000261; CHECK-NEXT: ret void
262entry:
263 br i1 %cmp1, label %L0, label %L3
264L0:
265 %cmp = icmp eq i32 %i, 0
266 call void(i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ]
Anna Thomasc07d5542017-05-23 13:36:25 +0000267 call void @dummy(i1 %cmp)
Anna Thomas7bca5912017-05-18 13:12:18 +0000268 switch i1 %cmp, label %L3 [
269 i1 false, label %L1
270 i1 true, label %L2
271 ]
272
273L1:
274 ret void
275L2:
276 call void @f(i1 %cmp)
277 ret void
278L3:
279 ret void
280}
Max Kazantsevfd95ee02017-12-19 09:10:21 +0000281
282; Make sure that we don't PRE a non-speculable load across a guard.
283define 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
294entry:
295 br label %loop
296
297loop: ; 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
303exit: ; preds = %loop
304 ret void
305}
306
307; Make sure that we can safely PRE a speculable load across a guard.
308define 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
320entry:
321 br label %loop
322
323loop: ; 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
329exit: ; 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.
335define 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
346entry:
347 br label %loop
348
349loop: ; 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
355exit: ; preds = %loop
356 ret void
357}
358
359; Make sure that we can safely PRE a speculable load across a call.
360define 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
372entry:
373 br label %loop
374
375loop: ; 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
381exit: ; preds = %loop
382 ret void
383}