1// Auto-generated file. Do not edit! 2// Template: src/f32-gemm/4x8-aarch32-neon-cortex-a53.S.in 3// Generator: tools/xngen 4// 5// Copyright 2019 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#include <xnnpack/assembly.h> 11 12.syntax unified 13 14// void xnn_f32_gemm_minmax_ukernel_4x8__aarch32_neon_cortex_a53( 15// size_t mr, r0 16// size_t nc, r1 17// size_t kc, r2 -> r5 -> sp + 0 18// const uint8_t*restrict a, r3 19// size_t a_stride, sp + 100 -> (r7) 20// const void*restrict w, sp + 104 -> r9 21// uint8_t*restrict c, sp + 108 -> r11 22// size_t cm_stride, sp + 112 -> (r6) 23// size_t cn_stride, sp + 116 -> (r0) 24// const union xnn_f32_minmax_params params) sp + 120 -> (r5) 25 26// d8-d15, r4-r11,r14(lr) need to be preserved if used. r13(sp),r15(pc) are reserved. 27 28// Register usage 29 30// r0, r2 scratch temporaries for loads 31// r14 (lr) unused 32 33// A0 r3 d0 34// A1 r12 d1 35// A2 r10 d2 36// A3 r7 d3 37 38// B r9 d8, d9, d10, d11 39// B d12, d13, d14, d15 40 41// C0 r11 d16-d17 q8 d18-d19 q9 42// C1 r4 d20-d21 q10 d22-d23 q11 43// C2 r8 d24-d25 q12 d26-d27 q13 44// C3 r6 d28-d29 q14 d30-d31 q15 45 46// Clamp (r5) d4 d5 d6 d7 47 48BEGIN_FUNCTION xnn_f32_gemm_minmax_ukernel_4x8__aarch32_neon_cortex_a53 49 .arm 50#ifndef __APPLE__ 51 .arch armv7-a 52 .fpu neon 53#endif 54 # Push 100 bytes 55 # r2 will be reloaded in outer loop 56 VPUSH {d8-d15} // 64 57 PUSH {r2, r4, r5, r6, r7, r8, r9, r10, r11} // +36 = 100 58 59 LDR r7, [sp, 100] // a_stride 60 LDR r11, [sp, 108] // c 61 LDR r6, [sp, 112] // cm_stride 62 LDR r9, [sp, 104] // w 63 64 # Clamp A and C pointers 65 CMP r0, 2 // if mr >= 2 66 ADD r12, r3, r7 // a1 = a0 + a_stride 67 ADD r4, r11, r6 // c1 = c0 + cm_stride 68 MOVLO r12, r3 // a1 69 MOVLO r4, r11 // c1 70 // if mr > 2 71 ADD r10, r12, r7 // a2 = a1 + a_stride 72 ADD r8, r4, r6 // c2 = c1 + cm_stride 73 MOVLS r10, r12 // a2 74 MOVLS r8, r4 // c2 75 76 CMP r0, 4 // if mr >=4 77 ADD r7, r10, r7 // a3 = a2 + a_stride 78 ADD r6, r8, r6 // c3 = c2 + cm_stride 79 MOVLO r7, r10 // a3 80 MOVLO r6, r8 // c3 81 82 .p2align 3 830: 84 # Load initial bias from w into accumulators 85 VLDM r9!, {d16-d19} // Bias 86 87 SUBS r5, r2, 16 // kc - 16 88 VMOV q10, q8 89 VMOV q11, q9 90 VMOV q12, q8 91 VMOV q13, q9 92 VMOV q14, q8 93 VMOV q15, q9 94 BLO 4f // less than 4 channels? 95 96 # Prologue 97 VLD1.32 {d0}, [r3]! // A0 98 VLD1.32 {d1}, [r12]! // A1 99 VLD1.32 {d2}, [r10]! // A2 100 VLD1.32 {d3}, [r7]! // A3 101 SUBS r5, r5, 16 102 VLDM r9, {d8-d11} // B0 103 LDR r0, [r9, 56] // B1 low VMOV is in BLOCK 0 104 LDR r2, [r9, 60] // B1 high 105 VLDR d13, [r9, 40] // B1 106 107 BLO 2f // less than 4 channels? skip main loop 108 109 # Main loop - 4 floats of A (16 bytes) 110 # 32 FMA + 8 LD64 A + 8 LDR B 111 .p2align 3 1121: 113 # First group of 16 FMA, Second group loads 114 # BLOCK 0 115 VLD1.32 {d4}, [r3]! // A0 116 VMOV d15, r0, r2 // b1 VMOV b from second group 117 VMLA.F32 q8, q4, d0[0] 118 LDR r0, [r12] // A1 low 119 VMLA.F32 q10, q4, d1[0] 120 LDR r2, [r12, 4] // A1 high 121 VMLA.F32 q12, q4, d2[0] 122 123 # BLOCK 1 124 VLDR d12, [r9, 32] // B1 125 VMOV d5, r0, r2 // a1 VMOV 126 VMLA.F32 q14, q4, d3[0] 127 LDR r0, [r9, 72] // B0 low 128 VMLA.F32 q9, q5, d0[0] 129 LDR r2, [r9, 76] // B0 high 130 VMLA.F32 q11, q5, d1[0] 131 132 # BLOCK 2 133 VLD1.32 {d6}, [r10]! // A2 134 VMOV d9, r0, r2 // b0 VMOV 135 VMLA.F32 q13, q5, d2[0] 136 LDR r0, [r7] // A3 low 137 VMLA.F32 q15, q5, d3[0] 138 LDR r2, [r7, 4] // A3 high 139 VMLA.F32 q8, q6, d0[1] 140 141 # BLOCK 3 142 VLDR d14, [r9, 48] // B1 143 VMOV d7, r0, r2 // a3 VMOV 144 VMLA.F32 q10, q6, d1[1] 145 LDR r0, [r9, 88] // B0 low 146 VMLA.F32 q12, q6, d2[1] 147 LDR r2, [r9, 92] // B0 high 148 VMLA.F32 q14, q6, d3[1] 149 150 # BLOCK 4 151 VLDR d8, [r9, 64] // B0 152 VMOV d11, r0, r2 // B0 VMOV 153 VMLA.F32 q9, q7, d0[1] 154 LDR r0, [r9, 104] // B1 low VMOV is in BLOCK 0 155 VMLA.F32 q11, q7, d1[1] 156 LDR r2, [r9, 108] // B1 high 157 VMLA.F32 q13, q7, d2[1] 158 159 # BLOCK 5 160 VLDR d10, [r9, 80] // B0 161 VMOV d13, r0, r2 // b1 VMOV b from second group 162 VMLA.F32 q15, q7, d3[1] 163 LDR r0, [r9, 120] // B1 low VMOV is in BLOCK 0 164 NOP 165 LDR r2, [r9, 124] // B1 high 166 NOP 167 168 # Second group of 16 FMA, First group of loads 169 # BLOCK 0 170 VLD1.32 {d0}, [r3]! // A0 171 VMOV d15, r0, r2 // b1 VMOV b from second group 172 VMLA.F32 q8, q4, d4[0] 173 LDR r0, [r12, 8] // A1 low 174 VMLA.F32 q10, q4, d5[0] 175 LDR r2, [r12, 12] // A1 high 176 VMLA.F32 q12, q4, d6[0] 177 # NOP 178 179 # BLOCK 1 180 VLDR d12, [r9, 96] // B1 181 VMOV d1, r0, r2 // a1 VMOV 182 VMLA.F32 q14, q4, d7[0] 183 LDR r0, [r9, 136] // B0 low 184 VMLA.F32 q9, q5, d4[0] 185 LDR r2, [r9, 140] // B0 high 186 VMLA.F32 q11, q5, d5[0] 187 # NOP 188 189 # BLOCK 2 190 VLD1.32 {d2}, [r10]! // A2 191 VMOV d9, r0, r2 // b0 VMOV 192 VMLA.F32 q13, q5, d6[0] 193 LDR r0, [r7, 8] // A3 low 194 VMLA.F32 q15, q5, d7[0] 195 LDR r2, [r7, 12] // A3 high 196 VMLA.F32 q8, q6, d4[1] 197 # NOP 198 199 # BLOCK 3 200 VLDR d14, [r9, 112] // B1 201 VMOV d3, r0, r2 // a3 VMOV 202 VMLA.F32 q10, q6, d5[1] 203 LDR r0, [r9, 152] // B0 low 204 VMLA.F32 q12, q6, d6[1] 205 LDR r2, [r9, 156] // B0 high 206 VMLA.F32 q14, q6, d7[1] 207 ADD r12, r12, 16 // A1++ 208 209 # BLOCK 4 210 VLDR d8, [r9, 128] // B0 211 VMOV d11, r0, r2 // B0 VMOV 212 VMLA.F32 q9, q7, d4[1] 213 LDR r0, [r9, 168] // B1 low 214 VMLA.F32 q11, q7, d5[1] 215 LDR r2, [r9, 172] // B1 high 216 VMLA.F32 q13, q7, d6[1] 217 ADD r7, r7, 16 // A3++ 218 219 # BLOCK 5 220 VLDR d10, [r9, 144] // B0 221 VMOV d13, r0, r2 // b1 VMOV b 222 VMLA.F32 q15, q7, d7[1] 223 LDR r0, [r9, 184] // B1 low VMOV is in BLOCK 0 224 SUBS r5, r5, 16 225 LDR r2, [r9, 188] // B1 high 226 ADD r9, r9, 128 // B++ 227 BHS 1b 228 229 # Epilogue - 4 floats of A (16 bytes) 2302: 231 # First group of 16 FMA, Second group loads 232 # BLOCK 0 233 VLD1.32 {d4}, [r3]! // A0 234 VMOV d15, r0, r2 // b1 VMOV b from second group 235 VMLA.F32 q8, q4, d0[0] 236 LDR r0, [r12] // A1 low 237 VMLA.F32 q10, q4, d1[0] 238 LDR r2, [r12, 4] // A1 high 239 VMLA.F32 q12, q4, d2[0] 240 # NOP 241 242 # BLOCK 1 243 VLDR d12, [r9, 32] // B1 244 VMOV d5, r0, r2 // a1 VMOV 245 VMLA.F32 q14, q4, d3[0] 246 LDR r0, [r9, 72] // B0 low 247 VMLA.F32 q9, q5, d0[0] 248 LDR r2, [r9, 76] // B0 high 249 VMLA.F32 q11, q5, d1[0] 250 # NOP 251 252 # BLOCK 2 253 VLD1.32 {d6}, [r10]! // A2 254 VMOV d9, r0, r2 // b0 VMOV 255 VMLA.F32 q13, q5, d2[0] 256 LDR r0, [r7] // A3 low 257 VMLA.F32 q15, q5, d3[0] 258 LDR r2, [r7, 4] // A3 high 259 VMLA.F32 q8, q6, d0[1] 260 # NOP 261 262 # BLOCK 3 263 VLDR d14, [r9, 48] // B1 264 VMOV d7, r0, r2 // a3 VMOV 265 VMLA.F32 q10, q6, d1[1] 266 LDR r0, [r9, 88] // B0 low 267 VMLA.F32 q12, q6, d2[1] 268 LDR r2, [r9, 92] // B0 high 269 VMLA.F32 q14, q6, d3[1] 270 # NOP 271 272 # BLOCK 4 273 VLDR d8, [r9, 64] // B0 274 VMOV d11, r0, r2 // B0 VMOV 275 VMLA.F32 q9, q7, d0[1] 276 LDR r0, [r9, 104] // B1 low 277 VMLA.F32 q11, q7, d1[1] 278 LDR r2, [r9, 108] // B1 high 279 VMLA.F32 q13, q7, d2[1] 280 # NOP 281 282 # BLOCK 5 283 VLDR d10, [r9, 80] // B0 284 VMOV d13, r0, r2 // b1 VMOV b 285 VMLA.F32 q15, q7, d3[1] 286 LDR r0, [r9, 120] // B1 low VMOV is in BLOCK 0 287 NOP 288 LDR r2, [r9, 124] // B1 high 289 NOP 290 NOP 291 292 # Second group of 16 FMA, First group of loads 293 # BLOCK 0 294 VLDR d12, [r9, 96] // B1 295 VMOV d15, r0, r2 // b1 VMOV b from second group 296 VMLA.F32 q8, q4, d4[0] 297 VMLA.F32 q10, q4, d5[0] 298 VMLA.F32 q12, q4, d6[0] 299 300 # BLOCK 1 301 VLDR d14, [r9, 112] // B1 302 VMLA.F32 q14, q4, d7[0] 303 VMLA.F32 q9, q5, d4[0] 304 VMLA.F32 q11, q5, d5[0] 305 ADD r12, r12, 8 // A1++ 306 307 # BLOCK 2 308 ADD r7, r7, 8 // A3++ VLDR B1 lands here 309 ADD r9, r9, 128 // B++ 310 VMLA.F32 q13, q5, d6[0] 311 VMLA.F32 q15, q5, d7[0] 312 VMLA.F32 q8, q6, d4[1] 313 314 # BLOCK 3 315 VMLA.F32 q10, q6, d5[1] 316 VMLA.F32 q12, q6, d6[1] 317 VMLA.F32 q14, q6, d7[1] 318 TST r5, 15 319 320 # BLOCK 4 321 VMLA.F32 q9, q7, d4[1] 322 VMLA.F32 q11, q7, d5[1] 323 VMLA.F32 q13, q7, d6[1] 324 325 # BLOCK 5 326 VMLA.F32 q15, q7, d7[1] 327 328 # Is there a remainder?- 1 to 3 floats of A (4, 8 or 12 bytes) 329 BNE 4f 330 331 .p2align 3 3323: 333 # Load params pointer 334 LDR r0, [sp, 116] // cn_stride 335 LDR r5, [sp, 120] // params 336 LDR r2, [sp] // kc 337 SUBS r1, r1, 8 338 339 # Load min/max values 340 VLD1.32 {d4[],d5[]}, [r5]! 341 VLD1.32 {d6[],d7[]}, [r5] 342 343 # Clamp 344 VMAX.F32 q8, q8, q2 345 VMAX.F32 q9, q9, q2 346 VMAX.F32 q10, q10, q2 347 VMAX.F32 q11, q11, q2 348 VMAX.F32 q12, q12, q2 349 VMAX.F32 q13, q13, q2 350 VMAX.F32 q14, q14, q2 351 VMAX.F32 q15, q15, q2 352 VMIN.F32 q8, q8, q3 353 VMIN.F32 q9, q9, q3 354 VMIN.F32 q10, q10, q3 355 VMIN.F32 q11, q11, q3 356 VMIN.F32 q12, q12, q3 357 VMIN.F32 q13, q13, q3 358 VMIN.F32 q14, q14, q3 359 VMIN.F32 q15, q15, q3 360 361 # Store full 4 x 8 362 BLO 6f 363 VST1.32 {d16-d19}, [r11], r0 364 SUB r7, r7, r2 365 VST1.32 {d20-d23}, [r4], r0 366 SUB r10, r10, r2 367 VST1.32 {d24-d27}, [r8], r0 368 SUB r12, r12, r2 369 VST1.32 {d28-d31}, [r6], r0 370 SUB r3, r3, r2 371 BHI 0b 372 373 ADD sp, sp, 4 374 POP {r4, r5, r6, r7, r8, r9, r10, r11} 375 VPOP {d8-d15} 376 BX lr 377 378 .p2align 3 3794: 380 # Is there a remainder?- 2 floats of A (8 bytes) 381 TST r5, 8 382 BEQ 5f 383 384 # Remainder - 2 floats of A (8 bytes) 385 VLD1.32 {d0}, [r3]! // A0 386 VLDM r9!, {d8-d11} // B0 387 VLD1.32 {d1}, [r12]! // A1 388 VLD1.32 {d2}, [r10]! // A2 389 VLD1.32 {d3}, [ r7]! // A3 390 391 VMLA.F32 q8, q4, d0[0] 392 VMLA.F32 q9, q5, d0[0] 393 VMLA.F32 q10, q4, d1[0] 394 VMLA.F32 q11, q5, d1[0] 395 VLDM r9!, {d12-d15} // B1 396 VMLA.F32 q12, q4, d2[0] 397 VMLA.F32 q13, q5, d2[0] 398 VMLA.F32 q14, q4, d3[0] 399 VMLA.F32 q15, q5, d3[0] 400 VMLA.F32 q8, q6, d0[1] 401 VMLA.F32 q9, q7, d0[1] 402 VMLA.F32 q10, q6, d1[1] 403 VMLA.F32 q11, q7, d1[1] 404 VMLA.F32 q12, q6, d2[1] 405 VMLA.F32 q13, q7, d2[1] 406 VMLA.F32 q14, q6, d3[1] 407 VMLA.F32 q15, q7, d3[1] 408 409 # Is there a remainder?- 1 float of A (4 bytes) 410 TST r5, 4 411 BEQ 3b 412 4135: 414 # Remainder- 1 float of A (4 bytes) 415 VLDM r3!, {s0} // A0 416 VLDM r9!, {d8-d11} // B0 417 VLDM r12!, {s2} // A1 418 VLDM r10!, {s4} // A2 419 VLDM r7!, {s6} // A3 420 VMLA.F32 q8, q4, d0[0] 421 VMLA.F32 q9, q5, d0[0] 422 VMLA.F32 q10, q4, d1[0] 423 VMLA.F32 q11, q5, d1[0] 424 VMLA.F32 q12, q4, d2[0] 425 VMLA.F32 q13, q5, d2[0] 426 VMLA.F32 q14, q4, d3[0] 427 VMLA.F32 q15, q5, d3[0] 428 B 3b 429 430 # Store odd width 4316: 432 TST r1, 4 433 BEQ 7f 434 VST1.32 {d16-d17}, [r11]! 435 VST1.32 {d20-d21}, [r4]! 436 VMOV q8, q9 437 VMOV q10, q11 438 VST1.32 {d24-d25}, [r8]! 439 VST1.32 {d28-d29}, [r6]! 440 VMOV q12, q13 441 VMOV q14, q15 442 4437: 444 TST r1, 2 445 BEQ 8f 446 VST1.32 {d16}, [r11]! 447 VST1.32 {d20}, [r4]! 448 VMOV d16, d17 449 VMOV d20, d21 450 VST1.32 {d24}, [r8]! 451 VST1.32 {d28}, [r6]! 452 VMOV d24, d25 453 VMOV d28, d29 454 4558: 456 TST r1, 1 457 BEQ 9f 458 VST1.32 {d16[0]}, [r11] 459 VST1.32 {d20[0]}, [r4] 460 VST1.32 {d24[0]}, [r8] 461 VST1.32 {d28[0]}, [r6] 462 4639: 464 ADD sp, sp, 4 465 POP {r4, r5, r6, r7, r8, r9, r10, r11} 466 VPOP {d8-d15} 467 BX lr 468 469END_FUNCTION xnn_f32_gemm_minmax_ukernel_4x8__aarch32_neon_cortex_a53 470 471#ifdef __ELF__ 472.section ".note.GNU-stack","",%progbits 473#endif 474