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