1// Auto-generated file. Do not edit! 2// Template: src/qs8-igemm/4x8c4-aarch32-neondot-ld64.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_igemm_minmax_fp32_ukernel_4x8c4__aarch32_neondot_ld64( 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_ld64 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 98 LDR r3, [r2, 0] 99 LDR r12, [r2, 4] 100 LDR r10, [r2, 8] 101 LDR r0, [r2, 12] 102 ADD r2, r2, 16 103 104 # Add a_offset 105 LDR r5, [sp, 116] // a_offset 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, 52] // 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 of A. 124 # 16 SDOT, 4 LD64 A, 4 LD128 B 125 .p2align 3 1262: 127 VLD1.8 {d0}, [r3]! // A0 128 VLD1.8 {q2}, [r9]! // B0 129 VLD1.8 {d1}, [r12]! // A1 130 VLD1.8 {q3}, [r9]! // B1 131 VLD1.8 {d2}, [r10]! // A2 132 VLD1.8 {q4}, [r9]! // B2 133 VLD1.8 {d3}, [r0]! // A3 134 VLD1.8 {q5}, [r9]! // B3 135 SUBS r5, r5, 8 136 137 VSDOT.S8 q8, q2, d0[0] 138 VSDOT.S8 q9, q3, d0[0] 139 VSDOT.S8 q10, q2, d1[0] 140 VSDOT.S8 q11, q3, d1[0] 141 VSDOT.S8 q12, q2, d2[0] 142 VSDOT.S8 q13, q3, d2[0] 143 VSDOT.S8 q14, q2, d3[0] 144 VSDOT.S8 q15, q3, d3[0] 145 146 VSDOT.S8 q8, q4, d0[1] 147 VSDOT.S8 q9, q5, d0[1] 148 VSDOT.S8 q10, q4, d1[1] 149 VSDOT.S8 q11, q5, d1[1] 150 VSDOT.S8 q12, q4, d2[1] 151 VSDOT.S8 q13, q5, d2[1] 152 VSDOT.S8 q14, q4, d3[1] 153 VSDOT.S8 q15, q5, d3[1] 154 BHS 2b 155 156 # Is there a remainder?- 4 bytes of A 157 TST r5, 4 158 BNE 4f 159 1603: 161 # ks loop 162 SUBS r14, r14, 16 // ks -= MR * sizeof(void*) 163 BHI 1b 164 165 LDR r7, [sp, 112] // cn_stride 166 LDR r14, [sp, 56] // p = ks 167 168 # QC8 FP32 quantization 169 VLD1.8 {q0-q1}, [r9]! 170 171 VCVT.F32.S32 q8, q8 172 VCVT.F32.S32 q9, q9 173 VCVT.F32.S32 q10, q10 174 VCVT.F32.S32 q11, q11 175 VCVT.F32.S32 q12, q12 176 VCVT.F32.S32 q13, q13 177 VCVT.F32.S32 q14, q14 178 VCVT.F32.S32 q15, q15 179 180 VMUL.F32 q8, q8, q0 // multiplier 181 VMUL.F32 q9, q9, q1 182 VMUL.F32 q10, q10, q0 183 VMUL.F32 q11, q11, q1 184 VMUL.F32 q12, q12, q0 185 VMUL.F32 q13, q13, q1 186 VMUL.F32 q14, q14, q0 187 VMUL.F32 q15, q15, q1 188 189 VCVTN.S32.F32 q8, q8 190 VCVTN.S32.F32 q9, q9 191 VCVTN.S32.F32 q10, q10 192 VCVTN.S32.F32 q11, q11 193 VCVTN.S32.F32 q12, q12 194 VCVTN.S32.F32 q13, q13 195 VCVTN.S32.F32 q14, q14 196 VCVTN.S32.F32 q15, q15 197 VDUP.16 q0, d13[2] // output_zero_point 198 199 VQMOVN.S32 d16, q8 200 VQMOVN.S32 d17, q9 201 VQMOVN.S32 d18, q10 202 VQMOVN.S32 d19, q11 203 VQMOVN.S32 d20, q12 204 VQMOVN.S32 d21, q13 205 VQMOVN.S32 d22, q14 206 VQMOVN.S32 d23, q15 207 208 VQADD.S16 q8, q8, q0 209 VQADD.S16 q9, q9, q0 210 VQADD.S16 q10, q10, q0 211 VQADD.S16 q11, q11, q0 212 213 VDUP.8 q12, d13[6] // output_min 214 215 VQMOVN.S16 d0, q8 216 VQMOVN.S16 d1, q9 217 VQMOVN.S16 d2, q10 218 VQMOVN.S16 d3, q11 219 220 VDUP.8 q13, d13[7] // output_max 221 222 VMAX.S8 q0, q0, q12 223 VMAX.S8 q1, q1, q12 224 225 SUBS r1, r1, 8 // nc -= 8 226 227 VMIN.S8 q0, q0, q13 228 VMIN.S8 q1, q1, q13 229 230 # Store full 4 x 8 231 BLO 5f 232 VST1.8 {d3}, [r6], r7 233 VST1.8 {d2}, [r8], r7 234 VST1.8 {d1}, [r4], r7 235 VST1.8 {d0}, [r11], r7 236 SUB r2, r2, r14 // a -= ks 237 BHI 0b 238 239 VPOP {d8-d13} 240 ADD sp, sp, 12 // skip pad, r2, r3 241 POP {r4, r5, r6, r7, r8, r9, r10, r11, pc} 242 2434: 244 # Remainder- 4 bytes of A 245 VLD1.32 {d0[0]}, [r3]! // A0 246 VLD1.32 {q2}, [r9]! // B0 247 VLD1.32 {d1[0]}, [r12]! // A1 248 VLD1.32 {q3}, [r9]! // B1 249 VLD1.32 {d2[0]}, [r10]! // A2 250 VLD1.32 {d3[0]}, [r0]! // A3 251 252 VSDOT.S8 q8, q2, d0[0] 253 VSDOT.S8 q9, q3, d0[0] 254 VSDOT.S8 q10, q2, d1[0] 255 VSDOT.S8 q11, q3, d1[0] 256 VSDOT.S8 q12, q2, d2[0] 257 VSDOT.S8 q13, q3, d2[0] 258 VSDOT.S8 q14, q2, d3[0] 259 VSDOT.S8 q15, q3, d3[0] 260 B 3b 261 262 # Store odd width 263 .p2align 3 2645: 265 TST r1, 4 266 BEQ 6f 267 VST1.32 {d3[0]}, [r6]! 268 VST1.32 {d2[0]}, [r8]! 269 VST1.32 {d1[0]}, [r4]! 270 VST1.32 {d0[0]}, [r11]! 271 VEXT.8 q1, q1, q1, 4 272 VEXT.8 q0, q0, q0, 4 2736: 274 TST r1, 2 275 BEQ 7f 276 VST1.16 {d3[0]}, [r6]! 277 VST1.16 {d2[0]}, [r8]! 278 VST1.16 {d1[0]}, [r4]! 279 VST1.16 {d0[0]}, [r11]! 280 VEXT.8 q1, q1, q1, 2 281 VEXT.8 q0, q0, q0, 2 282 2837: 284 TST r1, 1 285 BEQ 8f 286 VST1.8 {d3[0]}, [r6] 287 VST1.8 {d2[0]}, [r8] 288 VST1.8 {d1[0]}, [r4] 289 VST1.8 {d0[0]}, [r11] 290 2918: 292 VPOP {d8-d13} 293 ADD sp, sp, 12 // skip pad, r2, r3 294 POP {r4, r5, r6, r7, r8, r9, r10, r11, pc} 295 296END_FUNCTION xnn_qc8_igemm_minmax_fp32_ukernel_4x8c4__aarch32_neondot_ld64 297#endif // __APPLE__ 298 299#ifdef __ELF__ 300.section ".note.GNU-stack","",%progbits 301#endif 302