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