1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2 ; RUN: opt -S -passes=guard-widening < %s | FileCheck %s
3 ; RUN: opt -S -passes=guard-widening < %s | FileCheck %s
5 declare void @llvm.experimental.guard(i1,...)
7 ; Basic test case: we wide the first check to check both the
9 define void @f_0(i1 %cond_0, i1 %cond_1) {
12 ; CHECK-NEXT: [[COND_1_GW_FR:%.*]] = freeze i1 [[COND_1:%.*]]
13 ; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_1_GW_FR]]
14 ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]
15 ; CHECK-NEXT: ret void
19 call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ]
20 call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"() ]
24 ; Same as @f_0, but with using a more general notion of postdominance.
25 define void @f_1(i1 %cond_0, i1 %cond_1) {
28 ; CHECK-NEXT: [[COND_1_GW_FR:%.*]] = freeze i1 [[COND_1:%.*]]
29 ; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_1_GW_FR]]
30 ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]
31 ; CHECK-NEXT: br i1 undef, label [[LEFT:%.*]], label [[RIGHT:%.*]]
33 ; CHECK-NEXT: br label [[MERGE:%.*]]
35 ; CHECK-NEXT: br label [[MERGE]]
37 ; CHECK-NEXT: ret void
41 call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ]
42 br i1 undef, label %left, label %right
51 call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"() ]
55 ; Like @f_1, but we have some code we need to hoist before we can
56 ; widen a dominanting check.
57 define void @f_2(i32 %a, i32 %b) {
60 ; CHECK-NEXT: [[B_GW_FR:%.*]] = freeze i32 [[B:%.*]]
61 ; CHECK-NEXT: [[COND_0:%.*]] = icmp ult i32 [[A:%.*]], 10
62 ; CHECK-NEXT: [[COND_1:%.*]] = icmp ult i32 [[B_GW_FR]], 10
63 ; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0]], [[COND_1]]
64 ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]
65 ; CHECK-NEXT: br i1 undef, label [[LEFT:%.*]], label [[RIGHT:%.*]]
67 ; CHECK-NEXT: br label [[MERGE:%.*]]
69 ; CHECK-NEXT: br label [[MERGE]]
71 ; CHECK-NEXT: ret void
75 %cond_0 = icmp ult i32 %a, 10
76 call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ]
77 br i1 undef, label %left, label %right
86 %cond_1 = icmp ult i32 %b, 10
87 call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"() ]
91 ; Negative test: don't hoist stuff out of control flow
92 ; indiscriminately, since that can make us do more work than needed.
93 define void @f_3(i32 %a, i32 %b) {
96 ; CHECK-NEXT: [[COND_0:%.*]] = icmp ult i32 [[A:%.*]], 10
97 ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[COND_0]]) [ "deopt"() ]
98 ; CHECK-NEXT: br i1 undef, label [[LEFT:%.*]], label [[RIGHT:%.*]]
100 ; CHECK-NEXT: [[COND_1:%.*]] = icmp ult i32 [[B:%.*]], 10
101 ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[COND_1]]) [ "deopt"() ]
102 ; CHECK-NEXT: ret void
104 ; CHECK-NEXT: ret void
108 %cond_0 = icmp ult i32 %a, 10
109 call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ]
110 br i1 undef, label %left, label %right
114 %cond_1 = icmp ult i32 %b, 10
115 call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"() ]
122 ; But hoisting out of control flow is fine if it makes a loop computed
123 ; condition loop invariant. This behavior may require some tuning in
125 define void @f_4(i32 %a, i32 %b) {
128 ; CHECK-NEXT: [[B_GW_FR:%.*]] = freeze i32 [[B:%.*]]
129 ; CHECK-NEXT: [[COND_0:%.*]] = icmp ult i32 [[A:%.*]], 10
130 ; CHECK-NEXT: [[COND_1:%.*]] = icmp ult i32 [[B_GW_FR]], 10
131 ; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0]], [[COND_1]]
132 ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]
133 ; CHECK-NEXT: br i1 undef, label [[LOOP:%.*]], label [[LEAVE:%.*]]
135 ; CHECK-NEXT: br i1 undef, label [[LOOP]], label [[LEAVE]]
137 ; CHECK-NEXT: ret void
141 %cond_0 = icmp ult i32 %a, 10
142 call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ]
143 br i1 undef, label %loop, label %leave
146 %cond_1 = icmp ult i32 %b, 10
147 call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"() ]
148 br i1 undef, label %loop, label %leave
154 ; Hoisting out of control flow is also fine if we can widen the
155 ; dominating check without doing any extra work.
156 define void @f_5(i32 %a) {
159 ; CHECK-NEXT: [[COND_0:%.*]] = icmp ugt i32 [[A:%.*]], 7
160 ; CHECK-NEXT: [[WIDE_CHK:%.*]] = icmp uge i32 [[A]], 11
161 ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]
162 ; CHECK-NEXT: br i1 undef, label [[LEFT:%.*]], label [[RIGHT:%.*]]
164 ; CHECK-NEXT: [[COND_1:%.*]] = icmp ugt i32 [[A]], 10
165 ; CHECK-NEXT: ret void
167 ; CHECK-NEXT: ret void
171 %cond_0 = icmp ugt i32 %a, 7
172 call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ]
173 br i1 undef, label %left, label %right
176 %cond_1 = icmp ugt i32 %a, 10
177 call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"() ]
184 ; Negative test: the load from %a can be safely speculated to before
185 ; the first guard, but there is no guarantee that it will produce the
187 define void @f_6(ptr dereferenceable(32) %a, ptr %b, i1 %unknown) {
190 ; CHECK-NEXT: [[COND_0:%.*]] = load i1, ptr [[A:%.*]], align 1
191 ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[COND_0]]) [ "deopt"() ]
192 ; CHECK-NEXT: store i1 [[UNKNOWN:%.*]], ptr [[B:%.*]], align 1
193 ; CHECK-NEXT: [[COND_1:%.*]] = load i1, ptr [[A]], align 1
194 ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[COND_1]]) [ "deopt"() ]
195 ; CHECK-NEXT: ret void
198 %cond_0 = load i1, ptr %a
199 call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ]
200 store i1 %unknown, ptr %b
201 %cond_1 = load i1, ptr %a
202 call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"() ]
206 ; All else equal, we try to widen the earliest guard we can. This
207 ; heuristic can use some tuning.
208 define void @f_7(i32 %a, ptr %cond_buf) {
211 ; CHECK-NEXT: [[A_GW_FR:%.*]] = freeze i32 [[A:%.*]]
212 ; CHECK-NEXT: [[COND_1:%.*]] = load volatile i1, ptr [[COND_BUF:%.*]], align 1
213 ; CHECK-NEXT: [[COND_3:%.*]] = icmp ult i32 [[A_GW_FR]], 7
214 ; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_1]], [[COND_3]]
215 ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]
216 ; CHECK-NEXT: [[COND_2:%.*]] = load volatile i1, ptr [[COND_BUF]], align 1
217 ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[COND_2]]) [ "deopt"() ]
218 ; CHECK-NEXT: br i1 undef, label [[LEFT:%.*]], label [[RIGHT:%.*]]
220 ; CHECK-NEXT: br label [[LEFT]]
222 ; CHECK-NEXT: ret void
226 %cond_1 = load volatile i1, ptr %cond_buf
227 call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"() ]
228 %cond_2 = load volatile i1, ptr %cond_buf
229 call void(i1, ...) @llvm.experimental.guard(i1 %cond_2) [ "deopt"() ]
230 br i1 undef, label %left, label %right
233 %cond_3 = icmp ult i32 %a, 7
234 call void(i1, ...) @llvm.experimental.guard(i1 %cond_3) [ "deopt"() ]
241 ; In this case the earliest dominating guard is in a loop, and we
242 ; don't want to put extra work in there. This heuristic can use some
244 define void @f_8(i32 %a, i1 %cond_1, i1 %cond_2) {
247 ; CHECK-NEXT: [[A_GW_FR:%.*]] = freeze i32 [[A:%.*]]
248 ; CHECK-NEXT: br label [[LOOP:%.*]]
250 ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[COND_1:%.*]]) [ "deopt"() ]
251 ; CHECK-NEXT: br i1 undef, label [[LOOP]], label [[LEAVE:%.*]]
253 ; CHECK-NEXT: [[COND_3:%.*]] = icmp ult i32 [[A_GW_FR]], 7
254 ; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_2:%.*]], [[COND_3]]
255 ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]
256 ; CHECK-NEXT: br i1 undef, label [[LOOP2:%.*]], label [[LEAVE2:%.*]]
258 ; CHECK-NEXT: br label [[LOOP2]]
260 ; CHECK-NEXT: ret void
266 call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"() ]
267 br i1 undef, label %loop, label %leave
271 call void(i1, ...) @llvm.experimental.guard(i1 %cond_2) [ "deopt"() ]
272 br i1 undef, label %loop2, label %leave2
275 %cond_3 = icmp ult i32 %a, 7
276 call void(i1, ...) @llvm.experimental.guard(i1 %cond_3) [ "deopt"() ]
283 ; In cases like these where there isn't any "obviously profitable"
284 ; widening sites, we refuse to do anything.
285 define void @f_9(i32 %a, i1 %cond_0, i1 %cond_1) {
288 ; CHECK-NEXT: br label [[FIRST_LOOP:%.*]]
290 ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[COND_0:%.*]]) [ "deopt"() ]
291 ; CHECK-NEXT: br i1 undef, label [[FIRST_LOOP]], label [[SECOND_LOOP:%.*]]
292 ; CHECK: second_loop:
293 ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[COND_1:%.*]]) [ "deopt"() ]
294 ; CHECK-NEXT: br label [[SECOND_LOOP]]
301 call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ]
302 br i1 undef, label %first_loop, label %second_loop
306 call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"() ]
307 br label %second_loop
310 ; Same situation as in @f_9: no "obviously profitable" widening sites,
311 ; so we refuse to do anything.
312 define void @f_10(i32 %a, i1 %cond_0, i1 %cond_1) {
313 ; CHECK-LABEL: @f_10(
315 ; CHECK-NEXT: br label [[LOOP:%.*]]
317 ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[COND_0:%.*]]) [ "deopt"() ]
318 ; CHECK-NEXT: br i1 undef, label [[LOOP]], label [[NO_LOOP:%.*]]
320 ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[COND_1:%.*]]) [ "deopt"() ]
321 ; CHECK-NEXT: ret void
328 call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ]
329 br i1 undef, label %loop, label %no_loop
332 call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"() ]
336 ; With guards in loops, we're okay hoisting out the guard into the
338 define void @f_11(i32 %a, i1 %cond_0, i1 %cond_1) {
339 ; CHECK-LABEL: @f_11(
341 ; CHECK-NEXT: [[COND_1_GW_FR:%.*]] = freeze i1 [[COND_1:%.*]]
342 ; CHECK-NEXT: br label [[INNER:%.*]]
344 ; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_1_GW_FR]]
345 ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]
346 ; CHECK-NEXT: br i1 undef, label [[INNER]], label [[OUTER:%.*]]
348 ; CHECK-NEXT: br label [[INNER]]
355 call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ]
356 br i1 undef, label %inner, label %outer
359 call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"() ]
363 ; Checks that we are adequately guarded against exponential-time
364 ; behavior when hoisting code.
365 define void @f_12(i32 %a0) {
366 ; CHECK-LABEL: @f_12(
368 ; CHECK-NEXT: [[A0_GW_FR:%.*]] = freeze i32 [[A0:%.*]]
369 ; CHECK-NEXT: [[A1:%.*]] = mul i32 [[A0_GW_FR]], [[A0_GW_FR]]
370 ; CHECK-NEXT: [[A2:%.*]] = mul i32 [[A1]], [[A1]]
371 ; CHECK-NEXT: [[A3:%.*]] = mul i32 [[A2]], [[A2]]
372 ; CHECK-NEXT: [[A4:%.*]] = mul i32 [[A3]], [[A3]]
373 ; CHECK-NEXT: [[A5:%.*]] = mul i32 [[A4]], [[A4]]
374 ; CHECK-NEXT: [[A6:%.*]] = mul i32 [[A5]], [[A5]]
375 ; CHECK-NEXT: [[A7:%.*]] = mul i32 [[A6]], [[A6]]
376 ; CHECK-NEXT: [[A8:%.*]] = mul i32 [[A7]], [[A7]]
377 ; CHECK-NEXT: [[A9:%.*]] = mul i32 [[A8]], [[A8]]
378 ; CHECK-NEXT: [[A10:%.*]] = mul i32 [[A9]], [[A9]]
379 ; CHECK-NEXT: [[A11:%.*]] = mul i32 [[A10]], [[A10]]
380 ; CHECK-NEXT: [[A12:%.*]] = mul i32 [[A11]], [[A11]]
381 ; CHECK-NEXT: [[A13:%.*]] = mul i32 [[A12]], [[A12]]
382 ; CHECK-NEXT: [[A14:%.*]] = mul i32 [[A13]], [[A13]]
383 ; CHECK-NEXT: [[A15:%.*]] = mul i32 [[A14]], [[A14]]
384 ; CHECK-NEXT: [[A16:%.*]] = mul i32 [[A15]], [[A15]]
385 ; CHECK-NEXT: [[A17:%.*]] = mul i32 [[A16]], [[A16]]
386 ; CHECK-NEXT: [[A18:%.*]] = mul i32 [[A17]], [[A17]]
387 ; CHECK-NEXT: [[A19:%.*]] = mul i32 [[A18]], [[A18]]
388 ; CHECK-NEXT: [[A20:%.*]] = mul i32 [[A19]], [[A19]]
389 ; CHECK-NEXT: [[A21:%.*]] = mul i32 [[A20]], [[A20]]
390 ; CHECK-NEXT: [[A22:%.*]] = mul i32 [[A21]], [[A21]]
391 ; CHECK-NEXT: [[A23:%.*]] = mul i32 [[A22]], [[A22]]
392 ; CHECK-NEXT: [[A24:%.*]] = mul i32 [[A23]], [[A23]]
393 ; CHECK-NEXT: [[A25:%.*]] = mul i32 [[A24]], [[A24]]
394 ; CHECK-NEXT: [[A26:%.*]] = mul i32 [[A25]], [[A25]]
395 ; CHECK-NEXT: [[A27:%.*]] = mul i32 [[A26]], [[A26]]
396 ; CHECK-NEXT: [[A28:%.*]] = mul i32 [[A27]], [[A27]]
397 ; CHECK-NEXT: [[A29:%.*]] = mul i32 [[A28]], [[A28]]
398 ; CHECK-NEXT: [[A30:%.*]] = mul i32 [[A29]], [[A29]]
399 ; CHECK-NEXT: [[COND:%.*]] = trunc i32 [[A30]] to i1
400 ; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 true, [[COND]]
401 ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]
402 ; CHECK-NEXT: ret void
405 ; Eliding the earlier 29 multiplications for brevity
408 call void(i1, ...) @llvm.experimental.guard(i1 true) [ "deopt"() ]
409 %a1 = mul i32 %a0, %a0
410 %a2 = mul i32 %a1, %a1
411 %a3 = mul i32 %a2, %a2
412 %a4 = mul i32 %a3, %a3
413 %a5 = mul i32 %a4, %a4
414 %a6 = mul i32 %a5, %a5
415 %a7 = mul i32 %a6, %a6
416 %a8 = mul i32 %a7, %a7
417 %a9 = mul i32 %a8, %a8
418 %a10 = mul i32 %a9, %a9
419 %a11 = mul i32 %a10, %a10
420 %a12 = mul i32 %a11, %a11
421 %a13 = mul i32 %a12, %a12
422 %a14 = mul i32 %a13, %a13
423 %a15 = mul i32 %a14, %a14
424 %a16 = mul i32 %a15, %a15
425 %a17 = mul i32 %a16, %a16
426 %a18 = mul i32 %a17, %a17
427 %a19 = mul i32 %a18, %a18
428 %a20 = mul i32 %a19, %a19
429 %a21 = mul i32 %a20, %a20
430 %a22 = mul i32 %a21, %a21
431 %a23 = mul i32 %a22, %a22
432 %a24 = mul i32 %a23, %a23
433 %a25 = mul i32 %a24, %a24
434 %a26 = mul i32 %a25, %a25
435 %a27 = mul i32 %a26, %a26
436 %a28 = mul i32 %a27, %a27
437 %a29 = mul i32 %a28, %a28
438 %a30 = mul i32 %a29, %a29
439 %cond = trunc i32 %a30 to i1
440 call void(i1, ...) @llvm.experimental.guard(i1 %cond) [ "deopt"() ]
444 define void @f_13(i32 %a) {
445 ; CHECK-LABEL: @f_13(
447 ; CHECK-NEXT: [[COND_0:%.*]] = icmp ult i32 [[A:%.*]], 14
448 ; CHECK-NEXT: [[WIDE_CHK:%.*]] = icmp ult i32 [[A]], 10
449 ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]
450 ; CHECK-NEXT: br i1 undef, label [[LEFT:%.*]], label [[RIGHT:%.*]]
452 ; CHECK-NEXT: [[COND_1:%.*]] = icmp slt i32 [[A]], 10
453 ; CHECK-NEXT: ret void
455 ; CHECK-NEXT: ret void
459 %cond_0 = icmp ult i32 %a, 14
460 call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ]
461 br i1 undef, label %left, label %right
464 %cond_1 = icmp slt i32 %a, 10
465 call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"() ]
472 define void @f_14(i32 %a) {
473 ; CHECK-LABEL: @f_14(
475 ; CHECK-NEXT: [[COND_0:%.*]] = icmp ult i32 [[A:%.*]], 14
476 ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[COND_0]]) [ "deopt"() ]
477 ; CHECK-NEXT: br i1 undef, label [[LEFT:%.*]], label [[RIGHT:%.*]]
479 ; CHECK-NEXT: [[COND_1:%.*]] = icmp sgt i32 [[A]], 10
480 ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[COND_1]]) [ "deopt"() ]
481 ; CHECK-NEXT: ret void
483 ; CHECK-NEXT: ret void
487 %cond_0 = icmp ult i32 %a, 14
488 call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ]
489 br i1 undef, label %left, label %right
493 %cond_1 = icmp sgt i32 %a, 10
494 call void(i1, ...) @llvm.experimental.guard(i1 %cond_1) [ "deopt"() ]
501 ; Make sure we do not widen guard by trivial true conditions into something.
502 define void @f_15(i1 %cond_0, i1 %cond_1) {
503 ; CHECK-LABEL: @f_15(
505 ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[COND_0:%.*]]) [ "deopt"() ]
506 ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 true) [ "deopt"() ]
507 ; CHECK-NEXT: ret void
511 call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ]
512 call void(i1, ...) @llvm.experimental.guard(i1 true) [ "deopt"() ]
516 ; Make sure we do not widen guard by trivial false conditions into something.
517 define void @f_16(i1 %cond_0, i1 %cond_1) {
518 ; CHECK-LABEL: @f_16(
520 ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[COND_0:%.*]]) [ "deopt"() ]
521 ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 false) [ "deopt"() ]
522 ; CHECK-NEXT: ret void
526 call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ]
527 call void(i1, ...) @llvm.experimental.guard(i1 false) [ "deopt"() ]