xref: /llvm-project/mlir/test/Dialect/LLVMIR/sroa.mlir (revision 63d22f7a5b6afc515799f67c388bf5a8864274e4)
1// RUN: mlir-opt %s --pass-pipeline="builtin.module(llvm.func(sroa))" --split-input-file | FileCheck %s
2
3// CHECK-LABEL: llvm.func @basic_struct
4llvm.func @basic_struct() -> i32 {
5  // CHECK: %[[SIZE:.*]] = llvm.mlir.constant(1 : i32)
6  %0 = llvm.mlir.constant(1 : i32) : i32
7  // CHECK: %[[ALLOCA:.*]] = llvm.alloca %[[SIZE]] x i32
8  %1 = llvm.alloca %0 x !llvm.struct<"foo", (i32, f64, i32)> {alignment = 8 : i64} : (i32) -> !llvm.ptr
9  %2 = llvm.getelementptr inbounds %1[0, 2] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", (i32, f64, i32)>
10  // CHECK: %[[RES:.*]] = llvm.load %[[ALLOCA]]
11  %3 = llvm.load %2 : !llvm.ptr -> i32
12  // CHECK: llvm.return %[[RES]] : i32
13  llvm.return %3 : i32
14}
15
16// -----
17
18// CHECK-LABEL: llvm.func @basic_array
19llvm.func @basic_array() -> i32 {
20  // CHECK: %[[SIZE:.*]] = llvm.mlir.constant(1 : i32)
21  %0 = llvm.mlir.constant(1 : i32) : i32
22  // CHECK: %[[ALLOCA:.*]] = llvm.alloca %[[SIZE]] x i32
23  %1 = llvm.alloca %0 x !llvm.array<10 x i32> {alignment = 8 : i64} : (i32) -> !llvm.ptr
24  %2 = llvm.getelementptr inbounds %1[0, 2] : (!llvm.ptr) -> !llvm.ptr, !llvm.array<10 x i32>
25  // CHECK: %[[RES:.*]] = llvm.load %[[ALLOCA]]
26  %3 = llvm.load %2 : !llvm.ptr -> i32
27  // CHECK: llvm.return %[[RES]] : i32
28  llvm.return %3 : i32
29}
30
31// -----
32
33// CHECK-LABEL: llvm.func @multi_level_direct
34llvm.func @multi_level_direct() -> i32 {
35  // CHECK: %[[SIZE:.*]] = llvm.mlir.constant(1 : i32)
36  %0 = llvm.mlir.constant(1 : i32) : i32
37  // CHECK: %[[ALLOCA:.*]] = llvm.alloca %[[SIZE]] x i32
38  %1 = llvm.alloca %0 x !llvm.struct<"foo", (i32, f64, struct<"bar", (i8, array<10 x array<10 x i32>>, i8)>)> {alignment = 8 : i64} : (i32) -> !llvm.ptr
39  %2 = llvm.getelementptr inbounds %1[0, 2, 1, 5, 8] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", (i32, f64, struct<"bar", (i8, array<10 x array<10 x i32>>, i8)>)>
40  // CHECK: %[[RES:.*]] = llvm.load %[[ALLOCA]]
41  %3 = llvm.load %2 : !llvm.ptr -> i32
42  // CHECK: llvm.return %[[RES]] : i32
43  llvm.return %3 : i32
44}
45
46// -----
47
48// The first application of SROA would generate a GEP with indices [0, 0]. This
49// test ensures this GEP is not eliminated during the first application. Even
50// though doing it would be correct, it would prevent the second application
51// of SROA to eliminate the array. GEPs should be eliminated only when they are
52// truly trivial (with indices [0]).
53
54// CHECK-LABEL: llvm.func @multi_level_direct_two_applications
55llvm.func @multi_level_direct_two_applications() -> i32 {
56  // CHECK: %[[SIZE:.*]] = llvm.mlir.constant(1 : i32)
57  %0 = llvm.mlir.constant(1 : i32) : i32
58  // CHECK: %[[ALLOCA:.*]] = llvm.alloca %[[SIZE]] x i32
59  %1 = llvm.alloca %0 x !llvm.struct<"foo", (i32, f64, array<10 x i32>, i8)> {alignment = 8 : i64} : (i32) -> !llvm.ptr
60  %2 = llvm.getelementptr inbounds %1[0, 2, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", (i32, f64, array<10 x i32>, i8)>
61  // CHECK: %[[RES:.*]] = llvm.load %[[ALLOCA]]
62  %3 = llvm.load %2 : !llvm.ptr -> i32
63  // CHECK: llvm.return %[[RES]] : i32
64  llvm.return %3 : i32
65}
66
67// -----
68
69// CHECK-LABEL: llvm.func @multi_level_indirect
70llvm.func @multi_level_indirect() -> i32 {
71  // CHECK: %[[SIZE:.*]] = llvm.mlir.constant(1 : i32)
72  %0 = llvm.mlir.constant(1 : i32) : i32
73  // CHECK: %[[ALLOCA:.*]] = llvm.alloca %[[SIZE]] x i32
74  %1 = llvm.alloca %0 x !llvm.struct<"foo", (i32, f64, struct<"bar", (i8, array<10 x array<10 x i32>>, i8)>)> {alignment = 8 : i64} : (i32) -> !llvm.ptr
75  %2 = llvm.getelementptr inbounds %1[0, 2, 1, 5] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", (i32, f64, struct<"bar", (i8, array<10 x array<10 x i32>>, i8)>)>
76  %3 = llvm.getelementptr inbounds %2[0, 8] : (!llvm.ptr) -> !llvm.ptr, !llvm.array<10 x i32>
77  // CHECK: %[[RES:.*]] = llvm.load %[[ALLOCA]]
78  %4 = llvm.load %3 : !llvm.ptr -> i32
79  // CHECK: llvm.return %[[RES]] : i32
80  llvm.return %4 : i32
81}
82
83// -----
84
85// This verifies that a nested GEP's users are checked properly. In this case
86// the load goes over the bounds of the memory slot and thus should block the
87// splitting of the alloca.
88
89// CHECK-LABEL: llvm.func @nested_access_over_slot_bound
90llvm.func @nested_access_over_slot_bound() -> i64 {
91  %0 = llvm.mlir.constant(1 : i32) : i32
92  // CHECK: %[[ALLOCA:.*]] = llvm.alloca %{{.*}} x !llvm.struct<(i32, struct<(
93  %1 = llvm.alloca %0 x !llvm.struct<(i32, struct<(array<10 x i32>)>, i32)> {alignment = 8 : i64} : (i32) -> !llvm.ptr
94  // CHECK: %[[GEP0:.*]] = llvm.getelementptr inbounds %[[ALLOCA]]
95  %2 = llvm.getelementptr inbounds %1[0, 1, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(i32, struct<(array<10 x i32>)>, i32)>
96  // CHECK: %[[GEP1:.*]] = llvm.getelementptr inbounds %[[GEP0]]
97  %3 = llvm.getelementptr inbounds %2[0, 9] : (!llvm.ptr) -> !llvm.ptr, !llvm.array<10 x i32>
98  // CHECK: %[[RES:.*]] = llvm.load %[[GEP1]]
99  %4 = llvm.load %3 : !llvm.ptr -> i64
100  // CHECK: llvm.return %[[RES]] : i64
101  llvm.return %4 : i64
102}
103
104// -----
105
106// CHECK-LABEL: llvm.func @resolve_alias
107// CHECK-SAME: (%[[ARG:.*]]: i32)
108llvm.func @resolve_alias(%arg: i32) -> i32 {
109  // CHECK: %[[SIZE:.*]] = llvm.mlir.constant(1 : i32)
110  %0 = llvm.mlir.constant(1 : i32) : i32
111  // CHECK: %[[ALLOCA:.*]] = llvm.alloca %[[SIZE]] x i32
112  %1 = llvm.alloca %0 x !llvm.struct<"foo", (i32, f64, i32)> {alignment = 8 : i64} : (i32) -> !llvm.ptr
113  %2 = llvm.getelementptr %1[0, 2] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", (i32, f64, i32)>
114  %3 = llvm.getelementptr inbounds %1[0, 2] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", (i32, f64, i32)>
115  // CHECK: llvm.store %[[ARG]], %[[ALLOCA]]
116  llvm.store %arg, %2 : i32, !llvm.ptr
117  // CHECK: %[[RES:.*]] = llvm.load %[[ALLOCA]]
118  %4 = llvm.load %3 : !llvm.ptr -> i32
119  // CHECK: llvm.return %[[RES]] : i32
120  llvm.return %4 : i32
121}
122
123// -----
124
125// CHECK-LABEL: llvm.func @no_non_single_support
126llvm.func @no_non_single_support() -> i32 {
127  // CHECK: %[[SIZE:.*]] = llvm.mlir.constant
128  %0 = llvm.mlir.constant(2 : i32) : i32
129  // CHECK: %[[ALLOCA:.*]] = llvm.alloca %[[SIZE]] x !llvm.struct<"foo", (i32, f64, i32)> {alignment = 8 : i64} : (i32) -> !llvm.ptr
130  %1 = llvm.alloca %0 x !llvm.struct<"foo", (i32, f64, i32)> {alignment = 8 : i64} : (i32) -> !llvm.ptr
131  // CHECK-NOT: = llvm.alloca
132  %2 = llvm.getelementptr inbounds %1[0, 2] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", (i32, f64, i32)>
133  %3 = llvm.load %2 : !llvm.ptr -> i32
134  llvm.return %3 : i32
135}
136
137// -----
138
139// CHECK-LABEL: llvm.func @no_pointer_indexing
140llvm.func @no_pointer_indexing() -> i32 {
141  // CHECK: %[[SIZE:.*]] = llvm.mlir.constant(1 : i32)
142  %0 = llvm.mlir.constant(1 : i32) : i32
143  // CHECK: %[[ALLOCA:.*]] = llvm.alloca %[[SIZE]] x !llvm.struct<"foo", (i32, f64, i32)> {alignment = 8 : i64} : (i32) -> !llvm.ptr
144  %1 = llvm.alloca %0 x !llvm.struct<"foo", (i32, f64, i32)> {alignment = 8 : i64} : (i32) -> !llvm.ptr
145  // CHECK-NOT: = llvm.alloca
146  %2 = llvm.getelementptr %1[1, 2] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", (i32, f64, i32)>
147  %3 = llvm.load %2 : !llvm.ptr -> i32
148  llvm.return %3 : i32
149}
150
151// -----
152
153// CHECK-LABEL: llvm.func @no_direct_use
154llvm.func @no_direct_use() -> i32 {
155  // CHECK: %[[SIZE:.*]] = llvm.mlir.constant(1 : i32)
156  %0 = llvm.mlir.constant(1 : i32) : i32
157  // CHECK: %[[ALLOCA:.*]] = llvm.alloca %[[SIZE]] x !llvm.struct<"foo", (i32, f64, i32)> {alignment = 8 : i64} : (i32) -> !llvm.ptr
158  %1 = llvm.alloca %0 x !llvm.struct<"foo", (i32, f64, i32)> {alignment = 8 : i64} : (i32) -> !llvm.ptr
159  // CHECK-NOT: = llvm.alloca
160  %2 = llvm.getelementptr %1[0, 2] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", (i32, f64, i32)>
161  %3 = llvm.load %2 : !llvm.ptr -> i32
162  llvm.call @use(%1) : (!llvm.ptr) -> ()
163  llvm.return %3 : i32
164}
165
166llvm.func @use(!llvm.ptr)
167
168// -----
169
170// CHECK-LABEL: llvm.func @direct_promotable_use_is_fine
171llvm.func @direct_promotable_use_is_fine() -> i32 {
172  // CHECK: %[[SIZE:.*]] = llvm.mlir.constant(1 : i32)
173  %0 = llvm.mlir.constant(1 : i32) : i32
174  // CHECK: %[[ALLOCA:.*]] = llvm.alloca %[[SIZE]] x i32
175  %1 = llvm.alloca %0 x !llvm.struct<"foo", (i32, f64, i32)> {alignment = 8 : i64} : (i32) -> !llvm.ptr
176  %2 = llvm.getelementptr %1[0, 2] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", (i32, f64, i32)>
177  // CHECK: %[[RES:.*]] = llvm.load %[[ALLOCA]]
178  %3 = llvm.load %2 : !llvm.ptr -> i32
179  // This is a direct use of the slot but it can be removed because it implements PromotableOpInterface.
180  llvm.intr.lifetime.start 2, %1 : !llvm.ptr
181  // CHECK: llvm.return %[[RES]] : i32
182  llvm.return %3 : i32
183}
184
185// -----
186
187// CHECK-LABEL: llvm.func @direct_promotable_use_is_fine_on_accessor
188llvm.func @direct_promotable_use_is_fine_on_accessor() -> i32 {
189  // CHECK: %[[SIZE:.*]] = llvm.mlir.constant(1 : i32)
190  %0 = llvm.mlir.constant(1 : i32) : i32
191  // CHECK: %[[ALLOCA:.*]] = llvm.alloca %[[SIZE]] x i32
192  %1 = llvm.alloca %0 x !llvm.struct<"foo", (i32, f64, i32)> {alignment = 8 : i64} : (i32) -> !llvm.ptr
193  %2 = llvm.getelementptr %1[0, 2] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"foo", (i32, f64, i32)>
194  // This does not provide side-effect info but it can be removed because it implements PromotableOpInterface.
195  %3 = llvm.intr.invariant.start 2, %2 : !llvm.ptr
196  // CHECK: %[[RES:.*]] = llvm.load %[[ALLOCA]]
197  %4 = llvm.load %2 : !llvm.ptr -> i32
198  // This does not provide side-effect info but it can be removed because it implements PromotableOpInterface.
199  llvm.intr.invariant.end %3, 2, %2 : !llvm.ptr
200  // CHECK: llvm.return %[[RES]] : i32
201  llvm.return %4 : i32
202}
203
204// -----
205
206// CHECK-LABEL: llvm.func @no_dynamic_indexing
207// CHECK-SAME: (%[[ARG:.*]]: i32)
208llvm.func @no_dynamic_indexing(%arg: i32) -> i32 {
209  // CHECK: %[[SIZE:.*]] = llvm.mlir.constant(1 : i32)
210  %0 = llvm.mlir.constant(1 : i32) : i32
211  // CHECK: %[[ALLOCA:.*]] = llvm.alloca %[[SIZE]] x !llvm.array<10 x i32> {alignment = 8 : i64} : (i32) -> !llvm.ptr
212  %1 = llvm.alloca %0 x !llvm.array<10 x i32> {alignment = 8 : i64} : (i32) -> !llvm.ptr
213  // CHECK-NOT: = llvm.alloca
214  // CHECK: %[[GEP:.*]] = llvm.getelementptr %[[ALLOCA]][0, %[[ARG]]]
215  %2 = llvm.getelementptr %1[0, %arg] : (!llvm.ptr, i32) -> !llvm.ptr, !llvm.array<10 x i32>
216  // CHECK: %[[RES:.*]] = llvm.load %[[GEP]]
217  %3 = llvm.load %2 : !llvm.ptr -> i32
218  // CHECK: llvm.return %[[RES]] : i32
219  llvm.return %3 : i32
220}
221
222// -----
223
224// CHECK-LABEL: llvm.func @no_nested_dynamic_indexing
225// CHECK-SAME: (%[[ARG:.*]]: i32)
226llvm.func @no_nested_dynamic_indexing(%arg: i32) -> i32 {
227  // CHECK: %[[SIZE:.*]] = llvm.mlir.constant(1 : i32)
228  %0 = llvm.mlir.constant(1 : i32) : i32
229  // CHECK: %[[ALLOCA:.*]] = llvm.alloca %[[SIZE]] x !llvm.struct<(array<10 x i32>, i32)> {alignment = 8 : i64} : (i32) -> !llvm.ptr
230  %1 = llvm.alloca %0 x !llvm.struct<(array<10 x i32>, i32)> {alignment = 8 : i64} : (i32) -> !llvm.ptr
231  // CHECK-NOT: = llvm.alloca
232  // CHECK: %[[GEP:.*]] = llvm.getelementptr %[[ALLOCA]][0, 0, %[[ARG]]]
233  %2 = llvm.getelementptr %1[0, 0, %arg] : (!llvm.ptr, i32) -> !llvm.ptr, !llvm.struct<(array<10 x i32>, i32)>
234  // CHECK: %[[RES:.*]] = llvm.load %[[GEP]]
235  %3 = llvm.load %2 : !llvm.ptr -> i32
236  // CHECK: llvm.return %[[RES]] : i32
237  llvm.return %3 : i32
238}
239
240// -----
241
242// CHECK-LABEL: llvm.func @store_first_field
243llvm.func @store_first_field(%arg: i32) {
244  %0 = llvm.mlir.constant(1 : i32) : i32
245  // CHECK: %[[ALLOCA:.*]] = llvm.alloca %{{.*}} x i32
246  %1 = llvm.alloca %0 x !llvm.struct<"foo", (i32, i32, i32)> : (i32) -> !llvm.ptr
247  // CHECK-NEXT: llvm.store %{{.*}}, %[[ALLOCA]] : i32
248  llvm.store %arg, %1 : i32, !llvm.ptr
249  llvm.return
250}
251
252// -----
253
254// CHECK-LABEL: llvm.func @store_first_field_different_type
255// CHECK-SAME: (%[[ARG:.*]]: f32)
256llvm.func @store_first_field_different_type(%arg: f32) {
257  %0 = llvm.mlir.constant(1 : i32) : i32
258  // CHECK: %[[ALLOCA:.*]] = llvm.alloca %{{.*}} x i32
259  %1 = llvm.alloca %0 x !llvm.struct<"foo", (i32, i32, i32)> : (i32) -> !llvm.ptr
260  // CHECK-NEXT: llvm.store %[[ARG]], %[[ALLOCA]] : f32
261  llvm.store %arg, %1 : f32, !llvm.ptr
262  llvm.return
263}
264
265// -----
266
267// CHECK-LABEL: llvm.func @store_sub_field
268// CHECK-SAME: (%[[ARG:.*]]: f32)
269llvm.func @store_sub_field(%arg: f32) {
270  %0 = llvm.mlir.constant(1 : i32) : i32
271  // CHECK: %[[ALLOCA:.*]] = llvm.alloca %{{.*}} x i64
272  %1 = llvm.alloca %0 x !llvm.struct<"foo", (i64, i32)> : (i32) -> !llvm.ptr
273  // CHECK-NEXT: llvm.store %[[ARG]], %[[ALLOCA]] : f32
274  llvm.store %arg, %1 : f32, !llvm.ptr
275  llvm.return
276}
277
278// -----
279
280// CHECK-LABEL: llvm.func @load_first_field
281llvm.func @load_first_field() -> i32 {
282  %0 = llvm.mlir.constant(1 : i32) : i32
283  // CHECK: %[[ALLOCA:.*]] = llvm.alloca %{{.*}} x i32
284  %1 = llvm.alloca %0 x !llvm.struct<"foo", (i32, i32, i32)> : (i32) -> !llvm.ptr
285  // CHECK-NEXT: %[[RES:.*]] = llvm.load %[[ALLOCA]] : !llvm.ptr -> i32
286  %2 = llvm.load %1 : !llvm.ptr -> i32
287  // CHECK: llvm.return %[[RES]] : i32
288  llvm.return %2 : i32
289}
290
291// -----
292
293// CHECK-LABEL: llvm.func @load_first_field_different_type
294llvm.func @load_first_field_different_type() -> f32 {
295  %0 = llvm.mlir.constant(1 : i32) : i32
296  // CHECK: %[[ALLOCA:.*]] = llvm.alloca %{{.*}} x i32
297  %1 = llvm.alloca %0 x !llvm.struct<"foo", (i32, i32, i32)> : (i32) -> !llvm.ptr
298  // CHECK-NEXT: %[[RES:.*]] = llvm.load %[[ALLOCA]] : !llvm.ptr -> f32
299  %2 = llvm.load %1 : !llvm.ptr -> f32
300  // CHECK: llvm.return %[[RES]] : f32
301  llvm.return %2 : f32
302}
303
304// -----
305
306// CHECK-LABEL: llvm.func @load_sub_field
307llvm.func @load_sub_field() -> i32 {
308  %0 = llvm.mlir.constant(1 : i32) : i32
309  // CHECK: %[[ALLOCA:.*]] = llvm.alloca %{{.*}} x i64 : (i32) -> !llvm.ptr
310  %1 = llvm.alloca %0 x !llvm.struct<(i64, i32)> : (i32) -> !llvm.ptr
311  // CHECK-NEXT: %[[RES:.*]] = llvm.load %[[ALLOCA]]
312  %res = llvm.load %1 : !llvm.ptr -> i32
313  // CHECK: llvm.return %[[RES]] : i32
314  llvm.return %res : i32
315}
316
317// -----
318
319// CHECK-LABEL: llvm.func @vector_store_type_mismatch
320// CHECK-SAME: %[[ARG:.*]]: vector<4xi32>
321llvm.func @vector_store_type_mismatch(%arg: vector<4xi32>) {
322  %0 = llvm.mlir.constant(1 : i32) : i32
323  // CHECK: %[[ALLOCA:.*]] = llvm.alloca %{{.*}} x vector<4xf32>
324  %1 = llvm.alloca %0 x !llvm.struct<"foo", (vector<4xf32>)> : (i32) -> !llvm.ptr
325  // CHECK-NEXT: llvm.store %[[ARG]], %[[ALLOCA]]
326  llvm.store %arg, %1 : vector<4xi32>, !llvm.ptr
327  llvm.return
328}
329
330// -----
331
332// CHECK-LABEL: llvm.func @store_to_memory
333// CHECK-SAME: %[[ARG:.*]]: !llvm.ptr
334llvm.func @store_to_memory(%arg: !llvm.ptr) {
335  %0 = llvm.mlir.constant(1 : i32) : i32
336  // CHECK: %[[ALLOCA:.*]] = llvm.alloca %{{.*}} x !llvm.struct<
337  %1 = llvm.alloca %0 x !llvm.struct<"foo", (vector<4xf32>)> : (i32) -> !llvm.ptr
338  // CHECK-NEXT: llvm.store %[[ALLOCA]], %[[ARG]]
339  llvm.store %1, %arg : !llvm.ptr, !llvm.ptr
340  llvm.return
341}
342
343// -----
344
345// CHECK-LABEL: llvm.func @type_mismatch_array_access
346// CHECK-SAME: %[[ARG:.*]]: i32
347llvm.func @type_mismatch_array_access(%arg: i32) {
348  %0 = llvm.mlir.constant(1 : i32) : i32
349  // CHECK: %[[ALLOCA:.*]] = llvm.alloca %{{.*}} x i32
350  %1 = llvm.alloca %0 x !llvm.struct<(i32, i32, i32)> : (i32) -> !llvm.ptr
351  %2 = llvm.getelementptr %1[8] : (!llvm.ptr) -> !llvm.ptr, i8
352  // CHECK-NEXT: llvm.store %[[ARG]], %[[ALLOCA]]
353  llvm.store %arg, %2 : i32, !llvm.ptr
354  llvm.return
355}
356
357// -----
358
359// CHECK-LABEL: llvm.func @type_mismatch_struct_access
360// CHECK-SAME: %[[ARG:.*]]: i32
361llvm.func @type_mismatch_struct_access(%arg: i32) {
362  %0 = llvm.mlir.constant(1 : i32) : i32
363  // CHECK: %[[ALLOCA:.*]] = llvm.alloca %{{.*}} x i32
364  %1 = llvm.alloca %0 x !llvm.struct<(i32, i32, i32)> : (i32) -> !llvm.ptr
365  %2 = llvm.getelementptr %1[0, 1] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(i32, i32)>
366  // CHECK-NEXT: llvm.store %[[ARG]], %[[ALLOCA]]
367  llvm.store %arg, %2 : i32, !llvm.ptr
368  llvm.return
369}
370
371// -----
372
373// CHECK-LABEL: llvm.func @index_in_final_padding
374llvm.func @index_in_final_padding(%arg: i32) {
375  %0 = llvm.mlir.constant(1 : i32) : i32
376  // CHECK: %[[ALLOCA:.*]] = llvm.alloca %{{.*}} x !llvm.struct<"foo", (i32, i8)>
377  %1 = llvm.alloca %0 x !llvm.struct<"foo", (i32, i8)> : (i32) -> !llvm.ptr
378  // CHECK: = llvm.getelementptr %[[ALLOCA]][7] : (!llvm.ptr) -> !llvm.ptr, i8
379  %2 = llvm.getelementptr %1[7] : (!llvm.ptr) -> !llvm.ptr, i8
380  llvm.store %arg, %2 : i32, !llvm.ptr
381  llvm.return
382}
383
384// -----
385
386// CHECK-LABEL: llvm.func @index_out_of_bounds
387llvm.func @index_out_of_bounds(%arg: i32) {
388  %0 = llvm.mlir.constant(1 : i32) : i32
389  // CHECK: %[[ALLOCA:.*]] = llvm.alloca %{{.*}} x !llvm.struct<"foo", (i32, i32)>
390  %1 = llvm.alloca %0 x !llvm.struct<"foo", (i32, i32)> : (i32) -> !llvm.ptr
391  // CHECK: = llvm.getelementptr %[[ALLOCA]][9] : (!llvm.ptr) -> !llvm.ptr, i8
392  %2 = llvm.getelementptr %1[9] : (!llvm.ptr) -> !llvm.ptr, i8
393  llvm.store %arg, %2 : i32, !llvm.ptr
394  llvm.return
395}
396
397// -----
398
399// CHECK-LABEL: llvm.func @index_in_padding
400llvm.func @index_in_padding(%arg: i16) {
401  %0 = llvm.mlir.constant(1 : i32) : i32
402  // CHECK: %[[ALLOCA:.*]] = llvm.alloca %{{.*}} x !llvm.struct<"foo", (i16, i32)>
403  %1 = llvm.alloca %0 x !llvm.struct<"foo", (i16, i32)> : (i32) -> !llvm.ptr
404  // CHECK: = llvm.getelementptr %[[ALLOCA]][2] : (!llvm.ptr) -> !llvm.ptr, i8
405  %2 = llvm.getelementptr %1[2] : (!llvm.ptr) -> !llvm.ptr, i8
406  llvm.store %arg, %2 : i16, !llvm.ptr
407  llvm.return
408}
409
410// -----
411
412// CHECK-LABEL: llvm.func @index_not_in_padding_because_packed
413// CHECK-SAME: %[[ARG:.*]]: i16
414llvm.func @index_not_in_padding_because_packed(%arg: i16) {
415  %0 = llvm.mlir.constant(1 : i32) : i32
416  // CHECK: %[[ALLOCA:.*]] = llvm.alloca %{{.*}} x i32
417  %1 = llvm.alloca %0 x !llvm.struct<"foo", packed (i16, i32)> : (i32) -> !llvm.ptr
418  %2 = llvm.getelementptr %1[2] : (!llvm.ptr) -> !llvm.ptr, i8
419  // CHECK-NEXT: llvm.store %[[ARG]], %[[ALLOCA]]
420  llvm.store %arg, %2 : i16, !llvm.ptr
421  llvm.return
422}
423
424// -----
425
426// CHECK-LABEL: llvm.func @no_crash_on_negative_gep_index
427// CHECK-SAME: %[[ARG:.*]]: f16
428llvm.func @no_crash_on_negative_gep_index(%arg: f16) {
429  %0 = llvm.mlir.constant(1 : i32) : i32
430  // CHECK: %[[ALLOCA:.*]] = llvm.alloca %{{.*}} x !llvm.struct<"foo", (i32, i32, i32)>
431  %1 = llvm.alloca %0 x !llvm.struct<"foo", (i32, i32, i32)> : (i32) -> !llvm.ptr
432  // CHECK: llvm.getelementptr %[[ALLOCA]][-1] : (!llvm.ptr) -> !llvm.ptr, f32
433  %2 = llvm.getelementptr %1[-1] : (!llvm.ptr) -> !llvm.ptr, f32
434  llvm.store %arg, %2 : f16, !llvm.ptr
435  llvm.return
436}
437
438// -----
439
440// CHECK-LABEL: llvm.func @out_of_bound_gep_array_access
441// CHECK-SAME: %[[ARG:.*]]: i32
442llvm.func @out_of_bound_gep_array_access(%arg: i32) {
443  %0 = llvm.mlir.constant(1 : i32) : i32
444  // CHECK: %[[ALLOCA:.*]] = llvm.alloca %{{.*}} x i32
445  %1 = llvm.alloca %0 x !llvm.struct<"foo", (i32, i32)> : (i32) -> !llvm.ptr
446  %2 = llvm.getelementptr %1[0, 4] : (!llvm.ptr) -> !llvm.ptr, !llvm.array<4 x i8>
447  // CHECK-NEXT: llvm.store %[[ARG]], %[[ALLOCA]]
448  llvm.store %arg, %2 : i32, !llvm.ptr
449  llvm.return
450}
451