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_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_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 871: 88 # Load next 4 A pointers 89 LDR r3, [r2, 0] 90 LDR r12, [r2, 4] 91 LDR r10, [r2, 8] 92 LDR r0, [r2, 12] 93 ADD r2, r2, 16 94 95 # Add a_offset 96 LDR r5, [sp, 132] // a_offset 97 LDR r7, [sp, 136] // zero 98 CMP r3, r7 // if a0 == zero 99 ADD r3, r3, r5 // a0 += a_offset 100 MOVEQ r3, r7 // a0 = zero, else += a0 + a_offset 101 CMP r12, r7 // if a1 == zero 102 ADD r12, r12, r5 // a1 += a_offset 103 MOVEQ r12, r7 // a1 = zero, else += a1 + a_offset 104 CMP r10, r7 // if a2 == zero 105 ADD r10, r10, r5 // a2 += a_offset 106 MOVEQ r10, r7 // a2 = zero, else += a2 + a_offset 107 CMP r0, r7 // if a3 == zero 108 ADD r0, r0, r5 // a3 += a_offset 109 LDR r5, [sp, 68] // kc 110 MOVEQ r0, r7 // a3 = zero, else += a3 + a_offset 111 112 113 SUBS r5, r5, 16 // kc - 16 114 BLO 5f // less than 4 channels? 115 116 # Prologue 117 VLD1.32 {d0}, [r3]! // A0 118 VLDM r9!, {d8-d11} // B0 119 VLD1.32 {d1}, [r12]! // A1 120 VLD1.32 {d2}, [r10]! // A2 121 VLD1.32 {d3}, [ r0]! // A3 122 123 SUBS r5, r5, 16 124 BLO 3f // less than 4 channels? skip main loop 125 126 .p2align 3 127 128 # Main loop - 4 floats of A (16 bytes) 1292: 130 VMLA.F32 q8, q4, d0[0] 131 VLDM r9!, {d12-d15} // B1 132 VMLA.F32 q10, q4, d1[0] 133 VMLA.F32 q12, q4, d2[0] 134 VLD1.32 {d4}, [r3]! // A0 135 VMLA.F32 q14, q4, d3[0] 136 VMLA.F32 q9, q5, d0[0] 137 VLD1.32 {d5}, [r12]! // A1 138 VMLA.F32 q11, q5, d1[0] 139 VMLA.F32 q13, q5, d2[0] 140 VMLA.F32 q15, q5, d3[0] 141 VLD1.32 {d6}, [r10]! // A2 142 VMLA.F32 q8, q6, d0[1] 143 VMLA.F32 q10, q6, d1[1] 144 VLD1.32 {d7}, [ r0]! // A3 145 VMLA.F32 q12, q6, d2[1] 146 VMLA.F32 q14, q6, d3[1] 147 VLDM r9!, {d8-d11} // B0 148 VMLA.F32 q9, q7, d0[1] 149 VMLA.F32 q11, q7, d1[1] 150 VMLA.F32 q13, q7, d2[1] 151 VMLA.F32 q15, q7, d3[1] 152 153 VMLA.F32 q8, q4, d4[0] 154 VLDM r9!, {d12-d15} // B1 155 VMLA.F32 q10, q4, d5[0] 156 VMLA.F32 q12, q4, d6[0] 157 VLD1.32 {d0}, [r3]! // A0 158 VMLA.F32 q14, q4, d7[0] 159 VMLA.F32 q9, q5, d4[0] 160 VLD1.32 {d1}, [r12]! // A1 161 VMLA.F32 q11, q5, d5[0] 162 VMLA.F32 q13, q5, d6[0] 163 VLD1.32 {d2}, [r10]! // A2 164 VMLA.F32 q15, q5, d7[0] 165 VMLA.F32 q8, q6, d4[1] 166 VLD1.32 {d3}, [ r0]! // A3 167 VMLA.F32 q10, q6, d5[1] 168 VMLA.F32 q12, q6, d6[1] 169 VMLA.F32 q14, q6, d7[1] 170 VLDM r9!, {d8-d11} // B0 171 VMLA.F32 q9, q7, d4[1] 172 VMLA.F32 q11, q7, d5[1] 173 SUBS r5, r5, 16 174 VMLA.F32 q13, q7, d6[1] 175 VMLA.F32 q15, q7, d7[1] 176 BHS 2b 177 178 # Epilogue 1793: 180 VMLA.F32 q8, q4, d0[0] 181 VLDM r9!, {d12-d15} // B1 182 VMLA.F32 q10, q4, d1[0] 183 VMLA.F32 q12, q4, d2[0] 184 VLD1.32 {d4}, [r3]! // A0 185 VMLA.F32 q14, q4, d3[0] 186 VMLA.F32 q9, q5, d0[0] 187 VLD1.32 {d5}, [r12]! // A1 188 VMLA.F32 q11, q5, d1[0] 189 VMLA.F32 q13, q5, d2[0] 190 VMLA.F32 q15, q5, d3[0] 191 VLD1.32 {d6}, [r10]! // A2 192 VMLA.F32 q8, q6, d0[1] 193 VMLA.F32 q10, q6, d1[1] 194 VLD1.32 {d7}, [ r0]! // A3 195 VMLA.F32 q12, q6, d2[1] 196 VMLA.F32 q14, q6, d3[1] 197 VLDM r9!, {d8-d11} // B0 198 VMLA.F32 q9, q7, d0[1] 199 VMLA.F32 q11, q7, d1[1] 200 VMLA.F32 q13, q7, d2[1] 201 VMLA.F32 q15, q7, d3[1] 202 203 VMLA.F32 q8, q4, d4[0] 204 VLDM r9!, {d12-d15} // B1 205 VMLA.F32 q10, q4, d5[0] 206 VMLA.F32 q12, q4, d6[0] 207 VMLA.F32 q14, q4, d7[0] 208 VMLA.F32 q9, q5, d4[0] 209 VMLA.F32 q11, q5, d5[0] 210 VMLA.F32 q13, q5, d6[0] 211 VMLA.F32 q15, q5, d7[0] 212 VMLA.F32 q8, q6, d4[1] 213 VMLA.F32 q10, q6, d5[1] 214 VMLA.F32 q12, q6, d6[1] 215 VMLA.F32 q14, q6, d7[1] 216 VMLA.F32 q9, q7, d4[1] 217 VMLA.F32 q11, q7, d5[1] 218 VMLA.F32 q13, q7, d6[1] 219 VMLA.F32 q15, q7, d7[1] 220 221 # Is there a remainder?- 1 to 3 floats of A (4, 8 or 12 bytes) 222 TST r5, 12 223 BNE 5f 224 225 .p2align 3 2264: 227 # ks loop 228 SUBS r14, r14, 16 // ks -= MR * sizeof(void*) 229 BHI 1b 230 231 # Load params pointer 232 LDR r5, [sp, 140] // params 233 LDR r7, [sp, 128] // cn_stride 234 LDR r14, [sp, 72] // p = ks 235 236 # Load min/max values 237 VLD1.32 {d4[],d5[]}, [r5]! 238 SUBS r1, r1, 8 239 VLD1.32 {d6[],d7[]}, [r5] 240 241 # Clamp 242 VMAX.F32 q8, q8, q2 243 VMAX.F32 q9, q9, q2 244 VMAX.F32 q10, q10, q2 245 VMAX.F32 q11, q11, q2 246 VMAX.F32 q12, q12, q2 247 VMAX.F32 q13, q13, q2 248 VMAX.F32 q14, q14, q2 249 VMAX.F32 q15, q15, q2 250 VMIN.F32 q8, q8, q3 251 VMIN.F32 q9, q9, q3 252 VMIN.F32 q10, q10, q3 253 VMIN.F32 q11, q11, q3 254 VMIN.F32 q12, q12, q3 255 VMIN.F32 q13, q13, q3 256 VMIN.F32 q14, q14, q3 257 VMIN.F32 q15, q15, q3 258 259 # Store full 4 x 8 260 BLO 7f 261 VST1.32 {d28-d31}, [r6], r7 262 VST1.32 {d24-d27}, [r8], r7 263 VST1.32 {d20-d23}, [r4], r7 264 VST1.32 {d16-d19}, [r11], r7 265 SUB r2, r2, r14 // a -= ks 266 BHI 0b 267 268 VPOP {d8-d15} 269 ADD sp, sp, 12 // skip pad, r2, r3 270 POP {r4, r5, r6, r7, r8, r9, r10, r11, pc} 271 272 .p2align 3 2735: 274 # Is there a remainder?- 2 floats of A (8 bytes) 275 TST r5, 8 276 BEQ 6f 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 4b 306 3076: 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 4b 323 324 # Store odd width 3257: 326 TST r1, 4 327 BEQ 8f 328 VST1.32 {d28-d29}, [r6]! 329 VST1.32 {d24-d25}, [r8]! 330 VMOV q14, q15 331 VMOV q12, q13 332 VST1.32 {d20-d21}, [r4]! 333 VST1.32 {d16-d17}, [r11]! 334 VMOV q10, q11 335 VMOV q8, q9 336 3378: 338 TST r1, 2 339 BEQ 9f 340 VST1.32 {d28}, [r6]! 341 VST1.32 {d24}, [r8]! 342 VMOV d28, d29 343 VMOV d24, d25 344 VST1.32 {d20}, [r4]! 345 VST1.32 {d16}, [r11]! 346 VMOV d20, d21 347 VMOV d16, d17 348 3499: 350 TST r1, 1 351 BEQ 10f 352 VST1.32 {d28[0]}, [r6]! 353 VST1.32 {d24[0]}, [r8]! 354 VST1.32 {d20[0]}, [r4]! 355 VST1.32 {d16[0]}, [r11]! 356 35710: 358 VPOP {d8-d15} 359 ADD sp, sp, 12 // skip pad, r2, r3 360 POP {r4, r5, r6, r7, r8, r9, r10, r11, pc} 361 362END_FUNCTION xnn_f32_igemm_minmax_ukernel_4x8__aarch32_neon_cortex_a75 363 364#ifdef __ELF__ 365.section ".note.GNU-stack","",%progbits 366#endif 367