[rtsan] Add fork/execve interceptors (#117198)
[llvm-project.git] / llvm / test / Transforms / InferFunctionAttrs / dereferenceable.ll
bloba42cebda1e993a4b2d186ed404aa79cd70352598
1 ; RUN: opt < %s -passes=inferattrs -S | FileCheck %s
5 ; Determine dereference-ability before unused loads get deleted:
6 ; https://bugs.llvm.org/show_bug.cgi?id=21780
8 define <4 x double> @PR21780(ptr %ptr) {
9 ; CHECK-LABEL: @PR21780(ptr %ptr)
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
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
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
30 define double @PR21780_only_access3_with_inbounds(ptr %ptr) {
31 ; CHECK-LABEL: @PR21780_only_access3_with_inbounds(ptr %ptr)
33   %arrayidx3 = getelementptr inbounds double, ptr %ptr, i64 3
34   %t3 = load double, ptr %arrayidx3, align 8
35   ret double %t3
38 define 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
45 define double @PR21780_without_inbounds(ptr %ptr) {
46 ; CHECK-LABEL: @PR21780_without_inbounds(ptr %ptr)
48   %arrayidx1 = getelementptr double, ptr %ptr, i64 1
49   %arrayidx2 = getelementptr double, ptr %ptr, i64 2
50   %arrayidx3 = getelementptr double, ptr %ptr, i64 3
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
57   ret double %t3
60 ; Unsimplified, but still valid. Also, throw in some bogus arguments.
62 define 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
73 ; Order of accesses does not change computation.
74 ; Multiple arguments may be dereferenceable.
76 define 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
89 ; Not in entry block.
91 define void @not_entry_but_guaranteed_to_execute(ptr %ptr) {
92 ; CHECK-LABEL: @not_entry_but_guaranteed_to_execute(ptr %ptr)
93 entry:
94   br label %exit
95 exit:
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
104 ; Not in entry block and not guaranteed to execute.
106 define void @not_entry_not_guaranteed_to_execute(ptr %ptr, i1 %cond) {
107 ; CHECK-LABEL: @not_entry_not_guaranteed_to_execute(ptr %ptr, i1 %cond)
108 entry:
109   br i1 %cond, label %loads, label %exit
110 loads:
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
117 exit:
118   ret void
121 ; The last load may not execute, so derefenceable bytes only covers the 1st two loads.
123 define void @partial_in_entry(ptr %ptr, i1 %cond) {
124 ; CHECK-LABEL: @partial_in_entry(ptr %ptr, i1 %cond)
125 entry:
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
131 loads:
132   %t2 = load i16, ptr %arrayidx2
133   ret void
134 exit:
135   ret void
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.
141 define 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
151 ; TODO: We should allow inference for atomic (but not volatile) ops.
153 define 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
163 declare void @may_not_return()
165 define 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
176 ; We must have consecutive accesses.
178 define 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
188 ; Deal with >1 GEP index.
190 define 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
197 ; Could round weird bitwidths down?
199 define void @not_byte_multiple(ptr %ptr) {
200 ; CHECK-LABEL: @not_byte_multiple(ptr %ptr)
201   %t0 = load i9, ptr %ptr
202   ret void
205 ; Missing direct access from the pointer.
207 define 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
216 ; Out-of-order is ok, but missing access concludes dereferenceable range.
218 define 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
228 ; Improve on existing dereferenceable attribute.
230 define 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
242 ; Improve on existing dereferenceable_or_null attribute.
244 define 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
256 ; But don't pessimize existing dereferenceable attribute.
258 define 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
270 define 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
278 define 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
286   %a21 = getelementptr i64, ptr %arg2, i64 1
287   %ld20 = load i64, ptr %arg2
288   %ld21 = load i64, ptr %a21
289   ret void
292 define 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
300 define 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
308 define 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
316 define 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
323 define 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