xref: /llvm-project/llvm/test/Transforms/InferFunctionAttrs/dereferenceable.ll (revision f5e03912e766dcb43fa6c71f990068cee259bb31)
1; RUN: opt < %s -passes=inferattrs -S | FileCheck %s
2
3
4
5; Determine dereference-ability before unused loads get deleted:
6; https://bugs.llvm.org/show_bug.cgi?id=21780
7
8define <4 x double> @PR21780(ptr %ptr) {
9; CHECK-LABEL: @PR21780(ptr %ptr)
10
11  ; GEP of index 0 is simplified away.
12  %arrayidx1 = getelementptr inbounds double, ptr %ptr, i64 1
13  %arrayidx2 = getelementptr inbounds double, ptr %ptr, i64 2
14  %arrayidx3 = getelementptr inbounds double, ptr %ptr, i64 3
15
16  %t0 = load double, ptr %ptr, align 8
17  %t1 = load double, ptr %arrayidx1, align 8
18  %t2 = load double, ptr %arrayidx2, align 8
19  %t3 = load double, ptr %arrayidx3, align 8
20
21  %vecinit0 = insertelement <4 x double> undef, double %t0, i32 0
22  %vecinit1 = insertelement <4 x double> %vecinit0, double %t1, i32 1
23  %vecinit2 = insertelement <4 x double> %vecinit1, double %t2, i32 2
24  %vecinit3 = insertelement <4 x double> %vecinit2, double %t3, i32 3
25  %shuffle = shufflevector <4 x double> %vecinit3, <4 x double> %vecinit3, <4 x i32> <i32 0, i32 0, i32 2, i32 2>
26  ret <4 x double> %shuffle
27}
28
29
30define double @PR21780_only_access3_with_inbounds(ptr %ptr) {
31; CHECK-LABEL: @PR21780_only_access3_with_inbounds(ptr %ptr)
32
33  %arrayidx3 = getelementptr inbounds double, ptr %ptr, i64 3
34  %t3 = load double, ptr %arrayidx3, align 8
35  ret double %t3
36}
37
38define double @PR21780_only_access3_without_inbounds(ptr %ptr) {
39; CHECK-LABEL: @PR21780_only_access3_without_inbounds(ptr %ptr)
40  %arrayidx3 = getelementptr double, ptr %ptr, i64 3
41  %t3 = load double, ptr %arrayidx3, align 8
42  ret double %t3
43}
44
45define double @PR21780_without_inbounds(ptr %ptr) {
46; CHECK-LABEL: @PR21780_without_inbounds(ptr %ptr)
47
48  %arrayidx1 = getelementptr double, ptr %ptr, i64 1
49  %arrayidx2 = getelementptr double, ptr %ptr, i64 2
50  %arrayidx3 = getelementptr double, ptr %ptr, i64 3
51
52  %t0 = load double, ptr %ptr, align 8
53  %t1 = load double, ptr %arrayidx1, align 8
54  %t2 = load double, ptr %arrayidx2, align 8
55  %t3 = load double, ptr %arrayidx3, align 8
56
57  ret double %t3
58}
59
60; Unsimplified, but still valid. Also, throw in some bogus arguments.
61
62define void @gep0(ptr %unused, ptr %other, ptr %ptr) {
63; CHECK-LABEL: @gep0(ptr %unused, ptr %other, ptr %ptr)
64  %arrayidx1 = getelementptr i8, ptr %ptr, i64 1
65  %arrayidx2 = getelementptr i8, ptr %ptr, i64 2
66  %t0 = load i8, ptr %ptr
67  %t1 = load i8, ptr %arrayidx1
68  %t2 = load i8, ptr %arrayidx2
69  store i8 %t2, ptr %other
70  ret void
71}
72
73; Order of accesses does not change computation.
74; Multiple arguments may be dereferenceable.
75
76define void @ordering(ptr %ptr1, ptr %ptr2) {
77; CHECK-LABEL: @ordering(ptr %ptr1, ptr %ptr2)
78  %a12 = getelementptr i8, ptr %ptr1, i64 2
79  %t12 = load i8, ptr %a12
80  %a11 = getelementptr i8, ptr %ptr1, i64 1
81  %t20 = load i32, ptr %ptr2
82  %t10 = load i8, ptr %ptr1
83  %t11 = load i8, ptr %a11
84  %a21 = getelementptr i32, ptr %ptr2, i64 1
85  %t21 = load i32, ptr %a21
86  ret void
87}
88
89; Not in entry block.
90
91define void @not_entry_but_guaranteed_to_execute(ptr %ptr) {
92; CHECK-LABEL: @not_entry_but_guaranteed_to_execute(ptr %ptr)
93entry:
94  br label %exit
95exit:
96  %arrayidx1 = getelementptr i8, ptr %ptr, i64 1
97  %arrayidx2 = getelementptr i8, ptr %ptr, i64 2
98  %t0 = load i8, ptr %ptr
99  %t1 = load i8, ptr %arrayidx1
100  %t2 = load i8, ptr %arrayidx2
101  ret void
102}
103
104; Not in entry block and not guaranteed to execute.
105
106define void @not_entry_not_guaranteed_to_execute(ptr %ptr, i1 %cond) {
107; CHECK-LABEL: @not_entry_not_guaranteed_to_execute(ptr %ptr, i1 %cond)
108entry:
109  br i1 %cond, label %loads, label %exit
110loads:
111  %arrayidx1 = getelementptr i8, ptr %ptr, i64 1
112  %arrayidx2 = getelementptr i8, ptr %ptr, i64 2
113  %t0 = load i8, ptr %ptr
114  %t1 = load i8, ptr %arrayidx1
115  %t2 = load i8, ptr %arrayidx2
116  ret void
117exit:
118  ret void
119}
120
121; The last load may not execute, so derefenceable bytes only covers the 1st two loads.
122
123define void @partial_in_entry(ptr %ptr, i1 %cond) {
124; CHECK-LABEL: @partial_in_entry(ptr %ptr, i1 %cond)
125entry:
126  %arrayidx1 = getelementptr i16, ptr %ptr, i64 1
127  %arrayidx2 = getelementptr i16, ptr %ptr, i64 2
128  %t0 = load i16, ptr %ptr
129  %t1 = load i16, ptr %arrayidx1
130  br i1 %cond, label %loads, label %exit
131loads:
132  %t2 = load i16, ptr %arrayidx2
133  ret void
134exit:
135  ret void
136}
137
138; The volatile load can't be used to prove a non-volatile access is allowed.
139; The 2nd and 3rd loads may never execute.
140
141define void @volatile_is_not_dereferenceable(ptr %ptr) {
142; CHECK-LABEL: @volatile_is_not_dereferenceable(ptr %ptr)
143  %arrayidx1 = getelementptr i16, ptr %ptr, i64 1
144  %arrayidx2 = getelementptr i16, ptr %ptr, i64 2
145  %t0 = load volatile i16, ptr %ptr
146  %t1 = load i16, ptr %arrayidx1
147  %t2 = load i16, ptr %arrayidx2
148  ret void
149}
150
151; TODO: We should allow inference for atomic (but not volatile) ops.
152
153define void @atomic_is_alright(ptr %ptr) {
154; CHECK-LABEL: @atomic_is_alright(ptr %ptr)
155  %arrayidx1 = getelementptr i16, ptr %ptr, i64 1
156  %arrayidx2 = getelementptr i16, ptr %ptr, i64 2
157  %t0 = load atomic i16, ptr %ptr unordered, align 2
158  %t1 = load i16, ptr %arrayidx1
159  %t2 = load i16, ptr %arrayidx2
160  ret void
161}
162
163declare void @may_not_return()
164
165define void @not_guaranteed_to_transfer_execution(ptr %ptr) {
166; CHECK-LABEL: @not_guaranteed_to_transfer_execution(ptr %ptr)
167  %arrayidx1 = getelementptr i16, ptr %ptr, i64 1
168  %arrayidx2 = getelementptr i16, ptr %ptr, i64 2
169  %t0 = load i16, ptr %ptr
170  call void @may_not_return()
171  %t1 = load i16, ptr %arrayidx1
172  %t2 = load i16, ptr %arrayidx2
173  ret void
174}
175
176; We must have consecutive accesses.
177
178define void @variable_gep_index(ptr %unused, ptr %ptr, i64 %variable_index) {
179; CHECK-LABEL: @variable_gep_index(ptr %unused, ptr %ptr, i64 %variable_index)
180  %arrayidx1 = getelementptr i8, ptr %ptr, i64 %variable_index
181  %arrayidx2 = getelementptr i8, ptr %ptr, i64 2
182  %t0 = load i8, ptr %ptr
183  %t1 = load i8, ptr %arrayidx1
184  %t2 = load i8, ptr %arrayidx2
185  ret void
186}
187
188; Deal with >1 GEP index.
189
190define void @multi_index_gep(ptr %ptr) {
191; CHECK-LABEL: @multi_index_gep(ptr %ptr)
192; FIXME: %ptr should be dereferenceable(4)
193  %t0 = load i8, ptr %ptr
194  ret void
195}
196
197; Could round weird bitwidths down?
198
199define void @not_byte_multiple(ptr %ptr) {
200; CHECK-LABEL: @not_byte_multiple(ptr %ptr)
201  %t0 = load i9, ptr %ptr
202  ret void
203}
204
205; Missing direct access from the pointer.
206
207define void @no_pointer_deref(ptr %ptr) {
208; CHECK-LABEL: @no_pointer_deref(ptr %ptr)
209  %arrayidx1 = getelementptr i16, ptr %ptr, i64 1
210  %arrayidx2 = getelementptr i16, ptr %ptr, i64 2
211  %t1 = load i16, ptr %arrayidx1
212  %t2 = load i16, ptr %arrayidx2
213  ret void
214}
215
216; Out-of-order is ok, but missing access concludes dereferenceable range.
217
218define void @non_consecutive(ptr %ptr) {
219; CHECK-LABEL: @non_consecutive(ptr %ptr)
220  %arrayidx1 = getelementptr i32, ptr %ptr, i64 1
221  %arrayidx3 = getelementptr i32, ptr %ptr, i64 3
222  %t1 = load i32, ptr %arrayidx1
223  %t0 = load i32, ptr %ptr
224  %t3 = load i32, ptr %arrayidx3
225  ret void
226}
227
228; Improve on existing dereferenceable attribute.
229
230define void @more_bytes(ptr dereferenceable(8) %ptr) {
231; CHECK-LABEL: @more_bytes(ptr dereferenceable(8) %ptr)
232  %arrayidx3 = getelementptr i32, ptr %ptr, i64 3
233  %arrayidx1 = getelementptr i32, ptr %ptr, i64 1
234  %arrayidx2 = getelementptr i32, ptr %ptr, i64 2
235  %t3 = load i32, ptr %arrayidx3
236  %t1 = load i32, ptr %arrayidx1
237  %t2 = load i32, ptr %arrayidx2
238  %t0 = load i32, ptr %ptr
239  ret void
240}
241
242; Improve on existing dereferenceable_or_null attribute.
243
244define void @more_bytes_and_not_null(ptr dereferenceable_or_null(8) %ptr) {
245; CHECK-LABEL: @more_bytes_and_not_null(ptr dereferenceable_or_null(8) %ptr)
246  %arrayidx3 = getelementptr i32, ptr %ptr, i64 3
247  %arrayidx1 = getelementptr i32, ptr %ptr, i64 1
248  %arrayidx2 = getelementptr i32, ptr %ptr, i64 2
249  %t3 = load i32, ptr %arrayidx3
250  %t1 = load i32, ptr %arrayidx1
251  %t2 = load i32, ptr %arrayidx2
252  %t0 = load i32, ptr %ptr
253  ret void
254}
255
256; But don't pessimize existing dereferenceable attribute.
257
258define void @better_bytes(ptr dereferenceable(100) %ptr) {
259; CHECK-LABEL: @better_bytes(ptr dereferenceable(100) %ptr)
260  %arrayidx3 = getelementptr i32, ptr %ptr, i64 3
261  %arrayidx1 = getelementptr i32, ptr %ptr, i64 1
262  %arrayidx2 = getelementptr i32, ptr %ptr, i64 2
263  %t3 = load i32, ptr %arrayidx3
264  %t1 = load i32, ptr %arrayidx1
265  %t2 = load i32, ptr %arrayidx2
266  %t0 = load i32, ptr %ptr
267  ret void
268}
269
270define void @bitcast(ptr %arg) {
271; CHECK-LABEL: @bitcast(ptr %arg)
272  %arrayidx1 = getelementptr float, ptr %arg, i64 1
273  %t0 = load float, ptr %arg
274  %t1 = load float, ptr %arrayidx1
275  ret void
276}
277
278define void @bitcast_different_sizes(ptr %arg1, ptr %arg2) {
279; CHECK-LABEL: @bitcast_different_sizes(ptr %arg1, ptr %arg2)
280  %a11 = getelementptr float, ptr %arg1, i64 1
281  %a12 = getelementptr float, ptr %arg1, i64 2
282  %ld10 = load float, ptr %arg1
283  %ld11 = load float, ptr %a11
284  %ld12 = load float, ptr %a12
285
286  %a21 = getelementptr i64, ptr %arg2, i64 1
287  %ld20 = load i64, ptr %arg2
288  %ld21 = load i64, ptr %a21
289  ret void
290}
291
292define void @negative_offset(ptr %arg) {
293; CHECK-LABEL: @negative_offset(ptr %arg)
294  %arrayidx1 = getelementptr float, ptr %arg, i64 -1
295  %t0 = load float, ptr %arg
296  %t1 = load float, ptr %arrayidx1
297  ret void
298}
299
300define void @stores(ptr %arg) {
301; CHECK-LABEL: @stores(ptr %arg)
302  %arrayidx1 = getelementptr float, ptr %arg, i64 1
303  store float 1.0, ptr %arg
304  store float 2.0, ptr %arrayidx1
305  ret void
306}
307
308define void @load_store(ptr %arg) {
309; CHECK-LABEL: @load_store(ptr %arg)
310  %arrayidx1 = getelementptr float, ptr %arg, i64 1
311  %t1 = load float, ptr %arg
312  store float 2.0, ptr %arrayidx1
313  ret void
314}
315
316define void @different_size1(ptr %arg) {
317; CHECK-LABEL: @different_size1(ptr %arg)
318  store double 0.000000e+00, ptr %arg
319  store i32 0, ptr %arg
320  ret void
321}
322
323define void @different_size2(ptr %arg) {
324; CHECK-LABEL: @different_size2(ptr %arg)
325  store i32 0, ptr %arg
326  store double 0.000000e+00, ptr %arg
327  ret void
328}
329