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