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