1// Auto-generated file. Do not edit! 2// Template: src/qs8-igemm/4x8-aarch32-neon-mlal-lane-ld64.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_igemm_minmax_rndnu_ukernel_4x8__aarch32_neon_mlal_lane_prfm_ld64 16// size_t mr, (r0) 17// size_t nc, r1 18// size_t kc, (r2) -> r5 -> sp + 44 19// size_t ks, (r3) -> sp + 48 -> r14 20// const uint8_t**restrict a, sp + 88 -> r2 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// size_t a_offset, sp + 108 -> (r5) 26// const uint8_t* zero, sp + 112 -> (r7) 27// xnn_qs8_conv_minmax_params*params); sp + 116 -> (r5) 28 29// d8-d15, r4-r11,r14(lr) need to be preserved if used. r13(sp),r15(pc) are reserved. 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 d10-d11 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 d13-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_igemm_minmax_rndnu_ukernel_4x8__aarch32_neon_mlal_lane_prfm_ld64 58 # Push 88 bytes 59 # r2 will be reloaded in outer loop. r3 is ks 60 PUSH {r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, lr} // +44 61 SUB sp, sp, 4 // +4 62 VPUSH {d10-d14} // +40 = 88 63 64 LDR r11, [sp, 96] // c 65 LDR r6, [sp, 100] // cm_stride 66 LDR r2, [sp, 88] // a 67 LDR r9, [sp, 92] // w 68 LDR r5, [sp, 116] // params 69 MOV r14, r3 // p = ks 70 71 # Clamp C pointers 72 CMP r0, 2 // if mr >= 2 73 ADD r4, r11, r6 // c1 = c0 + cm_stride 74 MOVLO r4, r11 // c1 75 // if mr > 2 76 ADD r8, r4, r6 // c2 = c1 + cm_stride 77 MOVLS r8, r4 // c2 78 CMP r0, 4 // if mr >=4 79 ADD r6, r8, r6 // c3 = c2 + cm_stride 80 MOVLO r6, r8 // c3 81 82 # Load params values 83 VLD1.32 {d14[]}, [r5]! // QU8 kernel_zero_point 84 VLDM r5, {d12-d13} // RNDNU params 85 86 PLD [r9, 64] // Prefetch B 87 PLD [r9, 128] 88 PLD [r9, 192] 89 PLD [r9, 256] 90 PLD [r9, 320] 91 PLD [r9, 384] 92 93 .p2align 3 940: 95 # Load initial bias from w into accumulators 96 VLDM r9!, {d16-d19} // Bias 97 VMOV q10, q8 98 VMOV q11, q9 99 VMOV q12, q8 100 VMOV q13, q9 101 VMOV q14, q8 102 VMOV q15, q9 103 104 .p2align 3 1051: 106 # Load next 4 A pointers 107 LDR r3, [r2, 0] 108 LDR r12, [r2, 4] 109 LDR r10, [r2, 8] 110 LDR r0, [r2, 12] 111 ADD r2, r2, 16 112 113 PLD [r3, 64] 114 PLD [r12, 64] 115 PLD [r10, 64] 116 PLD [r0, 64] 117 118 # Add a_offset 119 LDR r5, [sp, 108] // a_offset 120 LDR r7, [sp, 112] // zero 121 CMP r3, r7 // if a0 == zero 122 ADD r3, r3, r5 // a0 += a_offset 123 MOVEQ r3, r7 // a0 = zero, else += a0 + a_offset 124 CMP r12, r7 // if a1 == zero 125 ADD r12, r12, r5 // a1 += a_offset 126 MOVEQ r12, r7 // a1 = zero, else += a1 + a_offset 127 CMP r10, r7 // if a2 == zero 128 ADD r10, r10, r5 // a2 += a_offset 129 MOVEQ r10, r7 // a2 = zero, else += a2 + a_offset 130 CMP r0, r7 // if a3 == zero 131 ADD r0, r0, r5 // a3 += a_offset 132 LDR r5, [sp, 44] // kc 133 MOVEQ r0, r7 // a3 = zero, else += a3 + a_offset 134 135 SUBS r5, r5, 8 // kc - 8 136 BLO 4f // less than 8 channels? 137 138 # Main loop - 8 bytes 139 # 64 bytes for weights. 140 .p2align 3 1412: 142 VLD1.8 {d0}, [r3]! // A0 143 VLD1.8 {d10}, [r9]! // B 144 VLD1.8 {d2}, [r12]! // A1 145 VLD1.8 {d4}, [r10]! // A2 146 VLD1.8 {d6}, [r0]! // A3 147 SUBS r5, r5, 8 148 PLD [r3, 128] 149 VMOVL.U8 q0, d0 150 PLD [r12, 128] 151 VSUBL.U8 q5, d10, d14 152 PLD [r10, 128] 153 VMOVL.U8 q1, d2 154 PLD [r0, 128] 155 VMOVL.U8 q2, d4 156 PLD [r9, 448] 157 VMOVL.U8 q3, d6 158 VMLAL.S16 q8, d10, d0[0] 159 VMLAL.S16 q9, d11, d0[0] 160 VMLAL.S16 q10, d10, d2[0] 161 VMLAL.S16 q11, d11, d2[0] 162 VMLAL.S16 q12, d10, d4[0] 163 VMLAL.S16 q13, d11, d4[0] 164 VMLAL.S16 q14, d10, d6[0] 165 VMLAL.S16 q15, d11, d6[0] 166 167 VLD1.8 {d10}, [r9]! 168 VSUBL.U8 q5, d10, d14 169 VMLAL.S16 q8, d10, d0[1] 170 VMLAL.S16 q9, d11, d0[1] 171 VMLAL.S16 q10, d10, d2[1] 172 VMLAL.S16 q11, d11, d2[1] 173 VMLAL.S16 q12, d10, d4[1] 174 VMLAL.S16 q13, d11, d4[1] 175 VMLAL.S16 q14, d10, d6[1] 176 VMLAL.S16 q15, d11, d6[1] 177 178 VLD1.8 {d10}, [r9]! 179 VSUBL.U8 q5, d10, d14 180 VMLAL.S16 q8, d10, d0[2] 181 VMLAL.S16 q9, d11, d0[2] 182 VMLAL.S16 q10, d10, d2[2] 183 VMLAL.S16 q11, d11, d2[2] 184 VMLAL.S16 q12, d10, d4[2] 185 VMLAL.S16 q13, d11, d4[2] 186 VMLAL.S16 q14, d10, d6[2] 187 VMLAL.S16 q15, d11, d6[2] 188 189 VLD1.8 {d10}, [r9]! 190 VSUBL.U8 q5, d10, d14 191 VMLAL.S16 q8, d10, d0[3] 192 VMLAL.S16 q9, d11, d0[3] 193 VMLAL.S16 q10, d10, d2[3] 194 VMLAL.S16 q11, d11, d2[3] 195 VMLAL.S16 q12, d10, d4[3] 196 VMLAL.S16 q13, d11, d4[3] 197 VMLAL.S16 q14, d10, d6[3] 198 VMLAL.S16 q15, d11, d6[3] 199 200 VLD1.8 {d10}, [r9]! 201 VSUBL.U8 q5, d10, d14 202 VMLAL.S16 q8, d10, d1[0] 203 VMLAL.S16 q9, d11, d1[0] 204 VMLAL.S16 q10, d10, d3[0] 205 VMLAL.S16 q11, d11, d3[0] 206 VMLAL.S16 q12, d10, d5[0] 207 VMLAL.S16 q13, d11, d5[0] 208 VMLAL.S16 q14, d10, d7[0] 209 VMLAL.S16 q15, d11, d7[0] 210 211 VLD1.8 {d10}, [r9]! 212 VSUBL.U8 q5, d10, d14 213 VMLAL.S16 q8, d10, d1[1] 214 VMLAL.S16 q9, d11, d1[1] 215 VMLAL.S16 q10, d10, d3[1] 216 VMLAL.S16 q11, d11, d3[1] 217 VMLAL.S16 q12, d10, d5[1] 218 VMLAL.S16 q13, d11, d5[1] 219 VMLAL.S16 q14, d10, d7[1] 220 VMLAL.S16 q15, d11, d7[1] 221 222 VLD1.8 {d10}, [r9]! 223 VSUBL.U8 q5, d10, d14 224 VMLAL.S16 q8, d10, d1[2] 225 VMLAL.S16 q9, d11, d1[2] 226 VMLAL.S16 q10, d10, d3[2] 227 VMLAL.S16 q11, d11, d3[2] 228 VMLAL.S16 q12, d10, d5[2] 229 VMLAL.S16 q13, d11, d5[2] 230 VMLAL.S16 q14, d10, d7[2] 231 VMLAL.S16 q15, d11, d7[2] 232 233 VLD1.8 {d10}, [r9]! 234 VSUBL.U8 q5, d10, d14 235 VMLAL.S16 q8, d10, d1[3] 236 VMLAL.S16 q9, d11, d1[3] 237 VMLAL.S16 q10, d10, d3[3] 238 VMLAL.S16 q11, d11, d3[3] 239 VMLAL.S16 q12, d10, d5[3] 240 VMLAL.S16 q13, d11, d5[3] 241 VMLAL.S16 q14, d10, d7[3] 242 VMLAL.S16 q15, d11, d7[3] 243 BHS 2b 244 245 # Is there a remainder?- 1-7 bytes of A 246 ADDS r5, r5, 8 247 BNE 4f 248 2493: 250 # ks loop 251 SUBS r14, r14, 16 // ks -= MR * sizeof(void*) 252 BHI 1b 253 254 LDR r7, [sp, 104] // cn_stride 255 LDR r14, [sp, 48] // p = ks 256 257 # RNDNU quantization 258 VDUP.32 q0, d12[0] // right_pre_shift 259 260 VQSHL.S32 q8, q8, q0 261 VQSHL.S32 q9, q9, q0 262 VQSHL.S32 q10, q10, q0 263 VQSHL.S32 q11, q11, q0 264 VQSHL.S32 q12, q12, q0 265 VQSHL.S32 q13, q13, q0 266 VQSHL.S32 q14, q14, q0 267 VQSHL.S32 q15, q15, q0 268 269 VDUP.32 q2, d13[0] // right_post_shift 270 271 VQDMULH.S32 q8, q8, d12[1] // multiplier 272 VQDMULH.S32 q9, q9, d12[1] 273 VQDMULH.S32 q10, q10, d12[1] 274 VQDMULH.S32 q11, q11, d12[1] 275 VQDMULH.S32 q12, q12, d12[1] 276 VQDMULH.S32 q13, q13, d12[1] 277 VQDMULH.S32 q14, q14, d12[1] 278 VQDMULH.S32 q15, q15, d12[1] 279 280 VRSHL.S32 q8, q8, q2 281 VRSHL.S32 q9, q9, q2 282 VRSHL.S32 q10, q10, q2 283 VRSHL.S32 q11, q11, q2 284 VRSHL.S32 q12, q12, q2 285 VRSHL.S32 q13, q13, q2 286 VRSHL.S32 q14, q14, q2 287 VRSHL.S32 q15, q15, q2 288 289 VDUP.16 q0, d13[2] // output_zero_point 290 291 VQMOVN.S32 d16, q8 292 VQMOVN.S32 d17, q9 293 VQMOVN.S32 d18, q10 294 VQMOVN.S32 d19, q11 295 VQMOVN.S32 d20, q12 296 VQMOVN.S32 d21, q13 297 VQMOVN.S32 d22, q14 298 VQMOVN.S32 d23, q15 299 300 VQADD.S16 q8, q8, q0 301 VQADD.S16 q9, q9, q0 302 VQADD.S16 q10, q10, q0 303 VQADD.S16 q11, q11, q0 304 305 VDUP.8 q12, d13[6] // output_min 306 307 VQMOVUN.S16 d0, q8 308 VQMOVUN.S16 d1, q9 309 VQMOVUN.S16 d2, q10 310 VQMOVUN.S16 d3, q11 311 312 VDUP.8 q13, d13[7] // output_max 313 314 VMAX.U8 q0, q0, q12 315 VMAX.U8 q1, q1, q12 316 317 SUBS r1, r1, 8 // nc -= 8 318 319 VMIN.U8 q0, q0, q13 320 VMIN.U8 q1, q1, q13 321 322 # Store full 4 x 8 323 BLO 5f 324 VST1.8 {d3}, [r6], r7 325 VST1.8 {d2}, [r8], r7 326 VST1.8 {d1}, [r4], r7 327 VST1.8 {d0}, [r11], r7 328 SUB r2, r2, r14 // a -= ks 329 BHI 0b 330 331 VPOP {d10-d14} 332 ADD sp, sp, 12 // skip pad of 4, r2, r3 333 POP {r4, r5, r6, r7, r8, r9, r10, r11, pc} 334 335 # Remainder- 1 to 7 bytes of A 336 .p2align 3 3374: 338 AND r5, r5, 7 // kc remainder 1 to 7 339 340 VLD1.8 {d0}, [r3] 341 VLD1.8 {d10}, [r9]! 342 VLD1.8 {d2}, [r12] 343 VLD1.8 {d4}, [r10] 344 VLD1.8 {d6}, [r0] 345 346 VMOVL.U8 q0, d0 347 VSUBL.U8 q5, d10, d14 348 VMOVL.U8 q1, d2 349 VMOVL.U8 q2, d4 350 VMOVL.U8 q3, d6 351 VMLAL.S16 q8, d10, d0[0] 352 VMLAL.S16 q9, d11, d0[0] 353 VMLAL.S16 q10, d10, d2[0] 354 VMLAL.S16 q11, d11, d2[0] 355 VMLAL.S16 q12, d10, d4[0] 356 VMLAL.S16 q13, d11, d4[0] 357 VMLAL.S16 q14, d10, d6[0] 358 VMLAL.S16 q15, d11, d6[0] 359 CMP r5, 2 360 BLO 3b 361 362 VLD1.8 {d10}, [r9]! 363 VSUBL.U8 q5, d10, d14 364 VMLAL.S16 q8, d10, d0[1] 365 VMLAL.S16 q9, d11, d0[1] 366 VMLAL.S16 q10, d10, d2[1] 367 VMLAL.S16 q11, d11, d2[1] 368 VMLAL.S16 q12, d10, d4[1] 369 VMLAL.S16 q13, d11, d4[1] 370 VMLAL.S16 q14, d10, d6[1] 371 VMLAL.S16 q15, d11, d6[1] 372 BEQ 3b 373 374 VLD1.8 {d10}, [r9]! 375 VSUBL.U8 q5, d10, d14 376 VMLAL.S16 q8, d10, d0[2] 377 VMLAL.S16 q9, d11, d0[2] 378 VMLAL.S16 q10, d10, d2[2] 379 VMLAL.S16 q11, d11, d2[2] 380 VMLAL.S16 q12, d10, d4[2] 381 VMLAL.S16 q13, d11, d4[2] 382 VMLAL.S16 q14, d10, d6[2] 383 VMLAL.S16 q15, d11, d6[2] 384 CMP r5, 4 385 BLO 3b 386 387 VLD1.8 {d10}, [r9]! 388 VSUBL.U8 q5, d10, d14 389 VMLAL.S16 q8, d10, d0[3] 390 VMLAL.S16 q9, d11, d0[3] 391 VMLAL.S16 q10, d10, d2[3] 392 VMLAL.S16 q11, d11, d2[3] 393 VMLAL.S16 q12, d10, d4[3] 394 VMLAL.S16 q13, d11, d4[3] 395 VMLAL.S16 q14, d10, d6[3] 396 VMLAL.S16 q15, d11, d6[3] 397 BEQ 3b 398 399 VLD1.8 {d10}, [r9]! 400 VSUBL.U8 q5, d10, d14 401 VMLAL.S16 q8, d10, d1[0] 402 VMLAL.S16 q9, d11, d1[0] 403 VMLAL.S16 q10, d10, d3[0] 404 VMLAL.S16 q11, d11, d3[0] 405 VMLAL.S16 q12, d10, d5[0] 406 VMLAL.S16 q13, d11, d5[0] 407 VMLAL.S16 q14, d10, d7[0] 408 VMLAL.S16 q15, d11, d7[0] 409 CMP r5, 6 410 BLO 3b 411 412 VLD1.8 {d10}, [r9]! 413 VSUBL.U8 q5, d10, d14 414 VMLAL.S16 q8, d10, d1[1] 415 VMLAL.S16 q9, d11, d1[1] 416 VMLAL.S16 q10, d10, d3[1] 417 VMLAL.S16 q11, d11, d3[1] 418 VMLAL.S16 q12, d10, d5[1] 419 VMLAL.S16 q13, d11, d5[1] 420 VMLAL.S16 q14, d10, d7[1] 421 VMLAL.S16 q15, d11, d7[1] 422 BEQ 3b 423 424 VLD1.8 {d10}, [r9]! 425 VSUBL.U8 q5, d10, d14 426 VMLAL.S16 q8, d10, d1[2] 427 VMLAL.S16 q9, d11, d1[2] 428 VMLAL.S16 q10, d10, d3[2] 429 VMLAL.S16 q11, d11, d3[2] 430 VMLAL.S16 q12, d10, d5[2] 431 VMLAL.S16 q13, d11, d5[2] 432 VMLAL.S16 q14, d10, d7[2] 433 VMLAL.S16 q15, d11, d7[2] 434 B 3b 435 436 # Store odd width 437 .p2align 3 4385: 439 TST r1, 4 440 BEQ 6f 441 VST1.32 {d3[0]}, [r6]! 442 VST1.32 {d2[0]}, [r8]! 443 VST1.32 {d1[0]}, [r4]! 444 VST1.32 {d0[0]}, [r11]! 445 VEXT.8 q1, q1, q1, 4 446 VEXT.8 q0, q0, q0, 4 4476: 448 TST r1, 2 449 BEQ 7f 450 VST1.16 {d3[0]}, [r6]! 451 VST1.16 {d2[0]}, [r8]! 452 VST1.16 {d1[0]}, [r4]! 453 VST1.16 {d0[0]}, [r11]! 454 VEXT.8 q1, q1, q1, 2 455 VEXT.8 q0, q0, q0, 2 456 4577: 458 TST r1, 1 459 BEQ 8f 460 VST1.8 {d3[0]}, [r6] 461 VST1.8 {d2[0]}, [r8] 462 VST1.8 {d1[0]}, [r4] 463 VST1.8 {d0[0]}, [r11] 464 4658: 466 VPOP {d10-d14} 467 ADD sp, sp, 12 // skip pad of 4, r2, r3 468 POP {r4, r5, r6, r7, r8, r9, r10, r11, pc} 469 470END_FUNCTION xnn_qu8_igemm_minmax_rndnu_ukernel_4x8__aarch32_neon_mlal_lane_prfm_ld64 471#ifdef __ELF__ 472.section ".note.GNU-stack","",%progbits 473#endif 474