1// Copyright 2022 Google LLC 2// 3// This source code is licensed under the BSD-style license found in the 4// LICENSE file in the root directory of this source tree. 5 6#include <xnnpack/assembly.h> 7 8.syntax unified 9 10// void xnn_qc8_dwconv_minmax_fp32_ukernel_up16x3__aarch32_neonv8_mla8_cortex_a35( 11// size_t channels, r0, r11 12// size_t output_width, r1 13// const int8_t** input, r2 14// const void* weights, r3 15// int8_t* output, r10, [sp, 88] 16// size_t input_stride, r6, [sp, 92] 17// size_t output_increment, r12, [sp, 96] 18// size_t input_offset, (r11),[sp, 100] 19// const int8_t* zero, r4, [sp, 104] 20// const union xnn_qs8_minmax_params params r5, [sp, 108] 21 22// d8-d15, r4-r11,r14(lr) need to be preserved if used. r13(sp),r15(pc) are reserved. 23 24// Register usage 25// A0 r5 q4 26// A1 r6 q5 27// A2 r8 q6 28 29// B r7/r3/lr q12 q13 q14 30 31// C0 r10 q12 q13 q14 q15 32 33// Prod q0 q1 q2 q3 34 35// params structure is 4 bytes 36// struct { 37// int16_t output_zero_point; d20[0] q10 38// int8_t output_min; d20[2] q9 39// int8_t output_max; d20[3] q11 40// } xnn_qs8_minmax_params.neonv8; 41 42// r7 temp B 43// r9 B post increment 80 or 16 44 45// unused q7 46 47BEGIN_FUNCTION xnn_qc8_dwconv_minmax_fp32_ukernel_up16x3__aarch32_neonv8_mla8_cortex_a35 48 // 88 bytes of stack 49 PUSH {r4, r5, r6, r7, r8, r9, r10, r11, lr} // 40 50 SUB sp, sp, 4 51 VPUSH {d8, d9, d10, d11, d12, d13} // 48 52 53 LDR r5, [sp, 108] // params 54 LDR r10, [sp, 88] // output 55 LDR r12, [sp, 96] // output_increment 56 LDR r4, [sp, 104] // zero 57 58 VLD1.32 {d20[]}, [r5] // QC8 params 59 VDUP.8 q9 , d20[2] // output_min 60 VDUP.8 q11, d20[3] // output_max 61 VDUP.16 q10, d20[0] // output_zero_point 62 63 .p2align 3 640: 65 LDR r11, [sp, 100] // input_offset 66 LDMIB r2, {r5, r6} // i0, i1 67 LDR r8, [r2] // i2 68 CMP r5, r4 // i0 == zero? 69 ADDNE r5, r5, r11 // i0 += input_offset 70 CMP r6, r4 // i1 == zero? 71 ADDNE r6, r6, r11 // i1 += input_offset 72 CMP r8, r4 // i2 == zero? 73 ADDNE r8, r8, r11 // i2 += input_offset 74 75 MOV lr, r3 76 MOV r9, 80 77 78 // Is there at least 16 channels for main loop? 79 SUBS r11, r0, 16 80 BLO 2f 81 82// Main loop - 16 channels 83// lr weights. r3 reset 84// r0/r11 loop counter. 85// r5 i0 86// r6 i1 87// r8 i2 88// q12 q13 q14 q15 accumulators 89 90 .p2align 3 911: 92 ADD r7, lr, 64 // skip over bias to get weights 93 VLD1.8 {q4}, [r8]! // i2 94 VLD1.8 {q12}, [r7]! // w0 95 VLD1.8 {q5}, [r5]! // i0 96 VLD1.8 {q13}, [r7]! // w1 97 VLD1.8 {q6}, [r6]! // i1 98 VLD1.8 {q14}, [r7] // w2 99 100 VMULL.S8 q1, d8, d24 // i2 * w0 101 VMULL.S8 q2, d9, d25 102 VMLAL.S8 q1, d10, d26 // i0 * w1 103 VMLAL.S8 q2, d11, d27 104 VMULL.S8 q0, d12, d28 // i1 * w2 105 VLD1.8 {q12, q13}, [lr]! // load bias 106 VMULL.S8 q3, d13, d29 107 VLD1.8 {q14, q15}, [lr], r9 108 109 VADDW.S16 q12, q12, d0 110 VADDW.S16 q13, q13, d1 111 VADDW.S16 q14, q14, d4 112 VADDW.S16 q15, q15, d5 113 VADDW.S16 q12, q12, d2 114 VADDW.S16 q13, q13, d3 115 VADDW.S16 q14, q14, d6 116 VLD1.32 {q0, q1}, [lr]! // quant per channel scale values 117 VADDW.S16 q15, q15, d7 118 VLD1.32 {q2, q3}, [lr]! 119 120 // QC8 FP32 quantization 121 122 VCVT.F32.S32 q12, q12 123 VCVT.F32.S32 q13, q13 124 VCVT.F32.S32 q14, q14 125 VCVT.F32.S32 q15, q15 126 127 VMUL.F32 q12, q0, q12 128 VMUL.F32 q13, q1, q13 129 VMUL.F32 q14, q2, q14 130 VMUL.F32 q15, q3, q15 131 132 VCVTN.S32.F32 q12, q12 133 VCVTN.S32.F32 q13, q13 134 VCVTN.S32.F32 q14, q14 135 VCVTN.S32.F32 q15, q15 136 137 VQMOVN.S32 d24, q12 138 VQMOVN.S32 d25, q13 139 VQMOVN.S32 d28, q14 140 VQMOVN.S32 d29, q15 141 142 VQADD.S16 q12, q12, q10 143 VQADD.S16 q14, q14, q10 144 VQMOVN.S16 d24, q12 145 VQMOVN.S16 d25, q14 146 VMIN.S8 q12, q12, q11 147 VMAX.S8 q12, q12, q9 148 SUBS r11, r11, 16 149 VST1.8 {q12}, [r10]! 150 BHS 1b 151 1522: 153 // Is there a remainder channels? 1-15 154 ANDS r11, r11, 15 155 BNE 4f 156 1573: 158 LDR r6, [sp, 92] // input_stride 159 SUBS r1, r1, 1 // output_width 160 ADD r10, r10, r12 // output += output_increment 161 ADD r2, r2, r6 // input += input_stride 162 BNE 0b 163 164 VPOP {d8, d9, d10, d11, d12, d13} 165 ADD sp, sp, 4 // pad 166 POP {r4, r5, r6, r7, r8, r9, r10, r11, pc} 167 168// Small Remainder - 1-8 channels 1694: 170 CMP r11, 9 // handle 9 or more 171 ADD r7, lr, 64 // skip over bias to get weights 172 BHS 5f 173 174 MOV r9, 16 175 176 VLD1.8 {d8}, [r8] // i2 177 VLD1.8 {d24}, [r7], r9 // w0 178 VLD1.8 {d10}, [r5] // i0 179 VLD1.8 {d26}, [r7], r9 // w1 180 VLD1.8 {d12}, [r6] // i1 181 VLD1.8 {d28}, [r7] // w2 182 183 VMULL.S8 q1, d8, d24 // i2 * w0 184 VMLAL.S8 q1, d10, d26 // i0 * w1 185 VMULL.S8 q0, d12, d28 // i1 * w2 186 VLD1.8 {q12, q13}, [lr] // load bias 187 ADD lr, lr, 112 188 189 VADDW.S16 q12, q12, d0 190 VADDW.S16 q13, q13, d1 191 VADDW.S16 q12, q12, d2 192 VADDW.S16 q13, q13, d3 193 VLD1.32 {q0, q1}, [lr] // quant per channel scale values 194 195 // QC8 FP32 quantization 196 197 VCVT.F32.S32 q12, q12 198 VCVT.F32.S32 q13, q13 199 200 VMUL.F32 q12, q0, q12 201 VMUL.F32 q13, q1, q13 202 203 VCVTN.S32.F32 q12, q12 204 VCVTN.S32.F32 q13, q13 205 206 VQMOVN.S32 d24, q12 207 VQMOVN.S32 d25, q13 208 209 VQADD.S16 q12, q12, q10 210 VQMOVN.S16 d24, q12 211 VMIN.S8 d24, d24, d22 212 VMAX.S8 d24, d24, d18 213 214 // Store 8 215 TST r11, 8 216 BEQ 6f 217 VST1.8 {d24}, [r10]! 218 B 3b 219 220 .p2align 3 221// Large Remainder - 9-15 channels 222// Process 16 same as main loop, but conditional store 223 2245: 225 VLD1.8 {q4}, [r8]! // i2 226 VLD1.8 {q12}, [r7]! // w0 227 VLD1.8 {q5}, [r5]! // i0 228 VLD1.8 {q13}, [r7]! // w1 229 VLD1.8 {q6}, [r6]! // i1 230 VLD1.8 {q14}, [r7] // w2 231 232 VMULL.S8 q1, d8, d24 // i2 * w0 233 VMULL.S8 q2, d9, d25 234 VMLAL.S8 q1, d10, d26 // i0 * w1 235 VMLAL.S8 q2, d11, d27 236 VMULL.S8 q0, d12, d28 // i1 * w2 237 VLD1.8 {q12, q13}, [lr]! // load bias 238 VMULL.S8 q3, d13, d29 239 VLD1.8 {q14, q15}, [lr], r9 240 241 VADDW.S16 q12, q12, d0 242 VADDW.S16 q13, q13, d1 243 VADDW.S16 q14, q14, d4 244 VADDW.S16 q15, q15, d5 245 VADDW.S16 q12, q12, d2 246 VADDW.S16 q13, q13, d3 247 VADDW.S16 q14, q14, d6 248 VLD1.32 {q0, q1}, [lr]! // quant per channel scale values 249 VADDW.S16 q15, q15, d7 250 VLD1.32 {q2, q3}, [lr] 251 252 // QC8 FP32 quantization 253 254 VCVT.F32.S32 q12, q12 255 VCVT.F32.S32 q13, q13 256 VCVT.F32.S32 q14, q14 257 VCVT.F32.S32 q15, q15 258 259 VMUL.F32 q12, q0, q12 260 VMUL.F32 q13, q1, q13 261 VMUL.F32 q14, q2, q14 262 VMUL.F32 q15, q3, q15 263 264 VCVTN.S32.F32 q12, q12 265 VCVTN.S32.F32 q13, q13 266 VCVTN.S32.F32 q14, q14 267 VCVTN.S32.F32 q15, q15 268 269 VQMOVN.S32 d24, q12 270 VQMOVN.S32 d25, q13 271 VQMOVN.S32 d28, q14 272 VQMOVN.S32 d29, q15 273 274 VQADD.S16 q12, q12, q10 275 VQADD.S16 q14, q14, q10 276 VQMOVN.S16 d24, q12 277 VQMOVN.S16 d25, q14 278 VMIN.S8 q12, q12, q11 279 VMAX.S8 q12, q12, q9 280 281 // Store 8 282 VST1.8 {d24}, [r10]! 283 VMOV d24, d25 284 285 // Store 4 2866: 287 TST r11, 4 288 BEQ 7f 289 VST1.32 {d24[0]}, [r10]! 290 VEXT.8 d24, d24, d24, 4 291 292 // Store 2 2937: 294 TST r11, 2 295 BEQ 8f 296 VST1.16 {d24[0]}, [r10]! 297 VEXT.8 d24, d24, d24, 2 298 299 // Store 1 3008: 301 TST r11, 1 302 BEQ 3b 303 VST1.8 {d24[0]}, [r10]! 304 B 3b 305 306 307END_FUNCTION xnn_qc8_dwconv_minmax_fp32_ukernel_up16x3__aarch32_neonv8_mla8_cortex_a35 308#ifdef __ELF__ 309.section ".note.GNU-stack","",%progbits 310#endif 311