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_qs8_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 int8_t*restrict a, r3 20// size_t a_stride, sp + 88 -> (r7) 21// const void*restrict w, sp + 92 -> r9 22// int8_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 16 bytes 47// struct { 48// int32_t right_pre_shift; d12[0] 49// int32_t multiplier; d12[1] 50// int32_t right_post_shift; d13[0] 51// int16_t output_zero_point; d13[2] 52// int8_t output_min; d13[6] 53// int8_t output_max; d13[7] 54// } rndnu_neon; 55 56BEGIN_FUNCTION xnn_qs8_gemm_minmax_rndnu_ukernel_4x8__aarch32_neon_mlal_lane_prfm_cortex_a7 57 # Push 88 bytes 58 PUSH {r4, r5, r6, r7, r8, r9, r10, r11} // 32 59 SUB sp, sp, 8 // +8 60 VPUSH {d8-d13} // +48 = 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 VLDM r5, {d12-d13} // RNDNU params 88 LDR r7, [sp, 104] // cn_stride 89 90 PLD [r9, 64] // Prefetch B 91 PLD [r9, 128] 92 PLD [r9, 192] 93 PLD [r9, 256] 94 PLD [r9, 320] 95 PLD [r9, 384] 96 97 .p2align 3 980: 99 # Load initial bias from w into accumulators 100 VLDM r9!, {d16-d19} // Bias 101 SUBS r5, r2, 8 // k = kc - 8 102 103 VMOV q10, q8 104 PLD [r3, 64] // Prefetch A 105 VMOV q11, q9 106 PLD [r12, 64] 107 VMOV q12, q8 108 PLD [r10, 64] 109 VMOV q13, q9 110 PLD [r0, 64] 111 VMOV q14, q8 112 VMOV q15, q9 113 BLO 4f // less than 8 channels? 114 115 // Prologue - load 4A's and B0 116 VLD1.8 {d0}, [r3]! // A0 117 VLD1.8 {d2}, [r12]! // A1 118 VLD1.8 {d4}, [r10]! // A2 119 VLD1.8 {d6}, [r0]! // A3 120 VLD1.8 {d8}, [r9]! // B0 121 122 SUBS r5, r5, 8 // k = k - 8 123 BLO 2f // less than 8 channels? 124 125 // Main loop - 8 bytes 126 // 64 bytes for weights. 127 // 5 VMOVL = 4 A and 1 B = 5 cycles 128 // 7 blocks with VLD B, VMOVL, 8 VMLA = 10 cycles 129 // 1 blocks with VLD B, VMLA = 9 cycles 130 // total = 84 cycles 131 .p2align 3 1321: 133 // Extend - 5 cycles 134 VMOVL.S8 q0, d0 135 VMOVL.S8 q4, d8 136 PLD [r9, 448] 137 VMOVL.S8 q1, d2 138 VMOVL.S8 q2, d4 139 VMOVL.S8 q3, d6 140 141 // BLOCK 0 - 10 cycles 142 VLD1.8 {d10}, [r9]! // B1 143 VMLAL.S16 q8, d8, d0[0] 144 VMLAL.S16 q9, d9, d0[0] 145 VMLAL.S16 q10, d8, d2[0] 146 VMLAL.S16 q11, d9, d2[0] 147 VMOVL.S8 q5, d10 148 VMLAL.S16 q12, d8, d4[0] 149 VMLAL.S16 q13, d9, d4[0] 150 VMLAL.S16 q14, d8, d6[0] 151 VMLAL.S16 q15, d9, d6[0] 152 153 // BLOCK 1 - 10 cycles 154 VLD1.8 {d8}, [r9]! // B2 155 VMLAL.S16 q8, d10, d0[1] 156 VMLAL.S16 q9, d11, d0[1] 157 VMLAL.S16 q10, d10, d2[1] 158 VMLAL.S16 q11, d11, d2[1] 159 VMOVL.S8 q4, d8 160 VMLAL.S16 q12, d10, d4[1] 161 VMLAL.S16 q13, d11, d4[1] 162 VMLAL.S16 q14, d10, d6[1] 163 VMLAL.S16 q15, d11, d6[1] 164 165 // BLOCK 2 - 10 cycles 166 VLD1.8 {d10}, [r9]! // B3 167 VMLAL.S16 q8, d8, d0[2] 168 VMLAL.S16 q9, d9, d0[2] 169 VMLAL.S16 q10, d8, d2[2] 170 VMLAL.S16 q11, d9, d2[2] 171 VMOVL.S8 q5, d10 172 VMLAL.S16 q12, d8, d4[2] 173 VMLAL.S16 q13, d9, d4[2] 174 VMLAL.S16 q14, d8, d6[2] 175 VMLAL.S16 q15, d9, d6[2] 176 177 // BLOCK 3 - 10 cycles 178 VLD1.8 {d8}, [r9]! // B4 179 VMLAL.S16 q8, d10, d0[3] 180 VMLAL.S16 q9, d11, d0[3] 181 VMLAL.S16 q10, d10, d2[3] 182 VMLAL.S16 q11, d11, d2[3] 183 VLD1.8 {d0}, [r3]! // A0 184 VMOVL.S8 q4, d8 185 VMLAL.S16 q12, d10, d4[3] 186 VMLAL.S16 q13, d11, d4[3] 187 VMLAL.S16 q14, d10, d6[3] 188 VMLAL.S16 q15, d11, d6[3] 189 190 // BLOCK 4 - 10 cycles 191 VLD1.8 {d10}, [r9]! // B5 192 VMLAL.S16 q8, d8, d1[0] 193 VMLAL.S16 q9, d9, d1[0] 194 VMLAL.S16 q10, d8, d3[0] 195 VMLAL.S16 q11, d9, d3[0] 196 VLD1.8 {d2}, [r12]! // A1 197 VMOVL.S8 q5, d10 198 VMLAL.S16 q12, d8, d5[0] 199 VMLAL.S16 q13, d9, d5[0] 200 VMLAL.S16 q14, d8, d7[0] 201 VMLAL.S16 q15, d9, d7[0] 202 203 // BLOCK 5 - 10 cycles 204 VLD1.8 {d8}, [r9]! // B6 205 VMLAL.S16 q8, d10, d1[1] 206 VMLAL.S16 q9, d11, d1[1] 207 VMLAL.S16 q10, d10, d3[1] 208 VMLAL.S16 q11, d11, d3[1] 209 VLD1.8 {d4}, [r10]! // A2 210 VMOVL.S8 q4, d8 211 VMLAL.S16 q12, d10, d5[1] 212 VMLAL.S16 q13, d11, d5[1] 213 VMLAL.S16 q14, d10, d7[1] 214 VMLAL.S16 q15, d11, d7[1] 215 216 // BLOCK 6 - 10 cycles 217 VLD1.8 {d10}, [r9]! // B7 218 VMLAL.S16 q8, d8, d1[2] 219 VMLAL.S16 q9, d9, d1[2] 220 VMLAL.S16 q10, d8, d3[2] 221 VMLAL.S16 q11, d9, d3[2] 222 VLD1.8 {d6}, [r0]! // A3 223 VMOVL.S8 q5, d10 224 VMLAL.S16 q12, d8, d5[2] 225 VMLAL.S16 q13, d9, d5[2] 226 VMLAL.S16 q14, d8, d7[2] 227 VMLAL.S16 q15, d9, d7[2] 228 229 // BLOCK 7 - 9 cycles 230 VLD1.8 {d8}, [r9]! // B0 231 VMLAL.S16 q8, d10, d1[3] 232 VMLAL.S16 q9, d11, d1[3] 233 VMLAL.S16 q10, d10, d3[3] 234 VMLAL.S16 q11, d11, d3[3] 235 VMLAL.S16 q12, d10, d5[3] 236 VMLAL.S16 q13, d11, d5[3] 237 SUBS r5, r5, 8 238 VMLAL.S16 q14, d10, d7[3] 239 VMLAL.S16 q15, d11, d7[3] 240 BHS 1b 241 242 // Epilogue 243 244 .p2align 3 2452: 246 VMOVL.S8 q0, d0 247 VMOVL.S8 q4, d8 248 VMOVL.S8 q1, d2 249 VMOVL.S8 q2, d4 250 VMOVL.S8 q3, d6 251 252 VLD1.8 {d10}, [r9]! // B1 253 VMLAL.S16 q8, d8, d0[0] 254 VMLAL.S16 q9, d9, d0[0] 255 VMLAL.S16 q10, d8, d2[0] 256 VMLAL.S16 q11, d9, d2[0] 257 VMOVL.S8 q5, d10 258 VMLAL.S16 q12, d8, d4[0] 259 VMLAL.S16 q13, d9, d4[0] 260 VMLAL.S16 q14, d8, d6[0] 261 VMLAL.S16 q15, d9, d6[0] 262 263 VLD1.8 {d8}, [r9]! // B2 264 VMLAL.S16 q8, d10, d0[1] 265 VMLAL.S16 q9, d11, d0[1] 266 VMLAL.S16 q10, d10, d2[1] 267 VMLAL.S16 q11, d11, d2[1] 268 VMOVL.S8 q4, d8 269 VMLAL.S16 q12, d10, d4[1] 270 VMLAL.S16 q13, d11, d4[1] 271 VMLAL.S16 q14, d10, d6[1] 272 VMLAL.S16 q15, d11, d6[1] 273 274 VLD1.8 {d10}, [r9]! // B3 275 VMLAL.S16 q8, d8, d0[2] 276 VMLAL.S16 q9, d9, d0[2] 277 VMLAL.S16 q10, d8, d2[2] 278 VMLAL.S16 q11, d9, d2[2] 279 VMOVL.S8 q5, d10 280 VMLAL.S16 q12, d8, d4[2] 281 VMLAL.S16 q13, d9, d4[2] 282 VMLAL.S16 q14, d8, d6[2] 283 VMLAL.S16 q15, d9, d6[2] 284 285 VLD1.8 {d8}, [r9]! // B4 286 VMLAL.S16 q8, d10, d0[3] 287 VMLAL.S16 q9, d11, d0[3] 288 VMLAL.S16 q10, d10, d2[3] 289 VMLAL.S16 q11, d11, d2[3] 290 VMOVL.S8 q4, d8 291 VMLAL.S16 q12, d10, d4[3] 292 VMLAL.S16 q13, d11, d4[3] 293 VMLAL.S16 q14, d10, d6[3] 294 VMLAL.S16 q15, d11, d6[3] 295 296 VLD1.8 {d10}, [r9]! // B5 297 VMLAL.S16 q8, d8, d1[0] 298 VMLAL.S16 q9, d9, d1[0] 299 VMLAL.S16 q10, d8, d3[0] 300 VMLAL.S16 q11, d9, d3[0] 301 VMOVL.S8 q5, d10 302 VMLAL.S16 q12, d8, d5[0] 303 VMLAL.S16 q13, d9, d5[0] 304 VMLAL.S16 q14, d8, d7[0] 305 VMLAL.S16 q15, d9, d7[0] 306 307 VLD1.8 {d8}, [r9]! // B6 308 VMLAL.S16 q8, d10, d1[1] 309 VMLAL.S16 q9, d11, d1[1] 310 VMLAL.S16 q10, d10, d3[1] 311 VMLAL.S16 q11, d11, d3[1] 312 VMOVL.S8 q4, d8 313 VMLAL.S16 q12, d10, d5[1] 314 VMLAL.S16 q13, d11, d5[1] 315 VMLAL.S16 q14, d10, d7[1] 316 VMLAL.S16 q15, d11, d7[1] 317 318 VLD1.8 {d10}, [r9]! // B7 319 VMLAL.S16 q8, d8, d1[2] 320 VMLAL.S16 q9, d9, d1[2] 321 VMLAL.S16 q10, d8, d3[2] 322 VMLAL.S16 q11, d9, d3[2] 323 VMOVL.S8 q5, d10 324 VMLAL.S16 q12, d8, d5[2] 325 VMLAL.S16 q13, d9, d5[2] 326 VMLAL.S16 q14, d8, d7[2] 327 VMLAL.S16 q15, d9, d7[2] 328 329 VMLAL.S16 q8, d10, d1[3] 330 VMLAL.S16 q9, d11, d1[3] 331 VMLAL.S16 q10, d10, d3[3] 332 VMLAL.S16 q11, d11, d3[3] 333 VMLAL.S16 q12, d10, d5[3] 334 VMLAL.S16 q13, d11, d5[3] 335 ADDS r5, r5, 8 336 VMLAL.S16 q14, d10, d7[3] 337 VMLAL.S16 q15, d11, d7[3] 338 339 # Is there a remainder?- 1-7 bytes of A 340 BNE 4f 341 3423: 343 # RNDNU quantization 344 VDUP.32 q0, d12[0] // right_pre_shift 345 346 VQSHL.S32 q8, q8, q0 347 VQSHL.S32 q9, q9, q0 348 VQSHL.S32 q10, q10, q0 349 VQSHL.S32 q11, q11, q0 350 VQSHL.S32 q12, q12, q0 351 VQSHL.S32 q13, q13, q0 352 VQSHL.S32 q14, q14, q0 353 VQSHL.S32 q15, q15, q0 354 355 VDUP.32 q2, d13[0] // right_post_shift 356 357 VQDMULH.S32 q8, q8, d12[1] // multiplier 358 VQDMULH.S32 q9, q9, d12[1] 359 VQDMULH.S32 q10, q10, d12[1] 360 VQDMULH.S32 q11, q11, d12[1] 361 VQDMULH.S32 q12, q12, d12[1] 362 VQDMULH.S32 q13, q13, d12[1] 363 VQDMULH.S32 q14, q14, d12[1] 364 VQDMULH.S32 q15, q15, d12[1] 365 366 VRSHL.S32 q8, q8, q2 367 VRSHL.S32 q9, q9, q2 368 VRSHL.S32 q10, q10, q2 369 VRSHL.S32 q11, q11, q2 370 VRSHL.S32 q12, q12, q2 371 VRSHL.S32 q13, q13, q2 372 VRSHL.S32 q14, q14, q2 373 VRSHL.S32 q15, q15, q2 374 375 VDUP.16 q0, d13[2] // output_zero_point 376 377 VQMOVN.S32 d16, q8 378 VQMOVN.S32 d17, q9 379 VQMOVN.S32 d18, q10 380 VQMOVN.S32 d19, q11 381 VQMOVN.S32 d20, q12 382 VQMOVN.S32 d21, q13 383 VQMOVN.S32 d22, q14 384 VQMOVN.S32 d23, q15 385 386 VQADD.S16 q8, q8, q0 387 VQADD.S16 q9, q9, q0 388 VQADD.S16 q10, q10, q0 389 VQADD.S16 q11, q11, q0 390 391 VDUP.8 q12, d13[6] // output_min 392 393 VQMOVN.S16 d0, q8 394 VQMOVN.S16 d1, q9 395 VQMOVN.S16 d2, q10 396 VQMOVN.S16 d3, q11 397 398 VDUP.8 q13, d13[7] // output_max 399 400 VMAX.S8 q0, q0, q12 401 VMAX.S8 q1, q1, q12 402 403 SUBS r1, r1, 8 404 405 VMIN.S8 q0, q0, q13 406 VMIN.S8 q1, q1, q13 407 408 # Store full 4 x 8 409 BLO 5f 410 VST1.8 {d0}, [r11], r7 411 SUB r3, r3, r2 412 VST1.8 {d1}, [r4], r7 413 SUB r12, r12, r2 414 VST1.8 {d2}, [r8], r7 415 SUB r10, r10, r2 416 VST1.8 {d3}, [r6], r7 417 SUB r0, r0, r2 418 BHI 0b 419 420 VPOP {d8-d13} 421 ADD sp, sp, 8 // skip 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.S8 q0, d0 437 VMOVL.S8 q4, d8 438 VMOVL.S8 q1, d2 439 VMOVL.S8 q2, d4 440 VMOVL.S8 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 VMOVL.S8 q4, d8 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 VMOVL.S8 q4, d8 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 VMOVL.S8 q4, d8 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 VMOVL.S8 q4, d8 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 VMOVL.S8 q4, d8 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 VMOVL.S8 q4, d8 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-d13} 557 ADD sp, sp, 8 // skip d14 558 POP {r4, r5, r6, r7, r8, r9, r10, r11} 559 BX lr 560 561END_FUNCTION xnn_qs8_gemm_minmax_rndnu_ukernel_4x8__aarch32_neon_mlal_lane_prfm_cortex_a7 562 563#ifdef __ELF__ 564.section ".note.GNU-stack","",%progbits 565#endif 566 567