1 ; RUN: opt < %s -jump-threading -dce -S | FileCheck %s
3 declare void @llvm.experimental.guard(i1, ...)
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
15 ; CHECK: %v1 = call i32 @f1()
17 ; CHECK-NEXT: br label %Merge
23 ; CHECK: %v2 = call i32 @f2()
25 ; CHECK-NEXT: %condGuard
26 ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 %condGuard
27 ; CHECK-NEXT: br label %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"() ]
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
48 ; CHECK-NEXT: %v1 = call i32 @f1()
50 ; CHECK-NEXT: %condGuard
51 ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 %condGuard
52 ; CHECK-NEXT: br label %Merge
58 ; CHECK-NEXT: %v2 = call i32 @f2()
60 ; CHECK-NEXT: br label %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"() ]
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
81 ; CHECK-NEXT: %v1 = call i32 @f1()
82 ; CHECK-NEXT: br label %Merge
88 ; CHECK-NEXT: %v2 = call i32 @f2()
89 ; CHECK-NEXT: br label %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"() ]
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
111 ; CHECK-NEXT: %v1 = call i32 @f1()
112 ; CHECK-NEXT: br label %Merge
118 ; CHECK-NEXT: %v2 = call i32 @f2()
119 ; CHECK-NEXT: br label %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"() ]
134 define i32 @not_a_diamond1(i32 %a, i1 %cond1) {
135 ; CHECK-LABEL: @not_a_diamond1(
136 br i1 %cond1, label %Pred, label %Exit
140 ; CHECK-NEXT: switch i32 %a, label %Exit
141 switch i32 %a, label %Exit [
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"() ]
155 ; CHECK-NEXT: ret i32 %a
159 define void @not_a_diamond2(i32 %a, i1 %cond1) {
160 ; CHECK-LABEL: @not_a_diamond2(
164 call void(i1, ...) @llvm.experimental.guard(i1 %cond1)[ "deopt"() ]
169 ; CHECK-NEXT: switch i32 %a, label %Exit
170 switch i32 %a, label %Exit [
180 ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 %cond1) [ "deopt"() ]
181 ; CHECK-NEXT: ret void
185 declare void @never_called(i1)
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
202 call void @never_called(i1 %c2)
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
227 call void @never_called(i1 %c2)
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
244 call void @never_called(i1 %cmp)
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
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
263 br i1 %cmp1, label %L0, label %L3
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 [
276 call void @f(i1 %cmp)
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) {
285 ; CHECK-LABEL: @unsafe_pre_across_guard(
286 ; CHECK-NOT: loaded.pr
288 ; CHECK-NEXT: br label %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
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
303 exit: ; preds = %loop
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) {
310 ; CHECK-LABEL: @safe_pre_across_guard(
312 ; CHECK-NEXT: %loaded.pr = load i8, i8* %p
313 ; CHECK-NEXT: br label %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
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
329 exit: ; preds = %loop
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) {
337 ; CHECK-LABEL: @unsafe_pre_across_call(
338 ; CHECK-NOT: loaded.pr
340 ; CHECK-NEXT: br label %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
349 loop: ; preds = %loop, %entry
351 %loaded = load i8, i8* %p
352 %continue = icmp eq i8 %loaded, 0
353 br i1 %continue, label %exit, label %loop
355 exit: ; preds = %loop
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) {
362 ; CHECK-LABEL: @safe_pre_across_call(
364 ; CHECK-NEXT: %loaded.pr = load i8, i8* %p
365 ; CHECK-NEXT: br label %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
375 loop: ; preds = %loop, %entry
377 %loaded = load i8, i8* %p
378 %continue = icmp eq i8 %loaded, 0
379 br i1 %continue, label %exit, label %loop
381 exit: ; preds = %loop