1// Auto-generated file. Do not edit! 2// Template: src/qs8-gemm/4x8-aarch32-neon-mlal-lane-cortex-a7.S.in 3// Generator: tools/xngen 4// 5// Copyright 2021 Google LLC 6// 7// This source code is licensed under the BSD-style license found in the 8// LICENSE file in the root directory of this source tree. 9 10 11#include <xnnpack/assembly.h> 12 13.syntax unified 14 15// void xnn_qu8_gemm_minmax_rndnu_ukernel_4x8__aarch32_neon_mlal_lane_prfm_cortex_a7( 16// size_t mr, r0 17// size_t nc, r1 18// size_t kc, (r2) -> r5 19// const uint8_t*restrict a, r3 20// size_t a_stride, sp + 88 -> (r7) 21// const void*restrict w, sp + 92 -> r9 22// uint8_t*restrict c, sp + 96 -> r11 23// size_t cm_stride, sp + 100 -> (r6) 24// size_t cn_stride, sp + 104 -> r7 25// xnn_qs8_conv_minmax_params params) sp + 108 -> (r5) 26 27// d8-d15, r4-r11,r14(lr) need to be preserved if used. r13(sp),r15(pc) are reserved. 28 29// Based on cortex_a53 microkernel but with Neon loads 30 31// Register usage 32// A0 r3 d0-d1 q0 33// A1 r12 d2-d3 q1 34// A2 r10 d4-d5 q2 35// A3 r0 d6-d7 q3 36 37// B r9 d8-d9 q4 q5 38 39// C0 r11 d16-d17 q8 d18-d19 q9 40// C1 r4 d20-d21 q10 d22-d23 q11 41// C2 r8 d24-d25 q12 d26-d27 q13 42// C3 r6 d28-d29 q14 d30-d31 q15 43 44// Unused d15 45 46# params structure is 20 bytes 47# struct { 48# uint8_t kernel_zero_point[4]; d14 49# int32_t right_pre_shift; d12[0] 50# int32_t multiplier; d12[1] 51# int32_t right_post_shift; d13[0] 52# int16_t output_zero_point; d13[2] 53# uint8_t output_min; d13[6] 54# uint8_t output_max; d13[7] 55# } rndnu_neon; 56 57BEGIN_FUNCTION xnn_qu8_gemm_minmax_rndnu_ukernel_4x8__aarch32_neon_mlal_lane_prfm_cortex_a7 58 # Push 88 bytes 59 PUSH {r4, r5, r6, r7, r8, r9, r10, r11} // 32 60 VPUSH {d8-d14} // +56 = 88 61 62 LDR r7, [sp, 88] // a_stride 63 LDR r11, [sp, 96] // c 64 LDR r6, [sp, 100] // cm_stride 65 LDR r9, [sp, 92] // w 66 LDR r5, [sp, 108] // params 67 68 # Clamp A and C pointers 69 CMP r0, 2 // if mr >= 2 70 ADD r12, r3, r7 // a1 = a0 + a_stride 71 ADD r4, r11, r6 // c1 = c0 + cm_stride 72 MOVLO r12, r3 // a1 73 MOVLO r4, r11 // c1 74 // if mr > 2 75 ADD r10, r12, r7 // a2 = a1 + a_stride 76 ADD r8, r4, r6 // c2 = c1 + cm_stride 77 MOVLS r10, r12 // a2 78 MOVLS r8, r4 // c2 79 80 CMP r0, 4 // if mr >=4 81 ADD r0, r10, r7 // a3 = a2 + a_stride 82 ADD r6, r8, r6 // c3 = c2 + cm_stride 83 MOVLO r0, r10 // a3 84 MOVLO r6, r8 // c3 85 86 # Load params values 87 VLD1.32 {d14[]}, [r5]! // QU8 kernel_zero_point 88 VLDM r5, {d12-d13} // RNDNU params 89 LDR r7, [sp, 104] // cn_stride 90 91 PLD [r9, 64] // Prefetch B 92 PLD [r9, 128] 93 PLD [r9, 192] 94 PLD [r9, 256] 95 PLD [r9, 320] 96 PLD [r9, 384] 97 98 .p2align 3 990: 100 # Load initial bias from w into accumulators 101 VLDM r9!, {d16-d19} // Bias 102 SUBS r5, r2, 8 // k = kc - 8 103 104 VMOV q10, q8 105 PLD [r3, 64] // Prefetch A 106 VMOV q11, q9 107 PLD [r12, 64] 108 VMOV q12, q8 109 PLD [r10, 64] 110 VMOV q13, q9 111 PLD [r0, 64] 112 VMOV q14, q8 113 VMOV q15, q9 114 BLO 4f // less than 8 channels? 115 116 // Prologue - load 4A's and B0 117 VLD1.8 {d0}, [r3]! // A0 118 VLD1.8 {d2}, [r12]! // A1 119 VLD1.8 {d4}, [r10]! // A2 120 VLD1.8 {d6}, [r0]! // A3 121 VLD1.8 {d8}, [r9]! // B0 122 123 SUBS r5, r5, 8 // k = k - 8 124 BLO 2f // less than 8 channels? 125 126 // Main loop - 8 bytes 127 // 64 bytes for weights. 128 // 5 VMOVL = 4 A and 1 B = 5 cycles 129 // 7 blocks with VLD B, VMOVL, 8 VMLA = 10 cycles 130 // 1 blocks with VLD B, VMLA = 9 cycles 131 // total = 84 cycles 132 .p2align 3 1331: 134 // Extend - 5 cycles 135 VMOVL.U8 q0, d0 136 VSUBL.U8 q4, d8, d14 137 PLD [r9, 448] 138 VMOVL.U8 q1, d2 139 VMOVL.U8 q2, d4 140 VMOVL.U8 q3, d6 141 142 // BLOCK 0 - 10 cycles 143 VLD1.8 {d10}, [r9]! // B1 144 VMLAL.S16 q8, d8, d0[0] 145 VMLAL.S16 q9, d9, d0[0] 146 VMLAL.S16 q10, d8, d2[0] 147 VMLAL.S16 q11, d9, d2[0] 148 VSUBL.U8 q5, d10, d14 149 VMLAL.S16 q12, d8, d4[0] 150 VMLAL.S16 q13, d9, d4[0] 151 VMLAL.S16 q14, d8, d6[0] 152 VMLAL.S16 q15, d9, d6[0] 153 154 // BLOCK 1 - 10 cycles 155 VLD1.8 {d8}, [r9]! // B2 156 VMLAL.S16 q8, d10, d0[1] 157 VMLAL.S16 q9, d11, d0[1] 158 VMLAL.S16 q10, d10, d2[1] 159 VMLAL.S16 q11, d11, d2[1] 160 VSUBL.U8 q4, d8, d14 161 VMLAL.S16 q12, d10, d4[1] 162 VMLAL.S16 q13, d11, d4[1] 163 VMLAL.S16 q14, d10, d6[1] 164 VMLAL.S16 q15, d11, d6[1] 165 166 // BLOCK 2 - 10 cycles 167 VLD1.8 {d10}, [r9]! // B3 168 VMLAL.S16 q8, d8, d0[2] 169 VMLAL.S16 q9, d9, d0[2] 170 VMLAL.S16 q10, d8, d2[2] 171 VMLAL.S16 q11, d9, d2[2] 172 VSUBL.U8 q5, d10, d14 173 VMLAL.S16 q12, d8, d4[2] 174 VMLAL.S16 q13, d9, d4[2] 175 VMLAL.S16 q14, d8, d6[2] 176 VMLAL.S16 q15, d9, d6[2] 177 178 // BLOCK 3 - 10 cycles 179 VLD1.8 {d8}, [r9]! // B4 180 VMLAL.S16 q8, d10, d0[3] 181 VMLAL.S16 q9, d11, d0[3] 182 VMLAL.S16 q10, d10, d2[3] 183 VMLAL.S16 q11, d11, d2[3] 184 VLD1.8 {d0}, [r3]! // A0 185 VSUBL.U8 q4, d8, d14 186 VMLAL.S16 q12, d10, d4[3] 187 VMLAL.S16 q13, d11, d4[3] 188 VMLAL.S16 q14, d10, d6[3] 189 VMLAL.S16 q15, d11, d6[3] 190 191 // BLOCK 4 - 10 cycles 192 VLD1.8 {d10}, [r9]! // B5 193 VMLAL.S16 q8, d8, d1[0] 194 VMLAL.S16 q9, d9, d1[0] 195 VMLAL.S16 q10, d8, d3[0] 196 VMLAL.S16 q11, d9, d3[0] 197 VLD1.8 {d2}, [r12]! // A1 198 VSUBL.U8 q5, d10, d14 199 VMLAL.S16 q12, d8, d5[0] 200 VMLAL.S16 q13, d9, d5[0] 201 VMLAL.S16 q14, d8, d7[0] 202 VMLAL.S16 q15, d9, d7[0] 203 204 // BLOCK 5 - 10 cycles 205 VLD1.8 {d8}, [r9]! // B6 206 VMLAL.S16 q8, d10, d1[1] 207 VMLAL.S16 q9, d11, d1[1] 208 VMLAL.S16 q10, d10, d3[1] 209 VMLAL.S16 q11, d11, d3[1] 210 VLD1.8 {d4}, [r10]! // A2 211 VSUBL.U8 q4, d8, d14 212 VMLAL.S16 q12, d10, d5[1] 213 VMLAL.S16 q13, d11, d5[1] 214 VMLAL.S16 q14, d10, d7[1] 215 VMLAL.S16 q15, d11, d7[1] 216 217 // BLOCK 6 - 10 cycles 218 VLD1.8 {d10}, [r9]! // B7 219 VMLAL.S16 q8, d8, d1[2] 220 VMLAL.S16 q9, d9, d1[2] 221 VMLAL.S16 q10, d8, d3[2] 222 VMLAL.S16 q11, d9, d3[2] 223 VLD1.8 {d6}, [r0]! // A3 224 VSUBL.U8 q5, d10, d14 225 VMLAL.S16 q12, d8, d5[2] 226 VMLAL.S16 q13, d9, d5[2] 227 VMLAL.S16 q14, d8, d7[2] 228 VMLAL.S16 q15, d9, d7[2] 229 230 // BLOCK 7 - 9 cycles 231 VLD1.8 {d8}, [r9]! // B0 232 VMLAL.S16 q8, d10, d1[3] 233 VMLAL.S16 q9, d11, d1[3] 234 VMLAL.S16 q10, d10, d3[3] 235 VMLAL.S16 q11, d11, d3[3] 236 VMLAL.S16 q12, d10, d5[3] 237 VMLAL.S16 q13, d11, d5[3] 238 SUBS r5, r5, 8 239 VMLAL.S16 q14, d10, d7[3] 240 VMLAL.S16 q15, d11, d7[3] 241 BHS 1b 242 243 // Epilogue 244 245 .p2align 3 2462: 247 VMOVL.U8 q0, d0 248 VSUBL.U8 q4, d8, d14 249 VMOVL.U8 q1, d2 250 VMOVL.U8 q2, d4 251 VMOVL.U8 q3, d6 252 253 VLD1.8 {d10}, [r9]! // B1 254 VMLAL.S16 q8, d8, d0[0] 255 VMLAL.S16 q9, d9, d0[0] 256 VMLAL.S16 q10, d8, d2[0] 257 VMLAL.S16 q11, d9, d2[0] 258 VSUBL.U8 q5, d10, d14 259 VMLAL.S16 q12, d8, d4[0] 260 VMLAL.S16 q13, d9, d4[0] 261 VMLAL.S16 q14, d8, d6[0] 262 VMLAL.S16 q15, d9, d6[0] 263 264 VLD1.8 {d8}, [r9]! // B2 265 VMLAL.S16 q8, d10, d0[1] 266 VMLAL.S16 q9, d11, d0[1] 267 VMLAL.S16 q10, d10, d2[1] 268 VMLAL.S16 q11, d11, d2[1] 269 VSUBL.U8 q4, d8, d14 270 VMLAL.S16 q12, d10, d4[1] 271 VMLAL.S16 q13, d11, d4[1] 272 VMLAL.S16 q14, d10, d6[1] 273 VMLAL.S16 q15, d11, d6[1] 274 275 VLD1.8 {d10}, [r9]! // B3 276 VMLAL.S16 q8, d8, d0[2] 277 VMLAL.S16 q9, d9, d0[2] 278 VMLAL.S16 q10, d8, d2[2] 279 VMLAL.S16 q11, d9, d2[2] 280 VSUBL.U8 q5, d10, d14 281 VMLAL.S16 q12, d8, d4[2] 282 VMLAL.S16 q13, d9, d4[2] 283 VMLAL.S16 q14, d8, d6[2] 284 VMLAL.S16 q15, d9, d6[2] 285 286 VLD1.8 {d8}, [r9]! // B4 287 VMLAL.S16 q8, d10, d0[3] 288 VMLAL.S16 q9, d11, d0[3] 289 VMLAL.S16 q10, d10, d2[3] 290 VMLAL.S16 q11, d11, d2[3] 291 VSUBL.U8 q4, d8, d14 292 VMLAL.S16 q12, d10, d4[3] 293 VMLAL.S16 q13, d11, d4[3] 294 VMLAL.S16 q14, d10, d6[3] 295 VMLAL.S16 q15, d11, d6[3] 296 297 VLD1.8 {d10}, [r9]! // B5 298 VMLAL.S16 q8, d8, d1[0] 299 VMLAL.S16 q9, d9, d1[0] 300 VMLAL.S16 q10, d8, d3[0] 301 VMLAL.S16 q11, d9, d3[0] 302 VSUBL.U8 q5, d10, d14 303 VMLAL.S16 q12, d8, d5[0] 304 VMLAL.S16 q13, d9, d5[0] 305 VMLAL.S16 q14, d8, d7[0] 306 VMLAL.S16 q15, d9, d7[0] 307 308 VLD1.8 {d8}, [r9]! // B6 309 VMLAL.S16 q8, d10, d1[1] 310 VMLAL.S16 q9, d11, d1[1] 311 VMLAL.S16 q10, d10, d3[1] 312 VMLAL.S16 q11, d11, d3[1] 313 VSUBL.U8 q4, d8, d14 314 VMLAL.S16 q12, d10, d5[1] 315 VMLAL.S16 q13, d11, d5[1] 316 VMLAL.S16 q14, d10, d7[1] 317 VMLAL.S16 q15, d11, d7[1] 318 319 VLD1.8 {d10}, [r9]! // B7 320 VMLAL.S16 q8, d8, d1[2] 321 VMLAL.S16 q9, d9, d1[2] 322 VMLAL.S16 q10, d8, d3[2] 323 VMLAL.S16 q11, d9, d3[2] 324 VSUBL.U8 q5, d10, d14 325 VMLAL.S16 q12, d8, d5[2] 326 VMLAL.S16 q13, d9, d5[2] 327 VMLAL.S16 q14, d8, d7[2] 328 VMLAL.S16 q15, d9, d7[2] 329 330 VMLAL.S16 q8, d10, d1[3] 331 VMLAL.S16 q9, d11, d1[3] 332 VMLAL.S16 q10, d10, d3[3] 333 VMLAL.S16 q11, d11, d3[3] 334 VMLAL.S16 q12, d10, d5[3] 335 VMLAL.S16 q13, d11, d5[3] 336 ADDS r5, r5, 8 337 VMLAL.S16 q14, d10, d7[3] 338 VMLAL.S16 q15, d11, d7[3] 339 340 # Is there a remainder?- 1-7 bytes of A 341 BNE 4f 342 3433: 344 # RNDNU quantization 345 VDUP.32 q0, d12[0] // right_pre_shift 346 347 VQSHL.S32 q8, q8, q0 348 VQSHL.S32 q9, q9, q0 349 VQSHL.S32 q10, q10, q0 350 VQSHL.S32 q11, q11, q0 351 VQSHL.S32 q12, q12, q0 352 VQSHL.S32 q13, q13, q0 353 VQSHL.S32 q14, q14, q0 354 VQSHL.S32 q15, q15, q0 355 356 VDUP.32 q2, d13[0] // right_post_shift 357 358 VQDMULH.S32 q8, q8, d12[1] // multiplier 359 VQDMULH.S32 q9, q9, d12[1] 360 VQDMULH.S32 q10, q10, d12[1] 361 VQDMULH.S32 q11, q11, d12[1] 362 VQDMULH.S32 q12, q12, d12[1] 363 VQDMULH.S32 q13, q13, d12[1] 364 VQDMULH.S32 q14, q14, d12[1] 365 VQDMULH.S32 q15, q15, d12[1] 366 367 VRSHL.S32 q8, q8, q2 368 VRSHL.S32 q9, q9, q2 369 VRSHL.S32 q10, q10, q2 370 VRSHL.S32 q11, q11, q2 371 VRSHL.S32 q12, q12, q2 372 VRSHL.S32 q13, q13, q2 373 VRSHL.S32 q14, q14, q2 374 VRSHL.S32 q15, q15, q2 375 376 VDUP.16 q0, d13[2] // output_zero_point 377 378 VQMOVN.S32 d16, q8 379 VQMOVN.S32 d17, q9 380 VQMOVN.S32 d18, q10 381 VQMOVN.S32 d19, q11 382 VQMOVN.S32 d20, q12 383 VQMOVN.S32 d21, q13 384 VQMOVN.S32 d22, q14 385 VQMOVN.S32 d23, q15 386 387 VQADD.S16 q8, q8, q0 388 VQADD.S16 q9, q9, q0 389 VQADD.S16 q10, q10, q0 390 VQADD.S16 q11, q11, q0 391 392 VDUP.8 q12, d13[6] // output_min 393 394 VQMOVUN.S16 d0, q8 395 VQMOVUN.S16 d1, q9 396 VQMOVUN.S16 d2, q10 397 VQMOVUN.S16 d3, q11 398 399 VDUP.8 q13, d13[7] // output_max 400 401 VMAX.U8 q0, q0, q12 402 VMAX.U8 q1, q1, q12 403 404 SUBS r1, r1, 8 405 406 VMIN.U8 q0, q0, q13 407 VMIN.U8 q1, q1, q13 408 409 # Store full 4 x 8 410 BLO 5f 411 VST1.8 {d0}, [r11], r7 412 SUB r3, r3, r2 413 VST1.8 {d1}, [r4], r7 414 SUB r12, r12, r2 415 VST1.8 {d2}, [r8], r7 416 SUB r10, r10, r2 417 VST1.8 {d3}, [r6], r7 418 SUB r0, r0, r2 419 BHI 0b 420 421 VPOP {d8-d14} 422 POP {r4, r5, r6, r7, r8, r9, r10, r11} 423 BX lr 424 425 # Remainder- 1 to 7 bytes of A 426 .p2align 3 4274: 428 AND r5, r5, 7 // kc remainder 1 to 7 429 430 VLD1.8 {d0}, [r3], r5 431 VLD1.8 {d8}, [r9]! 432 VLD1.8 {d2}, [r12], r5 433 VLD1.8 {d4}, [r10], r5 434 VLD1.8 {d6}, [r0], r5 435 436 VMOVL.U8 q0, d0 437 VSUBL.U8 q4, d8, d14 438 VMOVL.U8 q1, d2 439 VMOVL.U8 q2, d4 440 VMOVL.U8 q3, d6 441 VMLAL.S16 q8, d8, d0[0] 442 VMLAL.S16 q9, d9, d0[0] 443 VMLAL.S16 q10, d8, d2[0] 444 VMLAL.S16 q11, d9, d2[0] 445 VMLAL.S16 q12, d8, d4[0] 446 VMLAL.S16 q13, d9, d4[0] 447 VMLAL.S16 q14, d8, d6[0] 448 VMLAL.S16 q15, d9, d6[0] 449 CMP r5, 2 450 BLO 3b 451 452 VLD1.8 {d8}, [r9]! 453 VSUBL.U8 q4, d8, d14 454 VMLAL.S16 q8, d8, d0[1] 455 VMLAL.S16 q9, d9, d0[1] 456 VMLAL.S16 q10, d8, d2[1] 457 VMLAL.S16 q11, d9, d2[1] 458 VMLAL.S16 q12, d8, d4[1] 459 VMLAL.S16 q13, d9, d4[1] 460 VMLAL.S16 q14, d8, d6[1] 461 VMLAL.S16 q15, d9, d6[1] 462 BEQ 3b 463 464 VLD1.8 {d8}, [r9]! 465 VSUBL.U8 q4, d8, d14 466 VMLAL.S16 q8, d8, d0[2] 467 VMLAL.S16 q9, d9, d0[2] 468 VMLAL.S16 q10, d8, d2[2] 469 VMLAL.S16 q11, d9, d2[2] 470 VMLAL.S16 q12, d8, d4[2] 471 VMLAL.S16 q13, d9, d4[2] 472 VMLAL.S16 q14, d8, d6[2] 473 VMLAL.S16 q15, d9, d6[2] 474 CMP r5, 4 475 BLO 3b 476 477 VLD1.8 {d8}, [r9]! 478 VSUBL.U8 q4, d8, d14 479 VMLAL.S16 q8, d8, d0[3] 480 VMLAL.S16 q9, d9, d0[3] 481 VMLAL.S16 q10, d8, d2[3] 482 VMLAL.S16 q11, d9, d2[3] 483 VMLAL.S16 q12, d8, d4[3] 484 VMLAL.S16 q13, d9, d4[3] 485 VMLAL.S16 q14, d8, d6[3] 486 VMLAL.S16 q15, d9, d6[3] 487 BEQ 3b 488 489 VLD1.8 {d8}, [r9]! 490 VSUBL.U8 q4, d8, d14 491 VMLAL.S16 q8, d8, d1[0] 492 VMLAL.S16 q9, d9, d1[0] 493 VMLAL.S16 q10, d8, d3[0] 494 VMLAL.S16 q11, d9, d3[0] 495 VMLAL.S16 q12, d8, d5[0] 496 VMLAL.S16 q13, d9, d5[0] 497 VMLAL.S16 q14, d8, d7[0] 498 VMLAL.S16 q15, d9, d7[0] 499 CMP r5, 6 500 BLO 3b 501 502 VLD1.8 {d8}, [r9]! 503 VSUBL.U8 q4, d8, d14 504 VMLAL.S16 q8, d8, d1[1] 505 VMLAL.S16 q9, d9, d1[1] 506 VMLAL.S16 q10, d8, d3[1] 507 VMLAL.S16 q11, d9, d3[1] 508 VMLAL.S16 q12, d8, d5[1] 509 VMLAL.S16 q13, d9, d5[1] 510 VMLAL.S16 q14, d8, d7[1] 511 VMLAL.S16 q15, d9, d7[1] 512 BEQ 3b 513 514 VLD1.8 {d8}, [r9]! 515 VSUBL.U8 q4, d8, d14 516 VMLAL.S16 q8, d8, d1[2] 517 VMLAL.S16 q9, d9, d1[2] 518 VMLAL.S16 q10, d8, d3[2] 519 VMLAL.S16 q11, d9, d3[2] 520 VMLAL.S16 q12, d8, d5[2] 521 VMLAL.S16 q13, d9, d5[2] 522 VMLAL.S16 q14, d8, d7[2] 523 VMLAL.S16 q15, d9, d7[2] 524 B 3b 525 526 # Store odd width 527 .p2align 3 5285: 529 TST r1, 4 530 BEQ 6f 531 VST1.32 {d0[0]}, [r11]! 532 VST1.32 {d1[0]}, [r4]! 533 VST1.32 {d2[0]}, [r8]! 534 VST1.32 {d3[0]}, [r6]! 535 VEXT.8 q0, q0, q0, 4 536 VEXT.8 q1, q1, q1, 4 5376: 538 TST r1, 2 539 BEQ 7f 540 VST1.16 {d0[0]}, [r11]! 541 VST1.16 {d1[0]}, [r4]! 542 VST1.16 {d2[0]}, [r8]! 543 VST1.16 {d3[0]}, [r6]! 544 VEXT.8 q0, q0, q0, 2 545 VEXT.8 q1, q1, q1, 2 546 5477: 548 TST r1, 1 549 BEQ 8f 550 VST1.8 {d0[0]}, [r11] 551 VST1.8 {d1[0]}, [r4] 552 VST1.8 {d2[0]}, [r8] 553 VST1.8 {d3[0]}, [r6] 554 5558: 556 VPOP {d8-d14} 557 POP {r4, r5, r6, r7, r8, r9, r10, r11} 558 BX lr 559 560END_FUNCTION xnn_qu8_gemm_minmax_rndnu_ukernel_4x8__aarch32_neon_mlal_lane_prfm_cortex_a7 561 562#ifdef __ELF__ 563.section ".note.GNU-stack","",%progbits 564#endif 565 566