314 lines · plain
1// RUN: mlir-opt -finalize-memref-to-llvm -llvm-request-c-wrappers -convert-func-to-llvm -reconcile-unrealized-casts %s | FileCheck %s2// RUN: mlir-opt -finalize-memref-to-llvm -convert-func-to-llvm -reconcile-unrealized-casts %s | FileCheck %s --check-prefix=EMIT_C_ATTRIBUTE3 4// This tests the default memref calling convention and the emission of C5// wrappers. We don't need to separate runs because the wrapper-emission6// version subsumes the calling convention and only adds new functions, that we7// 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: @external11// 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.poison : !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.poison : !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_external42 43// Verify that an interface function is emitted.44// CHECK-LABEL: llvm.func @_mlir_ciface_external45// CHECK: (!llvm.ptr, !llvm.ptr)46 47// Verify that the return value is not affected.48// CHECK-LABEL: @returner49// 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: @caller53func.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 return73}74 75// CHECK-LABEL: @callee76// EMIT_C_ATTRIBUTE-LABEL: @callee77func.func @callee(%arg0: memref<?xf32>, %arg1: index) {78 %0 = memref.load %arg0[%arg1] : memref<?xf32>79 return80}81 82// Verify that an interface function is emitted.83// CHECK-LABEL: @_mlir_ciface_callee84// CHECK: %[[ARG0:.*]]: !llvm.ptr85 // 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_callee99 100// CHECK-LABEL: @other_callee101// EMIT_C_ATTRIBUTE-LABEL: @other_callee102func.func @other_callee(%arg0: memref<?xf32>, %arg1: index) attributes { llvm.emit_c_interface } {103 %0 = memref.load %arg0[%arg1] : memref<?xf32>104 return105}106 107// CHECK: @_mlir_ciface_other_callee108// CHECK: llvm.call @other_callee109 110// EMIT_C_ATTRIBUTE: @_mlir_ciface_other_callee111// EMIT_C_ATTRIBUTE: llvm.call @other_callee112 113//===========================================================================//114// Calling convention on returning unranked memrefs.115//===========================================================================//116 117// CHECK-LABEL: llvm.func @return_var_memref_caller118func.func @return_var_memref_caller(%arg0: memref<4x3xf32>) {119 // CHECK: %[[CALL_RES:.*]] = llvm.call @return_var_memref120 %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.constant126 127 // CHECK: %[[PTR_SIZE:.*]] = llvm.mlir.constant128 // 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 i8135 // 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.poison : !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 return143}144 145// CHECK-LABEL: llvm.func @return_var_memref146func.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.alloca149 // CHECK: %[[RANK:.*]] = llvm.mlir.constant(2 : index)150 // CHECK: %[[DESC_0:.*]] = llvm.mlir.poison : !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.constant159 160 // CHECK: %[[PTR_SIZE:.*]] = llvm.mlir.constant161 // 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.poison : !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 parameter179// CHECK-LABEL: @_mlir_ciface_return_var_memref180// CHECK-SAME: (%{{.*}}: !llvm.ptr, %{{.*}}: !llvm.ptr)181 182// CHECK-LABEL: llvm.func @return_two_var_memref_caller183func.func @return_two_var_memref_caller(%arg0: memref<4x3xf32>) {184 // Only check that we create two different descriptors using different185 // memory, and deallocate both sources. The size computation is same as for186 // the single result.187 // CHECK: %[[CALL_RES:.*]] = llvm.call @return_two_var_memref188 // 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 i8193 // 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.poison : ![[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 i8201 // 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.poison : ![[DESC_TYPE]]205 // CHECK: %[[DESC_21:.*]] = llvm.insertvalue %{{.*}}, %[[DESC_2]][0]206 // CHECK: llvm.insertvalue %[[ALLOCA_2]], %[[DESC_21]][1]207 return208}209 210// CHECK-LABEL: llvm.func @return_two_var_memref211func.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.alloca214 // CHECK: %[[DESC_0:.*]] = llvm.mlir.poison : !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 calling221 // convention requires the caller to free them and the caller cannot know222 // 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.poison227 // 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.poison234 // 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.poison : !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 parameter245// CHECK-LABEL: @_mlir_ciface_return_two_var_memref246// CHECK-SAME: (%{{.*}}: !llvm.ptr,247// CHECK-SAME: %{{.*}}: !llvm.ptr)248 249// CHECK-LABEL: llvm.func @bare_ptr_calling_conv(250// CHECK-SAME: %[[ARG0:.*]]: !llvm.ptr251// CHECK-SAME: -> !llvm.ptr252func.func @bare_ptr_calling_conv(%arg0: memref<4x3xf32>, %arg1 : index, %arg2 : index, %arg3 : f32)253 -> (memref<4x3xf32>) attributes { llvm.bareptr } {254 // CHECK: %[[POISON_DESC:.*]] = llvm.mlir.poison : !llvm.struct<(ptr, ptr, i64, array<2 x i64>, array<2 x i64>)>255 // CHECK: %[[INSERT_ALLOCPTR:.*]] = llvm.insertvalue %[[ARG0]], %[[POISON_DESC]][0]256 // CHECK: %[[INSERT_ALIGNEDPTR:.*]] = llvm.insertvalue %[[ARG0]], %[[INSERT_ALLOCPTR]][1]257 // CHECK: %[[C0:.*]] = llvm.mlir.constant(0 : index) : i64258 // CHECK: %[[INSERT_OFFSET:.*]] = llvm.insertvalue %[[C0]], %[[INSERT_ALIGNEDPTR]][2]259 // CHECK: %[[C4:.*]] = llvm.mlir.constant(4 : index) : i64260 // CHECK: %[[INSERT_DIM0:.*]] = llvm.insertvalue %[[C4]], %[[INSERT_OFFSET]][3, 0]261 // CHECK: %[[C3:.*]] = llvm.mlir.constant(3 : index) : i64262 // CHECK: %[[INSERT_STRIDE0:.*]] = llvm.insertvalue %[[C3]], %[[INSERT_DIM0]][4, 0]263 // CHECK: %[[C3:.*]] = llvm.mlir.constant(3 : index) : i64264 // CHECK: %[[INSERT_DIM1:.*]] = llvm.insertvalue %[[C3]], %[[INSERT_STRIDE0]][3, 1]265 // CHECK: %[[C1:.*]] = llvm.mlir.constant(1 : index) : i64266 // CHECK: %[[INSERT_STRIDE1:.*]] = llvm.insertvalue %[[C1]], %[[INSERT_DIM1]][4, 1]267 268 // CHECK: %[[ALIGNEDPTR:.*]] = llvm.extractvalue %[[INSERT_STRIDE1]][1]269 // CHECK: %[[STOREPTR:.*]] = llvm.getelementptr inbounds|nuw %[[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.ptr280// 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: %[[POISON_DESC:.*]] = llvm.mlir.poison : !llvm.struct<(ptr, ptr, i64, array<2 x i64>, array<2 x i64>)>284 // CHECK: %[[INSERT_ALLOCPTR:.*]] = llvm.insertvalue %[[ARG0]], %[[POISON_DESC]][0]285 // CHECK: %[[INSERT_ALIGNEDPTR:.*]] = llvm.insertvalue %[[ARG0]], %[[INSERT_ALLOCPTR]][1]286 // CHECK: %[[C0:.*]] = llvm.mlir.constant(0 : index) : i64287 // CHECK: %[[INSERT_OFFSET:.*]] = llvm.insertvalue %[[C0]], %[[INSERT_ALIGNEDPTR]][2]288 // CHECK: %[[C4:.*]] = llvm.mlir.constant(4 : index) : i64289 // CHECK: %[[INSERT_DIM0:.*]] = llvm.insertvalue %[[C4]], %[[INSERT_OFFSET]][3, 0]290 // CHECK: %[[C3:.*]] = llvm.mlir.constant(3 : index) : i64291 // CHECK: %[[INSERT_STRIDE0:.*]] = llvm.insertvalue %[[C3]], %[[INSERT_DIM0]][4, 0]292 // CHECK: %[[C3:.*]] = llvm.mlir.constant(3 : index) : i64293 // CHECK: %[[INSERT_DIM1:.*]] = llvm.insertvalue %[[C3]], %[[INSERT_STRIDE0]][3, 1]294 // CHECK: %[[C1:.*]] = llvm.mlir.constant(1 : index) : i64295 // CHECK: %[[INSERT_STRIDE1:.*]] = llvm.insertvalue %[[C1]], %[[INSERT_DIM1]][4, 1]296 297 // CHECK: %[[ALIGNEDPTR:.*]] = llvm.extractvalue %[[INSERT_STRIDE1]][1]298 // CHECK: %[[STOREPTR:.*]] = llvm.getelementptr inbounds|nuw %[[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 inbounds|nuw %[[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.poison : !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