1// Auto-generated file. Do not edit! 2// Template: src/qs8-igemm/4x8c4-aarch32-neondot-cortex-a55.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_4x8c4__aarch32_neondot_cortex_a55( 16// size_t mr, r0 17// size_t nc, r1 18// size_t kc, r2 -> r5 -> sp + 52 19// size_t ks, r3 -> sp + 56 -> r14 20// const int8_t**restrict a, sp + 96 -> r2 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// size_t a_offset, sp + 116 -> (r5) 26// const int8_t* zero, sp + 120 -> (r7) 27// xnn_qs8_minmax_params*params); sp + 124 -> (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 33// A1 r12 d1 34// A2 r10 d2 35// A3 r0 d3 36 37// B r9 q2 q3 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 q7 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 53// iOS does not support 32 bit ARM with Neon DotProduct. 54#ifndef __APPLE__ 55BEGIN_FUNCTION xnn_qc8_igemm_minmax_fp32_ukernel_4x8c4__aarch32_neondot_cortex_a55 56 ADD r2, r2, 3 // kc = (kc + 3) & ~3 57 BIC r2, r2, 3 58 # Push 96 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 {d8-d13} // +48 = 96 63 64 LDR r11, [sp, 104] // c 65 LDR r6, [sp, 108] // cm_stride 66 LDR r2, [sp, 96] // a 67 LDR r9, [sp, 100] // w 68 LDR r5, [sp, 124] // 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 {d13[]}, [r5] // QC8 params 84 850: 86 # Load initial bias from w into accumulators 87 VLDM r9!, {d16-d19} // Bias 88 VMOV q10, q8 89 VMOV q11, q9 90 LDR r7, [sp, 120] // zero 91 VMOV q12, q8 92 VMOV q13, q9 93 VMOV q14, q8 94 VMOV q15, q9 95 961: 97 # Load next 4 A pointers + Add a_offset + Prologue 98 # - Load next 4 A pointers to GPR 99 # - Adjust A pointers by a_offset if not zero 100 # - Load prologue 101 # - Load k = kc from stack 102 LDR r3, [r2, 0] // A0 103 LDR r5, [sp, 116] // a_offset 104 CMP r3, r7 // if a0 == zero 105 LDR r12, [r2, 4] // A1 106 ADD r3, r3, r5 // a0 += a_offset 107 LDR r10, [r2, 8] // A2 108 MOVEQ r3, r7 // a0 = zero, else += a0 + a_offset 109 LDR r0, [r2, 12] // A3 110 CMP r12, r7 // if a1 == zero 111 VLD1.8 {d4}, [r9]! // B0 112 ADD r12, r12, r5 // a1 += a_offset 113 VLD1.8 {d5}, [r9]! // B1 114 MOVEQ r12, r7 // a1 = zero, else += a1 + a_offset 115 VLD1.8 {d6}, [r9]! // B2 116 CMP r10, r7 // if a2 == zero 117 VLD1.8 {d7}, [r9]! // B3 118 ADD r10, r10, r5 // a2 += a_offset 119 VLD1.8 {d0}, [r3]! // A0 120 MOVEQ r10, r7 // a2 = zero, else += a2 + a_offset 121 VLD1.8 {d1}, [r12]! // A1 122 CMP r0, r7 // if a3 == zero 123 ADD r0, r0, r5 // a3 += a_offset 124 LDR r5, [sp, 52] // k = kc 125 MOVEQ r0, r7 // a3 = zero, else += a3 + a_offset 126 SUBS r5, r5, 8 // k = k - 8 127 ADD r2, r2, 16 128 129 BLO 4f // less than 8 channels? 130 131 SUBS r5, r5, 8 // k = k - 8 132 BLO 21f // less than 8 channels? 133 134 # Main loop - 8 bytes of A. 135 # 16 SDOT, 12 LD64 136 .p2align 3 1372: 138 VSDOT.S8 q8, q2, d0[0] 139 VLD1.8 {d2}, [r10]! // A2 140 VSDOT.S8 q9, q3, d0[0] 141 VLD1.8 {d3}, [r0]! // A3 142 VSDOT.S8 q10, q2, d1[0] 143 VLD1.8 {d8}, [r9]! // B4 144 VSDOT.S8 q11, q3, d1[0] 145 VLD1.8 {d9}, [r9]! // B5 146 VSDOT.S8 q12, q2, d2[0] 147 VLD1.8 {d10}, [r9]! // B6 148 VSDOT.S8 q13, q3, d2[0] 149 VLD1.8 {d11}, [r9]! // B7 150 VSDOT.S8 q14, q2, d3[0] 151 VSDOT.S8 q15, q3, d3[0] 152 SUBS r5, r5, 8 153 154 VSDOT.S8 q8, q4, d0[1] 155 VLD1.8 {d4}, [r9]! // B0 156 VSDOT.S8 q9, q5, d0[1] 157 VLD1.8 {d5}, [r9]! // B1 158 VSDOT.S8 q10, q4, d1[1] 159 VLD1.8 {d6}, [r9]! // B2 160 VSDOT.S8 q11, q5, d1[1] 161 VLD1.8 {d7}, [r9]! // B3 162 VSDOT.S8 q12, q4, d2[1] 163 VLD1.8 {d0}, [r3]! // A0 164 VSDOT.S8 q13, q5, d2[1] 165 VLD1.8 {d1}, [r12]! // A1 166 VSDOT.S8 q14, q4, d3[1] 167 VSDOT.S8 q15, q5, d3[1] 168 BHS 2b 169 170 # Epilogue 171 .p2align 3 17221: 173 VSDOT.S8 q8, q2, d0[0] 174 VLD1.8 {d2}, [r10]! // A2 175 VSDOT.S8 q9, q3, d0[0] 176 VLD1.8 {d3}, [r0]! // A3 177 VSDOT.S8 q10, q2, d1[0] 178 VLD1.8 {d8}, [r9]! // B4 179 VSDOT.S8 q11, q3, d1[0] 180 VLD1.8 {d9}, [r9]! // B5 181 VSDOT.S8 q12, q2, d2[0] 182 VLD1.8 {d10}, [r9]! // B6 183 VSDOT.S8 q13, q3, d2[0] 184 VLD1.8 {d11}, [r9]! // B7 185 VSDOT.S8 q14, q2, d3[0] 186 VSDOT.S8 q15, q3, d3[0] 187 TST r5, 5 188 189 VSDOT.S8 q8, q4, d0[1] 190 VSDOT.S8 q9, q5, d0[1] 191 VSDOT.S8 q10, q4, d1[1] 192 VSDOT.S8 q11, q5, d1[1] 193 VSDOT.S8 q12, q4, d2[1] 194 VSDOT.S8 q13, q5, d2[1] 195 VSDOT.S8 q14, q4, d3[1] 196 VSDOT.S8 q15, q5, d3[1] 197 # Is there a remainder?- 4 bytes of A 198 BNE 40f 199 2003: 201 # ks loop 202 SUBS r14, r14, 16 // ks -= MR * sizeof(void*) 203 BHI 1b 204 205 LDR r7, [sp, 112] // cn_stride 206 LDR r14, [sp, 56] // p = ks 207 208 # QC8 FP32 quantization 209 VLD1.8 {q0-q1}, [r9]! 210 211 VCVT.F32.S32 q8, q8 212 VCVT.F32.S32 q9, q9 213 VCVT.F32.S32 q10, q10 214 VCVT.F32.S32 q11, q11 215 VCVT.F32.S32 q12, q12 216 VCVT.F32.S32 q13, q13 217 VCVT.F32.S32 q14, q14 218 VCVT.F32.S32 q15, q15 219 220 VMUL.F32 q8, q8, q0 // multiplier 221 VMUL.F32 q9, q9, q1 222 VMUL.F32 q10, q10, q0 223 VMUL.F32 q11, q11, q1 224 VMUL.F32 q12, q12, q0 225 VMUL.F32 q13, q13, q1 226 VMUL.F32 q14, q14, q0 227 VMUL.F32 q15, q15, q1 228 229 VCVTN.S32.F32 q8, q8 230 VCVTN.S32.F32 q9, q9 231 VCVTN.S32.F32 q10, q10 232 VCVTN.S32.F32 q11, q11 233 VCVTN.S32.F32 q12, q12 234 VCVTN.S32.F32 q13, q13 235 VCVTN.S32.F32 q14, q14 236 VCVTN.S32.F32 q15, q15 237 VDUP.16 q0, d13[2] // output_zero_point 238 239 VQMOVN.S32 d16, q8 240 VQMOVN.S32 d17, q9 241 VQMOVN.S32 d18, q10 242 VQMOVN.S32 d19, q11 243 VQMOVN.S32 d20, q12 244 VQMOVN.S32 d21, q13 245 VQMOVN.S32 d22, q14 246 VQMOVN.S32 d23, q15 247 248 VQADD.S16 q8, q8, q0 249 VQADD.S16 q9, q9, q0 250 VQADD.S16 q10, q10, q0 251 VQADD.S16 q11, q11, q0 252 253 VDUP.8 q12, d13[6] // output_min 254 255 VQMOVN.S16 d0, q8 256 VQMOVN.S16 d1, q9 257 VQMOVN.S16 d2, q10 258 VQMOVN.S16 d3, q11 259 260 VDUP.8 q13, d13[7] // output_min 261 262 VMAX.S8 q0, q0, q12 263 VMAX.S8 q1, q1, q12 264 265 SUBS r1, r1, 8 // nc -= 8 266 267 VMIN.S8 q0, q0, q13 268 VMIN.S8 q1, q1, q13 269 270 # Store full 4 x 8 271 BLO 5f 272 VST1.8 {d3}, [r6], r7 273 VST1.8 {d2}, [r8], r7 274 VST1.8 {d1}, [r4], r7 275 VST1.8 {d0}, [r11], r7 276 SUB r2, r2, r14 // a -= ks 277 BHI 0b 278 279 VPOP {d8-d13} 280 ADD sp, sp, 12 // skip pad, r2, r3 281 POP {r4, r5, r6, r7, r8, r9, r10, r11, pc} 282 283 # Remainder prologue 284 .p2align 3 28540: 286 VLD1.8 {d4}, [r9]! // B0 287 VLD1.8 {d0}, [r3]! // A0 288 VLD1.8 {d5}, [r9]! // B1 289 VLD1.8 {d6}, [r9]! // B2 290 VLD1.8 {d1}, [r12]! // A1 291 VLD1.8 {d7}, [r9]! // B3 292 293 # Remainder- 4 bytes of A 2944: 295 VSDOT.S8 q8, q2, d0[0] 296 VLD1.32 {d2[0]}, [r10]! // A2 297 VSDOT.S8 q9, q3, d0[0] 298 VLD1.32 {d3[0]}, [r0]! // A3 299 VSDOT.S8 q10, q2, d1[0] 300 SUB r3, r3, 4 // Rewind A0 301 VSDOT.S8 q11, q3, d1[0] 302 SUB r12, r12, 4 // Rewind A1 303 VSDOT.S8 q12, q2, d2[0] 304 VSDOT.S8 q13, q3, d2[0] 305 VSDOT.S8 q14, q2, d3[0] 306 VSDOT.S8 q15, q3, d3[0] 307 B 3b 308 309 # Store odd width 310 .p2align 3 3115: 312 TST r1, 4 313 BEQ 6f 314 VST1.32 {d3[0]}, [r6]! 315 VST1.32 {d2[0]}, [r8]! 316 VST1.32 {d1[0]}, [r4]! 317 VST1.32 {d0[0]}, [r11]! 318 VEXT.8 q0, q0, q0, 4 319 VEXT.8 q1, q1, q1, 4 3206: 321 TST r1, 2 322 BEQ 7f 323 VST1.16 {d3[0]}, [r6]! 324 VST1.16 {d2[0]}, [r8]! 325 VST1.16 {d1[0]}, [r4]! 326 VST1.16 {d0[0]}, [r11]! 327 VEXT.8 q0, q0, q0, 2 328 VEXT.8 q1, q1, q1, 2 329 3307: 331 TST r1, 1 332 BEQ 8f 333 VST1.8 {d3[0]}, [r6] 334 VST1.8 {d2[0]}, [r8] 335 VST1.8 {d1[0]}, [r4] 336 VST1.8 {d0[0]}, [r11] 337 3388: 339 VPOP {d8-d13} 340 ADD sp, sp, 12 // skip pad, r2, r3 341 POP {r4, r5, r6, r7, r8, r9, r10, r11, pc} 342 343END_FUNCTION xnn_qc8_igemm_minmax_fp32_ukernel_4x8c4__aarch32_neondot_cortex_a55 344#endif // __APPLE__ 345 346#ifdef __ELF__ 347.section ".note.GNU-stack","",%progbits 348#endif 349