1// Auto-generated file. Do not edit! 2// Template: src/qs8-gemm/4x8c4-aarch32-neondot-cortex-a55.S.in 3// Generator: tools/xngen 4// 5// Copyright 2022 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_gemm_minmax_rndnu_ukernel_4x8c4__aarch32_neondot_cortex_a55( 16// size_t mr, r0 17// size_t nc, r1 18// size_t kc, r2 -> r5 19// const uint8_t*restrict a, r3 20// size_t a_stride, sp + 80 -> (r7) 21// const void*restrict w, sp + 84 -> r9 22// uint8_t*restrict c, sp + 88 -> r11 23// size_t cm_stride, sp + 92 -> (r6) 24// size_t cn_stride, sp + 96 -> r7 25// xnn_qs8_conv_minmax_params params) sp + 100 -> (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 31// A1 r12 d1 32// A2 r10 d2 33// A3 r0 d3 34 35// B r9 q2 q3 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// unused q7 43 44// params structure is 16 bytes 45// struct { 46// int32_t right_pre_shift; d12[0] 47// int32_t multiplier; d12[1] 48// int32_t right_post_shift; d13[0] 49// int16_t output_zero_point; d13[2] 50// int8_t output_min; d13[6] 51// int8_t output_max; d13[7] 52// } rndnu_neon; 53 54// iOS does not support 32 bit ARM with Neon DotProduct. 55#ifndef __APPLE__ 56BEGIN_FUNCTION xnn_qs8_gemm_minmax_rndnu_ukernel_4x8c4__aarch32_neondot_cortex_a55 57 # Push 80 bytes 58 PUSH {r4, r5, r6, r7, r8, r9, r10, r11} // 32 59 VPUSH {d8-d13} // +48 = 80 60 61 LDR r7, [sp, 80] // a_stride 62 ADD r2, r2, 3 // kc = (kc + 3) & ~3 63 LDR r11, [sp, 88] // c 64 LDR r6, [sp, 92] // cm_stride 65 LDR r9, [sp, 84] // w 66 BIC r2, r2, 3 67 LDR r5, [sp, 100] // params 68 69 # Clamp A and C pointers 70 CMP r0, 2 // if mr >= 2 71 ADD r12, r3, r7 // a1 = a0 + a_stride 72 ADD r4, r11, r6 // c1 = c0 + cm_stride 73 MOVLO r12, r3 // a1 74 MOVLO r4, r11 // c1 75 // if mr > 2 76 ADD r10, r12, r7 // a2 = a1 + a_stride 77 ADD r8, r4, r6 // c2 = c1 + cm_stride 78 MOVLS r10, r12 // a2 79 MOVLS r8, r4 // c2 80 81 CMP r0, 4 // if mr >=4 82 ADD r0, r10, r7 // a3 = a2 + a_stride 83 ADD r6, r8, r6 // c3 = c2 + cm_stride 84 MOVLO r0, r10 // a3 85 MOVLO r6, r8 // c3 86 87 # Load params values 88 VLDM r5, {d12-d13} // RNDNU params 89 LDR r7, [sp, 96] // cn_stride 90 91 .p2align 3 920: 93 # Load initial bias from w into accumulators 94 VLDM r9!, {d16-d19} // Bias 95 SUBS r5, r2, 8 // k = kc - 8 96 97 # Prologue + Bias 98 VLD1.8 {d4}, [r9]! // B0 99 VMOV q10, q8 100 VLD1.8 {d0}, [r3]! // A0 101 VMOV q11, q9 102 VLD1.8 {d5}, [r9]! // B1 103 VMOV q12, q8 104 VLD1.8 {d6}, [r9]! // B2 105 VMOV q13, q9 106 VLD1.8 {d1}, [r12]! // A1 107 VMOV q14, q8 108 VLD1.8 {d7}, [r9]! // B3 109 VMOV q15, q9 110 BLO 4f // less than 8 channels? 111 112 SUBS r5, r5, 8 // k = k - 8 113 BLO 12f // less than 16 channels - skip mainloop 114 115 # Main loop - 8 bytes of A. 116 # 16 SDOT, 12 LD64 117 .p2align 3 1181: 119 VSDOT.S8 q8, q2, d0[0] 120 VLD1.8 {d2}, [r10]! // A2 121 VSDOT.S8 q9, q3, d0[0] 122 VLD1.8 {d3}, [r0]! // A3 123 VSDOT.S8 q10, q2, d1[0] 124 VLD1.8 {d8}, [r9]! // B4 125 VSDOT.S8 q11, q3, d1[0] 126 VLD1.8 {d9}, [r9]! // B5 127 VSDOT.S8 q12, q2, d2[0] 128 VLD1.8 {d10}, [r9]! // B6 129 VSDOT.S8 q13, q3, d2[0] 130 VLD1.8 {d11}, [r9]! // B7 131 VSDOT.S8 q14, q2, d3[0] 132 VSDOT.S8 q15, q3, d3[0] 133 SUBS r5, r5, 8 134 135 VSDOT.S8 q8, q4, d0[1] 136 VLD1.8 {d4}, [r9]! // B0 137 VSDOT.S8 q9, q5, d0[1] 138 VLD1.8 {d5}, [r9]! // B1 139 VSDOT.S8 q10, q4, d1[1] 140 VLD1.8 {d6}, [r9]! // B2 141 VSDOT.S8 q11, q5, d1[1] 142 VLD1.8 {d7}, [r9]! // B3 143 VSDOT.S8 q12, q4, d2[1] 144 VLD1.8 {d0}, [r3]! // A0 145 VSDOT.S8 q13, q5, d2[1] 146 VLD1.8 {d1}, [r12]! // A1 147 VSDOT.S8 q14, q4, d3[1] 148 VSDOT.S8 q15, q5, d3[1] 149 BHS 1b 150 151 # Epilogue 152 .p2align 3 15312: 154 VSDOT.S8 q8, q2, d0[0] 155 VLD1.8 {d2}, [r10]! // A2 156 VSDOT.S8 q9, q3, d0[0] 157 VLD1.8 {d3}, [r0]! // A3 158 VSDOT.S8 q10, q2, d1[0] 159 VLD1.8 {d8}, [r9]! // B4 160 VSDOT.S8 q11, q3, d1[0] 161 VLD1.8 {d9}, [r9]! // B5 162 VSDOT.S8 q12, q2, d2[0] 163 VLD1.8 {d10}, [r9]! // B6 164 VSDOT.S8 q13, q3, d2[0] 165 VLD1.8 {d11}, [r9]! // B7 166 VSDOT.S8 q14, q2, d3[0] 167 VSDOT.S8 q15, q3, d3[0] 168 TST r5, 7 169 170 VSDOT.S8 q8, q4, d0[1] 171 VSDOT.S8 q9, q5, d0[1] 172 VSDOT.S8 q10, q4, d1[1] 173 VSDOT.S8 q11, q5, d1[1] 174 VSDOT.S8 q12, q4, d2[1] 175 VSDOT.S8 q13, q5, d2[1] 176 VSDOT.S8 q14, q4, d3[1] 177 VSDOT.S8 q15, q5, d3[1] 178 179 # Is there a remainder?- 4 bytes of A 180 BNE 3f 181 1822: 183 # RNDNU quantization 184 VDUP.32 q0, d12[0] // right_pre_shift 185 186 VQSHL.S32 q8, q8, q0 187 VQSHL.S32 q9, q9, q0 188 VQSHL.S32 q10, q10, q0 189 VQSHL.S32 q11, q11, q0 190 VQSHL.S32 q12, q12, q0 191 VQSHL.S32 q13, q13, q0 192 VQSHL.S32 q14, q14, q0 193 VQSHL.S32 q15, q15, q0 194 195 VDUP.32 q2, d13[0] // right_post_shift 196 197 VQDMULH.S32 q8, q8, d12[1] // multiplier 198 VQDMULH.S32 q9, q9, d12[1] 199 VQDMULH.S32 q10, q10, d12[1] 200 VQDMULH.S32 q11, q11, d12[1] 201 VQDMULH.S32 q12, q12, d12[1] 202 VQDMULH.S32 q13, q13, d12[1] 203 VQDMULH.S32 q14, q14, d12[1] 204 VQDMULH.S32 q15, q15, d12[1] 205 206 VRSHL.S32 q8, q8, q2 207 VRSHL.S32 q9, q9, q2 208 VRSHL.S32 q10, q10, q2 209 VRSHL.S32 q11, q11, q2 210 VRSHL.S32 q12, q12, q2 211 VRSHL.S32 q13, q13, q2 212 VRSHL.S32 q14, q14, q2 213 VRSHL.S32 q15, q15, q2 214 215 VDUP.16 q0, d13[2] // output_zero_point 216 217 VQMOVN.S32 d16, q8 218 VQMOVN.S32 d17, q9 219 VQMOVN.S32 d18, q10 220 VQMOVN.S32 d19, q11 221 VQMOVN.S32 d20, q12 222 VQMOVN.S32 d21, q13 223 VQMOVN.S32 d22, q14 224 VQMOVN.S32 d23, q15 225 226 VQADD.S16 q8, q8, q0 227 VQADD.S16 q9, q9, q0 228 VQADD.S16 q10, q10, q0 229 VQADD.S16 q11, q11, q0 230 231 VDUP.8 q12, d13[6] // output_min 232 233 VQMOVN.S16 d0, q8 234 VQMOVN.S16 d1, q9 235 VQMOVN.S16 d2, q10 236 VQMOVN.S16 d3, q11 237 238 VDUP.8 q13, d13[7] // output_max 239 240 VMAX.S8 q0, q0, q12 241 VMAX.S8 q1, q1, q12 242 243 SUBS r1, r1, 8 244 245 VMIN.S8 q0, q0, q13 246 VMIN.S8 q1, q1, q13 247 248 # Store full 4 x 8 249 BLO 5f 250 VST1.8 {d0}, [r11], r7 251 SUB r3, r3, r2 252 VST1.8 {d1}, [r4], r7 253 SUB r12, r12, r2 254 VST1.8 {d2}, [r8], r7 255 SUB r10, r10, r2 256 VST1.8 {d3}, [r6], r7 257 SUB r0, r0, r2 258 BHI 0b 259 260 VPOP {d8-d13} 261 POP {r4, r5, r6, r7, r8, r9, r10, r11} 262 BX lr 263 264 # Remainder prologue 265 .p2align 3 2663: 267 VLD1.8 {d4}, [r9]! // B0 268 VLD1.8 {d0}, [r3]! // A0 269 VLD1.8 {d5}, [r9]! // B1 270 VLD1.8 {d6}, [r9]! // B2 271 VLD1.8 {d1}, [r12]! // A1 272 VLD1.8 {d7}, [r9]! // B3 273 274 # Remainder- 4 bytes of A 2754: 276 VSDOT.S8 q8, q2, d0[0] 277 VLD1.32 {d2[0]}, [r10]! // A2 278 VSDOT.S8 q9, q3, d0[0] 279 VLD1.32 {d3[0]}, [r0]! // A3 280 VSDOT.S8 q10, q2, d1[0] 281 SUB r3, r3, 4 // Rewind A0 282 VSDOT.S8 q11, q3, d1[0] 283 SUB r12, r12, 4 // Rewind A1 284 VSDOT.S8 q12, q2, d2[0] 285 VSDOT.S8 q13, q3, d2[0] 286 VSDOT.S8 q14, q2, d3[0] 287 VSDOT.S8 q15, q3, d3[0] 288 B 2b 289 290 # Store odd width 291 .p2align 3 2925: 293 TST r1, 4 294 BEQ 6f 295 VST1.32 {d0[0]}, [r11]! 296 VST1.32 {d1[0]}, [r4]! 297 VST1.32 {d2[0]}, [r8]! 298 VST1.32 {d3[0]}, [r6]! 299 VEXT.8 q0, q0, q0, 4 300 VEXT.8 q1, q1, q1, 4 3016: 302 TST r1, 2 303 BEQ 7f 304 VST1.16 {d0[0]}, [r11]! 305 VST1.16 {d1[0]}, [r4]! 306 VST1.16 {d2[0]}, [r8]! 307 VST1.16 {d3[0]}, [r6]! 308 VEXT.8 q0, q0, q0, 2 309 VEXT.8 q1, q1, q1, 2 310 3117: 312 TST r1, 1 313 BEQ 12f 314 VST1.8 {d0[0]}, [r11] 315 VST1.8 {d1[0]}, [r4] 316 VST1.8 {d2[0]}, [r8] 317 VST1.8 {d3[0]}, [r6] 318 31912: 320 VPOP {d8-d13} 321 POP {r4, r5, r6, r7, r8, r9, r10, r11} 322 BX lr 323 324END_FUNCTION xnn_qs8_gemm_minmax_rndnu_ukernel_4x8c4__aarch32_neondot_cortex_a55 325#endif // __APPLE__ 326 327#ifdef __ELF__ 328.section ".note.GNU-stack","",%progbits 329#endif 330 331