xref: /llvm-project/llvm/test/Transforms/InstCombine/freeze.ll (revision 9efb07f261b2cd673c0a5abf2ed2546ad288ab48)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals
2; RUN: opt < %s -passes=instcombine -S | FileCheck %s
3
4define i32 @fold(i32 %x) {
5; CHECK-LABEL: @fold(
6; CHECK-NEXT:    [[Y:%.*]] = freeze i32 [[X:%.*]]
7; CHECK-NEXT:    ret i32 [[Y]]
8;
9  %y = freeze i32 %x
10  %z = freeze i32 %y
11  ret i32 %z
12}
13
14define i32 @make_const() {
15; CHECK-LABEL: @make_const(
16; CHECK-NEXT:    ret i32 10
17;
18  %x = freeze i32 10
19  ret i32 %x
20}
21
22define i32 @and_freeze_undef(i32 %x) {
23; CHECK-LABEL: @and_freeze_undef(
24; CHECK-NEXT:    ret i32 0
25;
26  %f = freeze i32 undef
27  %res = and i32 %x, %f
28  ret i32 %res
29}
30
31declare void @use_i32(i32)
32declare void @use_p32(ptr)
33
34define i32 @and_freeze_undef_multipleuses(i32 %x) {
35; CHECK-LABEL: @and_freeze_undef_multipleuses(
36; CHECK-NEXT:    call void @use_i32(i32 0)
37; CHECK-NEXT:    ret i32 0
38;
39  %f = freeze i32 undef
40  %res = and i32 %x, %f
41  call void @use_i32(i32 %f)
42  ret i32 %res
43}
44
45define i32 @or_freeze_undef(i32 %x) {
46; CHECK-LABEL: @or_freeze_undef(
47; CHECK-NEXT:    ret i32 -1
48;
49  %f = freeze i32 undef
50  %res = or i32 %x, %f
51  ret i32 %res
52}
53
54define i32 @or_freeze_undef_multipleuses(i32 %x) {
55; CHECK-LABEL: @or_freeze_undef_multipleuses(
56; CHECK-NEXT:    call void @use_i32(i32 0)
57; CHECK-NEXT:    ret i32 [[X:%.*]]
58;
59  %f = freeze i32 undef
60  %res = or i32 %x, %f
61  call void @use_i32(i32 %f)
62  ret i32 %res
63}
64
65declare void @use_i32_i1(i32, i1)
66
67define void @or_select_multipleuses(i32 %x, i1 %y) {
68; CHECK-LABEL: @or_select_multipleuses(
69; CHECK-NEXT:    call void @use_i32_i1(i32 32, i1 [[Y:%.*]])
70; CHECK-NEXT:    ret void
71;
72  %f = freeze i1 undef
73  %a = select i1 %f, i32 %x, i32 32 ; prefers %f to be false
74  %b = or i1 %f, %y ; prefers %f to be true
75  call void @use_i32_i1(i32 %a, i1 %b)
76  ret void
77}
78
79define void @or_select_multipleuses_logical(i32 %x, i1 %y) {
80; CHECK-LABEL: @or_select_multipleuses_logical(
81; CHECK-NEXT:    call void @use_i32_i1(i32 32, i1 [[Y:%.*]])
82; CHECK-NEXT:    ret void
83;
84  %f = freeze i1 undef
85  %a = select i1 %f, i32 %x, i32 32 ; prefers %f to be false
86  %b = select i1 %f, i1 true, i1 %y ; prefers %f to be true
87  call void @use_i32_i1(i32 %a, i1 %b)
88  ret void
89}
90
91define <3 x i4> @partial_undef_vec() {
92; CHECK-LABEL: @partial_undef_vec(
93; CHECK-NEXT:    ret <3 x i4> <i4 0, i4 1, i4 0>
94;
95  %f = freeze <3 x i4> <i4 poison, i4 1, i4 undef>
96  ret <3 x i4> %f
97}
98
99; Move the freeze forward to prevent poison from spreading.
100
101define i32 @early_freeze_test1(i32 %x, i32 %y) {
102; CHECK-LABEL: @early_freeze_test1(
103; CHECK-NEXT:    [[V1:%.*]] = add i32 [[X:%.*]], [[Y:%.*]]
104; CHECK-NEXT:    [[V1_FR:%.*]] = freeze i32 [[V1]]
105; CHECK-NEXT:    [[V2:%.*]] = shl i32 [[V1_FR]], 1
106; CHECK-NEXT:    [[V3:%.*]] = and i32 [[V2]], 2
107; CHECK-NEXT:    ret i32 [[V3]]
108;
109  %v1 = add i32 %x, %y
110  %v2 = shl i32 %v1, 1
111  %v3 = and i32 %v2, 2
112  %v3.fr = freeze i32 %v3
113  ret i32 %v3.fr
114}
115
116define i1 @early_freeze_test2(ptr %ptr) {
117; CHECK-LABEL: @early_freeze_test2(
118; CHECK-NEXT:    [[V1:%.*]] = load i32, ptr [[PTR:%.*]], align 4
119; CHECK-NEXT:    [[V1_FR:%.*]] = freeze i32 [[V1]]
120; CHECK-NEXT:    [[V2:%.*]] = and i32 [[V1_FR]], 1
121; CHECK-NEXT:    [[COND:%.*]] = icmp eq i32 [[V2]], 0
122; CHECK-NEXT:    ret i1 [[COND]]
123;
124  %v1 = load i32, ptr %ptr
125  %v2 = and i32 %v1, 1
126  %cond = icmp eq i32 %v2, 0
127  %cond.fr = freeze i1 %cond
128  ret i1 %cond.fr
129}
130
131define i32 @early_freeze_test3(i32 %v1) {
132; CHECK-LABEL: @early_freeze_test3(
133; CHECK-NEXT:    [[V1_FR:%.*]] = freeze i32 [[V1:%.*]]
134; CHECK-NEXT:    [[V2:%.*]] = shl i32 [[V1_FR]], 1
135; CHECK-NEXT:    [[V4:%.*]] = add i32 [[V2]], 3
136; CHECK-NEXT:    ret i32 [[V4]]
137;
138  %v2 = shl i32 %v1, 1
139  %v3 = add nuw i32 %v2, 2
140  %v4 = or i32 %v3, 1
141  %v4.fr = freeze i32 %v4
142  ret i32 %v4.fr
143}
144
145; If replace all dominated uses of v to freeze(v).
146
147define void @freeze_dominated_uses_test1(i32 %v) {
148; CHECK-LABEL: @freeze_dominated_uses_test1(
149; CHECK-NEXT:    [[V_FR:%.*]] = freeze i32 [[V:%.*]]
150; CHECK-NEXT:    call void @use_i32(i32 [[V_FR]])
151; CHECK-NEXT:    call void @use_i32(i32 [[V_FR]])
152; CHECK-NEXT:    ret void
153;
154  %v.fr = freeze i32 %v
155  call void @use_i32(i32 %v)
156  call void @use_i32(i32 %v.fr)
157  ret void
158}
159
160define void @freeze_dominated_uses_test2(i32 %v) {
161; CHECK-LABEL: @freeze_dominated_uses_test2(
162; CHECK-NEXT:  entry:
163; CHECK-NEXT:    [[A:%.*]] = alloca i32, align 4
164; CHECK-NEXT:    [[V_FR:%.*]] = freeze i32 [[V:%.*]]
165; CHECK-NEXT:    call void @use_p32(ptr nonnull [[A]])
166; CHECK-NEXT:    call void @use_i32(i32 [[V_FR]])
167; CHECK-NEXT:    [[COND:%.*]] = icmp eq i32 [[V_FR]], 0
168; CHECK-NEXT:    br i1 [[COND]], label [[BB0:%.*]], label [[BB1:%.*]]
169; CHECK:       bb0:
170; CHECK-NEXT:    call void @use_i32(i32 [[V_FR]])
171; CHECK-NEXT:    call void @use_i32(i32 [[V_FR]])
172; CHECK-NEXT:    br label [[END:%.*]]
173; CHECK:       bb1:
174; CHECK-NEXT:    call void @use_i32(i32 [[V_FR]])
175; CHECK-NEXT:    br label [[END]]
176; CHECK:       end:
177; CHECK-NEXT:    ret void
178;
179entry:
180  %a = alloca i32
181  call void @use_p32(ptr %a)
182  call void @use_i32(i32 %v)
183  %cond = icmp eq i32 %v, 0
184  br i1 %cond, label %bb0, label %bb1
185
186bb0:
187  %v.fr = freeze i32 %v
188  call void @use_i32(i32 %v.fr)
189  call void @use_i32(i32 %v)
190  br label %end
191
192bb1:
193  call void @use_i32(i32 %v)
194  br label %end
195
196end:
197  ret void
198}
199
200; If there is a duplicate freeze, it will be removed.
201
202define void @freeze_dominated_uses_test3(i32 %v, i1 %cond) {
203; CHECK-LABEL: @freeze_dominated_uses_test3(
204; CHECK-NEXT:  entry:
205; CHECK-NEXT:    [[V_FR1:%.*]] = freeze i32 [[V:%.*]]
206; CHECK-NEXT:    call void @use_i32(i32 [[V_FR1]])
207; CHECK-NEXT:    br i1 [[COND:%.*]], label [[BB0:%.*]], label [[BB1:%.*]]
208; CHECK:       bb0:
209; CHECK-NEXT:    call void @use_i32(i32 [[V_FR1]])
210; CHECK-NEXT:    br label [[END:%.*]]
211; CHECK:       bb1:
212; CHECK-NEXT:    call void @use_i32(i32 [[V_FR1]])
213; CHECK-NEXT:    br label [[END]]
214; CHECK:       end:
215; CHECK-NEXT:    ret void
216;
217entry:
218  %v.fr1 = freeze i32 %v
219  call void @use_i32(i32 %v.fr1)
220  br i1 %cond, label %bb0, label %bb1
221
222bb0:
223  %v.fr2 = freeze i32 %v
224  call void @use_i32(i32 %v.fr2)
225  br label %end
226
227bb1:
228  call void @use_i32(i32 %v)
229  br label %end
230
231end:
232  ret void
233}
234
235declare i32 @__CxxFrameHandler3(...)
236
237define void @freeze_dominated_uses_catchswitch(i1 %c, i32 %x) personality ptr @__CxxFrameHandler3 {
238; CHECK-LABEL: @freeze_dominated_uses_catchswitch(
239; CHECK-NEXT:  entry:
240; CHECK-NEXT:    br i1 [[C:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
241; CHECK:       if.then:
242; CHECK-NEXT:    invoke void @use_i32(i32 0)
243; CHECK-NEXT:            to label [[CLEANUP:%.*]] unwind label [[CATCH_DISPATCH:%.*]]
244; CHECK:       if.else:
245; CHECK-NEXT:    invoke void @use_i32(i32 1)
246; CHECK-NEXT:            to label [[CLEANUP]] unwind label [[CATCH_DISPATCH]]
247; CHECK:       catch.dispatch:
248; CHECK-NEXT:    [[PHI:%.*]] = phi i32 [ 0, [[IF_THEN]] ], [ [[X:%.*]], [[IF_ELSE]] ]
249; CHECK-NEXT:    [[CS:%.*]] = catchswitch within none [label [[CATCH:%.*]], label %catch2] unwind to caller
250; CHECK:       catch:
251; CHECK-NEXT:    [[CP:%.*]] = catchpad within [[CS]] [ptr null, i32 64, ptr null]
252; CHECK-NEXT:    [[PHI_FREEZE:%.*]] = freeze i32 [[PHI]]
253; CHECK-NEXT:    call void @use_i32(i32 [[PHI_FREEZE]]) [ "funclet"(token [[CP]]) ]
254; CHECK-NEXT:    unreachable
255; CHECK:       catch2:
256; CHECK-NEXT:    [[CP2:%.*]] = catchpad within [[CS]] [ptr null, i32 64, ptr null]
257; CHECK-NEXT:    call void @use_i32(i32 [[PHI]]) [ "funclet"(token [[CP2]]) ]
258; CHECK-NEXT:    unreachable
259; CHECK:       cleanup:
260; CHECK-NEXT:    ret void
261;
262entry:
263  br i1 %c, label %if.then, label %if.else
264
265if.then:
266  invoke void @use_i32(i32 0)
267  to label %cleanup unwind label %catch.dispatch
268
269if.else:
270  invoke void @use_i32(i32 1)
271  to label %cleanup unwind label %catch.dispatch
272
273catch.dispatch:
274  %phi = phi i32 [ 0, %if.then ], [ %x, %if.else ]
275  %cs = catchswitch within none [label %catch, label %catch2] unwind to caller
276
277catch:
278  %cp = catchpad within %cs [ptr null, i32 64, ptr null]
279  %phi.freeze = freeze i32 %phi
280  call void @use_i32(i32 %phi.freeze) [ "funclet"(token %cp) ]
281  unreachable
282
283catch2:
284  %cp2 = catchpad within %cs [ptr null, i32 64, ptr null]
285  call void @use_i32(i32 %phi) [ "funclet"(token %cp2) ]
286  unreachable
287
288cleanup:
289  ret void
290}
291
292declare i32 @get_i32()
293
294define i32 @freeze_use_in_different_branches(i1 %c) {
295; CHECK-LABEL: @freeze_use_in_different_branches(
296; CHECK-NEXT:  entry:
297; CHECK-NEXT:    [[X:%.*]] = call i32 @get_i32()
298; CHECK-NEXT:    [[FR:%.*]] = freeze i32 [[X]]
299; CHECK-NEXT:    call void @use_i32(i32 0)
300; CHECK-NEXT:    br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]
301; CHECK:       if:
302; CHECK-NEXT:    call void @use_i32(i32 [[FR]])
303; CHECK-NEXT:    ret i32 0
304; CHECK:       else:
305; CHECK-NEXT:    call void @use_i32(i32 [[FR]])
306; CHECK-NEXT:    call void @use_i32(i32 [[FR]])
307; CHECK-NEXT:    ret i32 1
308;
309entry:
310  %x = call i32 @get_i32()
311  call void @use_i32(i32 0)
312  br i1 %c, label %if, label %else
313
314if:
315  call void @use_i32(i32 %x)
316  ret i32 0
317
318else:
319  call void @use_i32(i32 %x)
320  %fr = freeze i32 %x
321  call void @use_i32(i32 %fr)
322  ret i32 1
323}
324
325define i32 @freeze_phi_use(i1 %c) {
326; CHECK-LABEL: @freeze_phi_use(
327; CHECK-NEXT:  entry:
328; CHECK-NEXT:    [[X:%.*]] = call i32 @get_i32()
329; CHECK-NEXT:    [[FR:%.*]] = freeze i32 [[X]]
330; CHECK-NEXT:    call void @use_i32(i32 0)
331; CHECK-NEXT:    br i1 [[C:%.*]], label [[IF:%.*]], label [[JOIN:%.*]]
332; CHECK:       if:
333; CHECK-NEXT:    br label [[JOIN]]
334; CHECK:       join:
335; CHECK-NEXT:    [[PHI:%.*]] = phi i32 [ [[FR]], [[IF]] ], [ 0, [[ENTRY:%.*]] ]
336; CHECK-NEXT:    call void @use_i32(i32 [[FR]])
337; CHECK-NEXT:    ret i32 [[PHI]]
338;
339entry:
340  %x = call i32 @get_i32()
341  call void @use_i32(i32 0)
342  br i1 %c, label %if, label %join
343
344if:
345  br label %join
346
347join:
348  %phi = phi i32 [ %x, %if ], [ 0, %entry ]
349  %fr = freeze i32 %x
350  call void @use_i32(i32 %fr)
351  ret i32 %phi
352}
353
354define i32 @freeze_phi_followed_by_phi(i1 %c, i32 %y, i32 %z) {
355; CHECK-LABEL: @freeze_phi_followed_by_phi(
356; CHECK-NEXT:  entry:
357; CHECK-NEXT:    br i1 [[C:%.*]], label [[IF:%.*]], label [[JOIN:%.*]]
358; CHECK:       if:
359; CHECK-NEXT:    br label [[JOIN]]
360; CHECK:       join:
361; CHECK-NEXT:    [[X:%.*]] = phi i32 [ [[Y:%.*]], [[IF]] ], [ [[Z:%.*]], [[ENTRY:%.*]] ]
362; CHECK-NEXT:    [[PHI:%.*]] = phi i32 [ [[Z]], [[IF]] ], [ [[Y]], [[ENTRY]] ]
363; CHECK-NEXT:    [[FR:%.*]] = freeze i32 [[X]]
364; CHECK-NEXT:    call void @use_i32(i32 [[FR]])
365; CHECK-NEXT:    call void @use_i32(i32 [[FR]])
366; CHECK-NEXT:    ret i32 [[PHI]]
367;
368entry:
369  br i1 %c, label %if, label %join
370
371if:
372  br label %join
373
374join:
375  %x = phi i32 [ %y, %if ], [ %z, %entry ]
376  %phi = phi i32 [ %z, %if ], [ %y, %entry ]
377  call void @use_i32(i32 %x)
378  %fr = freeze i32 %x
379  call void @use_i32(i32 %fr)
380  ret i32 %phi
381}
382
383define i32 @freeze_invoke_use_in_phi(i1 %c) personality ptr undef {
384; CHECK-LABEL: @freeze_invoke_use_in_phi(
385; CHECK-NEXT:  entry:
386; CHECK-NEXT:    [[X:%.*]] = invoke i32 @get_i32()
387; CHECK-NEXT:            to label [[INVOKE_CONT:%.*]] unwind label [[INVOKE_UNWIND:%.*]]
388; CHECK:       invoke.cont:
389; CHECK-NEXT:    [[PHI:%.*]] = phi i32 [ [[X]], [[ENTRY:%.*]] ], [ 0, [[INVOKE_CONT]] ]
390; CHECK-NEXT:    [[FR:%.*]] = freeze i32 [[X]]
391; CHECK-NEXT:    call void @use_i32(i32 [[FR]])
392; CHECK-NEXT:    call void @use_i32(i32 [[PHI]])
393; CHECK-NEXT:    br label [[INVOKE_CONT]]
394; CHECK:       invoke.unwind:
395; CHECK-NEXT:    [[TMP0:%.*]] = landingpad i8
396; CHECK-NEXT:            cleanup
397; CHECK-NEXT:    unreachable
398;
399entry:
400  %x = invoke i32 @get_i32()
401  to label %invoke.cont unwind label %invoke.unwind
402
403invoke.cont:
404  %phi = phi i32 [ %x, %entry ], [ 0, %invoke.cont ]
405  %fr = freeze i32 %x
406  call void @use_i32(i32 %fr)
407  call void @use_i32(i32 %phi)
408  br label %invoke.cont
409
410invoke.unwind:
411  landingpad i8 cleanup
412  unreachable
413}
414
415define i32 @freeze_invoke_use_after_phi(i1 %c) personality ptr undef {
416; CHECK-LABEL: @freeze_invoke_use_after_phi(
417; CHECK-NEXT:  entry:
418; CHECK-NEXT:    [[X:%.*]] = invoke i32 @get_i32()
419; CHECK-NEXT:            to label [[INVOKE_CONT:%.*]] unwind label [[INVOKE_UNWIND:%.*]]
420; CHECK:       invoke.cont:
421; CHECK-NEXT:    [[PHI:%.*]] = phi i32 [ [[X]], [[ENTRY:%.*]] ], [ 0, [[INVOKE_CONT]] ]
422; CHECK-NEXT:    [[FR:%.*]] = freeze i32 [[X]]
423; CHECK-NEXT:    call void @use_i32(i32 [[FR]])
424; CHECK-NEXT:    call void @use_i32(i32 [[FR]])
425; CHECK-NEXT:    call void @use_i32(i32 [[PHI]])
426; CHECK-NEXT:    br label [[INVOKE_CONT]]
427; CHECK:       invoke.unwind:
428; CHECK-NEXT:    [[TMP0:%.*]] = landingpad i8
429; CHECK-NEXT:            cleanup
430; CHECK-NEXT:    unreachable
431;
432entry:
433  %x = invoke i32 @get_i32()
434  to label %invoke.cont unwind label %invoke.unwind
435
436invoke.cont:
437  %phi = phi i32 [ %x, %entry ], [ 0, %invoke.cont ]
438  call void @use_i32(i32 %x)
439  %fr = freeze i32 %x
440  call void @use_i32(i32 %fr)
441  call void @use_i32(i32 %phi)
442  br label %invoke.cont
443
444invoke.unwind:
445  landingpad i8 cleanup
446  unreachable
447}
448
449define i32 @freeze_callbr_use_after_phi(i1 %c) {
450; CHECK-LABEL: @freeze_callbr_use_after_phi(
451; CHECK-NEXT:  entry:
452; CHECK-NEXT:    [[X:%.*]] = callbr i32 asm sideeffect "", "=r"() #[[ATTR1:[0-9]+]]
453; CHECK-NEXT:            to label [[CALLBR_CONT:%.*]] []
454; CHECK:       callbr.cont:
455; CHECK-NEXT:    [[PHI:%.*]] = phi i32 [ [[X]], [[ENTRY:%.*]] ], [ 0, [[CALLBR_CONT]] ]
456; CHECK-NEXT:    call void @use_i32(i32 [[X]])
457; CHECK-NEXT:    [[FR:%.*]] = freeze i32 [[X]]
458; CHECK-NEXT:    call void @use_i32(i32 [[FR]])
459; CHECK-NEXT:    call void @use_i32(i32 [[PHI]])
460; CHECK-NEXT:    br label [[CALLBR_CONT]]
461;
462entry:
463  %x = callbr i32 asm sideeffect "", "=r"()
464  to label %callbr.cont []
465
466callbr.cont:
467  %phi = phi i32 [ %x, %entry ], [ 0, %callbr.cont ]
468  call void @use_i32(i32 %x)
469  %fr = freeze i32 %x
470  call void @use_i32(i32 %fr)
471  call void @use_i32(i32 %phi)
472  br label %callbr.cont
473}
474
475define i1 @combine_and_after_freezing_uses(i32 %x) {
476; CHECK-LABEL: @combine_and_after_freezing_uses(
477; CHECK-NEXT:    [[X_FR:%.*]] = freeze i32 [[X:%.*]]
478; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[X_FR]], 15
479; CHECK-NEXT:    [[AND:%.*]] = icmp eq i32 [[TMP1]], 15
480; CHECK-NEXT:    ret i1 [[AND]]
481;
482  %and1 = and i32 %x, 4
483  %cmp1 = icmp ne i32 %and1, 0
484  %x.fr = freeze i32 %x
485  %and2 = and i32 %x.fr, 11
486  %cmp2 = icmp eq i32 %and2, 11
487  %and = and i1 %cmp1, %cmp2
488  ret i1 %and
489}
490
491declare i1 @mock_use(i64, i64)
492define i1 @fully_propagate_freeze(i32 %0, i32 noundef %1) {
493; CHECK-LABEL: @fully_propagate_freeze(
494; CHECK-NEXT:    [[DOTFR:%.*]] = freeze i32 [[TMP0:%.*]]
495; CHECK-NEXT:    [[DR:%.*]] = lshr i32 [[DOTFR]], 2
496; CHECK-NEXT:    [[IDX1:%.*]] = zext nneg i32 [[DR]] to i64
497; CHECK-NEXT:    [[ADD:%.*]] = add nuw nsw i32 [[DR]], 1
498; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[ADD]], [[TMP1:%.*]]
499; CHECK-NEXT:    [[IDX2:%.*]] = zext nneg i32 [[DR]] to i64
500; CHECK-NEXT:    [[V:%.*]] = call i1 @mock_use(i64 [[IDX1]], i64 [[IDX2]])
501; CHECK-NEXT:    [[RET:%.*]] = and i1 [[V]], [[CMP]]
502; CHECK-NEXT:    ret i1 [[RET]]
503;
504  %dr = lshr i32 %0, 2
505  %idx1 = zext i32 %dr to i64
506  %add = add i32 %dr, 1
507  %cmp = icmp slt i32 %add, %1
508  %cmp.fr = freeze i1 %cmp
509  %idx2 = zext i32 %dr to i64
510  %v = call i1 @mock_use(i64 %idx1, i64 %idx2)
511  %ret = and i1 %v, %cmp.fr
512  ret i1 %ret
513}
514
515define i32 @propagate_drop_flags_add(i32 %arg) {
516; CHECK-LABEL: @propagate_drop_flags_add(
517; CHECK-NEXT:    [[ARG_FR:%.*]] = freeze i32 [[ARG:%.*]]
518; CHECK-NEXT:    [[V1:%.*]] = add i32 [[ARG_FR]], 2
519; CHECK-NEXT:    ret i32 [[V1]]
520;
521  %v1 = add nsw nuw i32 %arg, 2
522  %v1.fr = freeze i32 %v1
523  ret i32 %v1.fr
524}
525
526define i32 @propagate_drop_flags_add_foldaway(i32 noundef %arg) {
527; CHECK-LABEL: @propagate_drop_flags_add_foldaway(
528; CHECK-NEXT:    [[V1:%.*]] = add i32 [[ARG:%.*]], 2
529; CHECK-NEXT:    ret i32 [[V1]]
530;
531  %v1 = add nsw nuw i32 %arg, 2
532  %v1.fr = freeze i32 %v1
533  ret i32 %v1.fr
534}
535
536define i32 @propagate_drop_flags_sub(i32 %arg) {
537; CHECK-LABEL: @propagate_drop_flags_sub(
538; CHECK-NEXT:    [[ARG_FR:%.*]] = freeze i32 [[ARG:%.*]]
539; CHECK-NEXT:    [[V1:%.*]] = add i32 [[ARG_FR]], -2
540; CHECK-NEXT:    ret i32 [[V1]]
541;
542  %v1 = sub nsw nuw i32 %arg, 2
543  %v1.fr = freeze i32 %v1
544  ret i32 %v1.fr
545}
546
547define i32 @propagate_drop_flags_mul(i32 %arg) {
548; CHECK-LABEL: @propagate_drop_flags_mul(
549; CHECK-NEXT:    [[ARG_FR:%.*]] = freeze i32 [[ARG:%.*]]
550; CHECK-NEXT:    [[V1:%.*]] = shl i32 [[ARG_FR]], 1
551; CHECK-NEXT:    ret i32 [[V1]]
552;
553  %v1 = mul nsw nuw i32 %arg, 2
554  %v1.fr = freeze i32 %v1
555  ret i32 %v1.fr
556}
557
558define i32 @propagate_drop_flags_udiv(i32 %arg) {
559; CHECK-LABEL: @propagate_drop_flags_udiv(
560; CHECK-NEXT:    [[ARG_FR:%.*]] = freeze i32 [[ARG:%.*]]
561; CHECK-NEXT:    [[V11:%.*]] = lshr i32 [[ARG_FR]], 1
562; CHECK-NEXT:    ret i32 [[V11]]
563;
564  %v1 = udiv exact i32 %arg, 2
565  %v1.fr = freeze i32 %v1
566  ret i32 %v1.fr
567}
568
569define i32 @propagate_drop_flags_sdiv(i32 %arg) {
570; CHECK-LABEL: @propagate_drop_flags_sdiv(
571; CHECK-NEXT:    [[ARG_FR:%.*]] = freeze i32 [[ARG:%.*]]
572; CHECK-NEXT:    [[V1:%.*]] = ashr i32 [[ARG_FR]], 1
573; CHECK-NEXT:    ret i32 [[V1]]
574;
575  %v1 = sdiv exact i32 %arg, 2
576  %v1.fr = freeze i32 %v1
577  ret i32 %v1.fr
578}
579
580define i32 @propagate_drop_shl1(i32 %arg) {
581; CHECK-LABEL: @propagate_drop_shl1(
582; CHECK-NEXT:    [[ARG_FR:%.*]] = freeze i32 [[ARG:%.*]]
583; CHECK-NEXT:    [[V1:%.*]] = shl i32 [[ARG_FR]], 2
584; CHECK-NEXT:    ret i32 [[V1]]
585;
586  %v1 = shl nsw nuw i32 %arg, 2
587  %v1.fr = freeze i32 %v1
588  ret i32 %v1.fr
589}
590
591define i32 @propagate_drop_shl2(i32 %arg, i32 %unknown) {
592; CHECK-LABEL: @propagate_drop_shl2(
593; CHECK-NEXT:    [[V1:%.*]] = shl nuw nsw i32 [[ARG:%.*]], [[UNKNOWN:%.*]]
594; CHECK-NEXT:    [[V1_FR:%.*]] = freeze i32 [[V1]]
595; CHECK-NEXT:    ret i32 [[V1_FR]]
596;
597  %v1 = shl nsw nuw i32 %arg, %unknown
598  %v1.fr = freeze i32 %v1
599  ret i32 %v1.fr
600}
601
602define i32 @propagate_drop_ashr1(i32 %arg) {
603; CHECK-LABEL: @propagate_drop_ashr1(
604; CHECK-NEXT:    [[ARG_FR:%.*]] = freeze i32 [[ARG:%.*]]
605; CHECK-NEXT:    [[V1:%.*]] = ashr i32 [[ARG_FR]], 2
606; CHECK-NEXT:    ret i32 [[V1]]
607;
608  %v1 = ashr exact i32 %arg, 2
609  %v1.fr = freeze i32 %v1
610  ret i32 %v1.fr
611}
612
613define i32 @propagate_drop_ashr2(i32 %arg, i32 %unknown) {
614; CHECK-LABEL: @propagate_drop_ashr2(
615; CHECK-NEXT:    [[V1:%.*]] = ashr exact i32 [[ARG:%.*]], [[UNKNOWN:%.*]]
616; CHECK-NEXT:    [[V1_FR:%.*]] = freeze i32 [[V1]]
617; CHECK-NEXT:    ret i32 [[V1_FR]]
618;
619  %v1 = ashr exact i32 %arg, %unknown
620  %v1.fr = freeze i32 %v1
621  ret i32 %v1.fr
622}
623
624define i32 @propagate_drop_lshr1(i32 %arg) {
625; CHECK-LABEL: @propagate_drop_lshr1(
626; CHECK-NEXT:    [[ARG_FR:%.*]] = freeze i32 [[ARG:%.*]]
627; CHECK-NEXT:    [[V1:%.*]] = lshr i32 [[ARG_FR]], 2
628; CHECK-NEXT:    ret i32 [[V1]]
629;
630  %v1 = lshr exact i32 %arg, 2
631  %v1.fr = freeze i32 %v1
632  ret i32 %v1.fr
633}
634
635define i32 @propagate_drop_lshr2(i32 %arg, i32 %unknown) {
636; CHECK-LABEL: @propagate_drop_lshr2(
637; CHECK-NEXT:    [[V1:%.*]] = lshr exact i32 [[ARG:%.*]], [[UNKNOWN:%.*]]
638; CHECK-NEXT:    [[V1_FR:%.*]] = freeze i32 [[V1]]
639; CHECK-NEXT:    ret i32 [[V1_FR]]
640;
641  %v1 = lshr exact i32 %arg, %unknown
642  %v1.fr = freeze i32 %v1
643  ret i32 %v1.fr
644}
645
646define ptr @propagate_drop_gep1(ptr %arg) {
647; CHECK-LABEL: @propagate_drop_gep1(
648; CHECK-NEXT:    [[ARG_FR:%.*]] = freeze ptr [[ARG:%.*]]
649; CHECK-NEXT:    [[V1:%.*]] = getelementptr i8, ptr [[ARG_FR]], i64 16
650; CHECK-NEXT:    ret ptr [[V1]]
651;
652  %v1 = getelementptr inbounds i8, ptr %arg, i64 16
653  %v1.fr = freeze ptr %v1
654  ret ptr %v1.fr
655}
656
657define float @propagate_drop_fneg(float %arg) {
658; CHECK-LABEL: @propagate_drop_fneg(
659; CHECK-NEXT:    [[ARG_FR:%.*]] = freeze float [[ARG:%.*]]
660; CHECK-NEXT:    [[V1:%.*]] = fneg float [[ARG_FR]]
661; CHECK-NEXT:    ret float [[V1]]
662;
663  %v1 = fneg ninf nnan float %arg
664  %v1.fr = freeze float %v1
665  ret float %v1.fr
666}
667
668
669define float @propagate_drop_fadd(float %arg) {
670; CHECK-LABEL: @propagate_drop_fadd(
671; CHECK-NEXT:    [[ARG_FR:%.*]] = freeze float [[ARG:%.*]]
672; CHECK-NEXT:    [[V1:%.*]] = fadd float [[ARG_FR]], 2.000000e+00
673; CHECK-NEXT:    ret float [[V1]]
674;
675  %v1 = fadd ninf nnan float %arg, 2.0
676  %v1.fr = freeze float %v1
677  ret float %v1.fr
678}
679
680define float @propagate_drop_fsub(float %arg) {
681; CHECK-LABEL: @propagate_drop_fsub(
682; CHECK-NEXT:    [[ARG_FR:%.*]] = freeze float [[ARG:%.*]]
683; CHECK-NEXT:    [[V1:%.*]] = fadd float [[ARG_FR]], -2.000000e+00
684; CHECK-NEXT:    ret float [[V1]]
685;
686  %v1 = fsub ninf nnan float %arg, 2.0
687  %v1.fr = freeze float %v1
688  ret float %v1.fr
689}
690
691define float @propagate_drop_fmul(float %arg) {
692; CHECK-LABEL: @propagate_drop_fmul(
693; CHECK-NEXT:    [[ARG_FR:%.*]] = freeze float [[ARG:%.*]]
694; CHECK-NEXT:    [[V1:%.*]] = fmul float [[ARG_FR]], 2.000000e+00
695; CHECK-NEXT:    ret float [[V1]]
696;
697  %v1 = fmul ninf nnan float %arg, 2.0
698  %v1.fr = freeze float %v1
699  ret float %v1.fr
700}
701
702define float @propagate_drop_fdiv(float %arg) {
703; CHECK-LABEL: @propagate_drop_fdiv(
704; CHECK-NEXT:    [[ARG_FR:%.*]] = freeze float [[ARG:%.*]]
705; CHECK-NEXT:    [[V1:%.*]] = fmul float [[ARG_FR]], 5.000000e-01
706; CHECK-NEXT:    ret float [[V1]]
707;
708  %v1 = fdiv ninf nnan float %arg, 2.0
709  %v1.fr = freeze float %v1
710  ret float %v1.fr
711}
712
713define float @propagate_drop_frem(float %arg) {
714; CHECK-LABEL: @propagate_drop_frem(
715; CHECK-NEXT:    [[ARG_FR:%.*]] = freeze float [[ARG:%.*]]
716; CHECK-NEXT:    [[V1:%.*]] = frem float [[ARG_FR]], 2.000000e+00
717; CHECK-NEXT:    ret float [[V1]]
718;
719  %v1 = frem ninf nnan float %arg, 2.0
720  %v1.fr = freeze float %v1
721  ret float %v1.fr
722}
723
724define i1 @propagate_drop_fcmp(float %arg) {
725; CHECK-LABEL: @propagate_drop_fcmp(
726; CHECK-NEXT:    [[ARG_FR:%.*]] = freeze float [[ARG:%.*]]
727; CHECK-NEXT:    [[V1:%.*]] = fcmp une float [[ARG_FR]], 2.000000e+00
728; CHECK-NEXT:    ret i1 [[V1]]
729;
730  %v1 = fcmp ninf nnan une float %arg, 2.0
731  %v1.fr = freeze i1 %v1
732  ret i1 %v1.fr
733}
734
735define float @propagate_drop_fmath_select(i1 %arg) {
736; CHECK-LABEL: @propagate_drop_fmath_select(
737; CHECK-NEXT:    [[ARG_FR:%.*]] = freeze i1 [[ARG:%.*]]
738; CHECK-NEXT:    [[V1:%.*]] = select i1 [[ARG_FR]], float 1.000000e+00, float -1.000000e+00
739; CHECK-NEXT:    ret float [[V1]]
740;
741  %v1 = select ninf nnan i1 %arg, float 1.0, float -1.0
742  %v1.fr = freeze float %v1
743  ret float %v1.fr
744}
745
746define void @fold_phi_noop(i32 noundef %init, i32 %n) {
747; CHECK-LABEL: @fold_phi_noop(
748; CHECK-NEXT:  entry:
749; CHECK-NEXT:    br label [[LOOP:%.*]]
750; CHECK:       loop:
751; CHECK-NEXT:    [[I:%.*]] = phi i32 [ [[INIT:%.*]], [[ENTRY:%.*]] ], [ [[I_NEXT:%.*]], [[LOOP]] ]
752; CHECK-NEXT:    [[I_NEXT]] = add i32 [[I]], 1
753; CHECK-NEXT:    [[COND:%.*]] = icmp eq i32 [[I_NEXT]], [[N:%.*]]
754; CHECK-NEXT:    br i1 [[COND]], label [[LOOP]], label [[EXIT:%.*]]
755; CHECK:       exit:
756; CHECK-NEXT:    ret void
757;
758entry:
759  br label %loop
760
761loop:                                             ; preds = %loop, %entry
762  %i = phi i32 [ %init, %entry ], [ %i.next, %loop ]
763  %i.fr = freeze i32 %i
764  %i.next = add i32 %i.fr, 1
765  %cond = icmp eq i32 %i.next, %n
766  br i1 %cond, label %loop, label %exit
767
768exit:                                             ; preds = %loop
769  ret void
770}
771
772define void @fold_phi_through(i32 %init, i32 %n) {
773; CHECK-LABEL: @fold_phi_through(
774; CHECK-NEXT:  entry:
775; CHECK-NEXT:    [[TMP0:%.*]] = freeze i32 [[INIT:%.*]]
776; CHECK-NEXT:    br label [[LOOP:%.*]]
777; CHECK:       loop:
778; CHECK-NEXT:    [[I:%.*]] = phi i32 [ [[TMP0]], [[ENTRY:%.*]] ], [ [[I_NEXT:%.*]], [[LOOP]] ]
779; CHECK-NEXT:    [[I_NEXT]] = add i32 [[I]], 1
780; CHECK-NEXT:    [[COND:%.*]] = icmp eq i32 [[I_NEXT]], [[N:%.*]]
781; CHECK-NEXT:    br i1 [[COND]], label [[LOOP]], label [[EXIT:%.*]]
782; CHECK:       exit:
783; CHECK-NEXT:    ret void
784;
785entry:
786  br label %loop
787
788loop:                                             ; preds = %loop, %entry
789  %i = phi i32 [ %init, %entry ], [ %i.next, %loop ]
790  %i.fr = freeze i32 %i
791  %i.next = add i32 %i.fr, 1
792  %cond = icmp eq i32 %i.next, %n
793  br i1 %cond, label %loop, label %exit
794
795exit:                                             ; preds = %loop
796  ret void
797}
798
799define void @fold_phi_drop_flags(i32 %init, i32 %n) {
800; CHECK-LABEL: @fold_phi_drop_flags(
801; CHECK-NEXT:  entry:
802; CHECK-NEXT:    [[INIT_FR:%.*]] = freeze i32 [[INIT:%.*]]
803; CHECK-NEXT:    br label [[LOOP:%.*]]
804; CHECK:       loop:
805; CHECK-NEXT:    [[I:%.*]] = phi i32 [ [[INIT_FR]], [[ENTRY:%.*]] ], [ [[I_NEXT:%.*]], [[LOOP]] ]
806; CHECK-NEXT:    [[I_NEXT]] = add i32 [[I]], 1
807; CHECK-NEXT:    [[COND:%.*]] = icmp eq i32 [[I_NEXT]], [[N:%.*]]
808; CHECK-NEXT:    br i1 [[COND]], label [[LOOP]], label [[EXIT:%.*]]
809; CHECK:       exit:
810; CHECK-NEXT:    ret void
811;
812entry:
813  br label %loop
814
815loop:                                             ; preds = %loop, %entry
816  %i = phi i32 [ %init, %entry ], [ %i.next, %loop ]
817  %i.fr = freeze i32 %i
818  %i.next = add nsw nuw i32 %i.fr, 1
819  %cond = icmp eq i32 %i.next, %n
820  br i1 %cond, label %loop, label %exit
821
822exit:                                             ; preds = %loop
823  ret void
824}
825
826define void @fold_phi_non_add(i32 %init, i32 %n) {
827; CHECK-LABEL: @fold_phi_non_add(
828; CHECK-NEXT:  entry:
829; CHECK-NEXT:    [[TMP0:%.*]] = freeze i32 [[INIT:%.*]]
830; CHECK-NEXT:    br label [[LOOP:%.*]]
831; CHECK:       loop:
832; CHECK-NEXT:    [[I:%.*]] = phi i32 [ [[TMP0]], [[ENTRY:%.*]] ], [ [[I_NEXT:%.*]], [[LOOP]] ]
833; CHECK-NEXT:    [[I_NEXT]] = shl i32 [[I]], 1
834; CHECK-NEXT:    [[COND:%.*]] = icmp eq i32 [[I_NEXT]], [[N:%.*]]
835; CHECK-NEXT:    br i1 [[COND]], label [[LOOP]], label [[EXIT:%.*]]
836; CHECK:       exit:
837; CHECK-NEXT:    ret void
838;
839entry:
840  br label %loop
841
842loop:                                             ; preds = %loop, %entry
843  %i = phi i32 [ %init, %entry ], [ %i.next, %loop ]
844  %i.fr = freeze i32 %i
845  %i.next = shl i32 %i.fr, 1
846  %cond = icmp eq i32 %i.next, %n
847  br i1 %cond, label %loop, label %exit
848
849exit:                                             ; preds = %loop
850  ret void
851}
852
853define void @fold_phi_gep(ptr %init, ptr %end) {
854; CHECK-LABEL: @fold_phi_gep(
855; CHECK-NEXT:  entry:
856; CHECK-NEXT:    [[TMP0:%.*]] = freeze ptr [[INIT:%.*]]
857; CHECK-NEXT:    br label [[LOOP:%.*]]
858; CHECK:       loop:
859; CHECK-NEXT:    [[I:%.*]] = phi ptr [ [[TMP0]], [[ENTRY:%.*]] ], [ [[I_NEXT:%.*]], [[LOOP]] ]
860; CHECK-NEXT:    [[I_NEXT]] = getelementptr i8, ptr [[I]], i64 1
861; CHECK-NEXT:    [[COND:%.*]] = icmp eq ptr [[I_NEXT]], [[END:%.*]]
862; CHECK-NEXT:    br i1 [[COND]], label [[LOOP]], label [[EXIT:%.*]]
863; CHECK:       exit:
864; CHECK-NEXT:    ret void
865;
866entry:
867  br label %loop
868
869loop:                                             ; preds = %loop, %entry
870  %i = phi ptr [ %init, %entry ], [ %i.next, %loop ]
871  %i.fr = freeze ptr %i
872  %i.next = getelementptr i8, ptr %i.fr, i64 1
873  %cond = icmp eq ptr %i.next, %end
874  br i1 %cond, label %loop, label %exit
875
876exit:                                             ; preds = %loop
877  ret void
878}
879
880define void @fold_phi_multiple_insts(i32 %init, i32 %n) {
881; CHECK-LABEL: @fold_phi_multiple_insts(
882; CHECK-NEXT:  entry:
883; CHECK-NEXT:    [[INIT_FR:%.*]] = freeze i32 [[INIT:%.*]]
884; CHECK-NEXT:    br label [[LOOP:%.*]]
885; CHECK:       loop:
886; CHECK-NEXT:    [[I:%.*]] = phi i32 [ [[INIT_FR]], [[ENTRY:%.*]] ], [ [[I_NEXT:%.*]], [[LOOP]] ]
887; CHECK-NEXT:    [[I_SQ:%.*]] = mul i32 [[I]], [[I]]
888; CHECK-NEXT:    [[I_NEXT]] = add i32 [[I_SQ]], 1
889; CHECK-NEXT:    [[COND:%.*]] = icmp eq i32 [[I_NEXT]], [[N:%.*]]
890; CHECK-NEXT:    br i1 [[COND]], label [[LOOP]], label [[EXIT:%.*]]
891; CHECK:       exit:
892; CHECK-NEXT:    ret void
893;
894entry:
895  br label %loop
896
897loop:                                             ; preds = %loop, %entry
898  %i = phi i32 [ %init, %entry ], [ %i.next, %loop ]
899  %i.fr = freeze i32 %i
900  %i.sq = mul nsw nuw i32 %i.fr, %i.fr
901  %i.next = add nsw nuw i32 %i.sq, 1
902  %cond = icmp eq i32 %i.next, %n
903  br i1 %cond, label %loop, label %exit
904
905exit:                                             ; preds = %loop
906  ret void
907}
908
909define void @fold_phi_multiple_back_edges(i32 %init, i32 %n, i32 %m) {
910; CHECK-LABEL: @fold_phi_multiple_back_edges(
911; CHECK-NEXT:  entry:
912; CHECK-NEXT:    [[INIT_FR:%.*]] = freeze i32 [[INIT:%.*]]
913; CHECK-NEXT:    br label [[LOOP:%.*]]
914; CHECK:       loop:
915; CHECK-NEXT:    [[I:%.*]] = phi i32 [ [[INIT_FR]], [[ENTRY:%.*]] ], [ [[I_NEXT:%.*]], [[LOOP]] ], [ [[I_NEXT2:%.*]], [[LOOP_LATCH2:%.*]] ]
916; CHECK-NEXT:    [[I_NEXT]] = add i32 [[I]], 1
917; CHECK-NEXT:    [[COND:%.*]] = icmp eq i32 [[I_NEXT]], [[N:%.*]]
918; CHECK-NEXT:    br i1 [[COND]], label [[LOOP]], label [[LOOP_LATCH2]]
919; CHECK:       loop.latch2:
920; CHECK-NEXT:    [[I_NEXT2]] = add i32 [[I]], 2
921; CHECK-NEXT:    [[COND2:%.*]] = icmp eq i32 [[I_NEXT]], [[M:%.*]]
922; CHECK-NEXT:    br i1 [[COND2]], label [[LOOP]], label [[EXIT:%.*]]
923; CHECK:       exit:
924; CHECK-NEXT:    ret void
925;
926entry:
927  br label %loop
928
929loop:                                             ; preds = %loop, %entry
930  %i = phi i32 [ %init, %entry ], [ %i.next, %loop ], [ %i.next2, %loop.latch2 ]
931  %i.fr = freeze i32 %i
932  %i.next = add nsw nuw i32 %i.fr, 1
933  %cond = icmp eq i32 %i.next, %n
934  br i1 %cond, label %loop, label %loop.latch2
935
936loop.latch2:
937  %i.next2 = add nsw nuw i32 %i.fr, 2
938  %cond2 = icmp eq i32 %i.next, %m
939  br i1 %cond2, label %loop, label %exit
940
941exit:                                             ; preds = %loop
942  ret void
943}
944
945define void @fold_phi_multiple_start_values(i1 %c, i32 %init, i32 %init2, i32 %n) {
946; CHECK-LABEL: @fold_phi_multiple_start_values(
947; CHECK-NEXT:  entry:
948; CHECK-NEXT:    br i1 [[C:%.*]], label [[IF:%.*]], label [[LOOP:%.*]]
949; CHECK:       if:
950; CHECK-NEXT:    br label [[LOOP]]
951; CHECK:       loop:
952; CHECK-NEXT:    [[I:%.*]] = phi i32 [ [[INIT:%.*]], [[ENTRY:%.*]] ], [ [[INIT2:%.*]], [[IF]] ], [ [[I_NEXT:%.*]], [[LOOP]] ]
953; CHECK-NEXT:    [[I_FR:%.*]] = freeze i32 [[I]]
954; CHECK-NEXT:    [[I_NEXT]] = add nuw nsw i32 [[I_FR]], 1
955; CHECK-NEXT:    [[COND:%.*]] = icmp eq i32 [[I_NEXT]], [[N:%.*]]
956; CHECK-NEXT:    br i1 [[COND]], label [[LOOP]], label [[EXIT:%.*]]
957; CHECK:       exit:
958; CHECK-NEXT:    ret void
959;
960entry:
961  br i1 %c, label %if, label %loop
962
963if:
964  br label %loop
965
966loop:
967  %i = phi i32 [ %init, %entry ], [ %init2, %if ], [ %i.next, %loop ]
968  %i.fr = freeze i32 %i
969  %i.next = add nsw nuw i32 %i.fr, 1
970  %cond = icmp eq i32 %i.next, %n
971  br i1 %cond, label %loop, label %exit
972
973exit:
974  ret void
975}
976
977define void @fold_phi_invoke_start_value(i32 %n) personality ptr undef {
978; CHECK-LABEL: @fold_phi_invoke_start_value(
979; CHECK-NEXT:  entry:
980; CHECK-NEXT:    [[INIT:%.*]] = invoke i32 @get_i32()
981; CHECK-NEXT:            to label [[LOOP:%.*]] unwind label [[UNWIND:%.*]]
982; CHECK:       loop:
983; CHECK-NEXT:    [[I:%.*]] = phi i32 [ [[INIT]], [[ENTRY:%.*]] ], [ [[I_NEXT:%.*]], [[LOOP]] ]
984; CHECK-NEXT:    [[I_FR:%.*]] = freeze i32 [[I]]
985; CHECK-NEXT:    [[I_NEXT]] = add nuw nsw i32 [[I_FR]], 1
986; CHECK-NEXT:    [[COND:%.*]] = icmp eq i32 [[I_NEXT]], [[N:%.*]]
987; CHECK-NEXT:    br i1 [[COND]], label [[LOOP]], label [[EXIT:%.*]]
988; CHECK:       unwind:
989; CHECK-NEXT:    [[TMP0:%.*]] = landingpad i8
990; CHECK-NEXT:            cleanup
991; CHECK-NEXT:    unreachable
992; CHECK:       exit:
993; CHECK-NEXT:    ret void
994;
995entry:
996  %init = invoke i32 @get_i32()
997  to label %loop unwind label %unwind
998
999loop:
1000  %i = phi i32 [ %init, %entry ], [ %i.next, %loop ]
1001  %i.fr = freeze i32 %i
1002  %i.next = add nsw nuw i32 %i.fr, 1
1003  %cond = icmp eq i32 %i.next, %n
1004  br i1 %cond, label %loop, label %exit
1005
1006unwind:
1007  landingpad i8 cleanup
1008  unreachable
1009
1010exit:
1011  ret void
1012}
1013
1014define void @fold_phi_invoke_noundef_start_value(i32 %n) personality ptr undef {
1015; CHECK-LABEL: @fold_phi_invoke_noundef_start_value(
1016; CHECK-NEXT:  entry:
1017; CHECK-NEXT:    [[INIT:%.*]] = invoke noundef i32 @get_i32()
1018; CHECK-NEXT:            to label [[LOOP:%.*]] unwind label [[UNWIND:%.*]]
1019; CHECK:       loop:
1020; CHECK-NEXT:    [[I:%.*]] = phi i32 [ [[INIT]], [[ENTRY:%.*]] ], [ [[I_NEXT:%.*]], [[LOOP]] ]
1021; CHECK-NEXT:    [[I_NEXT]] = add i32 [[I]], 1
1022; CHECK-NEXT:    [[COND:%.*]] = icmp eq i32 [[I_NEXT]], [[N:%.*]]
1023; CHECK-NEXT:    br i1 [[COND]], label [[LOOP]], label [[EXIT:%.*]]
1024; CHECK:       unwind:
1025; CHECK-NEXT:    [[TMP0:%.*]] = landingpad i8
1026; CHECK-NEXT:            cleanup
1027; CHECK-NEXT:    unreachable
1028; CHECK:       exit:
1029; CHECK-NEXT:    ret void
1030;
1031entry:
1032  %init = invoke noundef i32 @get_i32()
1033  to label %loop unwind label %unwind
1034
1035loop:
1036  %i = phi i32 [ %init, %entry ], [ %i.next, %loop ]
1037  %i.fr = freeze i32 %i
1038  %i.next = add nsw nuw i32 %i.fr, 1
1039  %cond = icmp eq i32 %i.next, %n
1040  br i1 %cond, label %loop, label %exit
1041
1042unwind:
1043  landingpad i8 cleanup
1044  unreachable
1045
1046exit:
1047  ret void
1048}
1049
1050define ptr @freeze_load_noundef(ptr %ptr) {
1051; CHECK-LABEL: @freeze_load_noundef(
1052; CHECK-NEXT:    [[P:%.*]] = load ptr, ptr [[PTR:%.*]], align 8, !noundef [[META0:![0-9]+]]
1053; CHECK-NEXT:    ret ptr [[P]]
1054;
1055  %p = load ptr, ptr %ptr, !noundef !0
1056  %p.fr = freeze ptr %p
1057  ret ptr %p.fr
1058}
1059
1060define ptr @freeze_load_dereferenceable(ptr %ptr) {
1061; CHECK-LABEL: @freeze_load_dereferenceable(
1062; CHECK-NEXT:    [[P:%.*]] = load ptr, ptr [[PTR:%.*]], align 8, !dereferenceable [[META1:![0-9]+]]
1063; CHECK-NEXT:    ret ptr [[P]]
1064;
1065  %p = load ptr, ptr %ptr, !dereferenceable !1
1066  %p.fr = freeze ptr %p
1067  ret ptr %p.fr
1068}
1069
1070define ptr @freeze_load_dereferenceable_or_null(ptr %ptr) {
1071; CHECK-LABEL: @freeze_load_dereferenceable_or_null(
1072; CHECK-NEXT:    [[P:%.*]] = load ptr, ptr [[PTR:%.*]], align 8, !dereferenceable_or_null [[META1]]
1073; CHECK-NEXT:    ret ptr [[P]]
1074;
1075  %p = load ptr, ptr %ptr, !dereferenceable_or_null !1
1076  %p.fr = freeze ptr %p
1077  ret ptr %p.fr
1078}
1079
1080define i32 @freeze_load_with_range(ptr %ptr) {
1081; CHECK-LABEL: @freeze_load_with_range(
1082; CHECK-NEXT:    [[X:%.*]] = load i32, ptr [[PTR:%.*]], align 4, !range [[RNG2:![0-9]+]]
1083; CHECK-NEXT:    [[X_FR:%.*]] = freeze i32 [[X]]
1084; CHECK-NEXT:    ret i32 [[X_FR]]
1085;
1086  %x = load i32, ptr %ptr, !range !2
1087  %x.fr = freeze i32 %x
1088  ret i32 %x.fr
1089}
1090
1091declare i32 @foo.i32()
1092
1093define i32 @freeze_call_with_range() {
1094; CHECK-LABEL: @freeze_call_with_range(
1095; CHECK-NEXT:    [[X:%.*]] = call i32 @foo.i32(), !range [[RNG2]]
1096; CHECK-NEXT:    [[X_FR:%.*]] = freeze i32 [[X]]
1097; CHECK-NEXT:    ret i32 [[X_FR]]
1098;
1099  %x = call i32 @foo.i32(), !range !2
1100  %x.fr = freeze i32 %x
1101  ret i32 %x.fr
1102}
1103
1104declare i32 @llvm.ctpop.i32(i32)
1105
1106define i32 @freeze_ctpop(i32 %x) {
1107; CHECK-LABEL: @freeze_ctpop(
1108; CHECK-NEXT:    [[Y:%.*]] = lshr i32 2047, [[X:%.*]]
1109; CHECK-NEXT:    [[Y_FR:%.*]] = freeze i32 [[Y]]
1110; CHECK-NEXT:    [[CTPOP:%.*]] = call range(i32 0, 33) i32 @llvm.ctpop.i32(i32 [[Y_FR]])
1111; CHECK-NEXT:    ret i32 [[CTPOP]]
1112;
1113  %y = lshr i32 2047, %x
1114  %ctpop = call i32 @llvm.ctpop.i32(i32 %y)
1115  %fr = freeze i32 %ctpop
1116  ret i32 %fr
1117}
1118
1119define i32 @freeze_zext_nneg(i8 %x) {
1120; CHECK-LABEL: @freeze_zext_nneg(
1121; CHECK-NEXT:    [[X_FR:%.*]] = freeze i8 [[X:%.*]]
1122; CHECK-NEXT:    [[ZEXT:%.*]] = zext i8 [[X_FR]] to i32
1123; CHECK-NEXT:    ret i32 [[ZEXT]]
1124;
1125  %zext = zext nneg i8 %x to i32
1126  %fr = freeze i32 %zext
1127  ret i32 %fr
1128}
1129
1130define float @freeze_uitofp_nneg(i8 %x) {
1131; CHECK-LABEL: @freeze_uitofp_nneg(
1132; CHECK-NEXT:    [[X_FR:%.*]] = freeze i8 [[X:%.*]]
1133; CHECK-NEXT:    [[UITOFP:%.*]] = uitofp i8 [[X_FR]] to float
1134; CHECK-NEXT:    ret float [[UITOFP]]
1135;
1136  %uitofp = uitofp nneg i8 %x to float
1137  %fr = freeze float %uitofp
1138  ret float %fr
1139}
1140
1141define i32 @propagate_drop_flags_or(i32 %arg) {
1142; CHECK-LABEL: @propagate_drop_flags_or(
1143; CHECK-NEXT:    [[ARG_FR:%.*]] = freeze i32 [[ARG:%.*]]
1144; CHECK-NEXT:    [[V1:%.*]] = or i32 [[ARG_FR]], 2
1145; CHECK-NEXT:    ret i32 [[V1]]
1146;
1147  %v1 = or disjoint i32 %arg, 2
1148  %v1.fr = freeze i32 %v1
1149  ret i32 %v1.fr
1150}
1151
1152define i32 @propagate_drop_flags_trunc(i64 %arg) {
1153; CHECK-LABEL: @propagate_drop_flags_trunc(
1154; CHECK-NEXT:    [[ARG_FR:%.*]] = freeze i64 [[ARG:%.*]]
1155; CHECK-NEXT:    [[V1:%.*]] = trunc i64 [[ARG_FR]] to i32
1156; CHECK-NEXT:    ret i32 [[V1]]
1157;
1158  %v1 = trunc nsw nuw i64 %arg to i32
1159  %v1.fr = freeze i32 %v1
1160  ret i32 %v1.fr
1161}
1162
1163define ptr @propagate_drop_flags_gep_nusw(ptr %p) {
1164; CHECK-LABEL: @propagate_drop_flags_gep_nusw(
1165; CHECK-NEXT:    [[P_FR:%.*]] = freeze ptr [[P:%.*]]
1166; CHECK-NEXT:    [[GEP:%.*]] = getelementptr i8, ptr [[P_FR]], i64 1
1167; CHECK-NEXT:    ret ptr [[GEP]]
1168;
1169  %gep = getelementptr nusw i8, ptr %p, i64 1
1170  %gep.fr = freeze ptr %gep
1171  ret ptr %gep.fr
1172}
1173
1174define ptr @propagate_drop_flags_gep_nuw(ptr %p) {
1175; CHECK-LABEL: @propagate_drop_flags_gep_nuw(
1176; CHECK-NEXT:    [[P_FR:%.*]] = freeze ptr [[P:%.*]]
1177; CHECK-NEXT:    [[GEP:%.*]] = getelementptr i8, ptr [[P_FR]], i64 1
1178; CHECK-NEXT:    ret ptr [[GEP]]
1179;
1180  %gep = getelementptr nuw i8, ptr %p, i64 1
1181  %gep.fr = freeze ptr %gep
1182  ret ptr %gep.fr
1183}
1184
1185define i1 @propagate_drop_flags_icmp(i32 %a, i32 %b) {
1186; CHECK-LABEL: @propagate_drop_flags_icmp(
1187; CHECK-NEXT:    [[A_FR:%.*]] = freeze i32 [[A:%.*]]
1188; CHECK-NEXT:    [[RET:%.*]] = icmp ult i32 [[A_FR]], 3
1189; CHECK-NEXT:    ret i1 [[RET]]
1190;
1191  %ret = icmp samesign ult i32 %a, 3
1192  %ret.fr = freeze i1 %ret
1193  ret i1 %ret.fr
1194}
1195
1196declare i32 @llvm.umax.i32(i32 %a, i32 %b)
1197
1198define i32 @freeze_call_with_range_attr(i32 %a) {
1199; CHECK-LABEL: @freeze_call_with_range_attr(
1200; CHECK-NEXT:    [[Y:%.*]] = lshr i32 2047, [[A:%.*]]
1201; CHECK-NEXT:    [[Y_FR:%.*]] = freeze i32 [[Y]]
1202; CHECK-NEXT:    [[X:%.*]] = call i32 @llvm.umax.i32(i32 [[Y_FR]], i32 50)
1203; CHECK-NEXT:    ret i32 [[X]]
1204;
1205  %y = lshr i32 2047, %a
1206  %x = call range(i32 0, 2048) i32 @llvm.umax.i32(i32 %y, i32 50)
1207  %x.fr = freeze i32 %x
1208  ret i32 %x.fr
1209}
1210
1211declare ptr @llvm.ptrmask.p0.i64(ptr, i64)
1212
1213define ptr @freeze_ptrmask_align(ptr %p, i64 noundef %m) {
1214; CHECK-LABEL: @freeze_ptrmask_align(
1215; CHECK-NEXT:    [[P_FR:%.*]] = freeze ptr [[P:%.*]]
1216; CHECK-NEXT:    [[MASK:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[P_FR]], i64 [[M:%.*]])
1217; CHECK-NEXT:    ret ptr [[MASK]]
1218;
1219  %mask = call align(4) ptr @llvm.ptrmask.p0.i64(ptr %p, i64 %m)
1220  %fr =  freeze ptr %mask
1221  ret ptr %fr
1222}
1223
1224define ptr @freeze_ptrmask_nonnull(ptr %p, i64 noundef %m) {
1225; CHECK-LABEL: @freeze_ptrmask_nonnull(
1226; CHECK-NEXT:    [[P_FR:%.*]] = freeze ptr [[P:%.*]]
1227; CHECK-NEXT:    [[MASK:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[P_FR]], i64 [[M:%.*]])
1228; CHECK-NEXT:    ret ptr [[MASK]]
1229;
1230  %mask = call nonnull ptr @llvm.ptrmask.p0.i64(ptr %p, i64 %m)
1231  %fr =  freeze ptr %mask
1232  ret ptr %fr
1233}
1234
1235!0 = !{}
1236!1 = !{i64 4}
1237!2 = !{i32 0, i32 100}
1238;.
1239; CHECK: attributes #[[ATTR0:[0-9]+]] = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
1240; CHECK: attributes #[[ATTR1]] = { nounwind }
1241;.
1242; CHECK: [[META0]] = !{}
1243; CHECK: [[META1]] = !{i64 4}
1244; CHECK: [[RNG2]] = !{i32 0, i32 100}
1245;.
1246