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_qc8_gemm_minmax_fp32_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_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 10 bytes 47// struct { 48// float magic_bias; d12[0] 49// int32_t magic_bias_less_output_zero_point; d12[1] 50// int8_t output_min; d13[6] 51// int8_t output_max; d13[7] 52// } xnn_qs8_minmax_params.neon; 53 54BEGIN_FUNCTION xnn_qc8_gemm_minmax_fp32_ukernel_4x8__aarch32_neon_mlal_lane_prfm_cortex_a7 55 # Push 88 bytes 56 PUSH {r4, r5, r6, r7, r8, r9, r10, r11} // 32 57 SUB sp, sp, 8 // +8 58 VPUSH {d8-d13} // +48 = 88 59 60 LDR r7, [sp, 88] // a_stride 61 LDR r11, [sp, 96] // c 62 LDR r6, [sp, 100] // cm_stride 63 LDR r9, [sp, 92] // w 64 LDR r5, [sp, 108] // params 65 66 # Clamp A and C pointers 67 CMP r0, 2 // if mr >= 2 68 ADD r12, r3, r7 // a1 = a0 + a_stride 69 ADD r4, r11, r6 // c1 = c0 + cm_stride 70 MOVLO r12, r3 // a1 71 MOVLO r4, r11 // c1 72 // if mr > 2 73 ADD r10, r12, r7 // a2 = a1 + a_stride 74 ADD r8, r4, r6 // c2 = c1 + cm_stride 75 MOVLS r10, r12 // a2 76 MOVLS r8, r4 // c2 77 78 CMP r0, 4 // if mr >=4 79 ADD r0, r10, r7 // a3 = a2 + a_stride 80 ADD r6, r8, r6 // c3 = c2 + cm_stride 81 MOVLO r0, r10 // a3 82 MOVLO r6, r8 // c3 83 84 # Load params values 85 VLDM r5!, {d12} // QC8 neon params 86 VLD1.16 {d13[]}, [r5] // output_min/max 87 LDR r7, [sp, 104] // cn_stride 88 89 PLD [r9, 64] // Prefetch B 90 PLD [r9, 128] 91 PLD [r9, 192] 92 PLD [r9, 256] 93 PLD [r9, 320] 94 PLD [r9, 384] 95 96 .p2align 3 970: 98 # Load initial bias from w into accumulators 99 VLDM r9!, {d16-d19} // Bias 100 SUBS r5, r2, 8 // k = kc - 8 101 102 VMOV q10, q8 103 PLD [r3, 64] // Prefetch A 104 VMOV q11, q9 105 PLD [r12, 64] 106 VMOV q12, q8 107 PLD [r10, 64] 108 VMOV q13, q9 109 PLD [r0, 64] 110 VMOV q14, q8 111 VMOV q15, q9 112 BLO 4f // less than 8 channels? 113 114 // Prologue - load 4A's and B0 115 VLD1.8 {d0}, [r3]! // A0 116 VLD1.8 {d2}, [r12]! // A1 117 VLD1.8 {d4}, [r10]! // A2 118 VLD1.8 {d6}, [r0]! // A3 119 VLD1.8 {d8}, [r9]! // B0 120 121 SUBS r5, r5, 8 // k = k - 8 122 BLO 2f // less than 8 channels? 123 124 // Main loop - 8 bytes 125 // 64 bytes for weights. 126 // 5 VMOVL = 4 A and 1 B = 5 cycles 127 // 7 blocks with VLD B, VMOVL, 8 VMLA = 10 cycles 128 // 1 blocks with VLD B, VMLA = 9 cycles 129 // total = 84 cycles 130 .p2align 3 1311: 132 // Extend - 5 cycles 133 VMOVL.S8 q0, d0 134 VMOVL.S8 q4, d8 135 PLD [r9, 448] 136 VMOVL.S8 q1, d2 137 VMOVL.S8 q2, d4 138 VMOVL.S8 q3, d6 139 140 // BLOCK 0 - 10 cycles 141 VLD1.8 {d10}, [r9]! // B1 142 VMLAL.S16 q8, d8, d0[0] 143 VMLAL.S16 q9, d9, d0[0] 144 VMLAL.S16 q10, d8, d2[0] 145 VMLAL.S16 q11, d9, d2[0] 146 VMOVL.S8 q5, d10 147 VMLAL.S16 q12, d8, d4[0] 148 VMLAL.S16 q13, d9, d4[0] 149 VMLAL.S16 q14, d8, d6[0] 150 VMLAL.S16 q15, d9, d6[0] 151 152 // BLOCK 1 - 10 cycles 153 VLD1.8 {d8}, [r9]! // B2 154 VMLAL.S16 q8, d10, d0[1] 155 VMLAL.S16 q9, d11, d0[1] 156 VMLAL.S16 q10, d10, d2[1] 157 VMLAL.S16 q11, d11, d2[1] 158 VMOVL.S8 q4, d8 159 VMLAL.S16 q12, d10, d4[1] 160 VMLAL.S16 q13, d11, d4[1] 161 VMLAL.S16 q14, d10, d6[1] 162 VMLAL.S16 q15, d11, d6[1] 163 164 // BLOCK 2 - 10 cycles 165 VLD1.8 {d10}, [r9]! // B3 166 VMLAL.S16 q8, d8, d0[2] 167 VMLAL.S16 q9, d9, d0[2] 168 VMLAL.S16 q10, d8, d2[2] 169 VMLAL.S16 q11, d9, d2[2] 170 VMOVL.S8 q5, d10 171 VMLAL.S16 q12, d8, d4[2] 172 VMLAL.S16 q13, d9, d4[2] 173 VMLAL.S16 q14, d8, d6[2] 174 VMLAL.S16 q15, d9, d6[2] 175 176 // BLOCK 3 - 10 cycles 177 VLD1.8 {d8}, [r9]! // B4 178 VMLAL.S16 q8, d10, d0[3] 179 VMLAL.S16 q9, d11, d0[3] 180 VMLAL.S16 q10, d10, d2[3] 181 VMLAL.S16 q11, d11, d2[3] 182 VLD1.8 {d0}, [r3]! // A0 183 VMOVL.S8 q4, d8 184 VMLAL.S16 q12, d10, d4[3] 185 VMLAL.S16 q13, d11, d4[3] 186 VMLAL.S16 q14, d10, d6[3] 187 VMLAL.S16 q15, d11, d6[3] 188 189 // BLOCK 4 - 10 cycles 190 VLD1.8 {d10}, [r9]! // B5 191 VMLAL.S16 q8, d8, d1[0] 192 VMLAL.S16 q9, d9, d1[0] 193 VMLAL.S16 q10, d8, d3[0] 194 VMLAL.S16 q11, d9, d3[0] 195 VLD1.8 {d2}, [r12]! // A1 196 VMOVL.S8 q5, d10 197 VMLAL.S16 q12, d8, d5[0] 198 VMLAL.S16 q13, d9, d5[0] 199 VMLAL.S16 q14, d8, d7[0] 200 VMLAL.S16 q15, d9, d7[0] 201 202 // BLOCK 5 - 10 cycles 203 VLD1.8 {d8}, [r9]! // B6 204 VMLAL.S16 q8, d10, d1[1] 205 VMLAL.S16 q9, d11, d1[1] 206 VMLAL.S16 q10, d10, d3[1] 207 VMLAL.S16 q11, d11, d3[1] 208 VLD1.8 {d4}, [r10]! // A2 209 VMOVL.S8 q4, d8 210 VMLAL.S16 q12, d10, d5[1] 211 VMLAL.S16 q13, d11, d5[1] 212 VMLAL.S16 q14, d10, d7[1] 213 VMLAL.S16 q15, d11, d7[1] 214 215 // BLOCK 6 - 10 cycles 216 VLD1.8 {d10}, [r9]! // B7 217 VMLAL.S16 q8, d8, d1[2] 218 VMLAL.S16 q9, d9, d1[2] 219 VMLAL.S16 q10, d8, d3[2] 220 VMLAL.S16 q11, d9, d3[2] 221 VLD1.8 {d6}, [r0]! // A3 222 VMOVL.S8 q5, d10 223 VMLAL.S16 q12, d8, d5[2] 224 VMLAL.S16 q13, d9, d5[2] 225 VMLAL.S16 q14, d8, d7[2] 226 VMLAL.S16 q15, d9, d7[2] 227 228 // BLOCK 7 - 9 cycles 229 VLD1.8 {d8}, [r9]! // B0 230 VMLAL.S16 q8, d10, d1[3] 231 VMLAL.S16 q9, d11, d1[3] 232 VMLAL.S16 q10, d10, d3[3] 233 VMLAL.S16 q11, d11, d3[3] 234 VMLAL.S16 q12, d10, d5[3] 235 VMLAL.S16 q13, d11, d5[3] 236 SUBS r5, r5, 8 237 VMLAL.S16 q14, d10, d7[3] 238 VMLAL.S16 q15, d11, d7[3] 239 BHS 1b 240 241 // Epilogue 242 243 .p2align 3 2442: 245 VMOVL.S8 q0, d0 246 VMOVL.S8 q4, d8 247 VMOVL.S8 q1, d2 248 VMOVL.S8 q2, d4 249 VMOVL.S8 q3, d6 250 251 VLD1.8 {d10}, [r9]! // B1 252 VMLAL.S16 q8, d8, d0[0] 253 VMLAL.S16 q9, d9, d0[0] 254 VMLAL.S16 q10, d8, d2[0] 255 VMLAL.S16 q11, d9, d2[0] 256 VMOVL.S8 q5, d10 257 VMLAL.S16 q12, d8, d4[0] 258 VMLAL.S16 q13, d9, d4[0] 259 VMLAL.S16 q14, d8, d6[0] 260 VMLAL.S16 q15, d9, d6[0] 261 262 VLD1.8 {d8}, [r9]! // B2 263 VMLAL.S16 q8, d10, d0[1] 264 VMLAL.S16 q9, d11, d0[1] 265 VMLAL.S16 q10, d10, d2[1] 266 VMLAL.S16 q11, d11, d2[1] 267 VMOVL.S8 q4, d8 268 VMLAL.S16 q12, d10, d4[1] 269 VMLAL.S16 q13, d11, d4[1] 270 VMLAL.S16 q14, d10, d6[1] 271 VMLAL.S16 q15, d11, d6[1] 272 273 VLD1.8 {d10}, [r9]! // B3 274 VMLAL.S16 q8, d8, d0[2] 275 VMLAL.S16 q9, d9, d0[2] 276 VMLAL.S16 q10, d8, d2[2] 277 VMLAL.S16 q11, d9, d2[2] 278 VMOVL.S8 q5, d10 279 VMLAL.S16 q12, d8, d4[2] 280 VMLAL.S16 q13, d9, d4[2] 281 VMLAL.S16 q14, d8, d6[2] 282 VMLAL.S16 q15, d9, d6[2] 283 284 VLD1.8 {d8}, [r9]! // B4 285 VMLAL.S16 q8, d10, d0[3] 286 VMLAL.S16 q9, d11, d0[3] 287 VMLAL.S16 q10, d10, d2[3] 288 VMLAL.S16 q11, d11, d2[3] 289 VMOVL.S8 q4, d8 290 VMLAL.S16 q12, d10, d4[3] 291 VMLAL.S16 q13, d11, d4[3] 292 VMLAL.S16 q14, d10, d6[3] 293 VMLAL.S16 q15, d11, d6[3] 294 295 VLD1.8 {d10}, [r9]! // B5 296 VMLAL.S16 q8, d8, d1[0] 297 VMLAL.S16 q9, d9, d1[0] 298 VMLAL.S16 q10, d8, d3[0] 299 VMLAL.S16 q11, d9, d3[0] 300 VMOVL.S8 q5, d10 301 VMLAL.S16 q12, d8, d5[0] 302 VMLAL.S16 q13, d9, d5[0] 303 VMLAL.S16 q14, d8, d7[0] 304 VMLAL.S16 q15, d9, d7[0] 305 306 VLD1.8 {d8}, [r9]! // B6 307 VMLAL.S16 q8, d10, d1[1] 308 VMLAL.S16 q9, d11, d1[1] 309 VMLAL.S16 q10, d10, d3[1] 310 VMLAL.S16 q11, d11, d3[1] 311 VMOVL.S8 q4, d8 312 VMLAL.S16 q12, d10, d5[1] 313 VMLAL.S16 q13, d11, d5[1] 314 VMLAL.S16 q14, d10, d7[1] 315 VMLAL.S16 q15, d11, d7[1] 316 317 VLD1.8 {d10}, [r9]! // B7 318 VMLAL.S16 q8, d8, d1[2] 319 VMLAL.S16 q9, d9, d1[2] 320 VMLAL.S16 q10, d8, d3[2] 321 VMLAL.S16 q11, d9, d3[2] 322 VMOVL.S8 q5, d10 323 VMLAL.S16 q12, d8, d5[2] 324 VMLAL.S16 q13, d9, d5[2] 325 VMLAL.S16 q14, d8, d7[2] 326 VMLAL.S16 q15, d9, d7[2] 327 328 VMLAL.S16 q8, d10, d1[3] 329 VMLAL.S16 q9, d11, d1[3] 330 VMLAL.S16 q10, d10, d3[3] 331 VMLAL.S16 q11, d11, d3[3] 332 VMLAL.S16 q12, d10, d5[3] 333 VMLAL.S16 q13, d11, d5[3] 334 ADDS r5, r5, 8 335 VMLAL.S16 q14, d10, d7[3] 336 VMLAL.S16 q15, d11, d7[3] 337 338 # Is there a remainder?- 1-7 bytes of A 339 BNE 4f 340 3413: 342 # QC8 FP32 quantization 343 VLD1.8 {q0-q1}, [r9]! 344 345 VDUP.32 q2, d12[0] // magic_bias 346 VDUP.32 q3, d12[1] // magic_bias_less_output_zero_point 347 348 VCVT.F32.S32 q8, q8 349 VCVT.F32.S32 q9, q9 350 VCVT.F32.S32 q10, q10 351 VCVT.F32.S32 q11, q11 352 VCVT.F32.S32 q12, q12 353 VCVT.F32.S32 q13, q13 354 VCVT.F32.S32 q14, q14 355 VCVT.F32.S32 q15, q15 356 357 VMUL.F32 q8, q8, q0 // multiplier 358 VMUL.F32 q9, q9, q1 359 VMUL.F32 q10, q10, q0 360 VMUL.F32 q11, q11, q1 361 VMUL.F32 q12, q12, q0 362 VMUL.F32 q13, q13, q1 363 VMUL.F32 q14, q14, q0 364 VMUL.F32 q15, q15, q1 365 366 VADD.F32 q8, q8, q2 // magic_bias 367 VADD.F32 q9, q9, q2 368 VADD.F32 q10, q10, q2 369 VADD.F32 q11, q11, q2 370 VADD.F32 q12, q12, q2 371 VADD.F32 q13, q13, q2 372 VADD.F32 q14, q14, q2 373 VADD.F32 q15, q15, q2 374 375 VQSUB.S32 q8, q8, q3 // magic_bias_less_output_zero_point 376 VQSUB.S32 q9, q9, q3 377 VQSUB.S32 q10, q10, q3 378 VQSUB.S32 q11, q11, q3 379 VQSUB.S32 q12, q12, q3 380 VQSUB.S32 q13, q13, q3 381 VQSUB.S32 q14, q14, q3 382 VQSUB.S32 q15, q15, q3 383 384 385 VQMOVN.S32 d16, q8 386 VQMOVN.S32 d17, q9 387 VQMOVN.S32 d18, q10 388 VQMOVN.S32 d19, q11 389 VQMOVN.S32 d20, q12 390 VQMOVN.S32 d21, q13 391 VQMOVN.S32 d22, q14 392 VQMOVN.S32 d23, q15 393 394 395 VDUP.8 q12, d13[6] // output_min 396 397 VQMOVN.S16 d0, q8 398 VQMOVN.S16 d1, q9 399 VQMOVN.S16 d2, q10 400 VQMOVN.S16 d3, q11 401 402 VDUP.8 q13, d13[7] // output_max 403 404 VMAX.S8 q0, q0, q12 405 VMAX.S8 q1, q1, q12 406 407 SUBS r1, r1, 8 408 409 VMIN.S8 q0, q0, q13 410 VMIN.S8 q1, q1, q13 411 412 # Store full 4 x 8 413 BLO 5f 414 VST1.8 {d0}, [r11], r7 415 SUB r3, r3, r2 416 VST1.8 {d1}, [r4], r7 417 SUB r12, r12, r2 418 VST1.8 {d2}, [r8], r7 419 SUB r10, r10, r2 420 VST1.8 {d3}, [r6], r7 421 SUB r0, r0, r2 422 BHI 0b 423 424 VPOP {d8-d13} 425 ADD sp, sp, 8 // skip d14 426 POP {r4, r5, r6, r7, r8, r9, r10, r11} 427 BX lr 428 429 # Remainder- 1 to 7 bytes of A 430 .p2align 3 4314: 432 AND r5, r5, 7 // kc remainder 1 to 7 433 434 VLD1.8 {d0}, [r3], r5 435 VLD1.8 {d8}, [r9]! 436 VLD1.8 {d2}, [r12], r5 437 VLD1.8 {d4}, [r10], r5 438 VLD1.8 {d6}, [r0], r5 439 440 VMOVL.S8 q0, d0 441 VMOVL.S8 q4, d8 442 VMOVL.S8 q1, d2 443 VMOVL.S8 q2, d4 444 VMOVL.S8 q3, d6 445 VMLAL.S16 q8, d8, d0[0] 446 VMLAL.S16 q9, d9, d0[0] 447 VMLAL.S16 q10, d8, d2[0] 448 VMLAL.S16 q11, d9, d2[0] 449 VMLAL.S16 q12, d8, d4[0] 450 VMLAL.S16 q13, d9, d4[0] 451 VMLAL.S16 q14, d8, d6[0] 452 VMLAL.S16 q15, d9, d6[0] 453 CMP r5, 2 454 BLO 3b 455 456 VLD1.8 {d8}, [r9]! 457 VMOVL.S8 q4, d8 458 VMLAL.S16 q8, d8, d0[1] 459 VMLAL.S16 q9, d9, d0[1] 460 VMLAL.S16 q10, d8, d2[1] 461 VMLAL.S16 q11, d9, d2[1] 462 VMLAL.S16 q12, d8, d4[1] 463 VMLAL.S16 q13, d9, d4[1] 464 VMLAL.S16 q14, d8, d6[1] 465 VMLAL.S16 q15, d9, d6[1] 466 BEQ 3b 467 468 VLD1.8 {d8}, [r9]! 469 VMOVL.S8 q4, d8 470 VMLAL.S16 q8, d8, d0[2] 471 VMLAL.S16 q9, d9, d0[2] 472 VMLAL.S16 q10, d8, d2[2] 473 VMLAL.S16 q11, d9, d2[2] 474 VMLAL.S16 q12, d8, d4[2] 475 VMLAL.S16 q13, d9, d4[2] 476 VMLAL.S16 q14, d8, d6[2] 477 VMLAL.S16 q15, d9, d6[2] 478 CMP r5, 4 479 BLO 3b 480 481 VLD1.8 {d8}, [r9]! 482 VMOVL.S8 q4, d8 483 VMLAL.S16 q8, d8, d0[3] 484 VMLAL.S16 q9, d9, d0[3] 485 VMLAL.S16 q10, d8, d2[3] 486 VMLAL.S16 q11, d9, d2[3] 487 VMLAL.S16 q12, d8, d4[3] 488 VMLAL.S16 q13, d9, d4[3] 489 VMLAL.S16 q14, d8, d6[3] 490 VMLAL.S16 q15, d9, d6[3] 491 BEQ 3b 492 493 VLD1.8 {d8}, [r9]! 494 VMOVL.S8 q4, d8 495 VMLAL.S16 q8, d8, d1[0] 496 VMLAL.S16 q9, d9, d1[0] 497 VMLAL.S16 q10, d8, d3[0] 498 VMLAL.S16 q11, d9, d3[0] 499 VMLAL.S16 q12, d8, d5[0] 500 VMLAL.S16 q13, d9, d5[0] 501 VMLAL.S16 q14, d8, d7[0] 502 VMLAL.S16 q15, d9, d7[0] 503 CMP r5, 6 504 BLO 3b 505 506 VLD1.8 {d8}, [r9]! 507 VMOVL.S8 q4, d8 508 VMLAL.S16 q8, d8, d1[1] 509 VMLAL.S16 q9, d9, d1[1] 510 VMLAL.S16 q10, d8, d3[1] 511 VMLAL.S16 q11, d9, d3[1] 512 VMLAL.S16 q12, d8, d5[1] 513 VMLAL.S16 q13, d9, d5[1] 514 VMLAL.S16 q14, d8, d7[1] 515 VMLAL.S16 q15, d9, d7[1] 516 BEQ 3b 517 518 VLD1.8 {d8}, [r9]! 519 VMOVL.S8 q4, d8 520 VMLAL.S16 q8, d8, d1[2] 521 VMLAL.S16 q9, d9, d1[2] 522 VMLAL.S16 q10, d8, d3[2] 523 VMLAL.S16 q11, d9, d3[2] 524 VMLAL.S16 q12, d8, d5[2] 525 VMLAL.S16 q13, d9, d5[2] 526 VMLAL.S16 q14, d8, d7[2] 527 VMLAL.S16 q15, d9, d7[2] 528 B 3b 529 530 # Store odd width 531 .p2align 3 5325: 533 TST r1, 4 534 BEQ 6f 535 VST1.32 {d0[0]}, [r11]! 536 VST1.32 {d1[0]}, [r4]! 537 VST1.32 {d2[0]}, [r8]! 538 VST1.32 {d3[0]}, [r6]! 539 VEXT.8 q0, q0, q0, 4 540 VEXT.8 q1, q1, q1, 4 5416: 542 TST r1, 2 543 BEQ 7f 544 VST1.16 {d0[0]}, [r11]! 545 VST1.16 {d1[0]}, [r4]! 546 VST1.16 {d2[0]}, [r8]! 547 VST1.16 {d3[0]}, [r6]! 548 VEXT.8 q0, q0, q0, 2 549 VEXT.8 q1, q1, q1, 2 550 5517: 552 TST r1, 1 553 BEQ 8f 554 VST1.8 {d0[0]}, [r11] 555 VST1.8 {d1[0]}, [r4] 556 VST1.8 {d2[0]}, [r8] 557 VST1.8 {d3[0]}, [r6] 558 5598: 560 VPOP {d8-d13} 561 ADD sp, sp, 8 // skip d14 562 POP {r4, r5, r6, r7, r8, r9, r10, r11} 563 BX lr 564 565END_FUNCTION xnn_qc8_gemm_minmax_fp32_ukernel_4x8__aarch32_neon_mlal_lane_prfm_cortex_a7 566 567#ifdef __ELF__ 568.section ".note.GNU-stack","",%progbits 569#endif 570 571