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_qs8_igemm_minmax_rndnu_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_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_ld64 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 101 LDR r3, [r2, 0] 102 LDR r12, [r2, 4] 103 LDR r10, [r2, 8] 104 LDR r0, [r2, 12] 105 ADD r2, r2, 16 106 107 # Add a_offset 108 LDR r5, [sp, 116] // a_offset 109 CMP r3, r7 // if a0 == zero 110 ADD r3, r3, r5 // a0 += a_offset 111 MOVEQ r3, r7 // a0 = zero, else += a0 + a_offset 112 CMP r12, r7 // if a1 == zero 113 ADD r12, r12, r5 // a1 += a_offset 114 MOVEQ r12, r7 // a1 = zero, else += a1 + a_offset 115 CMP r10, r7 // if a2 == zero 116 ADD r10, r10, r5 // a2 += a_offset 117 MOVEQ r10, r7 // a2 = zero, else += a2 + a_offset 118 CMP r0, r7 // if a3 == zero 119 ADD r0, r0, r5 // a3 += a_offset 120 LDR r5, [sp, 52] // kc 121 MOVEQ r0, r7 // a3 = zero, else += a3 + a_offset 122 123 SUBS r5, r5, 8 // kc - 8 124 BLO 4f // less than 8 channels? 125 126 # Main loop - 8 bytes of A. 127 # 16 SDOT, 4 LD64 A, 4 LD128 B 128 .p2align 3 1292: 130 VLD1.8 {d0}, [r3]! // A0 131 VLD1.8 {q2}, [r9]! // B0 132 VLD1.8 {d1}, [r12]! // A1 133 VLD1.8 {q3}, [r9]! // B1 134 VLD1.8 {d2}, [r10]! // A2 135 VLD1.8 {q4}, [r9]! // B2 136 VLD1.8 {d3}, [r0]! // A3 137 VLD1.8 {q5}, [r9]! // B3 138 SUBS r5, r5, 8 139 140 VSDOT.S8 q8, q2, d0[0] 141 VSDOT.S8 q9, q3, d0[0] 142 VSDOT.S8 q10, q2, d1[0] 143 VSDOT.S8 q11, q3, d1[0] 144 VSDOT.S8 q12, q2, d2[0] 145 VSDOT.S8 q13, q3, d2[0] 146 VSDOT.S8 q14, q2, d3[0] 147 VSDOT.S8 q15, q3, d3[0] 148 149 VSDOT.S8 q8, q4, d0[1] 150 VSDOT.S8 q9, q5, d0[1] 151 VSDOT.S8 q10, q4, d1[1] 152 VSDOT.S8 q11, q5, d1[1] 153 VSDOT.S8 q12, q4, d2[1] 154 VSDOT.S8 q13, q5, d2[1] 155 VSDOT.S8 q14, q4, d3[1] 156 VSDOT.S8 q15, q5, d3[1] 157 BHS 2b 158 159 # Is there a remainder?- 4 bytes of A 160 TST r5, 4 161 BNE 4f 162 1633: 164 # ks loop 165 SUBS r14, r14, 16 // ks -= MR * sizeof(void*) 166 BHI 1b 167 168 LDR r7, [sp, 112] // cn_stride 169 LDR r14, [sp, 56] // p = ks 170 171 # RNDNU quantization 172 VDUP.32 q0, d12[0] // right_pre_shift 173 174 VQSHL.S32 q8, q8, q0 175 VQSHL.S32 q9, q9, q0 176 VQSHL.S32 q10, q10, q0 177 VQSHL.S32 q11, q11, q0 178 VQSHL.S32 q12, q12, q0 179 VQSHL.S32 q13, q13, q0 180 VQSHL.S32 q14, q14, q0 181 VQSHL.S32 q15, q15, q0 182 183 VDUP.32 q2, d13[0] // right_post_shift 184 185 VQDMULH.S32 q8, q8, d12[1] // multiplier 186 VQDMULH.S32 q9, q9, d12[1] 187 VQDMULH.S32 q10, q10, d12[1] 188 VQDMULH.S32 q11, q11, d12[1] 189 VQDMULH.S32 q12, q12, d12[1] 190 VQDMULH.S32 q13, q13, d12[1] 191 VQDMULH.S32 q14, q14, d12[1] 192 VQDMULH.S32 q15, q15, d12[1] 193 194 VRSHL.S32 q8, q8, q2 195 VRSHL.S32 q9, q9, q2 196 VRSHL.S32 q10, q10, q2 197 VRSHL.S32 q11, q11, q2 198 VRSHL.S32 q12, q12, q2 199 VRSHL.S32 q13, q13, q2 200 VRSHL.S32 q14, q14, q2 201 VRSHL.S32 q15, q15, q2 202 VDUP.16 q0, d13[2] // output_zero_point 203 204 VQMOVN.S32 d16, q8 205 VQMOVN.S32 d17, q9 206 VQMOVN.S32 d18, q10 207 VQMOVN.S32 d19, q11 208 VQMOVN.S32 d20, q12 209 VQMOVN.S32 d21, q13 210 VQMOVN.S32 d22, q14 211 VQMOVN.S32 d23, q15 212 213 VQADD.S16 q8, q8, q0 214 VQADD.S16 q9, q9, q0 215 VQADD.S16 q10, q10, q0 216 VQADD.S16 q11, q11, q0 217 218 VDUP.8 q12, d13[6] // output_min 219 220 VQMOVN.S16 d0, q8 221 VQMOVN.S16 d1, q9 222 VQMOVN.S16 d2, q10 223 VQMOVN.S16 d3, q11 224 225 VDUP.8 q13, d13[7] // output_max 226 227 VMAX.S8 q0, q0, q12 228 VMAX.S8 q1, q1, q12 229 230 SUBS r1, r1, 8 // nc -= 8 231 232 VMIN.S8 q0, q0, q13 233 VMIN.S8 q1, q1, q13 234 235 # Store full 4 x 8 236 BLO 5f 237 VST1.8 {d3}, [r6], r7 238 VST1.8 {d2}, [r8], r7 239 VST1.8 {d1}, [r4], r7 240 VST1.8 {d0}, [r11], r7 241 SUB r2, r2, r14 // a -= ks 242 BHI 0b 243 244 VPOP {d8-d13} 245 ADD sp, sp, 12 // skip pad, r2, r3 246 POP {r4, r5, r6, r7, r8, r9, r10, r11, pc} 247 2484: 249 # Remainder- 4 bytes of A 250 VLD1.32 {d0[0]}, [r3]! // A0 251 VLD1.32 {q2}, [r9]! // B0 252 VLD1.32 {d1[0]}, [r12]! // A1 253 VLD1.32 {q3}, [r9]! // B1 254 VLD1.32 {d2[0]}, [r10]! // A2 255 VLD1.32 {d3[0]}, [r0]! // A3 256 257 VSDOT.S8 q8, q2, d0[0] 258 VSDOT.S8 q9, q3, d0[0] 259 VSDOT.S8 q10, q2, d1[0] 260 VSDOT.S8 q11, q3, d1[0] 261 VSDOT.S8 q12, q2, d2[0] 262 VSDOT.S8 q13, q3, d2[0] 263 VSDOT.S8 q14, q2, d3[0] 264 VSDOT.S8 q15, q3, d3[0] 265 B 3b 266 267 # Store odd width 268 .p2align 3 2695: 270 TST r1, 4 271 BEQ 6f 272 VST1.32 {d3[0]}, [r6]! 273 VST1.32 {d2[0]}, [r8]! 274 VST1.32 {d1[0]}, [r4]! 275 VST1.32 {d0[0]}, [r11]! 276 VEXT.8 q1, q1, q1, 4 277 VEXT.8 q0, q0, q0, 4 2786: 279 TST r1, 2 280 BEQ 7f 281 VST1.16 {d3[0]}, [r6]! 282 VST1.16 {d2[0]}, [r8]! 283 VST1.16 {d1[0]}, [r4]! 284 VST1.16 {d0[0]}, [r11]! 285 VEXT.8 q1, q1, q1, 2 286 VEXT.8 q0, q0, q0, 2 287 2887: 289 TST r1, 1 290 BEQ 8f 291 VST1.8 {d3[0]}, [r6] 292 VST1.8 {d2[0]}, [r8] 293 VST1.8 {d1[0]}, [r4] 294 VST1.8 {d0[0]}, [r11] 295 2968: 297 VPOP {d8-d13} 298 ADD sp, sp, 12 // skip pad, r2, r3 299 POP {r4, r5, r6, r7, r8, r9, r10, r11, pc} 300 301END_FUNCTION xnn_qs8_igemm_minmax_rndnu_ukernel_4x8c4__aarch32_neondot_ld64 302#endif // __APPLE__ 303 304#ifdef __ELF__ 305.section ".note.GNU-stack","",%progbits 306#endif 307