1// Auto-generated file. Do not edit! 2// Template: src/qs8-gemm/4x8-aarch32-neon-mlal-lane-cortex-a53.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_cortex_a53( 16// size_t mr, r0 17// size_t nc, r1 18// size_t kc, (r2) -> sp + 56 -> r5 19// const int8_t*restrict a, r3 20// size_t a_stride, sp + 96 -> (r7) 21// const void*restrict w, sp + 100 -> r9 22// int8_t*restrict c, sp + 104 -> r11 23// size_t cm_stride, sp + 108 -> (r6) 24// size_t cn_stride, sp + 112 -> r7 25// xnn_qs8_minmax_params params) sp + 116 -> (r5) 26 27// d8-d15, r4-r11,r14(lr) need to be preserved if used. r13(sp),r15(pc) are reserved. 28 29// Register usage 30// A0 r3 d0-d1 q0 31// A1 r12 d2-d3 q1 32// A2 r10 d4-d5 q2 33// A3 r0 d6-d7 q3 34 35// B r9 d8-d9 q4 q5 36 37// C0 r11 d16-d17 q8 d18-d19 q9 38// C1 r4 d20-d21 q10 d22-d23 q11 39// C2 r8 d24-d25 q12 d26-d27 q13 40// C3 r6 d28-d29 q14 d30-d31 q15 41 42// r2,r14 A53 gpr temporary loads 43// Unused d15 44 45// params structure is 10 bytes 46// struct { 47// float magic_bias; d12[0] 48// int32_t magic_bias_less_output_zero_point; d12[1] 49// int8_t output_min; d13[6] 50// int8_t output_max; d13[7] 51// } xnn_qs8_minmax_params.neon; 52 53BEGIN_FUNCTION xnn_qc8_gemm_minmax_fp32_ukernel_4x8__aarch32_neon_mlal_lane_cortex_a53 54 # Push 96 bytes 55 PUSH {r2, r4, r5, r6, r7, r8, r9, r10, r11, lr} // 40 56 SUB sp, sp, 8 // +8 57 VPUSH {d8-d13} // +48 = 96 58 59 LDR r7, [sp, 96] // a_stride 60 LDR r11, [sp, 104] // c 61 LDR r6, [sp, 108] // cm_stride 62 LDR r9, [sp, 100] // w 63 LDR r5, [sp, 116] // params 64 65 # Clamp A and C pointers 66 CMP r0, 2 // if mr >= 2 67 ADD r12, r3, r7 // a1 = a0 + a_stride 68 ADD r4, r11, r6 // c1 = c0 + cm_stride 69 MOVLO r12, r3 // a1 70 MOVLO r4, r11 // c1 71 // if mr > 2 72 ADD r10, r12, r7 // a2 = a1 + a_stride 73 ADD r8, r4, r6 // c2 = c1 + cm_stride 74 MOVLS r10, r12 // a2 75 MOVLS r8, r4 // c2 76 77 CMP r0, 4 // if mr >=4 78 ADD r0, r10, r7 // a3 = a2 + a_stride 79 ADD r6, r8, r6 // c3 = c2 + cm_stride 80 MOVLO r0, r10 // a3 81 MOVLO r6, r8 // c3 82 83 # Load params values 84 VLDM r5!, {d12} // QC8 neon params 85 VLD1.16 {d13[]}, [r5] // output_min/max 86 LDR r7, [sp, 112] // cn_stride 87 88 89 .p2align 3 900: 91 # Load initial bias from w into accumulators 92 VLDM r9!, {d16-d19} // Bias 93 SUBS r5, r2, 8 // k = kc - 8 94 95 VMOV q10, q8 96 VMOV q11, q9 97 VMOV q12, q8 98 VMOV q13, q9 99 VMOV q14, q8 100 VMOV q15, q9 101 BLO 4f // less than 8 channels? 102 103 // Prologue - load 4A's and B0 104 VLD1.8 {d0}, [r3]! // A0 105 VLD1.8 {d2}, [r12]! // A1 106 VLD1.8 {d4}, [r10]! // A2 107 VLD1.8 {d6}, [r0]! // A3 108 VLD1.8 {d8}, [r9]! // B0 109 110 SUBS r5, r5, 8 // k = k - 8 111 BLO 2f // less than 8 channels? 112 113 // Main loop - 8 bytes 114 // 64 bytes for weights. 115 // 5 VMOVL = 4 A and 1 B = 5 cycles 116 // 7 blocks with VLD B, VMOVL, 8 VMLA = 10 cycles 117 // 1 blocks with VLD B, VMLA = 9 cycles 118 // total = 84 cycles 119 .p2align 3 1201: 121 // Extend - 5 cycles 122 VMOVL.S8 q0, d0 123 VMOVL.S8 q4, d8 124 VMOVL.S8 q1, d2 125 VMOVL.S8 q2, d4 126 VMOVL.S8 q3, d6 127 128 // BLOCK 0 - 10 cycles 129 VLD1.8 {d10}, [r9]! // B1 130 VMLAL.S16 q8, d8, d0[0] 131 VMLAL.S16 q9, d9, d0[0] 132 VMLAL.S16 q10, d8, d2[0] 133 VMLAL.S16 q11, d9, d2[0] 134 VMOVL.S8 q5, d10 135 VMLAL.S16 q12, d8, d4[0] 136 VMLAL.S16 q13, d9, d4[0] 137 VMLAL.S16 q14, d8, d6[0] 138 VMLAL.S16 q15, d9, d6[0] 139 140 // BLOCK 1 - 10 cycles 141 VLD1.8 {d8}, [r9]! // B2 142 VMLAL.S16 q8, d10, d0[1] 143 VMLAL.S16 q9, d11, d0[1] 144 VMLAL.S16 q10, d10, d2[1] 145 VMLAL.S16 q11, d11, d2[1] 146 VMOVL.S8 q4, d8 147 VMLAL.S16 q12, d10, d4[1] 148 VMLAL.S16 q13, d11, d4[1] 149 VMLAL.S16 q14, d10, d6[1] 150 VMLAL.S16 q15, d11, d6[1] 151 152 // BLOCK 2 - 10 cycles 153 VLD1.8 {d10}, [r9]! // B3 154 VMLAL.S16 q8, d8, d0[2] 155 VMLAL.S16 q9, d9, d0[2] 156 VMLAL.S16 q10, d8, d2[2] 157 VMLAL.S16 q11, d9, d2[2] 158 VMOVL.S8 q5, d10 159 VMLAL.S16 q12, d8, d4[2] 160 VMLAL.S16 q13, d9, d4[2] 161 VMLAL.S16 q14, d8, d6[2] 162 VMLAL.S16 q15, d9, d6[2] 163 164 // BLOCK 3 - 10 cycles 165 VLD1.8 {d8}, [r9]! // B4 166 VMLAL.S16 q8, d10, d0[3] 167 VMLAL.S16 q9, d11, d0[3] 168 VMLAL.S16 q10, d10, d2[3] 169 VMLAL.S16 q11, d11, d2[3] 170 VMOVL.S8 q4, d8 171 VMLAL.S16 q12, d10, d4[3] 172 LDR r2, [r3] // A0 low 173 VMLAL.S16 q13, d11, d4[3] 174 LDR r14, [r3, 4] // A0 high 175 VMLAL.S16 q14, d10, d6[3] 176 ADD r3, r3, 8 177 VMLAL.S16 q15, d11, d6[3] 178 179 // BLOCK 4 - 10 cycles 180 VLD1.8 {d10}, [r9]! // B5 181 VMOV d0, r2, r14 // A0 VMOV 182 VMLAL.S16 q8, d8, d1[0] 183 VMLAL.S16 q9, d9, d1[0] 184 VMLAL.S16 q10, d8, d3[0] 185 VMLAL.S16 q11, d9, d3[0] 186 VMOVL.S8 q5, d10 187 VMLAL.S16 q12, d8, d5[0] 188 LDR r2, [r12] // A1 low 189 VMLAL.S16 q13, d9, d5[0] 190 LDR r14, [r12, 4] // A1 high 191 VMLAL.S16 q14, d8, d7[0] 192 ADD r12, r12, 8 193 VMLAL.S16 q15, d9, d7[0] 194 195 // BLOCK 5 - 10 cycles 196 VLD1.8 {d8}, [r9]! // B6 197 VMOV d2, r2, r14 // A1 VMOV 198 VMLAL.S16 q8, d10, d1[1] 199 VMLAL.S16 q9, d11, d1[1] 200 VMLAL.S16 q10, d10, d3[1] 201 VMLAL.S16 q11, d11, d3[1] 202 VMOVL.S8 q4, d8 203 VMLAL.S16 q12, d10, d5[1] 204 LDR r2, [r10] // A2 low 205 VMLAL.S16 q13, d11, d5[1] 206 LDR r14, [r10, 4] // A2 high 207 VMLAL.S16 q14, d10, d7[1] 208 ADD r10, r10, 8 209 VMLAL.S16 q15, d11, d7[1] 210 211 // BLOCK 6 - 10 cycles 212 VLD1.8 {d10}, [r9]! // B7 213 VMOV d4, r2, r14 // A2 VMOV 214 VMLAL.S16 q8, d8, d1[2] 215 VMLAL.S16 q9, d9, d1[2] 216 VMLAL.S16 q10, d8, d3[2] 217 VMLAL.S16 q11, d9, d3[2] 218 VMOVL.S8 q5, d10 219 VMLAL.S16 q12, d8, d5[2] 220 LDR r2, [r0] // A3 low 221 VMLAL.S16 q13, d9, d5[2] 222 LDR r14, [r0, 4] // A3 high 223 VMLAL.S16 q14, d8, d7[2] 224 ADD r0, r0, 8 225 VMLAL.S16 q15, d9, d7[2] 226 227 // BLOCK 7 - 9 cycles 228 VLD1.8 {d8}, [r9]! // B0 229 VMOV d6, r2, r14 // A3 VMOV 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 LDR r2, [sp, 56] // kc 408 SUBS r1, r1, 8 409 410 VMIN.S8 q0, q0, q13 411 VMIN.S8 q1, q1, q13 412 413 # Store full 4 x 8 414 BLO 5f 415 VST1.8 {d0}, [r11], r7 416 SUB r3, r3, r2 417 VST1.8 {d1}, [r4], r7 418 SUB r12, r12, r2 419 VST1.8 {d2}, [r8], r7 420 SUB r10, r10, r2 421 VST1.8 {d3}, [r6], r7 422 SUB r0, r0, r2 423 BHI 0b 424 425 VPOP {d8-d13} 426 ADD sp, sp, 12 // skip pad of 8 + r2 427 POP {r4, r5, r6, r7, r8, r9, r10, r11, pc} 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, 12 // skip pad of 8 + r2 562 POP {r4, r5, r6, r7, r8, r9, r10, r11, pc} 563 564 565END_FUNCTION xnn_qc8_gemm_minmax_fp32_ukernel_4x8__aarch32_neon_mlal_lane_cortex_a53 566 567#ifdef __ELF__ 568.section ".note.GNU-stack","",%progbits 569#endif 570 571