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