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_qs8_igemm_minmax_rndnu_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_conv_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 16 bytes 47// struct { 48// int32_t right_pre_shift; d12[0] 49// int32_t multiplier; d12[1] 50// int32_t right_post_shift; d13[0] 51// int16_t output_zero_point; d13[2] 52// int8_t output_min; d13[6] 53// int8_t output_max; d13[7] 54// } rndnu_neon; 55 56// iOS does not support 32 bit ARM with Neon DotProduct. 57#ifndef __APPLE__ 58BEGIN_FUNCTION xnn_qs8_igemm_minmax_rndnu_ukernel_4x8c4__aarch32_neondot_cortex_a55 59 ADD r2, r2, 3 // kc = (kc + 3) & ~3 60 BIC r2, r2, 3 61 # Push 96 bytes 62 # r2 will be reloaded in outer loop. r3 is ks 63 PUSH {r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, lr} // +44 64 SUB sp, sp, 4 // 4 65 VPUSH {d8-d13} // +48 = 96 66 67 LDR r11, [sp, 104] // c 68 LDR r6, [sp, 108] // cm_stride 69 LDR r2, [sp, 96] // a 70 LDR r9, [sp, 100] // w 71 LDR r5, [sp, 124] // params 72 MOV r14, r3 // p = ks 73 74 # Clamp C pointers 75 CMP r0, 2 // if mr >= 2 76 ADD r4, r11, r6 // c1 = c0 + cm_stride 77 MOVLO r4, r11 // c1 78 // if mr > 2 79 ADD r8, r4, r6 // c2 = c1 + cm_stride 80 MOVLS r8, r4 // c2 81 CMP r0, 4 // if mr >=4 82 ADD r6, r8, r6 // c3 = c2 + cm_stride 83 MOVLO r6, r8 // c3 84 85 # Load params values 86 VLDM r5, {d12-d13} // RNDNU params 87 880: 89 # Load initial bias from w into accumulators 90 VLDM r9!, {d16-d19} // Bias 91 VMOV q10, q8 92 VMOV q11, q9 93 LDR r7, [sp, 120] // zero 94 VMOV q12, q8 95 VMOV q13, q9 96 VMOV q14, q8 97 VMOV q15, q9 98 991: 100 # Load next 4 A pointers + Add a_offset + Prologue 101 # - Load next 4 A pointers to GPR 102 # - Adjust A pointers by a_offset if not zero 103 # - Load prologue 104 # - Load k = kc from stack 105 LDR r3, [r2, 0] // A0 106 LDR r5, [sp, 116] // a_offset 107 CMP r3, r7 // if a0 == zero 108 LDR r12, [r2, 4] // A1 109 ADD r3, r3, r5 // a0 += a_offset 110 LDR r10, [r2, 8] // A2 111 MOVEQ r3, r7 // a0 = zero, else += a0 + a_offset 112 LDR r0, [r2, 12] // A3 113 CMP r12, r7 // if a1 == zero 114 VLD1.8 {d4}, [r9]! // B0 115 ADD r12, r12, r5 // a1 += a_offset 116 VLD1.8 {d5}, [r9]! // B1 117 MOVEQ r12, r7 // a1 = zero, else += a1 + a_offset 118 VLD1.8 {d6}, [r9]! // B2 119 CMP r10, r7 // if a2 == zero 120 VLD1.8 {d7}, [r9]! // B3 121 ADD r10, r10, r5 // a2 += a_offset 122 VLD1.8 {d0}, [r3]! // A0 123 MOVEQ r10, r7 // a2 = zero, else += a2 + a_offset 124 VLD1.8 {d1}, [r12]! // A1 125 CMP r0, r7 // if a3 == zero 126 ADD r0, r0, r5 // a3 += a_offset 127 LDR r5, [sp, 52] // k = kc 128 MOVEQ r0, r7 // a3 = zero, else += a3 + a_offset 129 SUBS r5, r5, 8 // k = k - 8 130 ADD r2, r2, 16 131 132 BLO 6f // less than 8 channels? 133 134 SUBS r5, r5, 8 // k = k - 8 135 BLO 3f // less than 8 channels? 136 137 # Main loop - 8 bytes of A. 138 # 16 SDOT, 12 LD64 139 .p2align 3 1402: 141 VSDOT.S8 q8, q2, d0[0] 142 VLD1.8 {d2}, [r10]! // A2 143 VSDOT.S8 q9, q3, d0[0] 144 VLD1.8 {d3}, [r0]! // A3 145 VSDOT.S8 q10, q2, d1[0] 146 VLD1.8 {d8}, [r9]! // B4 147 VSDOT.S8 q11, q3, d1[0] 148 VLD1.8 {d9}, [r9]! // B5 149 VSDOT.S8 q12, q2, d2[0] 150 VLD1.8 {d10}, [r9]! // B6 151 VSDOT.S8 q13, q3, d2[0] 152 VLD1.8 {d11}, [r9]! // B7 153 VSDOT.S8 q14, q2, d3[0] 154 VSDOT.S8 q15, q3, d3[0] 155 SUBS r5, r5, 8 156 157 VSDOT.S8 q8, q4, d0[1] 158 VLD1.8 {d4}, [r9]! // B0 159 VSDOT.S8 q9, q5, d0[1] 160 VLD1.8 {d5}, [r9]! // B1 161 VSDOT.S8 q10, q4, d1[1] 162 VLD1.8 {d6}, [r9]! // B2 163 VSDOT.S8 q11, q5, d1[1] 164 VLD1.8 {d7}, [r9]! // B3 165 VSDOT.S8 q12, q4, d2[1] 166 VLD1.8 {d0}, [r3]! // A0 167 VSDOT.S8 q13, q5, d2[1] 168 VLD1.8 {d1}, [r12]! // A1 169 VSDOT.S8 q14, q4, d3[1] 170 VSDOT.S8 q15, q5, d3[1] 171 BHS 2b 172 173 # Epilogue 174 .p2align 3 1753: 176 VSDOT.S8 q8, q2, d0[0] 177 VLD1.8 {d2}, [r10]! // A2 178 VSDOT.S8 q9, q3, d0[0] 179 VLD1.8 {d3}, [r0]! // A3 180 VSDOT.S8 q10, q2, d1[0] 181 VLD1.8 {d8}, [r9]! // B4 182 VSDOT.S8 q11, q3, d1[0] 183 VLD1.8 {d9}, [r9]! // B5 184 VSDOT.S8 q12, q2, d2[0] 185 VLD1.8 {d10}, [r9]! // B6 186 VSDOT.S8 q13, q3, d2[0] 187 VLD1.8 {d11}, [r9]! // B7 188 VSDOT.S8 q14, q2, d3[0] 189 VSDOT.S8 q15, q3, d3[0] 190 TST r5, 5 191 192 VSDOT.S8 q8, q4, d0[1] 193 VSDOT.S8 q9, q5, d0[1] 194 VSDOT.S8 q10, q4, d1[1] 195 VSDOT.S8 q11, q5, d1[1] 196 VSDOT.S8 q12, q4, d2[1] 197 VSDOT.S8 q13, q5, d2[1] 198 VSDOT.S8 q14, q4, d3[1] 199 VSDOT.S8 q15, q5, d3[1] 200 # Is there a remainder?- 4 bytes of A 201 BNE 5f 202 2034: 204 # ks loop 205 SUBS r14, r14, 16 // ks -= MR * sizeof(void*) 206 BHI 1b 207 208 LDR r7, [sp, 112] // cn_stride 209 LDR r14, [sp, 56] // p = ks 210 211 # RNDNU quantization 212 VDUP.32 q0, d12[0] // right_pre_shift 213 214 VQSHL.S32 q8, q8, q0 215 VQSHL.S32 q9, q9, q0 216 VQSHL.S32 q10, q10, q0 217 VQSHL.S32 q11, q11, q0 218 VQSHL.S32 q12, q12, q0 219 VQSHL.S32 q13, q13, q0 220 VQSHL.S32 q14, q14, q0 221 VQSHL.S32 q15, q15, q0 222 223 VDUP.32 q2, d13[0] // right_post_shift 224 225 VQDMULH.S32 q8, q8, d12[1] // multiplier 226 VQDMULH.S32 q9, q9, d12[1] 227 VQDMULH.S32 q10, q10, d12[1] 228 VQDMULH.S32 q11, q11, d12[1] 229 VQDMULH.S32 q12, q12, d12[1] 230 VQDMULH.S32 q13, q13, d12[1] 231 VQDMULH.S32 q14, q14, d12[1] 232 VQDMULH.S32 q15, q15, d12[1] 233 234 VRSHL.S32 q8, q8, q2 235 VRSHL.S32 q9, q9, q2 236 VRSHL.S32 q10, q10, q2 237 VRSHL.S32 q11, q11, q2 238 VRSHL.S32 q12, q12, q2 239 VRSHL.S32 q13, q13, q2 240 VRSHL.S32 q14, q14, q2 241 VRSHL.S32 q15, q15, q2 242 VDUP.16 q0, d13[2] // output_zero_point 243 244 VQMOVN.S32 d16, q8 245 VQMOVN.S32 d17, q9 246 VQMOVN.S32 d18, q10 247 VQMOVN.S32 d19, q11 248 VQMOVN.S32 d20, q12 249 VQMOVN.S32 d21, q13 250 VQMOVN.S32 d22, q14 251 VQMOVN.S32 d23, q15 252 253 VQADD.S16 q8, q8, q0 254 VQADD.S16 q9, q9, q0 255 VQADD.S16 q10, q10, q0 256 VQADD.S16 q11, q11, q0 257 258 VDUP.8 q12, d13[6] // output_min 259 260 VQMOVN.S16 d0, q8 261 VQMOVN.S16 d1, q9 262 VQMOVN.S16 d2, q10 263 VQMOVN.S16 d3, q11 264 265 VDUP.8 q13, d13[7] // output_max 266 267 VMAX.S8 q0, q0, q12 268 VMAX.S8 q1, q1, q12 269 270 SUBS r1, r1, 8 // nc -= 8 271 272 VMIN.S8 q0, q0, q13 273 VMIN.S8 q1, q1, q13 274 275 # Store full 4 x 8 276 BLO 7f 277 VST1.8 {d3}, [r6], r7 278 VST1.8 {d2}, [r8], r7 279 VST1.8 {d1}, [r4], r7 280 VST1.8 {d0}, [r11], r7 281 SUB r2, r2, r14 // a -= ks 282 BHI 0b 283 284 VPOP {d8-d13} 285 ADD sp, sp, 12 // skip pad, r2, r3 286 POP {r4, r5, r6, r7, r8, r9, r10, r11, pc} 287 288 # Remainder prologue 289 .p2align 3 2905: 291 VLD1.8 {d4}, [r9]! // B0 292 VLD1.8 {d0}, [r3]! // A0 293 VLD1.8 {d5}, [r9]! // B1 294 VLD1.8 {d6}, [r9]! // B2 295 VLD1.8 {d1}, [r12]! // A1 296 VLD1.8 {d7}, [r9]! // B3 297 298 # Remainder- 4 bytes of A 2996: 300 VSDOT.S8 q8, q2, d0[0] 301 VLD1.32 {d2[0]}, [r10]! // A2 302 VSDOT.S8 q9, q3, d0[0] 303 VLD1.32 {d3[0]}, [r0]! // A3 304 VSDOT.S8 q10, q2, d1[0] 305 SUB r3, r3, 4 // Rewind A0 306 VSDOT.S8 q11, q3, d1[0] 307 SUB r12, r12, 4 // Rewind A1 308 VSDOT.S8 q12, q2, d2[0] 309 VSDOT.S8 q13, q3, d2[0] 310 VSDOT.S8 q14, q2, d3[0] 311 VSDOT.S8 q15, q3, d3[0] 312 B 4b 313 314 # Store odd width 315 .p2align 3 3167: 317 TST r1, 4 318 BEQ 8f 319 VST1.32 {d3[0]}, [r6]! 320 VST1.32 {d2[0]}, [r8]! 321 VST1.32 {d1[0]}, [r4]! 322 VST1.32 {d0[0]}, [r11]! 323 VEXT.8 q1, q1, q1, 4 324 VEXT.8 q0, q0, q0, 4 3258: 326 TST r1, 2 327 BEQ 9f 328 VST1.16 {d3[0]}, [r6]! 329 VST1.16 {d2[0]}, [r8]! 330 VST1.16 {d1[0]}, [r4]! 331 VST1.16 {d0[0]}, [r11]! 332 VEXT.8 q1, q1, q1, 2 333 VEXT.8 q0, q0, q0, 2 334 3359: 336 TST r1, 1 337 BEQ 10f 338 VST1.8 {d3[0]}, [r6] 339 VST1.8 {d2[0]}, [r8] 340 VST1.8 {d1[0]}, [r4] 341 VST1.8 {d0[0]}, [r11] 342 34310: 344 VPOP {d8-d13} 345 ADD sp, sp, 12 // skip pad, r2, r3 346 POP {r4, r5, r6, r7, r8, r9, r10, r11, pc} 347 348END_FUNCTION xnn_qs8_igemm_minmax_rndnu_ukernel_4x8c4__aarch32_neondot_cortex_a55 349#endif // __APPLE__ 350 351#ifdef __ELF__ 352.section ".note.GNU-stack","",%progbits 353#endif 354