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