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_prfm_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_prfm_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 PLD [r3, 0] // Prefetch A 89 PLD [r3, 64] 90 VMOV q10, q8 91 PLD [r12, 0] 92 PLD [r12, 64] 93 VMOV q11, q9 94 PLD [r10, 0] 95 PLD [r10, 64] 96 VMOV q12, q8 97 PLD [r7, 0] 98 PLD [r7, 64] 99 VMOV q13, q9 100 PLD [r9, 0] // Prefetch B 101 PLD [r9, 64] 102 VMOV q14, q8 103 PLD [r9, 128] 104 PLD [r9, 192] 105 VMOV q15, q9 106 PLD [r9, 256] 107 PLD [r9, 320] 108 BLO 4f // less than 4 channels? 109 110 # Prologue 111 VLD1.32 {d0}, [r3]! // A0 112 VLD1.32 {d1}, [r12]! // A1 113 VLD1.32 {d2}, [r10]! // A2 114 VLD1.32 {d3}, [r7]! // A3 115 SUBS r5, r5, 16 116 VLDM r9, {d8-d11} // B0 117 LDR r0, [r9, 56] // B1 low VMOV is in BLOCK 0 118 LDR r2, [r9, 60] // B1 high 119 VLDR d13, [r9, 40] // B1 120 121 BLO 2f // less than 4 channels? skip main loop 122 123 # Main loop - 4 floats of A (16 bytes) 124 # 32 FMA + 8 LD64 A + 8 LDR B 125 .p2align 3 1261: 127 # First group of 16 FMA, Second group loads 128 # BLOCK 0 129 VLD1.32 {d4}, [r3]! // A0 130 VMOV d15, r0, r2 // b1 VMOV b from second group 131 VMLA.F32 q8, q4, d0[0] 132 LDR r0, [r12] // A1 low 133 VMLA.F32 q10, q4, d1[0] 134 LDR r2, [r12, 4] // A1 high 135 VMLA.F32 q12, q4, d2[0] 136 PLD [r3, 128] // Prefetch A0 137 138 # BLOCK 1 139 VLDR d12, [r9, 32] // B1 140 VMOV d5, r0, r2 // a1 VMOV 141 VMLA.F32 q14, q4, d3[0] 142 LDR r0, [r9, 72] // B0 low 143 VMLA.F32 q9, q5, d0[0] 144 LDR r2, [r9, 76] // B0 high 145 VMLA.F32 q11, q5, d1[0] 146 PLD [r12, 128] // Prefetch A1 147 148 # BLOCK 2 149 VLD1.32 {d6}, [r10]! // A2 150 VMOV d9, r0, r2 // b0 VMOV 151 VMLA.F32 q13, q5, d2[0] 152 LDR r0, [r7] // A3 low 153 VMLA.F32 q15, q5, d3[0] 154 LDR r2, [r7, 4] // A3 high 155 VMLA.F32 q8, q6, d0[1] 156 PLD [r10, 128] // Prefetch A2 157 158 # BLOCK 3 159 VLDR d14, [r9, 48] // B1 160 VMOV d7, r0, r2 // a3 VMOV 161 VMLA.F32 q10, q6, d1[1] 162 LDR r0, [r9, 88] // B0 low 163 VMLA.F32 q12, q6, d2[1] 164 LDR r2, [r9, 92] // B0 high 165 VMLA.F32 q14, q6, d3[1] 166 PLD [r7, 128] // Prefetch A3 167 168 # BLOCK 4 169 VLDR d8, [r9, 64] // B0 170 VMOV d11, r0, r2 // B0 VMOV 171 VMLA.F32 q9, q7, d0[1] 172 LDR r0, [r9, 104] // B1 low VMOV is in BLOCK 0 173 VMLA.F32 q11, q7, d1[1] 174 LDR r2, [r9, 108] // B1 high 175 VMLA.F32 q13, q7, d2[1] 176 PLD [r9, 384] // Prefetch B 177 178 # BLOCK 5 179 VLDR d10, [r9, 80] // B0 180 VMOV d13, r0, r2 // b1 VMOV b from second group 181 VMLA.F32 q15, q7, d3[1] 182 LDR r0, [r9, 120] // B1 low VMOV is in BLOCK 0 183 NOP 184 LDR r2, [r9, 124] // B1 high 185 NOP 186 PLD [r9, 448] // Prefetch B 187 188 # Second group of 16 FMA, First group of loads 189 # BLOCK 0 190 VLD1.32 {d0}, [r3]! // A0 191 VMOV d15, r0, r2 // b1 VMOV b from second group 192 VMLA.F32 q8, q4, d4[0] 193 LDR r0, [r12, 8] // A1 low 194 VMLA.F32 q10, q4, d5[0] 195 LDR r2, [r12, 12] // A1 high 196 VMLA.F32 q12, q4, d6[0] 197 # NOP 198 199 # BLOCK 1 200 VLDR d12, [r9, 96] // B1 201 VMOV d1, r0, r2 // a1 VMOV 202 VMLA.F32 q14, q4, d7[0] 203 LDR r0, [r9, 136] // B0 low 204 VMLA.F32 q9, q5, d4[0] 205 LDR r2, [r9, 140] // B0 high 206 VMLA.F32 q11, q5, d5[0] 207 # NOP 208 209 # BLOCK 2 210 VLD1.32 {d2}, [r10]! // A2 211 VMOV d9, r0, r2 // b0 VMOV 212 VMLA.F32 q13, q5, d6[0] 213 LDR r0, [r7, 8] // A3 low 214 VMLA.F32 q15, q5, d7[0] 215 LDR r2, [r7, 12] // A3 high 216 VMLA.F32 q8, q6, d4[1] 217 # NOP 218 219 # BLOCK 3 220 VLDR d14, [r9, 112] // B1 221 VMOV d3, r0, r2 // a3 VMOV 222 VMLA.F32 q10, q6, d5[1] 223 LDR r0, [r9, 152] // B0 low 224 VMLA.F32 q12, q6, d6[1] 225 LDR r2, [r9, 156] // B0 high 226 VMLA.F32 q14, q6, d7[1] 227 ADD r12, r12, 16 // A1++ 228 229 # BLOCK 4 230 VLDR d8, [r9, 128] // B0 231 VMOV d11, r0, r2 // B0 VMOV 232 VMLA.F32 q9, q7, d4[1] 233 LDR r0, [r9, 168] // B1 low 234 VMLA.F32 q11, q7, d5[1] 235 LDR r2, [r9, 172] // B1 high 236 VMLA.F32 q13, q7, d6[1] 237 ADD r7, r7, 16 // A3++ 238 239 # BLOCK 5 240 VLDR d10, [r9, 144] // B0 241 VMOV d13, r0, r2 // b1 VMOV b 242 VMLA.F32 q15, q7, d7[1] 243 LDR r0, [r9, 184] // B1 low VMOV is in BLOCK 0 244 SUBS r5, r5, 16 245 LDR r2, [r9, 188] // B1 high 246 ADD r9, r9, 128 // B++ 247 BHS 1b 248 249 # Epilogue - 4 floats of A (16 bytes) 2502: 251 # First group of 16 FMA, Second group loads 252 # BLOCK 0 253 VLD1.32 {d4}, [r3]! // A0 254 VMOV d15, r0, r2 // b1 VMOV b from second group 255 VMLA.F32 q8, q4, d0[0] 256 LDR r0, [r12] // A1 low 257 VMLA.F32 q10, q4, d1[0] 258 LDR r2, [r12, 4] // A1 high 259 VMLA.F32 q12, q4, d2[0] 260 # NOP 261 262 # BLOCK 1 263 VLDR d12, [r9, 32] // B1 264 VMOV d5, r0, r2 // a1 VMOV 265 VMLA.F32 q14, q4, d3[0] 266 LDR r0, [r9, 72] // B0 low 267 VMLA.F32 q9, q5, d0[0] 268 LDR r2, [r9, 76] // B0 high 269 VMLA.F32 q11, q5, d1[0] 270 # NOP 271 272 # BLOCK 2 273 VLD1.32 {d6}, [r10]! // A2 274 VMOV d9, r0, r2 // b0 VMOV 275 VMLA.F32 q13, q5, d2[0] 276 LDR r0, [r7] // A3 low 277 VMLA.F32 q15, q5, d3[0] 278 LDR r2, [r7, 4] // A3 high 279 VMLA.F32 q8, q6, d0[1] 280 # NOP 281 282 # BLOCK 3 283 VLDR d14, [r9, 48] // B1 284 VMOV d7, r0, r2 // a3 VMOV 285 VMLA.F32 q10, q6, d1[1] 286 LDR r0, [r9, 88] // B0 low 287 VMLA.F32 q12, q6, d2[1] 288 LDR r2, [r9, 92] // B0 high 289 VMLA.F32 q14, q6, d3[1] 290 # NOP 291 292 # BLOCK 4 293 VLDR d8, [r9, 64] // B0 294 VMOV d11, r0, r2 // B0 VMOV 295 VMLA.F32 q9, q7, d0[1] 296 LDR r0, [r9, 104] // B1 low 297 VMLA.F32 q11, q7, d1[1] 298 LDR r2, [r9, 108] // B1 high 299 VMLA.F32 q13, q7, d2[1] 300 # NOP 301 302 # BLOCK 5 303 VLDR d10, [r9, 80] // B0 304 VMOV d13, r0, r2 // b1 VMOV b 305 VMLA.F32 q15, q7, d3[1] 306 LDR r0, [r9, 120] // B1 low VMOV is in BLOCK 0 307 NOP 308 LDR r2, [r9, 124] // B1 high 309 NOP 310 NOP 311 312 # Second group of 16 FMA, First group of loads 313 # BLOCK 0 314 VLDR d12, [r9, 96] // B1 315 VMOV d15, r0, r2 // b1 VMOV b from second group 316 VMLA.F32 q8, q4, d4[0] 317 VMLA.F32 q10, q4, d5[0] 318 VMLA.F32 q12, q4, d6[0] 319 320 # BLOCK 1 321 VLDR d14, [r9, 112] // B1 322 VMLA.F32 q14, q4, d7[0] 323 VMLA.F32 q9, q5, d4[0] 324 VMLA.F32 q11, q5, d5[0] 325 ADD r12, r12, 8 // A1++ 326 327 # BLOCK 2 328 ADD r7, r7, 8 // A3++ VLDR B1 lands here 329 ADD r9, r9, 128 // B++ 330 VMLA.F32 q13, q5, d6[0] 331 VMLA.F32 q15, q5, d7[0] 332 VMLA.F32 q8, q6, d4[1] 333 334 # BLOCK 3 335 VMLA.F32 q10, q6, d5[1] 336 VMLA.F32 q12, q6, d6[1] 337 VMLA.F32 q14, q6, d7[1] 338 TST r5, 15 339 340 # BLOCK 4 341 VMLA.F32 q9, q7, d4[1] 342 VMLA.F32 q11, q7, d5[1] 343 VMLA.F32 q13, q7, d6[1] 344 345 # BLOCK 5 346 VMLA.F32 q15, q7, d7[1] 347 348 # Is there a remainder?- 1 to 3 floats of A (4, 8 or 12 bytes) 349 BNE 4f 350 351 .p2align 3 3523: 353 # Load params pointer 354 LDR r0, [sp, 116] // cn_stride 355 LDR r5, [sp, 120] // params 356 LDR r2, [sp] // kc 357 SUBS r1, r1, 8 358 359 # Load min/max values 360 VLD1.32 {d4[],d5[]}, [r5]! 361 VLD1.32 {d6[],d7[]}, [r5] 362 363 # Clamp 364 VMAX.F32 q8, q8, q2 365 VMAX.F32 q9, q9, q2 366 VMAX.F32 q10, q10, q2 367 VMAX.F32 q11, q11, q2 368 VMAX.F32 q12, q12, q2 369 VMAX.F32 q13, q13, q2 370 VMAX.F32 q14, q14, q2 371 VMAX.F32 q15, q15, q2 372 VMIN.F32 q8, q8, q3 373 VMIN.F32 q9, q9, q3 374 VMIN.F32 q10, q10, q3 375 VMIN.F32 q11, q11, q3 376 VMIN.F32 q12, q12, q3 377 VMIN.F32 q13, q13, q3 378 VMIN.F32 q14, q14, q3 379 VMIN.F32 q15, q15, q3 380 381 # Store full 4 x 8 382 BLO 6f 383 VST1.32 {d16-d19}, [r11], r0 384 SUB r7, r7, r2 385 VST1.32 {d20-d23}, [r4], r0 386 SUB r10, r10, r2 387 VST1.32 {d24-d27}, [r8], r0 388 SUB r12, r12, r2 389 VST1.32 {d28-d31}, [r6], r0 390 SUB r3, r3, r2 391 BHI 0b 392 393 ADD sp, sp, 4 394 POP {r4, r5, r6, r7, r8, r9, r10, r11} 395 VPOP {d8-d15} 396 BX lr 397 398 .p2align 3 3994: 400 # Is there a remainder?- 2 floats of A (8 bytes) 401 TST r5, 8 402 BEQ 5f 403 404 # Remainder - 2 floats of A (8 bytes) 405 VLD1.32 {d0}, [r3]! // A0 406 VLDM r9!, {d8-d11} // B0 407 VLD1.32 {d1}, [r12]! // A1 408 VLD1.32 {d2}, [r10]! // A2 409 VLD1.32 {d3}, [ r7]! // A3 410 411 VMLA.F32 q8, q4, d0[0] 412 VMLA.F32 q9, q5, d0[0] 413 VMLA.F32 q10, q4, d1[0] 414 VMLA.F32 q11, q5, d1[0] 415 VLDM r9!, {d12-d15} // B1 416 VMLA.F32 q12, q4, d2[0] 417 VMLA.F32 q13, q5, d2[0] 418 VMLA.F32 q14, q4, d3[0] 419 VMLA.F32 q15, q5, d3[0] 420 VMLA.F32 q8, q6, d0[1] 421 VMLA.F32 q9, q7, d0[1] 422 VMLA.F32 q10, q6, d1[1] 423 VMLA.F32 q11, q7, d1[1] 424 VMLA.F32 q12, q6, d2[1] 425 VMLA.F32 q13, q7, d2[1] 426 VMLA.F32 q14, q6, d3[1] 427 VMLA.F32 q15, q7, d3[1] 428 429 # Is there a remainder?- 1 float of A (4 bytes) 430 TST r5, 4 431 BEQ 3b 432 4335: 434 # Remainder- 1 float of A (4 bytes) 435 VLDM r3!, {s0} // A0 436 VLDM r9!, {d8-d11} // B0 437 VLDM r12!, {s2} // A1 438 VLDM r10!, {s4} // A2 439 VLDM r7!, {s6} // A3 440 VMLA.F32 q8, q4, d0[0] 441 VMLA.F32 q9, q5, d0[0] 442 VMLA.F32 q10, q4, d1[0] 443 VMLA.F32 q11, q5, d1[0] 444 VMLA.F32 q12, q4, d2[0] 445 VMLA.F32 q13, q5, d2[0] 446 VMLA.F32 q14, q4, d3[0] 447 VMLA.F32 q15, q5, d3[0] 448 B 3b 449 450 # Store odd width 4516: 452 TST r1, 4 453 BEQ 7f 454 VST1.32 {d16-d17}, [r11]! 455 VST1.32 {d20-d21}, [r4]! 456 VMOV q8, q9 457 VMOV q10, q11 458 VST1.32 {d24-d25}, [r8]! 459 VST1.32 {d28-d29}, [r6]! 460 VMOV q12, q13 461 VMOV q14, q15 462 4637: 464 TST r1, 2 465 BEQ 8f 466 VST1.32 {d16}, [r11]! 467 VST1.32 {d20}, [r4]! 468 VMOV d16, d17 469 VMOV d20, d21 470 VST1.32 {d24}, [r8]! 471 VST1.32 {d28}, [r6]! 472 VMOV d24, d25 473 VMOV d28, d29 474 4758: 476 TST r1, 1 477 BEQ 9f 478 VST1.32 {d16[0]}, [r11] 479 VST1.32 {d20[0]}, [r4] 480 VST1.32 {d24[0]}, [r8] 481 VST1.32 {d28[0]}, [r6] 482 4839: 484 ADD sp, sp, 4 485 POP {r4, r5, r6, r7, r8, r9, r10, r11} 486 VPOP {d8-d15} 487 BX lr 488 489END_FUNCTION xnn_f32_gemm_minmax_ukernel_4x8__aarch32_neon_prfm_cortex_a53 490 491#ifdef __ELF__ 492.section ".note.GNU-stack","",%progbits 493#endif 494