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