xref: /llvm-project/mlir/test/Conversion/FuncToLLVM/calling-convention.mlir (revision 5b007582bb9142ccab47134e5d2de0dd451338af)
1// RUN: mlir-opt -finalize-memref-to-llvm -llvm-request-c-wrappers -convert-func-to-llvm -reconcile-unrealized-casts %s | FileCheck %s
2// RUN: mlir-opt -finalize-memref-to-llvm -convert-func-to-llvm -reconcile-unrealized-casts %s | FileCheck %s --check-prefix=EMIT_C_ATTRIBUTE
3
4// This tests the default memref calling convention and the emission of C
5// wrappers. We don't need to separate runs because the wrapper-emission
6// version subsumes the calling convention and only adds new functions, that we
7// can also file-check in the same run.
8
9// An external function is transformed into the glue around calling an interface function.
10// CHECK-LABEL: @external
11// CHECK: %[[ALLOC0:.*]]: !llvm.ptr, %[[ALIGN0:.*]]: !llvm.ptr, %[[OFFSET0:.*]]: i64, %[[SIZE00:.*]]: i64, %[[SIZE01:.*]]: i64, %[[STRIDE00:.*]]: i64, %[[STRIDE01:.*]]: i64,
12// CHECK: %[[ALLOC1:.*]]: !llvm.ptr, %[[ALIGN1:.*]]: !llvm.ptr, %[[OFFSET1:.*]]: i64)
13func.func private @external(%arg0: memref<?x?xf32>, %arg1: memref<f32>)
14  // Populate the descriptor for arg0.
15  // CHECK: %[[DESC00:.*]] = llvm.mlir.undef : !llvm.struct<(ptr, ptr, i64, array<2 x i64>, array<2 x i64>)>
16  // CHECK: %[[DESC01:.*]] = llvm.insertvalue %arg0, %[[DESC00]][0]
17  // CHECK: %[[DESC02:.*]] = llvm.insertvalue %arg1, %[[DESC01]][1]
18  // CHECK: %[[DESC03:.*]] = llvm.insertvalue %arg2, %[[DESC02]][2]
19  // CHECK: %[[DESC04:.*]] = llvm.insertvalue %arg3, %[[DESC03]][3, 0]
20  // CHECK: %[[DESC05:.*]] = llvm.insertvalue %arg5, %[[DESC04]][4, 0]
21  // CHECK: %[[DESC06:.*]] = llvm.insertvalue %arg4, %[[DESC05]][3, 1]
22  // CHECK: %[[DESC07:.*]] = llvm.insertvalue %arg6, %[[DESC06]][4, 1]
23
24  // Allocate on stack and store to comply with C calling convention.
25  // CHECK: %[[C1:.*]] = llvm.mlir.constant(1 : index)
26  // CHECK: %[[DESC0_ALLOCA:.*]] = llvm.alloca %[[C1]] x !llvm.struct<(ptr, ptr, i64, array<2 x i64>, array<2 x i64>)>
27  // CHECK: llvm.store %[[DESC07]], %[[DESC0_ALLOCA]]
28
29  // Populate the descriptor for arg1.
30  // CHECK: %[[DESC10:.*]] = llvm.mlir.undef : !llvm.struct<(ptr, ptr, i64)>
31  // CHECK: %[[DESC11:.*]] = llvm.insertvalue %arg7, %[[DESC10]][0] : !llvm.struct<(ptr, ptr, i64)>
32  // CHECK: %[[DESC12:.*]] = llvm.insertvalue %arg8, %[[DESC11]][1] : !llvm.struct<(ptr, ptr, i64)>
33  // CHECK: %[[DESC13:.*]] = llvm.insertvalue %arg9, %[[DESC12]][2] : !llvm.struct<(ptr, ptr, i64)>
34
35  // Allocate on stack and store to comply with C calling convention.
36  // CHECK: %[[C1:.*]] = llvm.mlir.constant(1 : index)
37  // CHECK: %[[DESC1_ALLOCA:.*]] = llvm.alloca %[[C1]] x !llvm.struct<(ptr, ptr, i64)>
38  // CHECK: llvm.store %[[DESC13]], %[[DESC1_ALLOCA]]
39
40  // Call the interface function.
41  // CHECK: llvm.call @_mlir_ciface_external
42
43// Verify that an interface function is emitted.
44// CHECK-LABEL: llvm.func @_mlir_ciface_external
45// CHECK: (!llvm.ptr, !llvm.ptr)
46
47// Verify that the return value is not affected.
48// CHECK-LABEL: @returner
49// CHECK: -> !llvm.struct<(struct<(ptr, ptr, i64, array<2 x i64>, array<2 x i64>)>, struct<(ptr, ptr, i64)>)>
50func.func private @returner() -> (memref<?x?xf32>, memref<f32>)
51
52// CHECK-LABEL: @caller
53func.func @caller() {
54  %0:2 = call @returner() : () -> (memref<?x?xf32>, memref<f32>)
55  // Extract individual values from the descriptor for the first memref.
56  // CHECK: %[[ALLOC0:.*]] = llvm.extractvalue %[[DESC0:.*]][0] : !llvm.struct<(ptr, ptr, i64, array<2 x i64>, array<2 x i64>)>
57  // CHECK: %[[ALIGN0:.*]] = llvm.extractvalue %[[DESC0]][1]
58  // CHECK: %[[OFFSET0:.*]] = llvm.extractvalue %[[DESC0]][2]
59  // CHECK: %[[SIZE00:.*]] = llvm.extractvalue %[[DESC0]][3, 0]
60  // CHECK: %[[SIZE01:.*]] = llvm.extractvalue %[[DESC0]][3, 1]
61  // CHECK: %[[STRIDE00:.*]] = llvm.extractvalue %[[DESC0]][4, 0]
62  // CHECK: %[[STRIDE01:.*]] = llvm.extractvalue %[[DESC0]][4, 1]
63
64  // Extract individual values from the descriptor for the second memref.
65  // CHECK: %[[ALLOC1:.*]] = llvm.extractvalue %[[DESC1:.*]][0] : !llvm.struct<(ptr, ptr, i64)>
66  // CHECK: %[[ALIGN1:.*]] = llvm.extractvalue %[[DESC1]][1]
67  // CHECK: %[[OFFSET1:.*]] = llvm.extractvalue %[[DESC1]][2]
68
69  // Forward the values to the call.
70  // CHECK: llvm.call @external(%[[ALLOC0]], %[[ALIGN0]], %[[OFFSET0]], %[[SIZE00]], %[[SIZE01]], %[[STRIDE00]], %[[STRIDE01]], %[[ALLOC1]], %[[ALIGN1]], %[[OFFSET1]]) : (!llvm.ptr, !llvm.ptr, i64, i64, i64, i64, i64, !llvm.ptr, !llvm.ptr, i64) -> ()
71  call @external(%0#0, %0#1) : (memref<?x?xf32>, memref<f32>) -> ()
72  return
73}
74
75// CHECK-LABEL: @callee
76// EMIT_C_ATTRIBUTE-LABEL: @callee
77func.func @callee(%arg0: memref<?xf32>, %arg1: index) {
78  %0 = memref.load %arg0[%arg1] : memref<?xf32>
79  return
80}
81
82// Verify that an interface function is emitted.
83// CHECK-LABEL: @_mlir_ciface_callee
84// CHECK: %[[ARG0:.*]]: !llvm.ptr
85  // Load the memref descriptor pointer.
86  // CHECK: %[[DESC:.*]] = llvm.load %[[ARG0]] : !llvm.ptr -> !llvm.struct<(ptr, ptr, i64, array<1 x i64>, array<1 x i64>)>
87
88  // Extract individual components of the descriptor.
89  // CHECK: %[[ALLOC:.*]] = llvm.extractvalue %[[DESC]][0]
90  // CHECK: %[[ALIGN:.*]] = llvm.extractvalue %[[DESC]][1]
91  // CHECK: %[[OFFSET:.*]] = llvm.extractvalue %[[DESC]][2]
92  // CHECK: %[[SIZE:.*]] = llvm.extractvalue %[[DESC]][3, 0]
93  // CHECK: %[[STRIDE:.*]] = llvm.extractvalue %[[DESC]][4, 0]
94
95  // Forward the descriptor components to the call.
96  // CHECK: llvm.call @callee(%[[ALLOC]], %[[ALIGN]], %[[OFFSET]], %[[SIZE]], %[[STRIDE]], %{{.*}}) : (!llvm.ptr, !llvm.ptr, i64, i64, i64, i64) -> ()
97
98//   EMIT_C_ATTRIBUTE-NOT: @mlir_ciface_callee
99
100// CHECK-LABEL: @other_callee
101// EMIT_C_ATTRIBUTE-LABEL: @other_callee
102func.func @other_callee(%arg0: memref<?xf32>, %arg1: index) attributes { llvm.emit_c_interface } {
103  %0 = memref.load %arg0[%arg1] : memref<?xf32>
104  return
105}
106
107// CHECK: @_mlir_ciface_other_callee
108// CHECK:   llvm.call @other_callee
109
110// EMIT_C_ATTRIBUTE: @_mlir_ciface_other_callee
111// EMIT_C_ATTRIBUTE:   llvm.call @other_callee
112
113//===========================================================================//
114// Calling convention on returning unranked memrefs.
115//===========================================================================//
116
117// CHECK-LABEL: llvm.func @return_var_memref_caller
118func.func @return_var_memref_caller(%arg0: memref<4x3xf32>) {
119  // CHECK: %[[CALL_RES:.*]] = llvm.call @return_var_memref
120  %0 = call @return_var_memref(%arg0) : (memref<4x3xf32>) -> memref<*xf32>
121
122  // CHECK: %[[ONE:.*]] = llvm.mlir.constant(1 : index)
123  // CHECK: %[[TWO:.*]] = llvm.mlir.constant(2 : index)
124  // These sizes may depend on the data layout, not matching specific values.
125  // CHECK: %[[IDX_SIZE:.*]] = llvm.mlir.constant
126
127  // CHECK: %[[PTR_SIZE:.*]] = llvm.mlir.constant
128  // CHECK: %[[DOUBLE_PTR_SIZE:.*]] = llvm.mul %[[TWO]], %[[PTR_SIZE]]
129  // CHECK: %[[RANK:.*]] = llvm.extractvalue %[[CALL_RES]][0] : !llvm.struct<(i64, ptr)>
130  // CHECK: %[[DOUBLE_RANK:.*]] = llvm.mul %[[TWO]], %[[RANK]]
131  // CHECK: %[[DOUBLE_RANK_INC:.*]] = llvm.add %[[DOUBLE_RANK]], %[[ONE]]
132  // CHECK: %[[TABLES_SIZE:.*]] = llvm.mul %[[DOUBLE_RANK_INC]], %[[IDX_SIZE]]
133  // CHECK: %[[ALLOC_SIZE:.*]] = llvm.add %[[DOUBLE_PTR_SIZE]], %[[TABLES_SIZE]]
134  // CHECK: %[[ALLOCA:.*]] = llvm.alloca %[[ALLOC_SIZE]] x i8
135  // CHECK: %[[SOURCE:.*]] = llvm.extractvalue %[[CALL_RES]][1]
136  // CHECK: "llvm.intr.memcpy"(%[[ALLOCA]], %[[SOURCE]], %[[ALLOC_SIZE]]) <{isVolatile = false}>
137  // CHECK: llvm.call @free(%[[SOURCE]])
138  // CHECK: %[[DESC:.*]] = llvm.mlir.undef : !llvm.struct<(i64, ptr)>
139  // CHECK: %[[RANK:.*]] = llvm.extractvalue %[[CALL_RES]][0] : !llvm.struct<(i64, ptr)>
140  // CHECK: %[[DESC_1:.*]] = llvm.insertvalue %[[RANK]], %[[DESC]][0]
141  // CHECK: llvm.insertvalue %[[ALLOCA]], %[[DESC_1]][1]
142  return
143}
144
145// CHECK-LABEL: llvm.func @return_var_memref
146func.func @return_var_memref(%arg0: memref<4x3xf32>) -> memref<*xf32> attributes { llvm.emit_c_interface } {
147  // Match the construction of the unranked descriptor.
148  // CHECK: %[[ALLOCA:.*]] = llvm.alloca
149  // CHECK: %[[RANK:.*]] = llvm.mlir.constant(2 : index)
150  // CHECK: %[[DESC_0:.*]] = llvm.mlir.undef : !llvm.struct<(i64, ptr)>
151  // CHECK: %[[DESC_1:.*]] = llvm.insertvalue %[[RANK]], %[[DESC_0]][0]
152  // CHECK: %[[DESC_2:.*]] = llvm.insertvalue %[[ALLOCA]], %[[DESC_1]][1]
153  %0 = memref.cast %arg0: memref<4x3xf32> to memref<*xf32>
154
155  // CHECK: %[[ONE:.*]] = llvm.mlir.constant(1 : index)
156  // CHECK: %[[TWO:.*]] = llvm.mlir.constant(2 : index)
157  // These sizes may depend on the data layout, not matching specific values.
158  // CHECK: %[[IDX_SIZE:.*]] = llvm.mlir.constant
159
160  // CHECK: %[[PTR_SIZE:.*]] = llvm.mlir.constant
161  // CHECK: %[[DOUBLE_PTR_SIZE:.*]] = llvm.mul %[[TWO]], %[[PTR_SIZE]]
162  // CHECK: %[[RANK_EXTR:.*]] = llvm.extractvalue %[[DESC_2]][0]
163  // CHECK: %[[DOUBLE_RANK:.*]] = llvm.mul %[[TWO]], %[[RANK_EXTR]]
164  // CHECK: %[[DOUBLE_RANK_INC:.*]] = llvm.add %[[DOUBLE_RANK]], %[[ONE]]
165  // CHECK: %[[TABLES_SIZE:.*]] = llvm.mul %[[DOUBLE_RANK_INC]], %[[IDX_SIZE]]
166  // CHECK: %[[ALLOC_SIZE:.*]] = llvm.add %[[DOUBLE_PTR_SIZE]], %[[TABLES_SIZE]]
167  // CHECK: %[[ALLOCATED:.*]] = llvm.call @malloc(%[[ALLOC_SIZE]])
168  // CHECK: %[[ALLOCA_EXTRACTED:.*]] = llvm.extractvalue %[[DESC_2]][1]
169  // CHECK: "llvm.intr.memcpy"(%[[ALLOCATED]], %[[ALLOCA_EXTRACTED]], %[[ALLOC_SIZE]]) <{isVolatile = false}>
170  // CHECK: %[[NEW_DESC:.*]] = llvm.mlir.undef : !llvm.struct<(i64, ptr)>
171  // CHECK: %[[RANK_EXTRACTED:.*]] = llvm.extractvalue %[[DESC_2]][0]
172  // CHECK: %[[NEW_DESC_1:.*]] = llvm.insertvalue %[[RANK_EXTRACTED]], %[[NEW_DESC]][0]
173  // CHECK: %[[NEW_DESC_2:.*]] = llvm.insertvalue %[[ALLOCATED]], %[[NEW_DESC_1]][1]
174  // CHECK: llvm.return %[[NEW_DESC_2]]
175  return %0 : memref<*xf32>
176}
177
178// Check that the result memref is passed as parameter
179// CHECK-LABEL: @_mlir_ciface_return_var_memref
180// CHECK-SAME: (%{{.*}}: !llvm.ptr, %{{.*}}: !llvm.ptr)
181
182// CHECK-LABEL: llvm.func @return_two_var_memref_caller
183func.func @return_two_var_memref_caller(%arg0: memref<4x3xf32>) {
184  // Only check that we create two different descriptors using different
185  // memory, and deallocate both sources. The size computation is same as for
186  // the single result.
187  // CHECK: %[[CALL_RES:.*]] = llvm.call @return_two_var_memref
188  // CHECK: %[[RES_1:.*]] = llvm.extractvalue %[[CALL_RES]][0]
189  // CHECK: %[[RES_2:.*]] = llvm.extractvalue %[[CALL_RES]][1]
190  %0:2 = call @return_two_var_memref(%arg0) : (memref<4x3xf32>) -> (memref<*xf32>, memref<*xf32>)
191
192  // CHECK: %[[ALLOCA_1:.*]] = llvm.alloca %{{.*}} x i8
193  // CHECK: %[[SOURCE_1:.*]] = llvm.extractvalue %[[RES_1:.*]][1] : ![[DESC_TYPE:.*>]]
194  // CHECK: "llvm.intr.memcpy"(%[[ALLOCA_1]], %[[SOURCE_1]], %{{.*}}) <{isVolatile = false}>
195  // CHECK: llvm.call @free(%[[SOURCE_1]])
196  // CHECK: %[[DESC_1:.*]] = llvm.mlir.undef : ![[DESC_TYPE]]
197  // CHECK: %[[DESC_11:.*]] = llvm.insertvalue %{{.*}}, %[[DESC_1]][0]
198  // CHECK: llvm.insertvalue %[[ALLOCA_1]], %[[DESC_11]][1]
199
200  // CHECK: %[[ALLOCA_2:.*]] = llvm.alloca %{{.*}} x i8
201  // CHECK: %[[SOURCE_2:.*]] = llvm.extractvalue %[[RES_2:.*]][1]
202  // CHECK: "llvm.intr.memcpy"(%[[ALLOCA_2]], %[[SOURCE_2]], %{{.*}}) <{isVolatile = false}>
203  // CHECK: llvm.call @free(%[[SOURCE_2]])
204  // CHECK: %[[DESC_2:.*]] = llvm.mlir.undef : ![[DESC_TYPE]]
205  // CHECK: %[[DESC_21:.*]] = llvm.insertvalue %{{.*}}, %[[DESC_2]][0]
206  // CHECK: llvm.insertvalue %[[ALLOCA_2]], %[[DESC_21]][1]
207  return
208}
209
210// CHECK-LABEL: llvm.func @return_two_var_memref
211func.func @return_two_var_memref(%arg0: memref<4x3xf32>) -> (memref<*xf32>, memref<*xf32>) attributes { llvm.emit_c_interface } {
212  // Match the construction of the unranked descriptor.
213  // CHECK: %[[ALLOCA:.*]] = llvm.alloca
214  // CHECK: %[[DESC_0:.*]] = llvm.mlir.undef : !llvm.struct<(i64, ptr)>
215  // CHECK: %[[DESC_1:.*]] = llvm.insertvalue %{{.*}}, %[[DESC_0]][0]
216  // CHECK: %[[DESC_2:.*]] = llvm.insertvalue %[[ALLOCA]], %[[DESC_1]][1]
217  %0 = memref.cast %arg0 : memref<4x3xf32> to memref<*xf32>
218
219  // Only check that we allocate the memory for each operand of the "return"
220  // separately, even if both operands are the same value. The calling
221  // convention requires the caller to free them and the caller cannot know
222  // whether they are the same value or not.
223  // CHECK: %[[ALLOCATED_1:.*]] = llvm.call @malloc(%{{.*}})
224  // CHECK: %[[ALLOCA_EXTRACTED:.*]] = llvm.extractvalue %[[DESC_2]][1]
225  // CHECK: "llvm.intr.memcpy"(%[[ALLOCATED_1]], %[[ALLOCA_EXTRACTED]], %{{.*}}) <{isVolatile = false}>
226  // CHECK: %[[RES_1:.*]] = llvm.mlir.undef
227  // CHECK: %[[RES_11:.*]] = llvm.insertvalue %{{.*}}, %[[RES_1]][0]
228  // CHECK: %[[RES_12:.*]] = llvm.insertvalue %[[ALLOCATED_1]], %[[RES_11]][1]
229
230  // CHECK: %[[ALLOCATED_2:.*]] = llvm.call @malloc(%{{.*}})
231  // CHECK: %[[ALLOCA_EXTRACTED:.*]] = llvm.extractvalue %[[DESC_2]][1]
232  // CHECK: "llvm.intr.memcpy"(%[[ALLOCATED_2]], %[[ALLOCA_EXTRACTED]], %{{.*}}) <{isVolatile = false}>
233  // CHECK: %[[RES_2:.*]] = llvm.mlir.undef
234  // CHECK: %[[RES_21:.*]] = llvm.insertvalue %{{.*}}, %[[RES_2]][0]
235  // CHECK: %[[RES_22:.*]] = llvm.insertvalue %[[ALLOCATED_2]], %[[RES_21]][1]
236
237  // CHECK: %[[RESULTS:.*]] = llvm.mlir.undef : !llvm.struct<(struct<(i64, ptr)>, struct<(i64, ptr)>)>
238  // CHECK: %[[RESULTS_1:.*]] = llvm.insertvalue %[[RES_12]], %[[RESULTS]]
239  // CHECK: %[[RESULTS_2:.*]] = llvm.insertvalue %[[RES_22]], %[[RESULTS_1]]
240  // CHECK: llvm.return %[[RESULTS_2]]
241  return %0, %0 : memref<*xf32>, memref<*xf32>
242}
243
244// Check that the result memrefs are passed as parameter
245// CHECK-LABEL: @_mlir_ciface_return_two_var_memref
246// CHECK-SAME: (%{{.*}}: !llvm.ptr,
247// CHECK-SAME: %{{.*}}: !llvm.ptr)
248
249// CHECK-LABEL: llvm.func @bare_ptr_calling_conv(
250// CHECK-SAME: %[[ARG0:.*]]: !llvm.ptr
251// CHECK-SAME: -> !llvm.ptr
252func.func @bare_ptr_calling_conv(%arg0: memref<4x3xf32>, %arg1 : index, %arg2 : index, %arg3 : f32)
253     -> (memref<4x3xf32>) attributes { llvm.bareptr } {
254  // CHECK: %[[UNDEF_DESC:.*]] = llvm.mlir.undef : !llvm.struct<(ptr, ptr, i64, array<2 x i64>, array<2 x i64>)>
255  // CHECK: %[[INSERT_ALLOCPTR:.*]] = llvm.insertvalue %[[ARG0]], %[[UNDEF_DESC]][0]
256  // CHECK: %[[INSERT_ALIGNEDPTR:.*]] = llvm.insertvalue %[[ARG0]], %[[INSERT_ALLOCPTR]][1]
257  // CHECK: %[[C0:.*]] = llvm.mlir.constant(0 : index) : i64
258  // CHECK: %[[INSERT_OFFSET:.*]] = llvm.insertvalue %[[C0]], %[[INSERT_ALIGNEDPTR]][2]
259  // CHECK: %[[C4:.*]] = llvm.mlir.constant(4 : index) : i64
260  // CHECK: %[[INSERT_DIM0:.*]] = llvm.insertvalue %[[C4]], %[[INSERT_OFFSET]][3, 0]
261  // CHECK: %[[C3:.*]] = llvm.mlir.constant(3 : index) : i64
262  // CHECK: %[[INSERT_STRIDE0:.*]] = llvm.insertvalue %[[C3]], %[[INSERT_DIM0]][4, 0]
263  // CHECK: %[[C3:.*]] = llvm.mlir.constant(3 : index) : i64
264  // CHECK: %[[INSERT_DIM1:.*]] = llvm.insertvalue %[[C3]], %[[INSERT_STRIDE0]][3, 1]
265  // CHECK: %[[C1:.*]] = llvm.mlir.constant(1 : index) : i64
266  // CHECK: %[[INSERT_STRIDE1:.*]] = llvm.insertvalue %[[C1]], %[[INSERT_DIM1]][4, 1]
267
268  // CHECK: %[[ALIGNEDPTR:.*]] = llvm.extractvalue %[[INSERT_STRIDE1]][1]
269  // CHECK: %[[STOREPTR:.*]] = llvm.getelementptr %[[ALIGNEDPTR]]
270  // CHECK: llvm.store %{{.*}}, %[[STOREPTR]]
271  memref.store %arg3, %arg0[%arg1, %arg2] : memref<4x3xf32>
272
273  // CHECK: %[[EXTRACT_MEMREF:.*]] = llvm.extractvalue %[[INSERT_STRIDE1]][0]
274  // CHECK: llvm.return %[[EXTRACT_MEMREF]]
275  return %arg0 : memref<4x3xf32>
276}
277
278// CHECK-LABEL: llvm.func @bare_ptr_calling_conv_multiresult(
279// CHECK-SAME: %[[ARG0:.*]]: !llvm.ptr
280// CHECK-SAME: -> !llvm.struct<(f32, ptr)>
281func.func @bare_ptr_calling_conv_multiresult(%arg0: memref<4x3xf32>, %arg1 : index, %arg2 : index, %arg3 : f32)
282     -> (f32, memref<4x3xf32>) attributes { llvm.bareptr } {
283  // CHECK: %[[UNDEF_DESC:.*]] = llvm.mlir.undef : !llvm.struct<(ptr, ptr, i64, array<2 x i64>, array<2 x i64>)>
284  // CHECK: %[[INSERT_ALLOCPTR:.*]] = llvm.insertvalue %[[ARG0]], %[[UNDEF_DESC]][0]
285  // CHECK: %[[INSERT_ALIGNEDPTR:.*]] = llvm.insertvalue %[[ARG0]], %[[INSERT_ALLOCPTR]][1]
286  // CHECK: %[[C0:.*]] = llvm.mlir.constant(0 : index) : i64
287  // CHECK: %[[INSERT_OFFSET:.*]] = llvm.insertvalue %[[C0]], %[[INSERT_ALIGNEDPTR]][2]
288  // CHECK: %[[C4:.*]] = llvm.mlir.constant(4 : index) : i64
289  // CHECK: %[[INSERT_DIM0:.*]] = llvm.insertvalue %[[C4]], %[[INSERT_OFFSET]][3, 0]
290  // CHECK: %[[C3:.*]] = llvm.mlir.constant(3 : index) : i64
291  // CHECK: %[[INSERT_STRIDE0:.*]] = llvm.insertvalue %[[C3]], %[[INSERT_DIM0]][4, 0]
292  // CHECK: %[[C3:.*]] = llvm.mlir.constant(3 : index) : i64
293  // CHECK: %[[INSERT_DIM1:.*]] = llvm.insertvalue %[[C3]], %[[INSERT_STRIDE0]][3, 1]
294  // CHECK: %[[C1:.*]] = llvm.mlir.constant(1 : index) : i64
295  // CHECK: %[[INSERT_STRIDE1:.*]] = llvm.insertvalue %[[C1]], %[[INSERT_DIM1]][4, 1]
296
297  // CHECK: %[[ALIGNEDPTR:.*]] = llvm.extractvalue %[[INSERT_STRIDE1]][1]
298  // CHECK: %[[STOREPTR:.*]] = llvm.getelementptr %[[ALIGNEDPTR]]
299  // CHECK: llvm.store %{{.*}}, %[[STOREPTR]]
300  memref.store %arg3, %arg0[%arg1, %arg2] : memref<4x3xf32>
301
302  // CHECK: %[[ALIGNEDPTR0:.*]] = llvm.extractvalue %[[INSERT_STRIDE1]][1]
303  // CHECK: %[[LOADPTR:.*]] = llvm.getelementptr %[[ALIGNEDPTR0]]
304  // CHECK: %[[RETURN0:.*]] = llvm.load %[[LOADPTR]]
305  %0 = memref.load %arg0[%arg1, %arg2] : memref<4x3xf32>
306
307  // CHECK: %[[EXTRACT_MEMREF:.*]] = llvm.extractvalue %[[INSERT_STRIDE1]][0]
308  // CHECK: %[[RETURN_DESC:.*]] = llvm.mlir.undef : !llvm.struct<(f32, ptr)>
309  // CHECK: %[[INSERT_RETURN0:.*]] = llvm.insertvalue %[[RETURN0]], %[[RETURN_DESC]][0]
310  // CHECK: %[[INSERT_RETURN1:.*]] = llvm.insertvalue %[[EXTRACT_MEMREF]], %[[INSERT_RETURN0]][1]
311  // CHECK: llvm.return %[[INSERT_RETURN1]]
312  return %0, %arg0 : f32, memref<4x3xf32>
313}
314