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
4 declare void @use.ptr(ptr) memory(none)
5 declare void @use.i64(i64) memory(none)
6 declare void @use.i32(i32) memory(none)
8 define 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]]
15 %a = load i32, ptr %p, !range !0
16 %b = load i32, ptr %p, !range !0
21 define 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]]
28 %a = load i32, ptr %p, !range !0
34 define 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]]
41 %a = load i32, ptr %p, !range !0
42 %b = load i32, ptr %p, !range !1
47 define 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]]
54 %a = load i32, ptr %p, !range !0
55 %b = load i32, ptr %p, !range !2
60 define 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]]
67 %a = load i32, ptr %p, !range !3
68 %b = load i32, ptr %p, !range !4
73 define 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]]
80 %a = load i32, ptr %p, !range !5
81 %b = load i32, ptr %p, !range !6
86 define 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]]
93 %a = load i32, ptr %p, !range !7
94 %b = load i32, ptr %p, !range !8
99 define 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]]
106 %a = load i32, ptr %p, !range !9
107 %b = load i32, ptr %p, !range !10
112 define 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]]
119 %a = load i32, ptr %p, !range !0, !noundef !11
120 %b = load i32, ptr %p, !range !1
125 define 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]]
132 %a = load i32, ptr %p, !range !0
133 %b = load i32, ptr %p, !range !1, !noundef !11
138 define 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
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)
153 define 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
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)
168 define 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
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)
185 define 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
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)
202 define 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
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)
219 define 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
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)
236 define 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
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)
253 define 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
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)
271 define 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
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)
287 define 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]]
294 %v1 = load i64, ptr %p, !range !{i64 0, i64 10}
295 store i64 %v1, ptr %p2
296 %v2 = load i64, ptr %p2
300 define 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:%.*]]
306 ; CHECK-NEXT: br label [[JOIN]]
308 ; CHECK-NEXT: call void @use.i64(i64 [[V1]])
309 ; CHECK-NEXT: call void @use.i64(i64 [[V1]])
310 ; CHECK-NEXT: ret void
312 %v1 = load i64, ptr %p, !range !{i64 0, i64 10}
313 br i1 %c, label %if, label %join
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)
325 define 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:%.*]]
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:%.*]]
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]]
338 ; CHECK-NEXT: [[V3:%.*]] = phi i64 [ [[V2]], [[ELSE]] ], [ [[V1]], [[IF]] ]
339 ; CHECK-NEXT: call void @use.i64(i64 [[V3]])
340 ; CHECK-NEXT: ret void
342 br i1 %c, label %if, label %else
345 %v1 = load i64, ptr %p, !range !{i64 0, i64 10}
346 call void @use.i64(i64 %v1)
350 %v2 = load i64, ptr %p, !range !{i64 10, i64 20}
351 call void @use.i64(i64 %v2)
355 %v3 = load i64, ptr %p, !range !{i64 20, i64 30}
356 call void @use.i64(i64 %v3)
360 define 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:%.*]]
367 ; CHECK-NEXT: br label [[JOIN]]
369 ; CHECK-NEXT: call void @use.i64(i64 [[V1]])
370 ; CHECK-NEXT: call void @use.i64(i64 [[V1]])
371 ; CHECK-NEXT: ret void
373 %v1.ptr = load ptr, ptr %p, !nonnull !{}
374 %v1 = ptrtoint ptr %v1.ptr to i64
375 br i1 %c, label %if, label %join
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)
387 define 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:%.*]]
393 ; CHECK-NEXT: call void @use.i64(i64 [[V2_PRE]])
394 ; CHECK-NEXT: br label [[JOIN]]
396 ; CHECK-NEXT: call void @use.i64(i64 [[V2_PRE]])
397 ; CHECK-NEXT: ret void
399 br i1 %c, label %if, label %join
402 %v1 = load i64, ptr %p, !range !{i64 0, i64 10}
403 call void @use.i64(i64 %v1)
407 %v2 = load i64, ptr %p, !range !{i64 20, i64 30}
408 call void @use.i64(i64 %v2)
415 !3 = !{i32 -5, i32 -2}
417 !5 = !{i32 10, i32 1}
418 !6 = !{i32 12, i32 16}
419 !7 = !{i32 1, i32 2, i32 3, i32 4}
422 !10 = !{i32 5, i32 1}
425 ; CHECK: attributes #[[ATTR0:[0-9]+]] = { memory(none) }
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}