[RISCV] Fix the code alignment for GroupFloatVectors. NFC
[llvm-project.git] / mlir / test / Conversion / StandardToLLVM / calling-convention.mlir
blob4c6b0da4b1dac496a1094a51a344b73d8c828d35
1 // RUN: mlir-opt -convert-memref-to-llvm -convert-std-to-llvm='emit-c-wrappers=1' -reconcile-unrealized-casts %s | FileCheck %s
2 // RUN: mlir-opt -convert-memref-to-llvm -convert-std-to-llvm -reconcile-unrealized-casts %s | FileCheck %s --check-prefix=EMIT_C_ATTRIBUTE
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.
9 // An external function is transformed into the glue around calling an interface function.
10 // CHECK-LABEL: @external
11 // CHECK: %[[ALLOC0:.*]]: !llvm.ptr<f32>, %[[ALIGN0:.*]]: !llvm.ptr<f32>, %[[OFFSET0:.*]]: i64, %[[SIZE00:.*]]: i64, %[[SIZE01:.*]]: i64, %[[STRIDE00:.*]]: i64, %[[STRIDE01:.*]]: i64,
12 // CHECK: %[[ALLOC1:.*]]: !llvm.ptr<f32>, %[[ALIGN1:.*]]: !llvm.ptr<f32>, %[[OFFSET1:.*]]: i64)
13 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<f32>, ptr<f32>, 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]
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<f32>, ptr<f32>, i64, array<2 x i64>, array<2 x i64>)>
27   // CHECK: llvm.store %[[DESC07]], %[[DESC0_ALLOCA]]
29   // Populate the descriptor for arg1.
30   // CHECK: %[[DESC10:.*]] = llvm.mlir.undef : !llvm.struct<(ptr<f32>, ptr<f32>, i64)>
31   // CHECK: %[[DESC11:.*]] = llvm.insertvalue %arg7, %[[DESC10]][0] : !llvm.struct<(ptr<f32>, ptr<f32>, i64)>
32   // CHECK: %[[DESC12:.*]] = llvm.insertvalue %arg8, %[[DESC11]][1] : !llvm.struct<(ptr<f32>, ptr<f32>, i64)>
33   // CHECK: %[[DESC13:.*]] = llvm.insertvalue %arg9, %[[DESC12]][2] : !llvm.struct<(ptr<f32>, ptr<f32>, i64)>
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<f32>, ptr<f32>, i64)>
38   // CHECK: llvm.store %[[DESC13]], %[[DESC1_ALLOCA]]
40   // Call the interface function.
41   // CHECK: llvm.call @_mlir_ciface_external
43 // Verify that an interface function is emitted.
44 // CHECK-LABEL: llvm.func @_mlir_ciface_external
45 // CHECK: (!llvm.ptr<struct<(ptr<f32>, ptr<f32>, i64, array<2 x i64>, array<2 x i64>)>>, !llvm.ptr<struct<(ptr<f32>, ptr<f32>, i64)>>)
47 // Verify that the return value is not affected.
48 // CHECK-LABEL: @returner
49 // CHECK: -> !llvm.struct<(struct<(ptr<f32>, ptr<f32>, i64, array<2 x i64>, array<2 x i64>)>, struct<(ptr<f32>, ptr<f32>, i64)>)>
50 func private @returner() -> (memref<?x?xf32>, memref<f32>)
52 // CHECK-LABEL: @caller
53 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<f32>, ptr<f32>, 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]
64   // Extract individual values from the descriptor for the second memref.
65   // CHECK: %[[ALLOC1:.*]] = llvm.extractvalue %[[DESC1:.*]][0] : !llvm.struct<(ptr<f32>, ptr<f32>, i64)>
66   // CHECK: %[[ALIGN1:.*]] = llvm.extractvalue %[[DESC1]][1]
67   // CHECK: %[[OFFSET1:.*]] = llvm.extractvalue %[[DESC1]][2]
69   // Forward the values to the call.
70   // CHECK: llvm.call @external(%[[ALLOC0]], %[[ALIGN0]], %[[OFFSET0]], %[[SIZE00]], %[[SIZE01]], %[[STRIDE00]], %[[STRIDE01]], %[[ALLOC1]], %[[ALIGN1]], %[[OFFSET1]]) : (!llvm.ptr<f32>, !llvm.ptr<f32>, i64, i64, i64, i64, i64, !llvm.ptr<f32>, !llvm.ptr<f32>, i64) -> ()
71   call @external(%0#0, %0#1) : (memref<?x?xf32>, memref<f32>) -> ()
72   return
75 // CHECK-LABEL: @callee
76 // EMIT_C_ATTRIBUTE-LABEL: @callee
77 func @callee(%arg0: memref<?xf32>, %arg1: index) {
78   %0 = memref.load %arg0[%arg1] : memref<?xf32>
79   return
82 // Verify that an interface function is emitted.
83 // CHECK-LABEL: @_mlir_ciface_callee
84 // CHECK: %[[ARG0:.*]]: !llvm.ptr<struct<(ptr<f32>, ptr<f32>, i64, array<1 x i64>, array<1 x i64>)>>
85   // Load the memref descriptor pointer.
86   // CHECK: %[[DESC:.*]] = llvm.load %[[ARG0]] : !llvm.ptr<struct<(ptr<f32>, ptr<f32>, i64, array<1 x i64>, array<1 x i64>)>>
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]
95   // Forward the descriptor components to the call.
96   // CHECK: llvm.call @callee(%[[ALLOC]], %[[ALIGN]], %[[OFFSET]], %[[SIZE]], %[[STRIDE]], %{{.*}}) : (!llvm.ptr<f32>, !llvm.ptr<f32>, i64, i64, i64, i64) -> ()
98 //   EMIT_C_ATTRIBUTE-NOT: @mlir_ciface_callee
100 // CHECK-LABEL: @other_callee
101 // EMIT_C_ATTRIBUTE-LABEL: @other_callee
102 func @other_callee(%arg0: memref<?xf32>, %arg1: index) attributes { llvm.emit_c_interface } {
103   %0 = memref.load %arg0[%arg1] : memref<?xf32>
104   return
107 // CHECK: @_mlir_ciface_other_callee
108 // CHECK:   llvm.call @other_callee
110 // EMIT_C_ATTRIBUTE: @_mlir_ciface_other_callee
111 // EMIT_C_ATTRIBUTE:   llvm.call @other_callee
113 //===========================================================================//
114 // Calling convention on returning unranked memrefs.
115 //===========================================================================//
117 // CHECK-LABEL: llvm.func @return_var_memref_caller
118 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>
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: %[[PTR_SIZE:.*]] = llvm.mlir.constant
126   // CHECK: %[[IDX_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<i8>)>
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: %[[FALSE:.*]] = llvm.mlir.constant(false)
135   // CHECK: %[[ALLOCA:.*]] = llvm.alloca %[[ALLOC_SIZE]] x i8
136   // CHECK: %[[SOURCE:.*]] = llvm.extractvalue %[[CALL_RES]][1]
137   // CHECK: "llvm.intr.memcpy"(%[[ALLOCA]], %[[SOURCE]], %[[ALLOC_SIZE]], %[[FALSE]])
138   // CHECK: llvm.call @free(%[[SOURCE]])
139   // CHECK: %[[DESC:.*]] = llvm.mlir.undef : !llvm.struct<(i64, ptr<i8>)>
140   // CHECK: %[[RANK:.*]] = llvm.extractvalue %[[CALL_RES]][0] : !llvm.struct<(i64, ptr<i8>)>
141   // CHECK: %[[DESC_1:.*]] = llvm.insertvalue %[[RANK]], %[[DESC]][0]
142   // CHECK: llvm.insertvalue %[[ALLOCA]], %[[DESC_1]][1]
143   return
146 // CHECK-LABEL: llvm.func @return_var_memref
147 func @return_var_memref(%arg0: memref<4x3xf32>) -> memref<*xf32> attributes { llvm.emit_c_interface } {
148   // Match the construction of the unranked descriptor.
149   // CHECK: %[[ALLOCA:.*]] = llvm.alloca
150   // CHECK: %[[MEMORY:.*]] = llvm.bitcast %[[ALLOCA]]
151   // CHECK: %[[RANK:.*]] = llvm.mlir.constant(2 : i64)
152   // CHECK: %[[DESC_0:.*]] = llvm.mlir.undef : !llvm.struct<(i64, ptr<i8>)>
153   // CHECK: %[[DESC_1:.*]] = llvm.insertvalue %[[RANK]], %[[DESC_0]][0]
154   // CHECK: %[[DESC_2:.*]] = llvm.insertvalue %[[MEMORY]], %[[DESC_1]][1]
155   %0 = memref.cast %arg0: memref<4x3xf32> to memref<*xf32>
158   // CHECK: %[[ONE:.*]] = llvm.mlir.constant(1 : index)
159   // CHECK: %[[TWO:.*]] = llvm.mlir.constant(2 : index)
160   // These sizes may depend on the data layout, not matching specific values.
161   // CHECK: %[[PTR_SIZE:.*]] = llvm.mlir.constant
162   // CHECK: %[[IDX_SIZE:.*]] = llvm.mlir.constant
164   // CHECK: %[[DOUBLE_PTR_SIZE:.*]] = llvm.mul %[[TWO]], %[[PTR_SIZE]]
165   // CHECK: %[[DOUBLE_RANK:.*]] = llvm.mul %[[TWO]], %[[RANK]]
166   // CHECK: %[[DOUBLE_RANK_INC:.*]] = llvm.add %[[DOUBLE_RANK]], %[[ONE]]
167   // CHECK: %[[TABLES_SIZE:.*]] = llvm.mul %[[DOUBLE_RANK_INC]], %[[IDX_SIZE]]
168   // CHECK: %[[ALLOC_SIZE:.*]] = llvm.add %[[DOUBLE_PTR_SIZE]], %[[TABLES_SIZE]]
169   // CHECK: %[[FALSE:.*]] = llvm.mlir.constant(false)
170   // CHECK: %[[ALLOCATED:.*]] = llvm.call @malloc(%[[ALLOC_SIZE]])
171   // CHECK: "llvm.intr.memcpy"(%[[ALLOCATED]], %[[MEMORY]], %[[ALLOC_SIZE]], %[[FALSE]])
172   // CHECK: %[[NEW_DESC:.*]] = llvm.mlir.undef : !llvm.struct<(i64, ptr<i8>)>
173   // CHECK: %[[NEW_DESC_1:.*]] = llvm.insertvalue %[[RANK]], %[[NEW_DESC]][0]
174   // CHECK: %[[NEW_DESC_2:.*]] = llvm.insertvalue %[[ALLOCATED]], %[[NEW_DESC_1]][1]
175   // CHECK: llvm.return %[[NEW_DESC_2]]
176   return %0 : memref<*xf32>
179 // Check that the result memref is passed as parameter
180 // CHECK-LABEL: @_mlir_ciface_return_var_memref
181 // CHECK-SAME: (%{{.*}}: !llvm.ptr<struct<(i64, ptr<i8>)>>, %{{.*}}: !llvm.ptr<struct<(ptr<f32>, ptr<f32>, i64, array<2 x i64>, array<2 x i64>)>>)
183 // CHECK-LABEL: llvm.func @return_two_var_memref_caller
184 func @return_two_var_memref_caller(%arg0: memref<4x3xf32>) {
185   // Only check that we create two different descriptors using different
186   // memory, and deallocate both sources. The size computation is same as for
187   // the single result.
188   // CHECK: %[[CALL_RES:.*]] = llvm.call @return_two_var_memref
189   // CHECK: %[[RES_1:.*]] = llvm.extractvalue %[[CALL_RES]][0]
190   // CHECK: %[[RES_2:.*]] = llvm.extractvalue %[[CALL_RES]][1]
191   %0:2 = call @return_two_var_memref(%arg0) : (memref<4x3xf32>) -> (memref<*xf32>, memref<*xf32>)
193   // CHECK: %[[ALLOCA_1:.*]] = llvm.alloca %{{.*}} x i8
194   // CHECK: %[[SOURCE_1:.*]] = llvm.extractvalue %[[RES_1:.*]][1] : ![[DESC_TYPE:.*]]
195   // CHECK: "llvm.intr.memcpy"(%[[ALLOCA_1]], %[[SOURCE_1]], %{{.*}}, %[[FALSE:.*]])
196   // CHECK: llvm.call @free(%[[SOURCE_1]])
197   // CHECK: %[[DESC_1:.*]] = llvm.mlir.undef : ![[DESC_TYPE]]
198   // CHECK: %[[DESC_11:.*]] = llvm.insertvalue %{{.*}}, %[[DESC_1]][0]
199   // CHECK: llvm.insertvalue %[[ALLOCA_1]], %[[DESC_11]][1]
201   // CHECK: %[[ALLOCA_2:.*]] = llvm.alloca %{{.*}} x i8
202   // CHECK: %[[SOURCE_2:.*]] = llvm.extractvalue %[[RES_2:.*]][1]
203   // CHECK: "llvm.intr.memcpy"(%[[ALLOCA_2]], %[[SOURCE_2]], %{{.*}}, %[[FALSE]])
204   // CHECK: llvm.call @free(%[[SOURCE_2]])
205   // CHECK: %[[DESC_2:.*]] = llvm.mlir.undef : ![[DESC_TYPE]]
206   // CHECK: %[[DESC_21:.*]] = llvm.insertvalue %{{.*}}, %[[DESC_2]][0]
207   // CHECK: llvm.insertvalue %[[ALLOCA_2]], %[[DESC_21]][1]
208   return
211 // CHECK-LABEL: llvm.func @return_two_var_memref
212 func @return_two_var_memref(%arg0: memref<4x3xf32>) -> (memref<*xf32>, memref<*xf32>) attributes { llvm.emit_c_interface } {
213   // Match the construction of the unranked descriptor.
214   // CHECK: %[[ALLOCA:.*]] = llvm.alloca
215   // CHECK: %[[MEMORY:.*]] = llvm.bitcast %[[ALLOCA]]
216   // CHECK: %[[DESC_0:.*]] = llvm.mlir.undef : !llvm.struct<(i64, ptr<i8>)>
217   // CHECK: %[[DESC_1:.*]] = llvm.insertvalue %{{.*}}, %[[DESC_0]][0]
218   // CHECK: %[[DESC_2:.*]] = llvm.insertvalue %[[MEMORY]], %[[DESC_1]][1]
219   %0 = memref.cast %arg0 : memref<4x3xf32> to memref<*xf32>
221   // Only check that we allocate the memory for each operand of the "return"
222   // separately, even if both operands are the same value. The calling
223   // convention requires the caller to free them and the caller cannot know
224   // whether they are the same value or not.
225   // CHECK: %[[ALLOCATED_1:.*]] = llvm.call @malloc(%{{.*}})
226   // CHECK: "llvm.intr.memcpy"(%[[ALLOCATED_1]], %[[MEMORY]], %{{.*}}, %[[FALSE:.*]])
227   // CHECK: %[[RES_1:.*]] = llvm.mlir.undef
228   // CHECK: %[[RES_11:.*]] = llvm.insertvalue %{{.*}}, %[[RES_1]][0]
229   // CHECK: %[[RES_12:.*]] = llvm.insertvalue %[[ALLOCATED_1]], %[[RES_11]][1]
231   // CHECK: %[[ALLOCATED_2:.*]] = llvm.call @malloc(%{{.*}})
232   // CHECK: "llvm.intr.memcpy"(%[[ALLOCATED_2]], %[[MEMORY]], %{{.*}}, %[[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]
237   // CHECK: %[[RESULTS:.*]] = llvm.mlir.undef : !llvm.struct<(struct<(i64, ptr<i8>)>, struct<(i64, ptr<i8>)>)>
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>
244 // Check that the result memrefs are passed as parameter
245 // CHECK-LABEL: @_mlir_ciface_return_two_var_memref
246 // CHECK-SAME: (%{{.*}}: !llvm.ptr<struct<(struct<(i64, ptr<i8>)>, struct<(i64, ptr<i8>)>)>>,
247 // CHECK-SAME: %{{.*}}: !llvm.ptr<struct<(ptr<f32>, ptr<f32>, i64, array<2 x i64>, array<2 x i64>)>>)