460 lines · plain
1// REQUIRES: arm-emulator2 3// DEFINE: %{compile} = mlir-opt %s \4// DEFINE: --convert-vector-to-scf --convert-scf-to-cf --convert-vector-to-llvm='enable-arm-sve enable-arm-i8mm' \5// DEFINE: --expand-strided-metadata --convert-to-llvm --finalize-memref-to-llvm \6// DEFINE: --lower-affine --convert-arith-to-llvm --reconcile-unrealized-casts \7// DEFINE: -o %t8 9// DEFINE: %{entry_point} = main10 11// DEFINE: %{run} = %mcr_aarch64_cmd %t -e %{entry_point} -entry-point-result=void --march=aarch64 --mattr="+sve,+i8mm" \12// DEFINE: -shared-libs=%mlir_runner_utils,%mlir_c_runner_utils,%native_mlir_arm_runner_utils13 14// RUN: rm -f %t && %{compile} && FileCheck %s --input-file=%t -check-prefix CHECK-IR && %{run} | FileCheck %s15 16#packed_maps = [17 affine_map<(m, n, k) -> (m, k)>,18 affine_map<(m, n, k) -> (n, k)>,19 affine_map<(m, n, k) -> (m, n)>20]21 22//23// Test the lowering of `vector.contract` using the `LowerContractionToSVEBFMMLAPattern`24//25// The operation that the `vector.contract` in this test performs is matrix26// multiplication with accumulate27// OUT = ACC + LHS * RHS28// of two 8-bit integer matrices LHS and RHS, and a 32-bit integer matrix ACC29// into a 32-bit integer matrix OUT. The LHS and RHS can be sign- or zero- extended,30// this test covers all the possible variants.31//32// Tested are calculations as well as that the relevant `ArmSVE` dialect33// operations ('arm_sve.smmla`, arm_sve.ummla`, etc) are emitted.34//35// That pattern above handles (therefore this test prepares) input/output vectors with36// specific shapes:37// * LHS: vector<Mx8xi8>38// * RHS: vector<[N]x8xi8>39// * ACC, OUT: vector<Mx[N]xi32>40// Note that the RHS is transposed.41// This data layout makes it efficient to load data into SVE42// registers in the layout expected by FEAT_I8MM instructions.43// Such a `vector.contract` is representative of the code we aim to generate44// by scalable vectorisation of `linalg.mmt4d`.45// See mlir/lib/Dialect/ArmSVE/Transforms/LowerContractToSVEPatterns.cpp46// for more information and rationale about these shapes.47//48// In this specific test we use M == 4 and N == 449//50 51// Allocate and initialise a memref containing test data for use as the ACC52// operand. The memref has one dynamic dimension whose extent depends on the53// runtime value of VSCALE.54//55// The input parameter `%in` is a vector that is replicated VSCALE times56// across the columns of the memref.57func.func private @prepareAccTestData(%in: vector<4x4xi32>) -> memref<4x?xi32> {58 %c0 = arith.constant 0 : index59 %c1 = arith.constant 1 : index60 %c4 = arith.constant 4 : index61 %c0_i32 = arith.constant 0 : i3262 63 %vs = vector.vscale64 %d = arith.muli %c4, %vs : index65 %mem = memref.alloc(%d) : memref<4x?xi32>66 67 scf.for %j = %c0 to %d step %c4 {68 vector.transfer_write %in, %mem[%c0, %j] {in_bounds = [true, true]} : vector<4x4xi32>, memref<4x?xi32>69 }70 71 return %mem : memref<4x?xi32>72}73 74// Allocate and initialise a memref containing test data for use as the LHS75// operand. This function just writes the parameter `%in` into the memref.76// The size of the LHS does not depends on VSCALE.77func.func private @prepareLHSTestData(%in: vector<4x8xi8>) -> memref<4x8xi8> {78 %c0 = arith.constant 0 : index79 %c0_i8 = arith.constant 0 : i880 81 %mem = memref.alloc() : memref<4x8xi8>82 vector.transfer_write %in, %mem[%c0, %c0] {in_bounds = [true, true]} : vector<4x8xi8>, memref<4x8xi8>83 84 return %mem : memref<4x8xi8>85}86 87// Allocate and initialise a memref containing test data for use as the RHS88// operand. The memref has one dynamic dimension whose extent depends on the89// runtime value of VSCALE.90//91// The input parameter `%in` is a vector that is replicated VSCALE times92// across the rows of the memref.93//94// For convenience, flatten the memref, since the RHS vector is read first as a95// single-dimensional scalable vector and then cast into [N]x8 shape.96func.func private @prepareRHSTestData(%in: vector<4x8xi8>) -> memref<?xi8> {97 %c0 = arith.constant 0 : index98 %c1 = arith.constant 1 : index99 %c4 = arith.constant 4 : index100 %c0_i8 = arith.constant 0 : i8101 102 %vs = vector.vscale103 %d = arith.muli %c4, %vs : index104 %mem = memref.alloc(%d) : memref<?x8xi8>105 106 scf.for %i = %c0 to %d step %c4 {107 vector.transfer_write %in, %mem[%i, %c0] {in_bounds = [true, true]} : vector<4x8xi8>, memref<?x8xi8>108 }109 110 %mem_out = memref.collapse_shape %mem [[0, 1]] : memref<?x8xi8> into memref<?xi8>111 return %mem_out : memref<?xi8>112}113 114// Test the operation where both LHS and RHS are interpreted as signed, hence115// we ultimately emit and execute the `smmla` instruction.116 117// CHECK-IR-LABEL: llvm.func @test_smmla118// CHECK-IR-COUNT-4: arm_sve.intr.smmla119func.func @test_smmla() attributes {no_inline} {120 121 %c0 = arith.constant 0 : index122 %c0_i32 = arith.constant 0 : i32123 %c0_i8 = arith.constant 0 : i8124 125 // Accumulator test data126 %acc_cst = arith.constant dense<[[-44, 20, 44, -46],127 [ -8, 25, -34, 26],128 [-20, -36, -3, 39],129 [-48, -31, -25, -21]]> : vector<4x4xi32>130 131 %acc_mem = func.call @prepareAccTestData(%acc_cst) : (vector<4x4xi32>) -> memref<4x?xi32>132 %acc = vector.transfer_read %acc_mem[%c0, %c0], %c0_i32 {in_bounds = [true, true]} : memref<4x?xi32>, vector<4x[4]xi32>133 134 // LHS test data135 %lhs_cst = arith.constant dense<[[-35, -27, -36, -31, 23, -34, -8, -33],136 [-20, 17, -32, -47, 37, 22, -7, -21],137 [ -7, -35, 20, -4, 39, 46, -23, 40],138 [ 40, 27, 37, 43, 38, -6, 37, 49]]> : vector<4x8xi8>139 140 %lhs_mem = func.call @prepareLHSTestData(%lhs_cst) : (vector<4x8xi8>) -> memref<4x8xi8>141 %lhs = vector.transfer_read %lhs_mem[%c0, %c0], %c0_i8 {in_bounds = [true, true]} : memref<4x8xi8>, vector<4x8xi8>142 143 // RHS test data144 %rhs_cst = arith.constant dense<[[-17, -50, -1, 48, -13, 22, 39, 33],145 [-35, -24, 37, -32, 33, 30, -11, -17],146 [-28, 31, 3, -44, -15, -27, 22, 35],147 [-23, 39, 48, 26, -23, 32, -39, -38]]> : vector<4x8xi8>148 149 %rhs_mem = func.call @prepareRHSTestData(%rhs_cst) : (vector<4x8xi8>) -> memref<?xi8>150 %rhs_flat = vector.transfer_read %rhs_mem[%c0], %c0_i8 {in_bounds = [true]} : memref<?xi8>, vector<[32]xi8>151 %rhs = vector.shape_cast %rhs_flat : vector<[32]xi8> to vector<[4]x8xi8>152 153 // Matrix multiplication and accumulate with transposed RHS.154 %0 = arith.extsi %lhs : vector<4x8xi8> to vector<4x8xi32>155 %1 = arith.extsi %rhs : vector<[4]x8xi8> to vector<[4]x8xi32>156 %2 = vector.contract {indexing_maps = #packed_maps,157 iterator_types = ["parallel", "parallel", "reduction"],158 kind = #vector.kind<add>} %0, %1, %acc159 : vector<4x8xi32>, vector<[4]x8xi32> into vector<4x[4]xi32>160 161 // Display the result of the multiplication162 vector.print str "Result(SMMLA):\n"163 %u0 = vector.extract %2[0] : vector<[4]xi32> from vector<4x[4]xi32>164 %u1 = vector.extract %2[1] : vector<[4]xi32> from vector<4x[4]xi32>165 %u2 = vector.extract %2[2] : vector<[4]xi32> from vector<4x[4]xi32>166 %u3 = vector.extract %2[3] : vector<[4]xi32> from vector<4x[4]xi32>167 vector.print %u0 : vector<[4]xi32>168 vector.print %u1 : vector<[4]xi32>169 vector.print %u2 : vector<[4]xi32>170 vector.print %u3 : vector<[4]xi32>171 172 // Deallocate the buffers.173 memref.dealloc %acc_mem : memref<4x?xi32>174 memref.dealloc %lhs_mem : memref<4x8xi8>175 memref.dealloc %rhs_mem : memref<?xi8>176 177 return178}179 180// Test the operation where both LHS and RHS are interpreted as unsigned, hence181// we ultimately emit and execute the `ummla` instruction.182 183// CHECK-IR-LABEL: llvm.func @test_ummla184// CHECK-IR-COUNT-4: arm_sve.intr.ummla185func.func @test_ummla() attributes {no_inline} {186 187 %c0 = arith.constant 0 : index188 %c0_i32 = arith.constant 0 : i32189 %c0_i8 = arith.constant 0 : i8190 191 // Accumulator test data192 %acc_cst = arith.constant dense<[[16, 16, 48, 40],193 [40, 24, 35, 12],194 [33, 24, 29, 19],195 [28, 13, 33, 18]]> : vector<4x4xi32>196 197 %acc_mem = func.call @prepareAccTestData(%acc_cst) : (vector<4x4xi32>) -> memref<4x?xi32>198 %acc = vector.transfer_read %acc_mem[%c0, %c0], %c0_i32 {in_bounds = [true, true]} : memref<4x?xi32>, vector<4x[4]xi32>199 200 // LHS test data201 %lhs_cst = arith.constant dense<[[35, 42, 37, 49, 36, 36, 23, 33],202 [39, 34, 33, 45, 43, 10, 44, 47],203 [18, 35, 29, 25, 36, 33, 28, 29],204 [26, 49, 43, 32, 27, 16, 45, 33]]> : vector<4x8xi8>205 206 %lhs_mem = func.call @prepareLHSTestData(%lhs_cst) : (vector<4x8xi8>) -> memref<4x8xi8>207 %lhs = vector.transfer_read %lhs_mem[%c0, %c0], %c0_i8 {in_bounds = [true, true]} : memref<4x8xi8>, vector<4x8xi8>208 209 // RHS test data210 %rhs_cst = arith.constant dense<[[18, 31, 37, 35, 44, 22, 37, 28],211 [21, 22, 49, 39, 30, 28, 35, 37],212 [21, 47, 39, 35, 23, 43, 24, 49],213 [49, 49, 40, 32, 37, 20, 47, 40]]> : vector<4x8xi8>214 215 %rhs_mem = func.call @prepareRHSTestData(%rhs_cst) : (vector<4x8xi8>) -> memref<?xi8>216 %rhs_flat = vector.transfer_read %rhs_mem[%c0], %c0_i8 {in_bounds = [true]} : memref<?xi8>, vector<[32]xi8>217 %rhs = vector.shape_cast %rhs_flat : vector<[32]xi8> to vector<[4]x8xi8>218 219 // Matrix multiplication and accumulate with transposed RHS.220 %0 = arith.extui %lhs : vector<4x8xi8> to vector<4x8xi32>221 %1 = arith.extui %rhs : vector<[4]x8xi8> to vector<[4]x8xi32>222 %2 = vector.contract {indexing_maps = #packed_maps,223 iterator_types = ["parallel", "parallel", "reduction"],224 kind = #vector.kind<add>} %0, %1, %acc225 : vector<4x8xi32>, vector<[4]x8xi32> into vector<4x[4]xi32>226 227 // Display the result of the multiplication228 vector.print str "Result(UMMLA):\n"229 %u0 = vector.extract %2[0] : vector<[4]xi32> from vector<4x[4]xi32>230 %u1 = vector.extract %2[1] : vector<[4]xi32> from vector<4x[4]xi32>231 %u2 = vector.extract %2[2] : vector<[4]xi32> from vector<4x[4]xi32>232 %u3 = vector.extract %2[3] : vector<[4]xi32> from vector<4x[4]xi32>233 vector.print %u0 : vector<[4]xi32>234 vector.print %u1 : vector<[4]xi32>235 vector.print %u2 : vector<[4]xi32>236 vector.print %u3 : vector<[4]xi32>237 238 // Deallocate the buffers.239 memref.dealloc %acc_mem : memref<4x?xi32>240 memref.dealloc %lhs_mem : memref<4x8xi8>241 memref.dealloc %rhs_mem : memref<?xi8>242 243 return244}245 246// Test the operation where LHS is interpreted as unsigned and RHS is247// interpreted as signed, hence we ultimately emit and execute the `usmmla`248// instruction.249 250// CHECK-IR-LABEL: llvm.func @test_usmmla251// CHECK-IR-COUNT-4: arm_sve.intr.usmmla252func.func @test_usmmla() attributes {no_inline} {253 254 %c0 = arith.constant 0 : index255 %c0_i32 = arith.constant 0 : i32256 %c0_i8 = arith.constant 0 : i8257 258 // Accumulator test data259 %acc_cst = arith.constant dense<[[-44, 20, 44, -46],260 [ -8, 25, -34, 26],261 [-20, -36, -3, 39],262 [-48, -31, -25, -21]]> : vector<4x4xi32>263 264 %acc_mem = func.call @prepareAccTestData(%acc_cst) : (vector<4x4xi32>) -> memref<4x?xi32>265 %acc = vector.transfer_read %acc_mem[%c0, %c0], %c0_i32 {in_bounds = [true, true]} : memref<4x?xi32>, vector<4x[4]xi32>266 267 // LHS test data268 %lhs_cst = arith.constant dense<[[153, 161, 24, 157, 211, 154, 52, 27],269 [168, 77, 136, 124, 249, 28, 13, 122],270 [ 97, 82, 181, 39, 53, 25, 80, 240],271 [184, 227, 106, 165, 126, 113, 121, 228]]> : vector<4x8xi8>272 273 %lhs_mem = func.call @prepareLHSTestData(%lhs_cst) : (vector<4x8xi8>) -> memref<4x8xi8>274 %lhs = vector.transfer_read %lhs_mem[%c0, %c0], %c0_i8 {in_bounds = [true, true]} : memref<4x8xi8>, vector<4x8xi8>275 276 // RHS test data277 %rhs_cst = arith.constant dense<[[ 40, 27, 37, 43, 38, -6, 37, 49],278 [-17, -50, -1, 48, -13, 22, 39, 33],279 [-35, -24, 37, -32, 33, 30, -11, -17],280 [-28, 31, 3, -44, -15, -27, 22, 35]]> : vector<4x8xi8>281 282 %rhs_mem = func.call @prepareRHSTestData(%rhs_cst) : (vector<4x8xi8>) -> memref<?xi8>283 %rhs_flat = vector.transfer_read %rhs_mem[%c0], %c0_i8 {in_bounds = [true]} : memref<?xi8>, vector<[32]xi8>284 %rhs = vector.shape_cast %rhs_flat : vector<[32]xi8> to vector<[4]x8xi8>285 286 // Matrix multiplication and accumulate with transposed RHS.287 %0 = arith.extui %lhs : vector<4x8xi8> to vector<4x8xi32>288 %1 = arith.extsi %rhs : vector<[4]x8xi8> to vector<[4]x8xi32>289 %2 = vector.contract {indexing_maps = #packed_maps,290 iterator_types = ["parallel", "parallel", "reduction"],291 kind = #vector.kind<add>} %0, %1, %acc292 : vector<4x8xi32>, vector<[4]x8xi32> into vector<4x[4]xi32>293 294 // Display the result of the multiplication295 vector.print str "Result(USMMLA):\n"296 %u0 = vector.extract %2[0] : vector<[4]xi32> from vector<4x[4]xi32>297 %u1 = vector.extract %2[1] : vector<[4]xi32> from vector<4x[4]xi32>298 %u2 = vector.extract %2[2] : vector<[4]xi32> from vector<4x[4]xi32>299 %u3 = vector.extract %2[3] : vector<[4]xi32> from vector<4x[4]xi32>300 vector.print %u0 : vector<[4]xi32>301 vector.print %u1 : vector<[4]xi32>302 vector.print %u2 : vector<[4]xi32>303 vector.print %u3 : vector<[4]xi32>304 305 // Deallocate the buffers.306 memref.dealloc %acc_mem : memref<4x?xi32>307 memref.dealloc %lhs_mem : memref<4x8xi8>308 memref.dealloc %rhs_mem : memref<?xi8>309 310 return311}312 313// Test the operation where LHS is interpreted as signed and RHS is interpreted314// as unsigned. In this test we ultimately emit end execute the `usmmla`315// instruction with reversed operands, see `LowerContractToSVEPatterns.cpp`316// for more details.317 318// CHECK-IR-LABEL: llvm.func @test_summla319// CHECK-IR-COUNT-4: arm_sve.intr.usmmla320func.func @test_summla() attributes {no_inline} {321 322 %c0 = arith.constant 0 : index323 %c0_i32 = arith.constant 0 : i32324 %c0_i8 = arith.constant 0 : i8325 326 // Accumulator test data327 %acc_cst = arith.constant dense<[[-44, 20, 44, -46],328 [ -8, 25, -34, 26],329 [-20, -36, -3, 39],330 [-48, -31, -25, -21]]> : vector<4x4xi32>331 332 %acc_mem = func.call @prepareAccTestData(%acc_cst) : (vector<4x4xi32>) -> memref<4x?xi32>333 %acc = vector.transfer_read %acc_mem[%c0, %c0], %c0_i32 {in_bounds = [true, true]} : memref<4x?xi32>, vector<4x[4]xi32>334 335 // LHS test data336 %lhs_cst = arith.constant dense<[[-35, -27, -36, -31, 23, -34, -8, -33],337 [-20, 17, -32, -47, 37, 22, -7, -21],338 [ -7, -35, 20, -4, 39, 46, -23, 40],339 [ 40, 27, 37, 43, 38, -6, 37, 49]]> : vector<4x8xi8>340 341 %lhs_mem = func.call @prepareLHSTestData(%lhs_cst) : (vector<4x8xi8>) -> memref<4x8xi8>342 %lhs = vector.transfer_read %lhs_mem[%c0, %c0], %c0_i8 {in_bounds = [true, true]} : memref<4x8xi8>, vector<4x8xi8>343 344 // RHS test data345 %rhs_cst = arith.constant dense<[[125, 171, 138, 187, 108, 175, 82, 99],346 [221, 25, 164, 97, 156, 221, 218, 177],347 [171, 160, 219, 191, 144, 45, 161, 210],348 [223, 165, 123, 99, 108, 86, 37, 92]]> : vector<4x8xi8>349 350 %rhs_mem = func.call @prepareRHSTestData(%rhs_cst) : (vector<4x8xi8>) -> memref<?xi8>351 %rhs_flat = vector.transfer_read %rhs_mem[%c0], %c0_i8 {in_bounds = [true]} : memref<?xi8>, vector<[32]xi8>352 %rhs = vector.shape_cast %rhs_flat : vector<[32]xi8> to vector<[4]x8xi8>353 354 // Matrix multiplication and accumulate with transposed RHS.355 %0 = arith.extsi %lhs : vector<4x8xi8> to vector<4x8xi32>356 %1 = arith.extui %rhs : vector<[4]x8xi8> to vector<[4]x8xi32>357 %2 = vector.contract {indexing_maps = #packed_maps,358 iterator_types = ["parallel", "parallel", "reduction"],359 kind = #vector.kind<add>} %0, %1, %acc360 : vector<4x8xi32>, vector<[4]x8xi32> into vector<4x[4]xi32>361 362 // Display the result of the multiplication363 vector.print str "Result(SUMMLA (i.e. USMMLA transposed)):\n"364 %u0 = vector.extract %2[0] : vector<[4]xi32> from vector<4x[4]xi32>365 %u1 = vector.extract %2[1] : vector<[4]xi32> from vector<4x[4]xi32>366 %u2 = vector.extract %2[2] : vector<[4]xi32> from vector<4x[4]xi32>367 %u3 = vector.extract %2[3] : vector<[4]xi32> from vector<4x[4]xi32>368 vector.print %u0 : vector<[4]xi32>369 vector.print %u1 : vector<[4]xi32>370 vector.print %u2 : vector<[4]xi32>371 vector.print %u3 : vector<[4]xi32>372 373 // Deallocate the buffers.374 memref.dealloc %acc_mem : memref<4x?xi32>375 memref.dealloc %lhs_mem : memref<4x8xi8>376 memref.dealloc %rhs_mem : memref<?xi8>377 378 return379}380 381// Perform each test with SVE vector lengths 128 bits and 256 bits (i.e. VSCALEs382// 1 and 2, respectively). The vector length is set via the `setArmVLBits`383// function. The effect of setting a different vector length is that the tests384// allocate and operate on different sized buffers (see `prepare<X>TestData`385// functions).386 387func.func @main() {388 %c128 = arith.constant 128 : i32389 %c256 = arith.constant 256 : i32390 391// CHECK-LABEL: Result(SMMLA):392// CHECK: ( -1999, 1941, 685, -2879 )393// CHECK: ( -3705, 2952, 987, -685 )394// CHECK: ( 2565, 4157, -1589, -357 )395// CHECK: ( 2383, -2252, 32, -1365 )396 func.call @setArmVLBits(%c128) : (i32) -> ()397 func.call @test_smmla() : () -> ()398 399// CHECK: Result(SMMLA):400// CHECK: ( -1999, 1941, 685, -2879, -1999, 1941, 685, -2879 )401// CHECK: ( -3705, 2952, 987, -685, -3705, 2952, 987, -685 )402// CHECK: ( 2565, 4157, -1589, -357, 2565, 4157, -1589, -357 )403// CHECK: ( 2383, -2252, 32, -1365, 2383, -2252, 32, -1365 )404 func.call @setArmVLBits(%c256) : (i32) -> ()405 func.call @test_smmla() : () -> ()406 407// CHECK-LABEL: Result(UMMLA):408// CHECK: ( 9183, 9513, 10460, 11314 )409// CHECK: ( 9648, 9812, 10092, 12088 )410// CHECK: ( 7548, 7625, 8398, 9044 )411// CHECK: ( 8855, 9046, 9685, 11191 )412 func.call @setArmVLBits(%c128) : (i32) -> ()413 func.call @test_ummla() : () -> ()414 415// CHECK: Result(UMMLA):416// CHECK: ( 9183, 9513, 10460, 11314, 9183, 9513, 10460, 11314 )417// CHECK: ( 9648, 9812, 10092, 12088, 9648, 9812, 10092, 12088 )418// CHECK: ( 7548, 7625, 8398, 9044, 7548, 7625, 8398, 9044 )419// CHECK: ( 8855, 9046, 9685, 11191, 8855, 9046, 9685, 11191 )420 func.call @setArmVLBits(%c256) : (i32) -> ()421 func.call @test_ummla() : () -> ()422 423// CHECK-LABEL: Result(USMMLA):424// CHECK: ( 28403, 445, -2759, -11409 )425// CHECK: ( 34908, 1047, 142, -7274 )426// CHECK: ( 31032, 6807, -2378, 7382 )427// CHECK: ( 44217, 6396, -10930, 623 )428 func.call @setArmVLBits(%c128) : (i32) -> ()429 func.call @test_usmmla() : () -> ()430 431// CHECK: Result(USMMLA):432// CHECK: ( 28403, 445, -2759, -11409, 28403, 445, -2759, -11409 )433// CHECK: ( 34908, 1047, 142, -7274, 34908, 1047, 142, -7274 )434// CHECK: ( 31032, 6807, -2378, 7382, 31032, 6807, -2378, 7382 )435// CHECK: ( 44217, 6396, -10930, 623, 44217, 6396, -10930, 623 )436 func.call @setArmVLBits(%c256) : (i32) -> ()437 func.call @test_usmmla() : () -> ()438 439// CHECK-LABEL: Result(SUMMLA (i.e. USMMLA transposed)):440// CHECK: ( -27190, -28812, -30502, -23575 )441// CHECK: ( -7613, -8386, -15938, -6521 )442// CHECK: ( 9468, 18750, 9199, 5764 )443// CHECK: ( 33655, 41064, 48900, 31627 )444 func.call @setArmVLBits(%c128) : (i32) -> ()445 func.call @test_summla() : () -> ()446 447// CHECK: Result(SUMMLA (i.e. USMMLA transposed)):448// CHECK: ( -27190, -28812, -30502, -23575, -27190, -28812, -30502, -23575 )449// CHECK: ( -7613, -8386, -15938, -6521, -7613, -8386, -15938, -6521 )450// CHECK: ( 9468, 18750, 9199, 5764, 9468, 18750, 9199, 5764 )451// CHECK: ( 33655, 41064, 48900, 31627, 33655, 41064, 48900, 31627 )452 func.call @setArmVLBits(%c256) : (i32) -> ()453 func.call @test_summla() : () -> ()454 455 return456}457 458func.func private @setArmVLBits(%bits : i32)459func.func private @printMemrefI32(%ptr : memref<*xi32>)460