1// Auto-generated file. Do not edit! 2// Template: src/f32-gemm/4x8-minmax-aarch32-neon-cortex-a7.S.in 3// Generator: tools/xngen 4// 5// Copyright 2020 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_gemm_minmax_ukernel_4x8__aarch32_neon_cortex_a7( 15// size_t mr, r0 16// size_t nc, r1 17// size_t kc, r2 -> r5 18// const uint8_t*restrict a, r3 19// size_t a_stride, sp + 96 -> (r7) 20// const void*restrict w, sp + 100 -> r9 21// uint8_t*restrict c, sp + 104 -> r11 22// size_t cm_stride, sp + 108 -> (r6) 23// size_t cn_stride, sp + 112 -> r7 24// const union xnn_f32_minmax_params params) sp + 116 -> (r7) 25 26// d8-d15, r4-r11,r14(lr) need to be preserved if used. r13(sp),r15(pc) are reserved. 27 28// Register usage 29// A0 r3 d0 30// A1 r12 d1 31// A2 r10 d2 32// A3 r0 d3 33 34// B r9 d8, d9, d10, d11 35// B d12, d13, d14, d15 36 37// C0 r11 d16-d17 q8 d18-d19 q9 38// C1 r4 d20-d21 q10 d22-d23 q11 39// C2 r8 d24-d25 q12 d26-d27 q13 40// C3 r6 d28-d29 q14 d30-d31 q15 41 42// Clamp (r5) d4 d5 d6 d7 43 44BEGIN_FUNCTION xnn_f32_gemm_minmax_ukernel_4x8__aarch32_neon_cortex_a7 45 .arm 46#ifndef __APPLE__ 47 .arch armv7-a 48 .fpu neon 49#endif 50 # Push 96 bytes 51 PUSH {r4, r5, r6, r7, r8, r9, r10, r11} // 32 52 VPUSH {d8-d15} // +64 = 96 53 54 LDR r7, [sp, 96] // a_stride 55 LDR r11, [sp, 104] // c 56 LDR r6, [sp, 108] // cm_stride 57 LDR r9, [sp, 100] // w 58 LDR r5, [sp, 116] // params 59 60 # Clamp A and C pointers 61 CMP r0, 2 // if mr >= 2 62 ADD r12, r3, r7 // a1 = a0 + a_stride 63 ADD r4, r11, r6 // c1 = c0 + cm_stride 64 MOVLO r12, r3 // a1 65 MOVLO r4, r11 // c1 66 // if mr > 2 67 ADD r10, r12, r7 // a2 = a1 + a_stride 68 ADD r8, r4, r6 // c2 = c1 + cm_stride 69 MOVLS r10, r12 // a2 70 MOVLS r8, r4 // c2 71 72 CMP r0, 4 // if mr >=4 73 ADD r0, r10, r7 // a3 = a2 + a_stride 74 ADD r6, r8, r6 // c3 = c2 + cm_stride 75 MOVLO r0, r10 // a3 76 MOVLO r6, r8 // c3 77 78 # Load min/max values 79 VLD1.32 {d4[], d5[]}, [r5]! 80 LDR r7, [sp, 112] // cn_stride 81 VLD1.32 {d6[], d7[]}, [r5] 82 830: 84 # Load initial bias from w into accumulators 85 VLDM r9!, {d16-d19} // Bias 86 SUBS r5, r2, 8 87 VMOV q10, q8 88 VMOV q11, q9 89 VMOV q12, q8 90 VMOV q13, q9 91 VMOV q14, q8 92 VMOV q15, q9 93 94 PLD [r3, 0] // Prefetch A 95 PLD [r3, 64] 96 PLD [r12, 0] 97 PLD [r12, 64] 98 PLD [r10, 0] 99 PLD [r10, 64] 100 PLD [r0, 0] 101 PLD [r0, 64] 102 PLD [r9, 0] // Prefetch B 103 PLD [r9, 64] 104 PLD [r9, 128] 105 PLD [r9, 192] 106 PLD [r9, 256] 107 PLD [r9, 320] 108 PLD [r9, 384] 109 PLD [r9, 448] 110 BLO 3f // less than 2 channels? 111 112 # Main loop - 2 floats of A (8 bytes) 1131: 114 VLD1.32 {d0}, [r3]! // A0 115 VLDM r9!, {d8-d11} // B0 116 VLD1.32 {d1}, [r12]! // A1 117 VLD1.32 {d2}, [r10]! // A2 118 VLD1.32 {d3}, [ r0]! // A3 119 VLDM r9!, {d12-d15} // B1 120 VMLA.F32 q8, q4, d0[0] 121 VMLA.F32 q9, q5, d0[0] 122 VMLA.F32 q10, q4, d1[0] 123 VMLA.F32 q13, q5, d2[0] 124 VMLA.F32 q11, q5, d1[0] 125 VMLA.F32 q12, q4, d2[0] 126 VMLA.F32 q14, q4, d3[0] 127 VMLA.F32 q15, q5, d3[0] 128 VMLA.F32 q8, q6, d0[1] 129 VMLA.F32 q9, q7, d0[1] 130 VMLA.F32 q10, q6, d1[1] 131 VMLA.F32 q11, q7, d1[1] 132 SUBS r5, r5, 8 133 VMLA.F32 q12, q6, d2[1] 134 VMLA.F32 q13, q7, d2[1] 135 VMLA.F32 q14, q6, d3[1] 136 VMLA.F32 q15, q7, d3[1] 137 PLD [r9, 448] // Prefetch B 138 PLD [r3, 128] // Prefetch A0 139 PLD [r12, 128] // Prefetch A1 140 PLD [r10, 128] // Prefetch A2 141 PLD [r0, 128] // Prefetch A3 142 BHS 1b 143 144 # Is there a remainder?- 1 float of A (4 bytes) 145 TST r5, 4 146 BNE 3f 147 1482: 149 # Clamp 150 VMAX.F32 q8, q8, q2 151 SUBS r1, r1, 8 152 VMAX.F32 q9, q9, q2 153 VMAX.F32 q10, q10, q2 154 VMAX.F32 q11, q11, q2 155 VMAX.F32 q12, q12, q2 156 VMAX.F32 q13, q13, q2 157 VMAX.F32 q14, q14, q2 158 VMAX.F32 q15, q15, q2 159 VMIN.F32 q8, q8, q3 160 VMIN.F32 q9, q9, q3 161 VMIN.F32 q10, q10, q3 162 VMIN.F32 q11, q11, q3 163 VMIN.F32 q12, q12, q3 164 VMIN.F32 q13, q13, q3 165 VMIN.F32 q14, q14, q3 166 VMIN.F32 q15, q15, q3 167 168 # Store full 4 x 8 169 BLO 4f 170 VST1.32 {d16-d19}, [r11], r7 171 SUB r0, r0, r2 172 VST1.32 {d20-d23}, [r4], r7 173 SUB r10, r10, r2 174 VST1.32 {d24-d27}, [r8], r7 175 SUB r12, r12, r2 176 VST1.32 {d28-d31}, [r6], r7 177 SUB r3, r3, r2 178 BHI 0b 179 180 VPOP {d8-d15} 181 POP {r4, r5, r6, r7, r8, r9, r10, r11} 182 BX lr 183 1843: 185 # Remainder- 1 float of A (4 bytes) 186 VLDM r3!, {s0} // A0 187 VLDM r9!, {d8-d11} // B0 188 VLDM r12!, {s2} // A1 189 VLDM r10!, {s4} // A2 190 VLDM r0!, {s6} // A3 191 VMLA.F32 q8, q4, d0[0] 192 VMLA.F32 q9, q5, d0[0] 193 VMLA.F32 q10, q4, d1[0] 194 VMLA.F32 q11, q5, d1[0] 195 VMLA.F32 q12, q4, d2[0] 196 VMLA.F32 q13, q5, d2[0] 197 VMLA.F32 q14, q4, d3[0] 198 VMLA.F32 q15, q5, d3[0] 199 B 2b 200 201 # Store odd width 2024: 203 TST r1, 4 204 BEQ 5f 205 VST1.32 {d16-d17}, [r11]! 206 VST1.32 {d20-d21}, [r4]! 207 VMOV q8, q9 208 VMOV q10, q11 209 VST1.32 {d24-d25}, [r8]! 210 VST1.32 {d28-d29}, [r6]! 211 VMOV q12, q13 212 VMOV q14, q15 213 2145: 215 TST r1, 2 216 BEQ 6f 217 VST1.32 {d16}, [r11]! 218 VST1.32 {d20}, [r4]! 219 VMOV d16, d17 220 VMOV d20, d21 221 VST1.32 {d24}, [r8]! 222 VST1.32 {d28}, [r6]! 223 VMOV d24, d25 224 VMOV d28, d29 225 2266: 227 TST r1, 1 228 BEQ 7f 229 VST1.32 {d16[0]}, [r11] 230 VST1.32 {d20[0]}, [r4] 231 VST1.32 {d24[0]}, [r8] 232 VST1.32 {d28[0]}, [r6] 233 2347: 235 VPOP {d8-d15} 236 POP {r4, r5, r6, r7, r8, r9, r10, r11} 237 BX lr 238 239END_FUNCTION xnn_f32_gemm_minmax_ukernel_4x8__aarch32_neon_cortex_a7 240 241#ifdef __ELF__ 242.section ".note.GNU-stack","",%progbits 243#endif 244 245