1// Copyright 2019 Google LLC 2// 3// This source code is licensed under the BSD-style license found in the 4// LICENSE file in the root directory of this source tree. 5 6#include <xnnpack/assembly.h> 7 8.syntax unified 9 10// void xnn_f32_igemm_minmax_ukernel_4x8__aarch32_neon${"_prfm" if PREFETCH else ""}_ld64( 11// size_t mr, r0 12// size_t nc, r1 13// size_t kc, r2 -> r5 -> sp + 68 14// size_t ks, r3 -> sp + 72 -> r14 15// const float**restrict a, sp + 112 -> r2 16// const void*restrict w, sp + 116 -> r9 17// uint8_t*restrict c, sp + 120 -> r11 18// size_t cm_stride, sp + 124 -> (r6) 19// size_t cn_stride, sp + 128 -> (r7) 20// size_t a_offset, sp + 132 -> (r5) 21// const float* zero, sp + 136 -> (r7) 22// minmax_params*params, sp + 140 -> (r5) 23 24// d8-d15, r4-r11,r14(lr) need to be preserved if used. r13(sp),r15(pc) are reserved. 25 26// Register usage 27// A0 r3 d0 28// A1 r12 d1 29// A2 r10 d2 30// A3 r0 d3 31 32// B r9 d8, d9, d10, d11 33// B d12, d13, d14, d15 34 35// C0 r11 d16-d17 q8 d18-d19 q9 36// C1 r4 d20-d21 q10 d22-d23 q11 37// C2 r8 d24-d25 q12 d26-d27 q13 38// C3 r6 d28-d29 q14 d30-d31 q15 39 40// Clamp (r5) d4 d5 d6 d7 41 42BEGIN_FUNCTION xnn_f32_igemm_minmax_ukernel_4x8__aarch32_neon${"_prfm" if PREFETCH else ""}_ld64 43 .arm 44#ifndef __APPLE__ 45 .arch armv7-a 46 .fpu neon 47#endif 48 # Push 112 bytes 49 # r2 will be reloaded in outer loop. r3 is ks 50 PUSH {r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, lr} // +44 51 SUB sp, sp, 4 // 4 52 VPUSH {d8-d15} // +64 = 112 53 54 LDR r11, [sp, 120] // c 55 LDR r6, [sp, 124] // cm_stride 56 LDR r2, [sp, 112] // a 57 LDR r9, [sp, 116] // w 58 LDR r5, [sp, 140] // params 59 MOV r14, r3 // p = ks 60 61 # Clamp C pointers 62 CMP r0, 2 // if mr >= 2 63 ADD r4, r11, r6 // c1 = c0 + cm_stride 64 MOVLO r4, r11 // c1 65 // if mr > 2 66 ADD r8, r4, r6 // c2 = c1 + cm_stride 67 MOVLS r8, r4 // c2 68 CMP r0, 4 // if mr >=4 69 ADD r6, r8, r6 // c3 = c2 + cm_stride 70 MOVLO r6, r8 // c3 71 72 # Load min/max values 73 VLD1.32 {d4[], d5[]}, [r5]! 74 VLD1.32 {d6[], d7[]}, [r5] 75 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 $if PREFETCH: 87 PLD [r9, 0] // Prefetch B 88 PLD [r9, 64] 89 PLD [r9, 128] 90 PLD [r9, 192] 91 PLD [r9, 256] 92 PLD [r9, 320] 93 PLD [r9, 384] 94 PLD [r9, 448] 951: 96 # Load next 4 A pointers 97 LDR r3, [r2, 0] 98 LDR r12, [r2, 4] 99 LDR r10, [r2, 8] 100 LDR r0, [r2, 12] 101 ADD r2, r2, 16 102 103 # Add a_offset 104 LDR r5, [sp, 132] // a_offset 105 LDR r7, [sp, 136] // zero 106 CMP r3, r7 // if a0 == zero 107 ADD r3, r3, r5 // a0 += a_offset 108 MOVEQ r3, r7 // a0 = zero, else += a0 + a_offset 109 CMP r12, r7 // if a1 == zero 110 ADD r12, r12, r5 // a1 += a_offset 111 MOVEQ r12, r7 // a1 = zero, else += a1 + a_offset 112 CMP r10, r7 // if a2 == zero 113 ADD r10, r10, r5 // a2 += a_offset 114 MOVEQ r10, r7 // a2 = zero, else += a2 + a_offset 115 CMP r0, r7 // if a3 == zero 116 ADD r0, r0, r5 // a3 += a_offset 117 LDR r5, [sp, 68] // kc 118 MOVEQ r0, r7 // a3 = zero, else += a3 + a_offset 119 120 $if PREFETCH: 121 PLD [r3, 0] // Prefetch A 122 PLD [r3, 64] 123 PLD [r12, 0] 124 PLD [r12, 64] 125 PLD [r10, 0] 126 PLD [r10, 64] 127 PLD [r0, 0] 128 PLD [r0, 64] 129 130 SUBS r5, r5, 8 // kc - 8 131 BLO 4f // less than 2 channels? 132 133 # Main loop - 2 floats of A (8 bytes) 1342: 135 VLD1.32 {d0}, [r3]! // A0 136 VLDM r9!, {d8-d11} // B0 137 VLD1.32 {d1}, [r12]! // A1 138 VLD1.32 {d2}, [r10]! // A2 139 VLD1.32 {d3}, [ r0]! // A3 140 VLDM r9!, {d12-d15} // B1 141 142 VMLA.F32 q8, q4, d0[0] 143 VMLA.F32 q9, q5, d0[0] 144 $if PREFETCH: 145 PLD [r3, 128] // Prefetch A0 146 VMLA.F32 q10, q4, d1[0] 147 VMLA.F32 q11, q5, d1[0] 148 $if PREFETCH: 149 PLD [r12, 128] // Prefetch A1 150 VMLA.F32 q12, q4, d2[0] 151 VMLA.F32 q13, q5, d2[0] 152 $if PREFETCH: 153 PLD [r10, 128] // Prefetch A2 154 VMLA.F32 q14, q4, d3[0] 155 VMLA.F32 q15, q5, d3[0] 156 $if PREFETCH: 157 PLD [r0, 128] // Prefetch A3 158 VMLA.F32 q8, q6, d0[1] 159 VMLA.F32 q9, q7, d0[1] 160 $if PREFETCH: 161 PLD [r9, 448] // Prefetch B 162 VMLA.F32 q10, q6, d1[1] 163 VMLA.F32 q11, q7, d1[1] 164 SUBS r5, r5, 8 165 VMLA.F32 q12, q6, d2[1] 166 VMLA.F32 q13, q7, d2[1] 167 VMLA.F32 q14, q6, d3[1] 168 VMLA.F32 q15, q7, d3[1] 169 BHS 2b 170 171 # Is there a remainder?- 1 floats of A (4 bytes) 172 TST r5, 4 173 BNE 4f 174 1753: 176 # ks loop 177 SUBS r14, r14, 16 // ks -= MR * sizeof(void*) 178 BHI 1b 179 180 LDR r7, [sp, 128] // cn_stride 181 LDR r14, [sp, 72] // p = ks 182 183 # Clamp 184 VMAX.F32 q8, q8, q2 185 SUBS r1, r1, 8 186 VMAX.F32 q9, q9, q2 187 VMAX.F32 q10, q10, q2 188 VMAX.F32 q11, q11, q2 189 VMAX.F32 q12, q12, q2 190 VMAX.F32 q13, q13, q2 191 VMAX.F32 q14, q14, q2 192 VMAX.F32 q15, q15, q2 193 VMIN.F32 q8, q8, q3 194 VMIN.F32 q9, q9, q3 195 VMIN.F32 q10, q10, q3 196 VMIN.F32 q11, q11, q3 197 VMIN.F32 q12, q12, q3 198 VMIN.F32 q13, q13, q3 199 VMIN.F32 q14, q14, q3 200 VMIN.F32 q15, q15, q3 201 202 # Store full 4 x 8 203 BLO 5f 204 VST1.32 {d28-d31}, [r6], r7 205 VST1.32 {d24-d27}, [r8], r7 206 VST1.32 {d20-d23}, [r4], r7 207 VST1.32 {d16-d19}, [r11], r7 208 SUB r2, r2, r14 // a -= ks 209 BHI 0b 210 211 VPOP {d8-d15} 212 ADD sp, sp, 12 // skip pad, r2, r3 213 POP {r4, r5, r6, r7, r8, r9, r10, r11, pc} 214 2154: 216 # Remainder- 1 floats of A (4 bytes) 217 VLDM r3!, {s0} // A0 218 VLDM r9!, {d8-d11} // B0 219 VLDM r12!, {s2} // A1 220 VLDM r10!, {s4} // A2 221 VLDM r0!, {s6} // A3 222 VMLA.F32 q8, q4, d0[0] 223 VMLA.F32 q9, q5, d0[0] 224 VMLA.F32 q10, q4, d1[0] 225 VMLA.F32 q11, q5, d1[0] 226 VMLA.F32 q12, q4, d2[0] 227 VMLA.F32 q13, q5, d2[0] 228 VMLA.F32 q14, q4, d3[0] 229 VMLA.F32 q15, q5, d3[0] 230 B 3b 231 232 # Store odd width 2335: 234 TST r1, 4 235 BEQ 6f 236 VST1.32 {d28-d29}, [r6]! 237 VST1.32 {d24-d25}, [r8]! 238 VMOV q14, q15 239 VMOV q12, q13 240 VST1.32 {d20-d21}, [r4]! 241 VST1.32 {d16-d17}, [r11]! 242 VMOV q10, q11 243 VMOV q8, q9 244 2456: 246 TST r1, 2 247 BEQ 7f 248 VST1.32 {d28}, [r6]! 249 VST1.32 {d24}, [r8]! 250 VMOV d28, d29 251 VMOV d24, d25 252 VST1.32 {d20}, [r4]! 253 VST1.32 {d16}, [r11]! 254 VMOV d20, d21 255 VMOV d16, d17 256 2577: 258 TST r1, 1 259 BEQ 8f 260 VST1.32 {d28[0]}, [r6]! 261 VST1.32 {d24[0]}, [r8]! 262 VST1.32 {d20[0]}, [r4]! 263 VST1.32 {d16[0]}, [r11]! 264 2658: 266 VPOP {d8-d15} 267 ADD sp, sp, 12 // skip pad, r2, r3 268 POP {r4, r5, r6, r7, r8, r9, r10, r11, pc} 269 270END_FUNCTION xnn_f32_igemm_minmax_ukernel_4x8__aarch32_neon${"_prfm" if PREFETCH else ""}_ld64 271 272#ifdef __ELF__ 273.section ".note.GNU-stack","",%progbits 274#endif 275