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