1// Copyright 2019 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_f32_gemm_minmax_ukernel_4x8__aarch32_neon_${"pld_" if PREFETCH else ""}cortex_a75( 11// size_t mr, r0 12// size_t nc, r1 13// size_t kc, r2 -> r5 14// const uint8_t*restrict a, r3 15// size_t a_stride, sp + 96 -> (r7) 16// const void*restrict w, sp + 100 -> r9 17// uint8_t*restrict c, sp + 104 -> r11 18// size_t cm_stride, sp + 108 -> (r6) 19// size_t cn_stride, sp + 112 -> r7 20// const union xnn_f32_minmax_params params[restrict XNN_MIN_ELEMENTS(1)]) sp + 116 -> (r7) 21 22 23// inner loop registers 24 25// A0 r3 d0 26// A1 r12 d1 27// A2 r10 d2 28// A3 r0 d3 29 30// B r9 d8, d9, d10, d11 31// B d12, d13, d14, d15 32 33// C0 r11 d16-d17 q8 d18-d19 q9 34// C1 r4 d20-d21 q10 d22-d23 q11 35// C2 r8 d24-d25 q12 d26-d27 q13 36// C3 r6 d28-d29 q14 d30-d31 q15 37 38// Clamp (r5) d4 d5 d6 d7 39 40BEGIN_FUNCTION xnn_f32_gemm_minmax_ukernel_4x8__aarch32_neon_${"pld_" if PREFETCH else ""}cortex_a75 41 .arm 42#ifndef __APPLE__ 43 .arch armv7-a 44 .fpu neon 45#endif 46 // Push 96 bytes 47 PUSH {r4, r5, r6, r7, r8, r9, r10, r11} // 32 48 VPUSH {d8-d15} // +64 = 96 49 50 LDR r7, [sp, 96] // a_stride 51 LDR r6, [sp, 108] // cm_stride 52 LDR r11, [sp, 104] // c 53 LDR r9, [sp, 100] // w 54 55 // Clamp A and C pointers 56 CMP r0, 2 // if mr >= 2 57 ADD r12, r3, r7 // a1 = a0 + a_stride 58 ADD r4, r11, r6 // c1 = c0 + cm_stride 59 MOVLO r12, r3 // a1 60 MOVLO r4, r11 // c1 61 // if mr > 2 62 ADD r10, r12, r7 // a2 = a1 + a_stride 63 ADD r8, r4, r6 // c2 = c1 + cm_stride 64 MOVLS r10, r12 // a2 65 MOVLS r8, r4 // c2 66 67 CMP r0, 4 // if mr >=4 68 ADD r0, r10, r7 // a3 = a2 + a_stride 69 ADD r6, r8, r6 // c3 = c2 + cm_stride 70 MOVLO r0, r10 // a3 71 MOVLO r6, r8 // c3 72 73 LDR r7, [sp, 112] // cn_stride 74 75 .p2align 3 760: 77 # Load initial bias from w into accumulators 78 VLDM r9!, {d16-d19} // Bias 79 SUBS r5, r2, 16 80 VMOV q10, q8 81 VMOV q11, q9 82 VMOV q12, q8 83 VMOV q13, q9 84 VMOV q14, q8 85 VMOV q15, q9 86 87 $if PREFETCH: 88 PLD [r3, 0] // Prefetch A 89 PLD [r3, 64] 90 PLD [r12, 0] 91 PLD [r12, 64] 92 PLD [r10, 0] 93 PLD [r10, 64] 94 PLD [r0, 0] 95 PLD [r0, 64] 96 PLD [r9, 0] // Prefetch B 97 PLD [r9, 64] 98 PLD [r9, 128] 99 PLD [r9, 192] 100 PLD [r9, 256] 101 PLD [r9, 320] 102 PLD [r9, 384] 103 104 BLO 4f // less than 4 channels? 105 106 // Prologue 107 VLD1.32 {d0}, [r3]! // A0 108 VLDM r9!, {d8-d11} // B0 109 VLD1.32 {d1}, [r12]! // A1 110 VLD1.32 {d2}, [r10]! // A2 111 VLD1.32 {d3}, [ r0]! // A3 112 113 SUBS r5, r5, 16 114 BLO 2f // less than 4 channels? skip main loop 115 116 .p2align 3 117 118 // Main loop - 4 floats of A (16 bytes) 1191: 120 VMLA.F32 q8, q4, d0[0] 121 VLDM r9!, {d12-d15} // B1 122 VMLA.F32 q10, q4, d1[0] 123 VMLA.F32 q12, q4, d2[0] 124 VLD1.32 {d4}, [r3]! // A0 125 VMLA.F32 q14, q4, d3[0] 126 VMLA.F32 q9, q5, d0[0] 127 VLD1.32 {d5}, [r12]! // A1 128 VMLA.F32 q11, q5, d1[0] 129 VMLA.F32 q13, q5, d2[0] 130 VMLA.F32 q15, q5, d3[0] 131 VLD1.32 {d6}, [r10]! // A2 132 VMLA.F32 q8, q6, d0[1] 133 VMLA.F32 q10, q6, d1[1] 134 VLD1.32 {d7}, [ r0]! // A3 135 VMLA.F32 q12, q6, d2[1] 136 VMLA.F32 q14, q6, d3[1] 137 VLDM r9!, {d8-d11} // B0 138 VMLA.F32 q9, q7, d0[1] 139 VMLA.F32 q11, q7, d1[1] 140 VMLA.F32 q13, q7, d2[1] 141 VMLA.F32 q15, q7, d3[1] 142 143 VMLA.F32 q8, q4, d4[0] 144 VLDM r9!, {d12-d15} // B1 145 VMLA.F32 q10, q4, d5[0] 146 $if PREFETCH: 147 PLD [r3, 128] // Prefetch A0 148 VMLA.F32 q12, q4, d6[0] 149 VLD1.32 {d0}, [r3]! // A0 150 VMLA.F32 q14, q4, d7[0] 151 $if PREFETCH: 152 PLD [r12, 128] // Prefetch A1 153 VMLA.F32 q9, q5, d4[0] 154 VLD1.32 {d1}, [r12]! // A1 155 VMLA.F32 q11, q5, d5[0] 156 $if PREFETCH: 157 PLD [r10, 128] // Prefetch A2 158 VMLA.F32 q13, q5, d6[0] 159 VLD1.32 {d2}, [r10]! // A2 160 VMLA.F32 q15, q5, d7[0] 161 $if PREFETCH: 162 PLD [r0, 128] // Prefetch A3 163 VMLA.F32 q8, q6, d4[1] 164 VLD1.32 {d3}, [ r0]! // A3 165 VMLA.F32 q10, q6, d5[1] 166 $if PREFETCH: 167 PLD [r9, 352] // Prefetch B 168 VMLA.F32 q12, q6, d6[1] 169 $if PREFETCH: 170 PLD [r9, 416] // Prefetch B 171 VMLA.F32 q14, q6, d7[1] 172 VLDM r9!, {d8-d11} // B0 173 VMLA.F32 q9, q7, d4[1] 174 VMLA.F32 q11, q7, d5[1] 175 SUBS r5, r5, 16 176 VMLA.F32 q13, q7, d6[1] 177 VMLA.F32 q15, q7, d7[1] 178 BHS 1b 179 180 // Epilogue 1812: 182 VMLA.F32 q8, q4, d0[0] 183 VLDM r9!, {d12-d15} // B1 184 VMLA.F32 q10, q4, d1[0] 185 VMLA.F32 q12, q4, d2[0] 186 VLD1.32 {d4}, [r3]! // A0 187 VMLA.F32 q14, q4, d3[0] 188 VMLA.F32 q9, q5, d0[0] 189 VLD1.32 {d5}, [r12]! // A1 190 VMLA.F32 q11, q5, d1[0] 191 VMLA.F32 q13, q5, d2[0] 192 VMLA.F32 q15, q5, d3[0] 193 VLD1.32 {d6}, [r10]! // A2 194 VMLA.F32 q8, q6, d0[1] 195 VMLA.F32 q10, q6, d1[1] 196 VLD1.32 {d7}, [ r0]! // A3 197 VMLA.F32 q12, q6, d2[1] 198 VMLA.F32 q14, q6, d3[1] 199 VLDM r9!, {d8-d11} // B0 200 VMLA.F32 q9, q7, d0[1] 201 VMLA.F32 q11, q7, d1[1] 202 VMLA.F32 q13, q7, d2[1] 203 VMLA.F32 q15, q7, d3[1] 204 205 VMLA.F32 q8, q4, d4[0] 206 VLDM r9!, {d12-d15} // B1 207 VMLA.F32 q10, q4, d5[0] 208 VMLA.F32 q12, q4, d6[0] 209 VMLA.F32 q14, q4, d7[0] 210 VMLA.F32 q9, q5, d4[0] 211 VMLA.F32 q11, q5, d5[0] 212 VMLA.F32 q13, q5, d6[0] 213 VMLA.F32 q15, q5, d7[0] 214 VMLA.F32 q8, q6, d4[1] 215 VMLA.F32 q10, q6, d5[1] 216 VMLA.F32 q12, q6, d6[1] 217 VMLA.F32 q14, q6, d7[1] 218 VMLA.F32 q9, q7, d4[1] 219 VMLA.F32 q11, q7, d5[1] 220 TST r5, 15 221 VMLA.F32 q13, q7, d6[1] 222 VMLA.F32 q15, q7, d7[1] 223 224 // Is there a remainder?- 1 to 3 floats of A (4, 8 or 12 bytes) 225 BNE 4f 226 227 .p2align 3 2283: 229 // Load params pointer 230 LDR r5, [sp, 116] // params 231 232 // Load min/max values 233 VLD1.32 {d4[],d5[]}, [r5]! 234 SUBS r1, r1, 8 235 VLD1.32 {d6[],d7[]}, [r5] 236 237 // Clamp 238 VMAX.F32 q8, q8, q2 239 VMAX.F32 q9, q9, q2 240 VMAX.F32 q10, q10, q2 241 VMAX.F32 q11, q11, q2 242 VMAX.F32 q12, q12, q2 243 VMAX.F32 q13, q13, q2 244 VMAX.F32 q14, q14, q2 245 VMAX.F32 q15, q15, q2 246 VMIN.F32 q8, q8, q3 247 VMIN.F32 q9, q9, q3 248 VMIN.F32 q10, q10, q3 249 VMIN.F32 q11, q11, q3 250 VMIN.F32 q12, q12, q3 251 VMIN.F32 q13, q13, q3 252 VMIN.F32 q14, q14, q3 253 VMIN.F32 q15, q15, q3 254 255 // Store full 4 x 8 256 BLO 6f 257 VST1.32 {d16-d19}, [r11], r7 258 SUB r0, r0, r2 259 VST1.32 {d20-d23}, [r4], r7 260 SUB r10, r10, r2 261 VST1.32 {d24-d27}, [r8], r7 262 SUB r12, r12, r2 263 VST1.32 {d28-d31}, [r6], r7 264 SUB r3, r3, r2 265 BHI 0b 266 267 VPOP {d8-d15} 268 POP {r4, r5, r6, r7, r8, r9, r10, r11} 269 BX lr 270 271 .p2align 3 2724: 273 // Is there a remainder?- 2 floats of A (8 bytes) 274 TST r5, 8 275 BEQ 5f 276 277 // Remainder - 2 floats of A (8 bytes) 278 VLD1.32 {d0}, [r3]! // A0 279 VLDM r9!, {d8-d11} // B0 280 VLD1.32 {d1}, [r12]! // A1 281 VLD1.32 {d2}, [r10]! // A2 282 VLD1.32 {d3}, [ r0]! // A3 283 284 VMLA.F32 q8, q4, d0[0] 285 VMLA.F32 q9, q5, d0[0] 286 VMLA.F32 q10, q4, d1[0] 287 VMLA.F32 q11, q5, d1[0] 288 VLDM r9!, {d12-d15} // B1 289 VMLA.F32 q12, q4, d2[0] 290 VMLA.F32 q13, q5, d2[0] 291 VMLA.F32 q14, q4, d3[0] 292 VMLA.F32 q15, q5, d3[0] 293 VMLA.F32 q8, q6, d0[1] 294 VMLA.F32 q9, q7, d0[1] 295 VMLA.F32 q10, q6, d1[1] 296 VMLA.F32 q11, q7, d1[1] 297 VMLA.F32 q12, q6, d2[1] 298 VMLA.F32 q13, q7, d2[1] 299 VMLA.F32 q14, q6, d3[1] 300 VMLA.F32 q15, q7, d3[1] 301 302 // Is there a remainder?- 1 floats of A (4 bytes) 303 TST r5, 4 304 BEQ 3b 305 3065: 307 // Remainder- 1 floats of A (4 bytes) 308 VLDM r3!, {s0} // A0 309 VLDM r9!, {d8-d11} // B0 310 VLDM r12!, {s2} // A1 311 VLDM r10!, {s4} // A2 312 VLDM r0!, {s6} // A3 313 VMLA.F32 q8, q4, d0[0] 314 VMLA.F32 q9, q5, d0[0] 315 VMLA.F32 q10, q4, d1[0] 316 VMLA.F32 q11, q5, d1[0] 317 VMLA.F32 q12, q4, d2[0] 318 VMLA.F32 q13, q5, d2[0] 319 VMLA.F32 q14, q4, d3[0] 320 VMLA.F32 q15, q5, d3[0] 321 B 3b 322 323 // Store odd width 3246: 325 TST r1, 4 326 BEQ 7f 327 VST1.32 {d16-d17}, [r11]! 328 VMOV q8, q9 329 VST1.32 {d20-d21}, [r4]! 330 VMOV q10, q11 331 VST1.32 {d24-d25}, [r8]! 332 VMOV q12, q13 333 VST1.32 {d28-d29}, [r6]! 334 VMOV q14, q15 335 3367: 337 TST r1, 2 338 BEQ 8f 339 VST1.32 {d16}, [r11]! 340 VMOV d16, d17 341 VST1.32 {d20}, [r4]! 342 VMOV d20, d21 343 VST1.32 {d24}, [r8]! 344 VMOV d24, d25 345 VST1.32 {d28}, [r6]! 346 VMOV d28, d29 347 3488: 349 TST r1, 1 350 BEQ 9f 351 VST1.32 {d16[0]}, [r11] 352 VST1.32 {d20[0]}, [r4] 353 VST1.32 {d24[0]}, [r8] 354 VST1.32 {d28[0]}, [r6] 355 3569: 357 VPOP {d8-d15} 358 POP {r4, r5, r6, r7, r8, r9, r10, r11} 359 BX lr 360 361END_FUNCTION xnn_f32_gemm_minmax_ukernel_4x8__aarch32_neon_${"pld_" if PREFETCH else ""}cortex_a75 362 363#ifdef __ELF__ 364.section ".note.GNU-stack","",%progbits 365#endif 366 367