xref: /llvm-project/llvm/test/Transforms/GVN/metadata.ll (revision 84bcfa0e1b34938d1d11a44e9e17c6e222dd2f42)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals --version 2
2; RUN: opt -passes=gvn -S < %s | FileCheck %s
3
4declare void @use.ptr(ptr) memory(none)
5declare void @use.i64(i64) memory(none)
6declare void @use.i32(i32) memory(none)
7
8define i32 @test1(ptr %p) {
9; CHECK-LABEL: define i32 @test1
10; CHECK-SAME: (ptr [[P:%.*]]) {
11; CHECK-NEXT:    [[A:%.*]] = load i32, ptr [[P]], align 4, !range [[RNG0:![0-9]+]]
12; CHECK-NEXT:    [[C:%.*]] = add i32 [[A]], [[A]]
13; CHECK-NEXT:    ret i32 [[C]]
14;
15  %a = load i32, ptr %p, !range !0
16  %b = load i32, ptr %p, !range !0
17  %c = add i32 %a, %b
18  ret i32 %c
19}
20
21define i32 @test2(ptr %p) {
22; CHECK-LABEL: define i32 @test2
23; CHECK-SAME: (ptr [[P:%.*]]) {
24; CHECK-NEXT:    [[A:%.*]] = load i32, ptr [[P]], align 4
25; CHECK-NEXT:    [[C:%.*]] = add i32 [[A]], [[A]]
26; CHECK-NEXT:    ret i32 [[C]]
27;
28  %a = load i32, ptr %p, !range !0
29  %b = load i32, ptr %p
30  %c = add i32 %a, %b
31  ret i32 %c
32}
33
34define i32 @test3(ptr %p) {
35; CHECK-LABEL: define i32 @test3
36; CHECK-SAME: (ptr [[P:%.*]]) {
37; CHECK-NEXT:    [[A:%.*]] = load i32, ptr [[P]], align 4, !range [[RNG1:![0-9]+]]
38; CHECK-NEXT:    [[C:%.*]] = add i32 [[A]], [[A]]
39; CHECK-NEXT:    ret i32 [[C]]
40;
41  %a = load i32, ptr %p, !range !0
42  %b = load i32, ptr %p, !range !1
43  %c = add i32 %a, %b
44  ret i32 %c
45}
46
47define i32 @test4(ptr %p) {
48; CHECK-LABEL: define i32 @test4
49; CHECK-SAME: (ptr [[P:%.*]]) {
50; CHECK-NEXT:    [[A:%.*]] = load i32, ptr [[P]], align 4, !range [[RNG2:![0-9]+]]
51; CHECK-NEXT:    [[C:%.*]] = add i32 [[A]], [[A]]
52; CHECK-NEXT:    ret i32 [[C]]
53;
54  %a = load i32, ptr %p, !range !0
55  %b = load i32, ptr %p, !range !2
56  %c = add i32 %a, %b
57  ret i32 %c
58}
59
60define i32 @test5(ptr %p) {
61; CHECK-LABEL: define i32 @test5
62; CHECK-SAME: (ptr [[P:%.*]]) {
63; CHECK-NEXT:    [[A:%.*]] = load i32, ptr [[P]], align 4, !range [[RNG3:![0-9]+]]
64; CHECK-NEXT:    [[C:%.*]] = add i32 [[A]], [[A]]
65; CHECK-NEXT:    ret i32 [[C]]
66;
67  %a = load i32, ptr %p, !range !3
68  %b = load i32, ptr %p, !range !4
69  %c = add i32 %a, %b
70  ret i32 %c
71}
72
73define i32 @test6(ptr %p) {
74; CHECK-LABEL: define i32 @test6
75; CHECK-SAME: (ptr [[P:%.*]]) {
76; CHECK-NEXT:    [[A:%.*]] = load i32, ptr [[P]], align 4, !range [[RNG4:![0-9]+]]
77; CHECK-NEXT:    [[C:%.*]] = add i32 [[A]], [[A]]
78; CHECK-NEXT:    ret i32 [[C]]
79;
80  %a = load i32, ptr %p, !range !5
81  %b = load i32, ptr %p, !range !6
82  %c = add i32 %a, %b
83  ret i32 %c
84}
85
86define i32 @test7(ptr %p) {
87; CHECK-LABEL: define i32 @test7
88; CHECK-SAME: (ptr [[P:%.*]]) {
89; CHECK-NEXT:    [[A:%.*]] = load i32, ptr [[P]], align 4, !range [[RNG5:![0-9]+]]
90; CHECK-NEXT:    [[C:%.*]] = add i32 [[A]], [[A]]
91; CHECK-NEXT:    ret i32 [[C]]
92;
93  %a = load i32, ptr %p, !range !7
94  %b = load i32, ptr %p, !range !8
95  %c = add i32 %a, %b
96  ret i32 %c
97}
98
99define i32 @test8(ptr %p) {
100; CHECK-LABEL: define i32 @test8
101; CHECK-SAME: (ptr [[P:%.*]]) {
102; CHECK-NEXT:    [[A:%.*]] = load i32, ptr [[P]], align 4
103; CHECK-NEXT:    [[C:%.*]] = add i32 [[A]], [[A]]
104; CHECK-NEXT:    ret i32 [[C]]
105;
106  %a = load i32, ptr %p, !range !9
107  %b = load i32, ptr %p, !range !10
108  %c = add i32 %a, %b
109  ret i32 %c
110}
111
112define i32 @load_noundef_load(ptr %p) {
113; CHECK-LABEL: define i32 @load_noundef_load
114; CHECK-SAME: (ptr [[P:%.*]]) {
115; CHECK-NEXT:    [[A:%.*]] = load i32, ptr [[P]], align 4, !range [[RNG0]], !noundef !6
116; CHECK-NEXT:    [[C:%.*]] = add i32 [[A]], [[A]]
117; CHECK-NEXT:    ret i32 [[C]]
118;
119  %a = load i32, ptr %p, !range !0, !noundef !11
120  %b = load i32, ptr %p, !range !1
121  %c = add i32 %a, %b
122  ret i32 %c
123}
124
125define i32 @load_load_noundef(ptr %p) {
126; CHECK-LABEL: define i32 @load_load_noundef
127; CHECK-SAME: (ptr [[P:%.*]]) {
128; CHECK-NEXT:    [[A:%.*]] = load i32, ptr [[P]], align 4, !range [[RNG1]]
129; CHECK-NEXT:    [[C:%.*]] = add i32 [[A]], [[A]]
130; CHECK-NEXT:    ret i32 [[C]]
131;
132  %a = load i32, ptr %p, !range !0
133  %b = load i32, ptr %p, !range !1, !noundef !11
134  %c = add i32 %a, %b
135  ret i32 %c
136}
137
138define void @load_dereferenceable_dominating(ptr %p) {
139; CHECK-LABEL: define void @load_dereferenceable_dominating
140; CHECK-SAME: (ptr [[P:%.*]]) {
141; CHECK-NEXT:    [[A:%.*]] = load ptr, ptr [[P]], align 8, !dereferenceable !7
142; CHECK-NEXT:    call void @use.ptr(ptr [[A]])
143; CHECK-NEXT:    call void @use.ptr(ptr [[A]])
144; CHECK-NEXT:    ret void
145;
146  %a = load ptr, ptr %p, !dereferenceable !{i64 10}
147  %b = load ptr, ptr %p
148  call void @use.ptr(ptr %a)
149  call void @use.ptr(ptr %b)
150  ret void
151}
152
153define void @load_dereferenceable_not_dominating(ptr %p) {
154; CHECK-LABEL: define void @load_dereferenceable_not_dominating
155; CHECK-SAME: (ptr [[P:%.*]]) {
156; CHECK-NEXT:    [[A:%.*]] = load ptr, ptr [[P]], align 8
157; CHECK-NEXT:    call void @use.ptr(ptr [[A]])
158; CHECK-NEXT:    call void @use.ptr(ptr [[A]])
159; CHECK-NEXT:    ret void
160;
161  %a = load ptr, ptr %p
162  %b = load ptr, ptr %p, !dereferenceable !{i64 10}
163  call void @use.ptr(ptr %a)
164  call void @use.ptr(ptr %b)
165  ret void
166}
167
168define void @load_ptr_nonnull_to_i64(ptr %p) {
169; CHECK-LABEL: define void @load_ptr_nonnull_to_i64
170; CHECK-SAME: (ptr [[P:%.*]]) {
171; CHECK-NEXT:    [[VAL:%.*]] = load ptr, ptr [[P]], align 8
172; CHECK-NEXT:    [[VAL_INT:%.*]] = ptrtoint ptr [[VAL]] to i64
173; CHECK-NEXT:    call void @use.i64(i64 [[VAL_INT]])
174; CHECK-NEXT:    call void @use.i64(i64 [[VAL_INT]])
175; CHECK-NEXT:    ret void
176;
177  %val = load ptr, ptr %p, align 8, !nonnull !{}
178  %val.int = ptrtoint ptr %val to i64
179  %val2 = load i64, ptr %p, align 8
180  call void @use.i64(i64 %val.int)
181  call void @use.i64(i64 %val2)
182  ret void
183}
184
185define void @load_ptr_nonnull_noundef_to_i64(ptr %p) {
186; CHECK-LABEL: define void @load_ptr_nonnull_noundef_to_i64
187; CHECK-SAME: (ptr [[P:%.*]]) {
188; CHECK-NEXT:    [[VAL:%.*]] = load ptr, ptr [[P]], align 8, !nonnull !6, !noundef !6
189; CHECK-NEXT:    [[VAL_INT:%.*]] = ptrtoint ptr [[VAL]] to i64
190; CHECK-NEXT:    call void @use.i64(i64 [[VAL_INT]])
191; CHECK-NEXT:    call void @use.i64(i64 [[VAL_INT]])
192; CHECK-NEXT:    ret void
193;
194  %val = load ptr, ptr %p, align 8, !nonnull !{}, !noundef !{}
195  %val.int = ptrtoint ptr %val to i64
196  %val2 = load i64, ptr %p, align 8
197  call void @use.i64(i64 %val.int)
198  call void @use.i64(i64 %val2)
199  ret void
200}
201
202define void @load_ptr_invariant_load_to_i64(ptr %p) {
203; CHECK-LABEL: define void @load_ptr_invariant_load_to_i64
204; CHECK-SAME: (ptr [[P:%.*]]) {
205; CHECK-NEXT:    [[VAL:%.*]] = load ptr, ptr [[P]], align 8, !invariant.load !6
206; CHECK-NEXT:    [[VAL_INT:%.*]] = ptrtoint ptr [[VAL]] to i64
207; CHECK-NEXT:    call void @use.i64(i64 [[VAL_INT]])
208; CHECK-NEXT:    call void @use.i64(i64 [[VAL_INT]])
209; CHECK-NEXT:    ret void
210;
211  %val = load ptr, ptr %p, align 8, !invariant.load !{}
212  %val.int = ptrtoint ptr %val to i64
213  %val2 = load i64, ptr %p, align 8
214  call void @use.i64(i64 %val.int)
215  call void @use.i64(i64 %val2)
216  ret void
217}
218
219define void @load_ptr_dereferenceable_to_i64(ptr %p) {
220; CHECK-LABEL: define void @load_ptr_dereferenceable_to_i64
221; CHECK-SAME: (ptr [[P:%.*]]) {
222; CHECK-NEXT:    [[VAL:%.*]] = load ptr, ptr [[P]], align 8, !dereferenceable !7
223; CHECK-NEXT:    [[VAL_INT:%.*]] = ptrtoint ptr [[VAL]] to i64
224; CHECK-NEXT:    call void @use.i64(i64 [[VAL_INT]])
225; CHECK-NEXT:    call void @use.i64(i64 [[VAL_INT]])
226; CHECK-NEXT:    ret void
227;
228  %val = load ptr, ptr %p, align 8, !dereferenceable !{i64 10}
229  %val.int = ptrtoint ptr %val to i64
230  %val2 = load i64, ptr %p, align 8
231  call void @use.i64(i64 %val.int)
232  call void @use.i64(i64 %val2)
233  ret void
234}
235
236define void @load_ptr_dereferenceable_or_null_to_i64(ptr %p) {
237; CHECK-LABEL: define void @load_ptr_dereferenceable_or_null_to_i64
238; CHECK-SAME: (ptr [[P:%.*]]) {
239; CHECK-NEXT:    [[VAL:%.*]] = load ptr, ptr [[P]], align 8, !dereferenceable_or_null !7
240; CHECK-NEXT:    [[VAL_INT:%.*]] = ptrtoint ptr [[VAL]] to i64
241; CHECK-NEXT:    call void @use.i64(i64 [[VAL_INT]])
242; CHECK-NEXT:    call void @use.i64(i64 [[VAL_INT]])
243; CHECK-NEXT:    ret void
244;
245  %val = load ptr, ptr %p, align 8, !dereferenceable_or_null !{i64 10}
246  %val.int = ptrtoint ptr %val to i64
247  %val2 = load i64, ptr %p, align 8
248  call void @use.i64(i64 %val.int)
249  call void @use.i64(i64 %val2)
250  ret void
251}
252
253define void @load_ptr_nonnull_to_i32(ptr %p) {
254; CHECK-LABEL: define void @load_ptr_nonnull_to_i32
255; CHECK-SAME: (ptr [[P:%.*]]) {
256; CHECK-NEXT:    [[VAL:%.*]] = load ptr, ptr [[P]], align 8
257; CHECK-NEXT:    [[VAL_INT:%.*]] = ptrtoint ptr [[VAL]] to i64
258; CHECK-NEXT:    [[TMP1:%.*]] = trunc i64 [[VAL_INT]] to i32
259; CHECK-NEXT:    call void @use.i64(i64 [[VAL_INT]])
260; CHECK-NEXT:    call void @use.i32(i32 [[TMP1]])
261; CHECK-NEXT:    ret void
262;
263  %val = load ptr, ptr %p, align 8, !nonnull !{}
264  %val.int = ptrtoint ptr %val to i64
265  %val2 = load i32, ptr %p, align 8
266  call void @use.i64(i64 %val.int)
267  call void @use.i32(i32 %val2)
268  ret void
269}
270
271define void @load_i64_range_to_i32_range(ptr %p) {
272; CHECK-LABEL: define void @load_i64_range_to_i32_range
273; CHECK-SAME: (ptr [[P:%.*]]) {
274; CHECK-NEXT:    [[VAL:%.*]] = load i64, ptr [[P]], align 8
275; CHECK-NEXT:    [[TMP1:%.*]] = trunc i64 [[VAL]] to i32
276; CHECK-NEXT:    call void @use.i64(i64 [[VAL]])
277; CHECK-NEXT:    call void @use.i32(i32 [[TMP1]])
278; CHECK-NEXT:    ret void
279;
280  %val = load i64, ptr %p, align 8, !range !{i64 0, i64 10}
281  %val2 = load i32, ptr %p, align 8, !range !{i32 0, i32 10}
282  call void @use.i64(i64 %val)
283  call void @use.i32(i32 %val2)
284  ret void
285}
286
287define i64 @load_is_stored(ptr %p, ptr %p2) {
288; CHECK-LABEL: define i64 @load_is_stored
289; CHECK-SAME: (ptr [[P:%.*]], ptr [[P2:%.*]]) {
290; CHECK-NEXT:    [[V1:%.*]] = load i64, ptr [[P]], align 4, !range [[RNG8:![0-9]+]]
291; CHECK-NEXT:    store i64 [[V1]], ptr [[P2]], align 4
292; CHECK-NEXT:    ret i64 [[V1]]
293;
294  %v1 = load i64, ptr %p, !range !{i64 0, i64 10}
295  store i64 %v1, ptr %p2
296  %v2 = load i64, ptr %p2
297  ret i64 %v2
298}
299
300define void @non_local_dominating(i1 %c, ptr %p) {
301; CHECK-LABEL: define void @non_local_dominating
302; CHECK-SAME: (i1 [[C:%.*]], ptr [[P:%.*]]) {
303; CHECK-NEXT:    [[V1:%.*]] = load i64, ptr [[P]], align 4, !range [[RNG9:![0-9]+]]
304; CHECK-NEXT:    br i1 [[C]], label [[IF:%.*]], label [[JOIN:%.*]]
305; CHECK:       if:
306; CHECK-NEXT:    br label [[JOIN]]
307; CHECK:       join:
308; CHECK-NEXT:    call void @use.i64(i64 [[V1]])
309; CHECK-NEXT:    call void @use.i64(i64 [[V1]])
310; CHECK-NEXT:    ret void
311;
312  %v1 = load i64, ptr %p, !range !{i64 0, i64 10}
313  br i1 %c, label %if, label %join
314
315if:
316  br label %join
317
318join:
319  %v2 = load i64, ptr %p, !range !{i64 20, i64 30}
320  call void @use.i64(i64 %v1)
321  call void @use.i64(i64 %v2)
322  ret void
323}
324
325define void @non_local_non_dominating(i1 %c, ptr %p) {
326; CHECK-LABEL: define void @non_local_non_dominating
327; CHECK-SAME: (i1 [[C:%.*]], ptr [[P:%.*]]) {
328; CHECK-NEXT:    br i1 [[C]], label [[IF:%.*]], label [[ELSE:%.*]]
329; CHECK:       if:
330; CHECK-NEXT:    [[V1:%.*]] = load i64, ptr [[P]], align 4, !range [[RNG9]]
331; CHECK-NEXT:    call void @use.i64(i64 [[V1]])
332; CHECK-NEXT:    br label [[JOIN:%.*]]
333; CHECK:       else:
334; CHECK-NEXT:    [[V2:%.*]] = load i64, ptr [[P]], align 4, !range [[RNG10:![0-9]+]]
335; CHECK-NEXT:    call void @use.i64(i64 [[V2]])
336; CHECK-NEXT:    br label [[JOIN]]
337; CHECK:       join:
338; CHECK-NEXT:    [[V3:%.*]] = phi i64 [ [[V2]], [[ELSE]] ], [ [[V1]], [[IF]] ]
339; CHECK-NEXT:    call void @use.i64(i64 [[V3]])
340; CHECK-NEXT:    ret void
341;
342  br i1 %c, label %if, label %else
343
344if:
345  %v1 = load i64, ptr %p, !range !{i64 0, i64 10}
346  call void @use.i64(i64 %v1)
347  br label %join
348
349else:
350  %v2 = load i64, ptr %p, !range !{i64 10, i64 20}
351  call void @use.i64(i64 %v2)
352  br label %join
353
354join:
355  %v3 = load i64, ptr %p, !range !{i64 20, i64 30}
356  call void @use.i64(i64 %v3)
357  ret void
358}
359
360define void @non_local_coerced(i1 %c, ptr %p) {
361; CHECK-LABEL: define void @non_local_coerced
362; CHECK-SAME: (i1 [[C:%.*]], ptr [[P:%.*]]) {
363; CHECK-NEXT:    [[V1_PTR:%.*]] = load ptr, ptr [[P]], align 8
364; CHECK-NEXT:    [[V1:%.*]] = ptrtoint ptr [[V1_PTR]] to i64
365; CHECK-NEXT:    br i1 [[C]], label [[IF:%.*]], label [[JOIN:%.*]]
366; CHECK:       if:
367; CHECK-NEXT:    br label [[JOIN]]
368; CHECK:       join:
369; CHECK-NEXT:    call void @use.i64(i64 [[V1]])
370; CHECK-NEXT:    call void @use.i64(i64 [[V1]])
371; CHECK-NEXT:    ret void
372;
373  %v1.ptr = load ptr, ptr %p, !nonnull !{}
374  %v1 = ptrtoint ptr %v1.ptr to i64
375  br i1 %c, label %if, label %join
376
377if:
378  br label %join
379
380join:
381  %v2 = load i64, ptr %p, !range !{i64 20, i64 30}
382  call void @use.i64(i64 %v1)
383  call void @use.i64(i64 %v2)
384  ret void
385}
386
387define void @non_local_pre(i1 %c, ptr %p) {
388; CHECK-LABEL: define void @non_local_pre
389; CHECK-SAME: (i1 [[C:%.*]], ptr [[P:%.*]]) {
390; CHECK-NEXT:    [[V2_PRE:%.*]] = load i64, ptr [[P]], align 4, !range [[RNG9]]
391; CHECK-NEXT:    br i1 [[C]], label [[IF:%.*]], label [[JOIN:%.*]]
392; CHECK:       if:
393; CHECK-NEXT:    call void @use.i64(i64 [[V2_PRE]])
394; CHECK-NEXT:    br label [[JOIN]]
395; CHECK:       join:
396; CHECK-NEXT:    call void @use.i64(i64 [[V2_PRE]])
397; CHECK-NEXT:    ret void
398;
399  br i1 %c, label %if, label %join
400
401if:
402  %v1 = load i64, ptr %p, !range !{i64 0, i64 10}
403  call void @use.i64(i64 %v1)
404  br label %join
405
406join:
407  %v2 = load i64, ptr %p, !range !{i64 20, i64 30}
408  call void @use.i64(i64 %v2)
409  ret void
410}
411
412!0 = !{i32 0, i32 2}
413!1 = !{i32 3, i32 5}
414!2 = !{i32 2, i32 5}
415!3 = !{i32 -5, i32 -2}
416!4 = !{i32 1, i32 5}
417!5 = !{i32 10, i32 1}
418!6 = !{i32 12, i32 16}
419!7 = !{i32 1, i32 2, i32 3, i32 4}
420!8 = !{i32 5, i32 1}
421!9 = !{i32 1, i32 5}
422!10 = !{i32 5, i32 1}
423!11 = !{}
424;.
425; CHECK: attributes #[[ATTR0:[0-9]+]] = { memory(none) }
426;.
427; CHECK: [[RNG0]] = !{i32 0, i32 2}
428; CHECK: [[RNG1]] = !{i32 0, i32 2, i32 3, i32 5}
429; CHECK: [[RNG2]] = !{i32 0, i32 5}
430; CHECK: [[RNG3]] = !{i32 -5, i32 -2, i32 1, i32 5}
431; CHECK: [[RNG4]] = !{i32 10, i32 1}
432; CHECK: [[RNG5]] = !{i32 3, i32 4, i32 5, i32 2}
433; CHECK: [[META6:![0-9]+]] = !{}
434; CHECK: [[META7:![0-9]+]] = !{i64 10}
435; CHECK: [[RNG8]] = !{i64 0, i64 10}
436; CHECK: [[RNG9]] = !{i64 0, i64 10, i64 20, i64 30}
437; CHECK: [[RNG10]] = !{i64 10, i64 30}
438;.
439