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