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