1// Auto-generated file. Do not edit! 2// Template: src/f32-igemm/4x8-minmax-aarch32-neon-ld64.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_ld64( 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_ld64 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 LDR r5, [sp, 140] // params 63 MOV r14, r3 // p = ks 64 65 # Clamp C pointers 66 CMP r0, 2 // if mr >= 2 67 ADD r4, r11, r6 // c1 = c0 + cm_stride 68 MOVLO r4, r11 // c1 69 // if mr > 2 70 ADD r8, r4, r6 // c2 = c1 + cm_stride 71 MOVLS r8, r4 // c2 72 CMP r0, 4 // if mr >=4 73 ADD r6, r8, r6 // c3 = c2 + cm_stride 74 MOVLO r6, r8 // c3 75 76 # Load min/max values 77 VLD1.32 {d4[], d5[]}, [r5]! 78 VLD1.32 {d6[], d7[]}, [r5] 79 800: 81 # Load initial bias from w into accumulators 82 VLDM r9!, {d16-d19} // Bias 83 VMOV q10, q8 84 VMOV q11, q9 85 VMOV q12, q8 86 VMOV q13, q9 87 VMOV q14, q8 88 VMOV q15, q9 89 901: 91 # Load next 4 A pointers 92 LDR r3, [r2, 0] 93 LDR r12, [r2, 4] 94 LDR r10, [r2, 8] 95 LDR r0, [r2, 12] 96 ADD r2, r2, 16 97 98 # Add a_offset 99 LDR r5, [sp, 132] // a_offset 100 LDR r7, [sp, 136] // zero 101 CMP r3, r7 // if a0 == zero 102 ADD r3, r3, r5 // a0 += a_offset 103 MOVEQ r3, r7 // a0 = zero, else += a0 + a_offset 104 CMP r12, r7 // if a1 == zero 105 ADD r12, r12, r5 // a1 += a_offset 106 MOVEQ r12, r7 // a1 = zero, else += a1 + a_offset 107 CMP r10, r7 // if a2 == zero 108 ADD r10, r10, r5 // a2 += a_offset 109 MOVEQ r10, r7 // a2 = zero, else += a2 + a_offset 110 CMP r0, r7 // if a3 == zero 111 ADD r0, r0, r5 // a3 += a_offset 112 LDR r5, [sp, 68] // kc 113 MOVEQ r0, r7 // a3 = zero, else += a3 + a_offset 114 115 116 SUBS r5, r5, 8 // kc - 8 117 BLO 4f // less than 2 channels? 118 119 # Main loop - 2 floats of A (8 bytes) 1202: 121 VLD1.32 {d0}, [r3]! // A0 122 VLDM r9!, {d8-d11} // B0 123 VLD1.32 {d1}, [r12]! // A1 124 VLD1.32 {d2}, [r10]! // A2 125 VLD1.32 {d3}, [ r0]! // A3 126 VLDM r9!, {d12-d15} // B1 127 128 VMLA.F32 q8, q4, d0[0] 129 VMLA.F32 q9, q5, d0[0] 130 VMLA.F32 q10, q4, d1[0] 131 VMLA.F32 q11, q5, d1[0] 132 VMLA.F32 q12, q4, d2[0] 133 VMLA.F32 q13, q5, d2[0] 134 VMLA.F32 q14, q4, d3[0] 135 VMLA.F32 q15, q5, d3[0] 136 VMLA.F32 q8, q6, d0[1] 137 VMLA.F32 q9, q7, d0[1] 138 VMLA.F32 q10, q6, d1[1] 139 VMLA.F32 q11, q7, d1[1] 140 SUBS r5, r5, 8 141 VMLA.F32 q12, q6, d2[1] 142 VMLA.F32 q13, q7, d2[1] 143 VMLA.F32 q14, q6, d3[1] 144 VMLA.F32 q15, q7, d3[1] 145 BHS 2b 146 147 # Is there a remainder?- 1 float of A (4 bytes) 148 TST r5, 4 149 BNE 4f 150 1513: 152 # ks loop 153 SUBS r14, r14, 16 // ks -= MR * sizeof(void*) 154 BHI 1b 155 156 LDR r7, [sp, 128] // cn_stride 157 LDR r14, [sp, 72] // p = ks 158 159 # Clamp 160 VMAX.F32 q8, q8, q2 161 SUBS r1, r1, 8 162 VMAX.F32 q9, q9, q2 163 VMAX.F32 q10, q10, q2 164 VMAX.F32 q11, q11, q2 165 VMAX.F32 q12, q12, q2 166 VMAX.F32 q13, q13, q2 167 VMAX.F32 q14, q14, q2 168 VMAX.F32 q15, q15, q2 169 VMIN.F32 q8, q8, q3 170 VMIN.F32 q9, q9, q3 171 VMIN.F32 q10, q10, q3 172 VMIN.F32 q11, q11, q3 173 VMIN.F32 q12, q12, q3 174 VMIN.F32 q13, q13, q3 175 VMIN.F32 q14, q14, q3 176 VMIN.F32 q15, q15, q3 177 178 # Store full 4 x 8 179 BLO 5f 180 VST1.32 {d28-d31}, [r6], r7 181 VST1.32 {d24-d27}, [r8], r7 182 VST1.32 {d20-d23}, [r4], r7 183 VST1.32 {d16-d19}, [r11], r7 184 SUB r2, r2, r14 // a -= ks 185 BHI 0b 186 187 VPOP {d8-d15} 188 ADD sp, sp, 12 // skip pad, r2, r3 189 POP {r4, r5, r6, r7, r8, r9, r10, r11, pc} 190 1914: 192 # Remainder- 1 float of A (4 bytes) 193 VLDM r3!, {s0} // A0 194 VLDM r9!, {d8-d11} // B0 195 VLDM r12!, {s2} // A1 196 VLDM r10!, {s4} // A2 197 VLDM r0!, {s6} // A3 198 VMLA.F32 q8, q4, d0[0] 199 VMLA.F32 q9, q5, d0[0] 200 VMLA.F32 q10, q4, d1[0] 201 VMLA.F32 q11, q5, d1[0] 202 VMLA.F32 q12, q4, d2[0] 203 VMLA.F32 q13, q5, d2[0] 204 VMLA.F32 q14, q4, d3[0] 205 VMLA.F32 q15, q5, d3[0] 206 B 3b 207 208 # Store odd width 2095: 210 TST r1, 4 211 BEQ 6f 212 VST1.32 {d28-d29}, [r6]! 213 VST1.32 {d24-d25}, [r8]! 214 VMOV q14, q15 215 VMOV q12, q13 216 VST1.32 {d20-d21}, [r4]! 217 VST1.32 {d16-d17}, [r11]! 218 VMOV q10, q11 219 VMOV q8, q9 220 2216: 222 TST r1, 2 223 BEQ 7f 224 VST1.32 {d28}, [r6]! 225 VST1.32 {d24}, [r8]! 226 VMOV d28, d29 227 VMOV d24, d25 228 VST1.32 {d20}, [r4]! 229 VST1.32 {d16}, [r11]! 230 VMOV d20, d21 231 VMOV d16, d17 232 2337: 234 TST r1, 1 235 BEQ 8f 236 VST1.32 {d28[0]}, [r6]! 237 VST1.32 {d24[0]}, [r8]! 238 VST1.32 {d20[0]}, [r4]! 239 VST1.32 {d16[0]}, [r11]! 240 2418: 242 VPOP {d8-d15} 243 ADD sp, sp, 12 // skip pad, r2, r3 244 POP {r4, r5, r6, r7, r8, r9, r10, r11, pc} 245 246END_FUNCTION xnn_f32_igemm_minmax_ukernel_4x8__aarch32_neon_ld64 247 248#ifdef __ELF__ 249.section ".note.GNU-stack","",%progbits 250#endif 251