xref: /aosp_15_r20/external/gemmlowp/internal/output_neon.h (revision 5f39d1b313f0528e11bae88b3029b54b9e1033e7)
1*5f39d1b3SJooyung Han // Copyright 2015 The Gemmlowp Authors. All Rights Reserved.
2*5f39d1b3SJooyung Han //
3*5f39d1b3SJooyung Han // Licensed under the Apache License, Version 2.0 (the "License");
4*5f39d1b3SJooyung Han // you may not use this file except in compliance with the License.
5*5f39d1b3SJooyung Han // You may obtain a copy of the License at
6*5f39d1b3SJooyung Han //
7*5f39d1b3SJooyung Han //     http://www.apache.org/licenses/LICENSE-2.0
8*5f39d1b3SJooyung Han //
9*5f39d1b3SJooyung Han // Unless required by applicable law or agreed to in writing, software
10*5f39d1b3SJooyung Han // distributed under the License is distributed on an "AS IS" BASIS,
11*5f39d1b3SJooyung Han // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*5f39d1b3SJooyung Han // See the License for the specific language governing permissions and
13*5f39d1b3SJooyung Han // limitations under the License.
14*5f39d1b3SJooyung Han 
15*5f39d1b3SJooyung Han // output_neon.h: optimized NEON specializations of the templates in output.h.
16*5f39d1b3SJooyung Han 
17*5f39d1b3SJooyung Han #ifndef GEMMLOWP_INTERNAL_OUTPUT_NEON_H_
18*5f39d1b3SJooyung Han #define GEMMLOWP_INTERNAL_OUTPUT_NEON_H_
19*5f39d1b3SJooyung Han 
20*5f39d1b3SJooyung Han #include "output.h"
21*5f39d1b3SJooyung Han 
22*5f39d1b3SJooyung Han #include <arm_neon.h>
23*5f39d1b3SJooyung Han 
24*5f39d1b3SJooyung Han namespace gemmlowp {
25*5f39d1b3SJooyung Han 
26*5f39d1b3SJooyung Han template <>
27*5f39d1b3SJooyung Han struct OutputStageEvalBufferImpl<OutputStageSaturatingCastToUint8,
28*5f39d1b3SJooyung Han                                  RegBufferInt32<4>> {
29*5f39d1b3SJooyung Han   typedef RegBufferInt32<4> InputType;
30*5f39d1b3SJooyung Han   typedef RegBufferUint8<4> OutputType;
31*5f39d1b3SJooyung Han 
32*5f39d1b3SJooyung Han   typedef OutputStageSaturatingCastToUint8 OutputStage;
33*5f39d1b3SJooyung Han 
34*5f39d1b3SJooyung Han   OutputStageEvalBufferImpl(const OutputStage&) {}
35*5f39d1b3SJooyung Han 
36*5f39d1b3SJooyung Han   OutputType Eval(InputType input) const {
37*5f39d1b3SJooyung Han     OutputType output;
38*5f39d1b3SJooyung Han     int16x4_t res_16 = vqmovn_s32(input.reg[0]);
39*5f39d1b3SJooyung Han     uint8x8_t res_8 = vqmovun_s16(vcombine_s16(res_16, res_16));
40*5f39d1b3SJooyung Han     output.reg[0] = vget_lane_u32(vreinterpret_u32_u8(res_8), 0);
41*5f39d1b3SJooyung Han     return output;
42*5f39d1b3SJooyung Han   }
43*5f39d1b3SJooyung Han };
44*5f39d1b3SJooyung Han 
45*5f39d1b3SJooyung Han template <>
46*5f39d1b3SJooyung Han struct OutputStageEvalBufferImpl<OutputStageSaturatingCastToUint8,
47*5f39d1b3SJooyung Han                                  RegBufferInt32<8>> {
48*5f39d1b3SJooyung Han   typedef RegBufferInt32<8> InputType;
49*5f39d1b3SJooyung Han   typedef RegBufferUint8<8> OutputType;
50*5f39d1b3SJooyung Han 
51*5f39d1b3SJooyung Han   typedef OutputStageSaturatingCastToUint8 OutputStage;
52*5f39d1b3SJooyung Han 
53*5f39d1b3SJooyung Han   OutputStageEvalBufferImpl(const OutputStage&) {}
54*5f39d1b3SJooyung Han 
55*5f39d1b3SJooyung Han   OutputType Eval(InputType input) const {
56*5f39d1b3SJooyung Han     OutputType output;
57*5f39d1b3SJooyung Han     int16x8_t res_16 =
58*5f39d1b3SJooyung Han         vcombine_s16(vqmovn_s32(input.reg[0]), vqmovn_s32(input.reg[1]));
59*5f39d1b3SJooyung Han     output.reg[0] = vqmovun_s16(res_16);
60*5f39d1b3SJooyung Han     return output;
61*5f39d1b3SJooyung Han   }
62*5f39d1b3SJooyung Han };
63*5f39d1b3SJooyung Han 
64*5f39d1b3SJooyung Han template <>
65*5f39d1b3SJooyung Han struct OutputStageEvalBufferImpl<OutputStageSaturatingCastToUint8,
66*5f39d1b3SJooyung Han                                  RegBufferInt32<16>> {
67*5f39d1b3SJooyung Han   typedef RegBufferInt32<16> InputType;
68*5f39d1b3SJooyung Han   typedef RegBufferUint8<16> OutputType;
69*5f39d1b3SJooyung Han 
70*5f39d1b3SJooyung Han   typedef OutputStageSaturatingCastToUint8 OutputStage;
71*5f39d1b3SJooyung Han 
72*5f39d1b3SJooyung Han   OutputStageEvalBufferImpl(const OutputStage&) {}
73*5f39d1b3SJooyung Han 
74*5f39d1b3SJooyung Han   OutputType Eval(InputType input) const {
75*5f39d1b3SJooyung Han     OutputType output;
76*5f39d1b3SJooyung Han     int16x8_t res_16_0 =
77*5f39d1b3SJooyung Han         vcombine_s16(vqmovn_s32(input.reg[0]), vqmovn_s32(input.reg[1]));
78*5f39d1b3SJooyung Han     int16x8_t res_16_1 =
79*5f39d1b3SJooyung Han         vcombine_s16(vqmovn_s32(input.reg[2]), vqmovn_s32(input.reg[3]));
80*5f39d1b3SJooyung Han     output.reg[0] = vqmovun_s16(res_16_0);
81*5f39d1b3SJooyung Han     output.reg[1] = vqmovun_s16(res_16_1);
82*5f39d1b3SJooyung Han     return output;
83*5f39d1b3SJooyung Han   }
84*5f39d1b3SJooyung Han };
85*5f39d1b3SJooyung Han 
86*5f39d1b3SJooyung Han template <>
87*5f39d1b3SJooyung Han struct OutputStageEvalBufferImpl<OutputStageSaturatingCastToUint8,
88*5f39d1b3SJooyung Han                                  RegBufferInt32<32>> {
89*5f39d1b3SJooyung Han   typedef RegBufferInt32<32> InputType;
90*5f39d1b3SJooyung Han   typedef RegBufferUint8<32> OutputType;
91*5f39d1b3SJooyung Han 
92*5f39d1b3SJooyung Han   typedef OutputStageSaturatingCastToUint8 OutputStage;
93*5f39d1b3SJooyung Han 
94*5f39d1b3SJooyung Han   OutputStageEvalBufferImpl(const OutputStage&) {}
95*5f39d1b3SJooyung Han 
96*5f39d1b3SJooyung Han   OutputType Eval(InputType input) const {
97*5f39d1b3SJooyung Han     OutputType output;
98*5f39d1b3SJooyung Han     int16x8_t res_16[4];
99*5f39d1b3SJooyung Han     for (int i = 0; i < 4; i++) {
100*5f39d1b3SJooyung Han       res_16[i] = vcombine_s16(vqmovn_s32(input.reg[2 * i]),
101*5f39d1b3SJooyung Han                                vqmovn_s32(input.reg[2 * i + 1]));
102*5f39d1b3SJooyung Han     }
103*5f39d1b3SJooyung Han     for (int i = 0; i < 4; i++) {
104*5f39d1b3SJooyung Han       output.reg[i] = vqmovun_s16(res_16[i]);
105*5f39d1b3SJooyung Han     }
106*5f39d1b3SJooyung Han     return output;
107*5f39d1b3SJooyung Han   }
108*5f39d1b3SJooyung Han };
109*5f39d1b3SJooyung Han 
110*5f39d1b3SJooyung Han template <>
111*5f39d1b3SJooyung Han struct OutputStageEvalBufferImpl<OutputStageSaturatingCastToInt8,
112*5f39d1b3SJooyung Han                                  RegBufferInt32<4>> {
113*5f39d1b3SJooyung Han   typedef RegBufferInt32<4> InputType;
114*5f39d1b3SJooyung Han   typedef RegBufferInt8<4> OutputType;
115*5f39d1b3SJooyung Han 
116*5f39d1b3SJooyung Han   typedef OutputStageSaturatingCastToInt8 OutputStage;
117*5f39d1b3SJooyung Han 
118*5f39d1b3SJooyung Han   OutputStageEvalBufferImpl(const OutputStage&) {}
119*5f39d1b3SJooyung Han 
120*5f39d1b3SJooyung Han   OutputType Eval(InputType input) const {
121*5f39d1b3SJooyung Han     OutputType output;
122*5f39d1b3SJooyung Han     int16x4_t res_16 = vqmovn_s32(input.reg[0]);
123*5f39d1b3SJooyung Han     int8x8_t res_8 = vqmovn_s16(vcombine_s16(res_16, res_16));
124*5f39d1b3SJooyung Han     output.reg[0] = vget_lane_s32(vreinterpret_s32_s8(res_8), 0);
125*5f39d1b3SJooyung Han     return output;
126*5f39d1b3SJooyung Han   }
127*5f39d1b3SJooyung Han };
128*5f39d1b3SJooyung Han 
129*5f39d1b3SJooyung Han template <>
130*5f39d1b3SJooyung Han struct OutputStageEvalBufferImpl<OutputStageSaturatingCastToInt8,
131*5f39d1b3SJooyung Han                                  RegBufferInt32<8>> {
132*5f39d1b3SJooyung Han   typedef RegBufferInt32<8> InputType;
133*5f39d1b3SJooyung Han   typedef RegBufferInt8<8> OutputType;
134*5f39d1b3SJooyung Han 
135*5f39d1b3SJooyung Han   typedef OutputStageSaturatingCastToInt8 OutputStage;
136*5f39d1b3SJooyung Han 
137*5f39d1b3SJooyung Han   OutputStageEvalBufferImpl(const OutputStage&) {}
138*5f39d1b3SJooyung Han 
139*5f39d1b3SJooyung Han   OutputType Eval(InputType input) const {
140*5f39d1b3SJooyung Han     OutputType output;
141*5f39d1b3SJooyung Han     int16x8_t res_16 =
142*5f39d1b3SJooyung Han         vcombine_s16(vqmovn_s32(input.reg[0]), vqmovn_s32(input.reg[1]));
143*5f39d1b3SJooyung Han     output.reg[0] = vqmovn_s16(res_16);
144*5f39d1b3SJooyung Han     return output;
145*5f39d1b3SJooyung Han   }
146*5f39d1b3SJooyung Han };
147*5f39d1b3SJooyung Han 
148*5f39d1b3SJooyung Han template <>
149*5f39d1b3SJooyung Han struct OutputStageEvalBufferImpl<OutputStageSaturatingCastToInt8,
150*5f39d1b3SJooyung Han                                  RegBufferInt32<16>> {
151*5f39d1b3SJooyung Han   typedef RegBufferInt32<16> InputType;
152*5f39d1b3SJooyung Han   typedef RegBufferInt8<16> OutputType;
153*5f39d1b3SJooyung Han 
154*5f39d1b3SJooyung Han   typedef OutputStageSaturatingCastToInt8 OutputStage;
155*5f39d1b3SJooyung Han 
156*5f39d1b3SJooyung Han   OutputStageEvalBufferImpl(const OutputStage&) {}
157*5f39d1b3SJooyung Han 
158*5f39d1b3SJooyung Han   OutputType Eval(InputType input) const {
159*5f39d1b3SJooyung Han     OutputType output;
160*5f39d1b3SJooyung Han     int16x8_t res_16_0 =
161*5f39d1b3SJooyung Han         vcombine_s16(vqmovn_s32(input.reg[0]), vqmovn_s32(input.reg[1]));
162*5f39d1b3SJooyung Han     int16x8_t res_16_1 =
163*5f39d1b3SJooyung Han         vcombine_s16(vqmovn_s32(input.reg[2]), vqmovn_s32(input.reg[3]));
164*5f39d1b3SJooyung Han     output.reg[0] = vqmovn_s16(res_16_0);
165*5f39d1b3SJooyung Han     output.reg[1] = vqmovn_s16(res_16_1);
166*5f39d1b3SJooyung Han     return output;
167*5f39d1b3SJooyung Han   }
168*5f39d1b3SJooyung Han };
169*5f39d1b3SJooyung Han 
170*5f39d1b3SJooyung Han template <>
171*5f39d1b3SJooyung Han struct OutputStageEvalBufferImpl<OutputStageSaturatingCastToInt8,
172*5f39d1b3SJooyung Han                                  RegBufferInt32<32>> {
173*5f39d1b3SJooyung Han   typedef RegBufferInt32<32> InputType;
174*5f39d1b3SJooyung Han   typedef RegBufferInt8<32> OutputType;
175*5f39d1b3SJooyung Han 
176*5f39d1b3SJooyung Han   typedef OutputStageSaturatingCastToInt8 OutputStage;
177*5f39d1b3SJooyung Han 
178*5f39d1b3SJooyung Han   OutputStageEvalBufferImpl(const OutputStage&) {}
179*5f39d1b3SJooyung Han 
180*5f39d1b3SJooyung Han   OutputType Eval(InputType input) const {
181*5f39d1b3SJooyung Han     OutputType output;
182*5f39d1b3SJooyung Han     int16x8_t res_16[4];
183*5f39d1b3SJooyung Han     for (int i = 0; i < 4; i++) {
184*5f39d1b3SJooyung Han       res_16[i] = vcombine_s16(vqmovn_s32(input.reg[2 * i]),
185*5f39d1b3SJooyung Han                                vqmovn_s32(input.reg[2 * i + 1]));
186*5f39d1b3SJooyung Han     }
187*5f39d1b3SJooyung Han     for (int i = 0; i < 4; i++) {
188*5f39d1b3SJooyung Han       output.reg[i] = vqmovn_s16(res_16[i]);
189*5f39d1b3SJooyung Han     }
190*5f39d1b3SJooyung Han     return output;
191*5f39d1b3SJooyung Han   }
192*5f39d1b3SJooyung Han };
193*5f39d1b3SJooyung Han 
194*5f39d1b3SJooyung Han template <>
195*5f39d1b3SJooyung Han struct OutputStageEvalBufferImpl<OutputStageSaturatingCastToInt16,
196*5f39d1b3SJooyung Han                                  RegBufferInt32<4>> {
197*5f39d1b3SJooyung Han   typedef RegBufferInt32<4> InputType;
198*5f39d1b3SJooyung Han   typedef RegBufferInt16<4> OutputType;
199*5f39d1b3SJooyung Han 
200*5f39d1b3SJooyung Han   typedef OutputStageSaturatingCastToInt16 OutputStage;
201*5f39d1b3SJooyung Han 
202*5f39d1b3SJooyung Han   OutputStageEvalBufferImpl(const OutputStage&) {}
203*5f39d1b3SJooyung Han 
204*5f39d1b3SJooyung Han   OutputType Eval(InputType input) const {
205*5f39d1b3SJooyung Han     OutputType output;
206*5f39d1b3SJooyung Han     output.reg[0] = vqmovn_s32(input.reg[0]);
207*5f39d1b3SJooyung Han     return output;
208*5f39d1b3SJooyung Han   }
209*5f39d1b3SJooyung Han };
210*5f39d1b3SJooyung Han 
211*5f39d1b3SJooyung Han template <>
212*5f39d1b3SJooyung Han struct OutputStageEvalBufferImpl<OutputStageSaturatingCastToInt16,
213*5f39d1b3SJooyung Han                                  RegBufferInt32<8>> {
214*5f39d1b3SJooyung Han   typedef RegBufferInt32<8> InputType;
215*5f39d1b3SJooyung Han   typedef RegBufferInt16<8> OutputType;
216*5f39d1b3SJooyung Han 
217*5f39d1b3SJooyung Han   typedef OutputStageSaturatingCastToInt16 OutputStage;
218*5f39d1b3SJooyung Han 
219*5f39d1b3SJooyung Han   OutputStageEvalBufferImpl(const OutputStage&) {}
220*5f39d1b3SJooyung Han 
221*5f39d1b3SJooyung Han   OutputType Eval(InputType input) const {
222*5f39d1b3SJooyung Han     OutputType output;
223*5f39d1b3SJooyung Han     output.reg[0] =
224*5f39d1b3SJooyung Han         vcombine_s16(vqmovn_s32(input.reg[0]), vqmovn_s32(input.reg[1]));
225*5f39d1b3SJooyung Han     return output;
226*5f39d1b3SJooyung Han   }
227*5f39d1b3SJooyung Han };
228*5f39d1b3SJooyung Han 
229*5f39d1b3SJooyung Han template <>
230*5f39d1b3SJooyung Han struct OutputStageEvalBufferImpl<OutputStageSaturatingCastToInt16,
231*5f39d1b3SJooyung Han                                  RegBufferInt32<16>> {
232*5f39d1b3SJooyung Han   typedef RegBufferInt32<16> InputType;
233*5f39d1b3SJooyung Han   typedef RegBufferInt16<16> OutputType;
234*5f39d1b3SJooyung Han 
235*5f39d1b3SJooyung Han   typedef OutputStageSaturatingCastToInt16 OutputStage;
236*5f39d1b3SJooyung Han 
237*5f39d1b3SJooyung Han   OutputStageEvalBufferImpl(const OutputStage&) {}
238*5f39d1b3SJooyung Han 
239*5f39d1b3SJooyung Han   OutputType Eval(InputType input) const {
240*5f39d1b3SJooyung Han     OutputType output;
241*5f39d1b3SJooyung Han     output.reg[0] =
242*5f39d1b3SJooyung Han         vcombine_s16(vqmovn_s32(input.reg[0]), vqmovn_s32(input.reg[1]));
243*5f39d1b3SJooyung Han     output.reg[1] =
244*5f39d1b3SJooyung Han         vcombine_s16(vqmovn_s32(input.reg[2]), vqmovn_s32(input.reg[3]));
245*5f39d1b3SJooyung Han     return output;
246*5f39d1b3SJooyung Han   }
247*5f39d1b3SJooyung Han };
248*5f39d1b3SJooyung Han 
249*5f39d1b3SJooyung Han template <>
250*5f39d1b3SJooyung Han struct OutputStageEvalBufferImpl<OutputStageSaturatingCastToInt16,
251*5f39d1b3SJooyung Han                                  RegBufferInt32<32>> {
252*5f39d1b3SJooyung Han   typedef RegBufferInt32<32> InputType;
253*5f39d1b3SJooyung Han   typedef RegBufferInt16<32> OutputType;
254*5f39d1b3SJooyung Han 
255*5f39d1b3SJooyung Han   typedef OutputStageSaturatingCastToInt16 OutputStage;
256*5f39d1b3SJooyung Han 
257*5f39d1b3SJooyung Han   OutputStageEvalBufferImpl(const OutputStage&) {}
258*5f39d1b3SJooyung Han 
259*5f39d1b3SJooyung Han   OutputType Eval(InputType input) const {
260*5f39d1b3SJooyung Han     OutputType output;
261*5f39d1b3SJooyung Han     output.reg[0] =
262*5f39d1b3SJooyung Han         vcombine_s16(vqmovn_s32(input.reg[0]), vqmovn_s32(input.reg[1]));
263*5f39d1b3SJooyung Han     output.reg[1] =
264*5f39d1b3SJooyung Han         vcombine_s16(vqmovn_s32(input.reg[2]), vqmovn_s32(input.reg[3]));
265*5f39d1b3SJooyung Han     output.reg[2] =
266*5f39d1b3SJooyung Han         vcombine_s16(vqmovn_s32(input.reg[4]), vqmovn_s32(input.reg[5]));
267*5f39d1b3SJooyung Han     output.reg[3] =
268*5f39d1b3SJooyung Han         vcombine_s16(vqmovn_s32(input.reg[6]), vqmovn_s32(input.reg[7]));
269*5f39d1b3SJooyung Han     return output;
270*5f39d1b3SJooyung Han   }
271*5f39d1b3SJooyung Han };
272*5f39d1b3SJooyung Han 
273*5f39d1b3SJooyung Han template <typename DstType>
274*5f39d1b3SJooyung Han struct StoreFinalOutputImpl<RegBlockInt32<8, 1>, DstType> {
275*5f39d1b3SJooyung Han   static void Run(const RegBlockInt32<8, 1>& src, DstType* dst, int row,
276*5f39d1b3SJooyung Han                   int col) {
277*5f39d1b3SJooyung Han     if (DstType::kOrder == MapOrder::ColMajor) {
278*5f39d1b3SJooyung Han       StoreInt32x4(dst->data(row, col), src.buf.reg[0]);
279*5f39d1b3SJooyung Han       StoreInt32x4(dst->data(row + 4, col), src.buf.reg[1]);
280*5f39d1b3SJooyung Han     } else {
281*5f39d1b3SJooyung Han       vst1q_lane_s32(dst->data(row + 0, col), src.buf.reg[0], 0);
282*5f39d1b3SJooyung Han       vst1q_lane_s32(dst->data(row + 1, col), src.buf.reg[0], 1);
283*5f39d1b3SJooyung Han       vst1q_lane_s32(dst->data(row + 2, col), src.buf.reg[0], 2);
284*5f39d1b3SJooyung Han       vst1q_lane_s32(dst->data(row + 3, col), src.buf.reg[0], 3);
285*5f39d1b3SJooyung Han       vst1q_lane_s32(dst->data(row + 4, col), src.buf.reg[1], 0);
286*5f39d1b3SJooyung Han       vst1q_lane_s32(dst->data(row + 5, col), src.buf.reg[1], 1);
287*5f39d1b3SJooyung Han       vst1q_lane_s32(dst->data(row + 6, col), src.buf.reg[1], 2);
288*5f39d1b3SJooyung Han       vst1q_lane_s32(dst->data(row + 7, col), src.buf.reg[1], 3);
289*5f39d1b3SJooyung Han     }
290*5f39d1b3SJooyung Han   }
291*5f39d1b3SJooyung Han };
292*5f39d1b3SJooyung Han 
293*5f39d1b3SJooyung Han template <typename DstType>
294*5f39d1b3SJooyung Han struct StoreFinalOutputImpl<RegBlockInt16<4, 1>, DstType> {
295*5f39d1b3SJooyung Han   static void Run(const RegBlockInt16<4, 1>& src, DstType* dst, int row,
296*5f39d1b3SJooyung Han                   int col) {
297*5f39d1b3SJooyung Han     if (DstType::kOrder == MapOrder::ColMajor) {
298*5f39d1b3SJooyung Han       StoreInt16x4(dst->data(row, col), src.buf.reg[0]);
299*5f39d1b3SJooyung Han     } else {
300*5f39d1b3SJooyung Han       vst1_lane_s16(dst->data(row + 0, col), src.buf.reg[0], 0);
301*5f39d1b3SJooyung Han       vst1_lane_s16(dst->data(row + 1, col), src.buf.reg[0], 1);
302*5f39d1b3SJooyung Han       vst1_lane_s16(dst->data(row + 2, col), src.buf.reg[0], 2);
303*5f39d1b3SJooyung Han       vst1_lane_s16(dst->data(row + 3, col), src.buf.reg[0], 3);
304*5f39d1b3SJooyung Han     }
305*5f39d1b3SJooyung Han   }
306*5f39d1b3SJooyung Han };
307*5f39d1b3SJooyung Han 
308*5f39d1b3SJooyung Han template <typename DstType>
309*5f39d1b3SJooyung Han struct StoreFinalOutputImpl<RegBlockInt16<8, 1>, DstType> {
310*5f39d1b3SJooyung Han   static void Run(const RegBlockInt16<8, 1>& src, DstType* dst, int row,
311*5f39d1b3SJooyung Han                   int col) {
312*5f39d1b3SJooyung Han     if (DstType::kOrder == MapOrder::ColMajor) {
313*5f39d1b3SJooyung Han       StoreInt16x8(dst->data(row, col), src.buf.reg[0]);
314*5f39d1b3SJooyung Han     } else {
315*5f39d1b3SJooyung Han       vst1q_lane_s16(dst->data(row + 0, col), src.buf.reg[0], 0);
316*5f39d1b3SJooyung Han       vst1q_lane_s16(dst->data(row + 1, col), src.buf.reg[0], 1);
317*5f39d1b3SJooyung Han       vst1q_lane_s16(dst->data(row + 2, col), src.buf.reg[0], 2);
318*5f39d1b3SJooyung Han       vst1q_lane_s16(dst->data(row + 3, col), src.buf.reg[0], 3);
319*5f39d1b3SJooyung Han       vst1q_lane_s16(dst->data(row + 4, col), src.buf.reg[0], 4);
320*5f39d1b3SJooyung Han       vst1q_lane_s16(dst->data(row + 5, col), src.buf.reg[0], 5);
321*5f39d1b3SJooyung Han       vst1q_lane_s16(dst->data(row + 6, col), src.buf.reg[0], 6);
322*5f39d1b3SJooyung Han       vst1q_lane_s16(dst->data(row + 7, col), src.buf.reg[0], 7);
323*5f39d1b3SJooyung Han     }
324*5f39d1b3SJooyung Han   }
325*5f39d1b3SJooyung Han };
326*5f39d1b3SJooyung Han 
327*5f39d1b3SJooyung Han inline RegBlockInt32<4, 4> Transpose(const RegBlockInt32<4, 4>& src) {
328*5f39d1b3SJooyung Han   const int32x4x2_t t0 = vtrnq_s32(src.buf.reg[0], src.buf.reg[1]);
329*5f39d1b3SJooyung Han   const int32x4x2_t t1 = vtrnq_s32(src.buf.reg[2], src.buf.reg[3]);
330*5f39d1b3SJooyung Han   RegBlockInt32<4, 4> result;
331*5f39d1b3SJooyung Han   result.buf.reg[0] =
332*5f39d1b3SJooyung Han       vcombine_s32(vget_low_s32(t0.val[0]), vget_low_s32(t1.val[0]));
333*5f39d1b3SJooyung Han   result.buf.reg[1] =
334*5f39d1b3SJooyung Han       vcombine_s32(vget_low_s32(t0.val[1]), vget_low_s32(t1.val[1]));
335*5f39d1b3SJooyung Han   result.buf.reg[2] =
336*5f39d1b3SJooyung Han       vcombine_s32(vget_high_s32(t0.val[0]), vget_high_s32(t1.val[0]));
337*5f39d1b3SJooyung Han   result.buf.reg[3] =
338*5f39d1b3SJooyung Han       vcombine_s32(vget_high_s32(t0.val[1]), vget_high_s32(t1.val[1]));
339*5f39d1b3SJooyung Han   return result;
340*5f39d1b3SJooyung Han }
341*5f39d1b3SJooyung Han 
342*5f39d1b3SJooyung Han template <typename DstType>
343*5f39d1b3SJooyung Han struct StoreFinalOutputImpl<RegBlockInt32<4, 4>, DstType> {
344*5f39d1b3SJooyung Han   static void Run(const RegBlockInt32<4, 4>& src, DstType* dst, int row,
345*5f39d1b3SJooyung Han                   int col) {
346*5f39d1b3SJooyung Han     const auto& block =
347*5f39d1b3SJooyung Han         DstType::kOrder == MapOrder::ColMajor ? src : Transpose(src);
348*5f39d1b3SJooyung Han     std::int32_t* dst_ptr = dst->data(row, col);
349*5f39d1b3SJooyung Han     int stride = dst->stride();
350*5f39d1b3SJooyung Han     for (int i = 0; i < 4; i++) {
351*5f39d1b3SJooyung Han       vst1q_s32(dst_ptr + i * stride, block.buf.reg[i]);
352*5f39d1b3SJooyung Han     }
353*5f39d1b3SJooyung Han   }
354*5f39d1b3SJooyung Han };
355*5f39d1b3SJooyung Han 
356*5f39d1b3SJooyung Han template <typename DstType>
357*5f39d1b3SJooyung Han struct StoreFinalOutputImpl<RegBlockInt16<4, 4>, DstType> {
358*5f39d1b3SJooyung Han   static void Run(const RegBlockInt16<4, 4>& src, DstType* dst, int row,
359*5f39d1b3SJooyung Han                   int col) {
360*5f39d1b3SJooyung Han     if (DstType::kOrder == MapOrder::ColMajor) {
361*5f39d1b3SJooyung Han       vst1_s16(dst->data(row, col + 0), vget_low_s16(src.buf.reg[0]));
362*5f39d1b3SJooyung Han       vst1_s16(dst->data(row, col + 1), vget_high_s16(src.buf.reg[0]));
363*5f39d1b3SJooyung Han       vst1_s16(dst->data(row, col + 2), vget_low_s16(src.buf.reg[1]));
364*5f39d1b3SJooyung Han       vst1_s16(dst->data(row, col + 3), vget_high_s16(src.buf.reg[1]));
365*5f39d1b3SJooyung Han     } else {
366*5f39d1b3SJooyung Han       const int16x4x2_t t0 =
367*5f39d1b3SJooyung Han           vtrn_s16(vget_low_s16(src.buf.reg[0]), vget_high_s16(src.buf.reg[0]));
368*5f39d1b3SJooyung Han       const int16x4x2_t t1 =
369*5f39d1b3SJooyung Han           vtrn_s16(vget_low_s16(src.buf.reg[1]), vget_high_s16(src.buf.reg[1]));
370*5f39d1b3SJooyung Han       const int32x4x2_t t =
371*5f39d1b3SJooyung Han           vtrnq_s32(vreinterpretq_s32_s16(vcombine_s16(t0.val[0], t0.val[1])),
372*5f39d1b3SJooyung Han                     vreinterpretq_s32_s16(vcombine_s16(t1.val[0], t1.val[1])));
373*5f39d1b3SJooyung Han       vst1_s16(dst->data(row + 0, col),
374*5f39d1b3SJooyung Han                vget_low_s16(vreinterpretq_s16_s32(t.val[0])));
375*5f39d1b3SJooyung Han       vst1_s16(dst->data(row + 1, col),
376*5f39d1b3SJooyung Han                vget_high_s16(vreinterpretq_s16_s32(t.val[0])));
377*5f39d1b3SJooyung Han       vst1_s16(dst->data(row + 2, col),
378*5f39d1b3SJooyung Han                vget_low_s16(vreinterpretq_s16_s32(t.val[1])));
379*5f39d1b3SJooyung Han       vst1_s16(dst->data(row + 3, col),
380*5f39d1b3SJooyung Han                vget_high_s16(vreinterpretq_s16_s32(t.val[1])));
381*5f39d1b3SJooyung Han     }
382*5f39d1b3SJooyung Han   }
383*5f39d1b3SJooyung Han };
384*5f39d1b3SJooyung Han 
385*5f39d1b3SJooyung Han template <typename DstType>
386*5f39d1b3SJooyung Han struct StoreFinalOutputImpl<RegBlockInt32<8, 4>, DstType> {
387*5f39d1b3SJooyung Han   static void Run(const RegBlockInt32<8, 4>& src, DstType* dst, int row,
388*5f39d1b3SJooyung Han                   int col) {
389*5f39d1b3SJooyung Han     std::int32_t* dst_ptr = dst->data(row, col);
390*5f39d1b3SJooyung Han     if (DstType::kOrder == MapOrder::ColMajor) {
391*5f39d1b3SJooyung Han       int col_stride = dst->cols_stride();
392*5f39d1b3SJooyung Han       for (int i = 0; i < 4; i++) {
393*5f39d1b3SJooyung Han         vst1q_s32(dst_ptr + i * col_stride + 0, src.buf.reg[2 * i + 0]);
394*5f39d1b3SJooyung Han         vst1q_s32(dst_ptr + i * col_stride + 4, src.buf.reg[2 * i + 1]);
395*5f39d1b3SJooyung Han       }
396*5f39d1b3SJooyung Han     } else {
397*5f39d1b3SJooyung Han       int row_stride = dst->rows_stride();
398*5f39d1b3SJooyung Han       RegBlockInt32<4, 4> top;
399*5f39d1b3SJooyung Han       top.buf.reg[0] = src.buf.reg[0];
400*5f39d1b3SJooyung Han       top.buf.reg[1] = src.buf.reg[2];
401*5f39d1b3SJooyung Han       top.buf.reg[2] = src.buf.reg[4];
402*5f39d1b3SJooyung Han       top.buf.reg[3] = src.buf.reg[6];
403*5f39d1b3SJooyung Han       const auto transpose_top = Transpose(top);
404*5f39d1b3SJooyung Han       for (int i = 0; i < 4; i++) {
405*5f39d1b3SJooyung Han         vst1q_s32(dst_ptr + i * row_stride, transpose_top.buf.reg[i]);
406*5f39d1b3SJooyung Han       }
407*5f39d1b3SJooyung Han       RegBlockInt32<4, 4> bottom;
408*5f39d1b3SJooyung Han       bottom.buf.reg[0] = src.buf.reg[1];
409*5f39d1b3SJooyung Han       bottom.buf.reg[1] = src.buf.reg[3];
410*5f39d1b3SJooyung Han       bottom.buf.reg[2] = src.buf.reg[5];
411*5f39d1b3SJooyung Han       bottom.buf.reg[3] = src.buf.reg[7];
412*5f39d1b3SJooyung Han       const auto transpose_bottom = Transpose(bottom);
413*5f39d1b3SJooyung Han       for (int i = 0; i < 4; i++) {
414*5f39d1b3SJooyung Han         vst1q_s32(dst_ptr + (i + 4) * row_stride, transpose_bottom.buf.reg[i]);
415*5f39d1b3SJooyung Han       }
416*5f39d1b3SJooyung Han     }
417*5f39d1b3SJooyung Han   }
418*5f39d1b3SJooyung Han };
419*5f39d1b3SJooyung Han 
420*5f39d1b3SJooyung Han template <typename DstType>
421*5f39d1b3SJooyung Han struct StoreFinalOutputImpl<RegBlockInt16<8, 4>, DstType> {
422*5f39d1b3SJooyung Han   static void Run(const RegBlockInt16<8, 4>& src, DstType* dst, int row,
423*5f39d1b3SJooyung Han                   int col) {
424*5f39d1b3SJooyung Han     if (DstType::kOrder == MapOrder::ColMajor) {
425*5f39d1b3SJooyung Han       vst1q_s16(dst->data(row, col + 0), src.buf.reg[0]);
426*5f39d1b3SJooyung Han       vst1q_s16(dst->data(row, col + 1), src.buf.reg[1]);
427*5f39d1b3SJooyung Han       vst1q_s16(dst->data(row, col + 2), src.buf.reg[2]);
428*5f39d1b3SJooyung Han       vst1q_s16(dst->data(row, col + 3), src.buf.reg[3]);
429*5f39d1b3SJooyung Han     } else {
430*5f39d1b3SJooyung Han       const int16x8x2_t t0 = vtrnq_s16(src.buf.reg[0], src.buf.reg[1]);
431*5f39d1b3SJooyung Han       const int16x8x2_t t1 = vtrnq_s16(src.buf.reg[2], src.buf.reg[3]);
432*5f39d1b3SJooyung Han       const int32x4x2_t u0 = vtrnq_s32(vreinterpretq_s32_s16(t0.val[0]),
433*5f39d1b3SJooyung Han                                        vreinterpretq_s32_s16(t1.val[0]));
434*5f39d1b3SJooyung Han       const int32x4x2_t u1 = vtrnq_s32(vreinterpretq_s32_s16(t0.val[1]),
435*5f39d1b3SJooyung Han                                        vreinterpretq_s32_s16(t1.val[1]));
436*5f39d1b3SJooyung Han       vst1_s16(dst->data(row + 0, col),
437*5f39d1b3SJooyung Han                vget_low_s16(vreinterpretq_s16_s32(u0.val[0])));
438*5f39d1b3SJooyung Han       vst1_s16(dst->data(row + 1, col),
439*5f39d1b3SJooyung Han                vget_low_s16(vreinterpretq_s16_s32(u1.val[0])));
440*5f39d1b3SJooyung Han       vst1_s16(dst->data(row + 2, col),
441*5f39d1b3SJooyung Han                vget_low_s16(vreinterpretq_s16_s32(u0.val[1])));
442*5f39d1b3SJooyung Han       vst1_s16(dst->data(row + 3, col),
443*5f39d1b3SJooyung Han                vget_low_s16(vreinterpretq_s16_s32(u1.val[1])));
444*5f39d1b3SJooyung Han       vst1_s16(dst->data(row + 4, col),
445*5f39d1b3SJooyung Han                vget_high_s16(vreinterpretq_s16_s32(u0.val[0])));
446*5f39d1b3SJooyung Han       vst1_s16(dst->data(row + 5, col),
447*5f39d1b3SJooyung Han                vget_high_s16(vreinterpretq_s16_s32(u1.val[0])));
448*5f39d1b3SJooyung Han       vst1_s16(dst->data(row + 6, col),
449*5f39d1b3SJooyung Han                vget_high_s16(vreinterpretq_s16_s32(u0.val[1])));
450*5f39d1b3SJooyung Han       vst1_s16(dst->data(row + 7, col),
451*5f39d1b3SJooyung Han                vget_high_s16(vreinterpretq_s16_s32(u1.val[1])));
452*5f39d1b3SJooyung Han     }
453*5f39d1b3SJooyung Han   }
454*5f39d1b3SJooyung Han };
455*5f39d1b3SJooyung Han 
456*5f39d1b3SJooyung Han template <typename DstType>
457*5f39d1b3SJooyung Han struct StoreFinalOutputImpl<RegBlockInt32<8, 8>, DstType> {
458*5f39d1b3SJooyung Han   static void Run(const RegBlockInt32<8, 8>& src, DstType* dst, int row,
459*5f39d1b3SJooyung Han                   int col) {
460*5f39d1b3SJooyung Han     std::int32_t* dst_ptr = dst->data(row, col);
461*5f39d1b3SJooyung Han     if (DstType::kOrder == MapOrder::ColMajor) {
462*5f39d1b3SJooyung Han       int col_stride = dst->cols_stride();
463*5f39d1b3SJooyung Han       for (int i = 0; i < 8; i++) {
464*5f39d1b3SJooyung Han         vst1q_s32(dst_ptr + i * col_stride, src.buf.reg[2 * i]);
465*5f39d1b3SJooyung Han         vst1q_s32(dst_ptr + i * col_stride + 4, src.buf.reg[2 * i + 1]);
466*5f39d1b3SJooyung Han       }
467*5f39d1b3SJooyung Han     } else {
468*5f39d1b3SJooyung Han       int row_stride = dst->rows_stride();
469*5f39d1b3SJooyung Han       RegBlockInt32<4, 4> top_left;
470*5f39d1b3SJooyung Han       top_left.buf.reg[0] = src.buf.reg[0];
471*5f39d1b3SJooyung Han       top_left.buf.reg[1] = src.buf.reg[2];
472*5f39d1b3SJooyung Han       top_left.buf.reg[2] = src.buf.reg[4];
473*5f39d1b3SJooyung Han       top_left.buf.reg[3] = src.buf.reg[6];
474*5f39d1b3SJooyung Han       const auto transpose_top_left = Transpose(top_left);
475*5f39d1b3SJooyung Han       for (int i = 0; i < 4; i++) {
476*5f39d1b3SJooyung Han         vst1q_s32(dst_ptr + i * row_stride, transpose_top_left.buf.reg[i]);
477*5f39d1b3SJooyung Han       }
478*5f39d1b3SJooyung Han       RegBlockInt32<4, 4> bottom_left;
479*5f39d1b3SJooyung Han       bottom_left.buf.reg[0] = src.buf.reg[1];
480*5f39d1b3SJooyung Han       bottom_left.buf.reg[1] = src.buf.reg[3];
481*5f39d1b3SJooyung Han       bottom_left.buf.reg[2] = src.buf.reg[5];
482*5f39d1b3SJooyung Han       bottom_left.buf.reg[3] = src.buf.reg[7];
483*5f39d1b3SJooyung Han       const auto transpose_bottom_left = Transpose(bottom_left);
484*5f39d1b3SJooyung Han       for (int i = 0; i < 4; i++) {
485*5f39d1b3SJooyung Han         vst1q_s32(dst_ptr + (i + 4) * row_stride,
486*5f39d1b3SJooyung Han                   transpose_bottom_left.buf.reg[i]);
487*5f39d1b3SJooyung Han       }
488*5f39d1b3SJooyung Han       RegBlockInt32<4, 4> top_right;
489*5f39d1b3SJooyung Han       top_right.buf.reg[0] = src.buf.reg[8];
490*5f39d1b3SJooyung Han       top_right.buf.reg[1] = src.buf.reg[10];
491*5f39d1b3SJooyung Han       top_right.buf.reg[2] = src.buf.reg[12];
492*5f39d1b3SJooyung Han       top_right.buf.reg[3] = src.buf.reg[14];
493*5f39d1b3SJooyung Han       const auto transpose_top_right = Transpose(top_right);
494*5f39d1b3SJooyung Han       for (int i = 0; i < 4; i++) {
495*5f39d1b3SJooyung Han         vst1q_s32(dst_ptr + i * row_stride + 4, transpose_top_right.buf.reg[i]);
496*5f39d1b3SJooyung Han       }
497*5f39d1b3SJooyung Han       RegBlockInt32<4, 4> bottom_right;
498*5f39d1b3SJooyung Han       bottom_right.buf.reg[0] = src.buf.reg[9];
499*5f39d1b3SJooyung Han       bottom_right.buf.reg[1] = src.buf.reg[11];
500*5f39d1b3SJooyung Han       bottom_right.buf.reg[2] = src.buf.reg[13];
501*5f39d1b3SJooyung Han       bottom_right.buf.reg[3] = src.buf.reg[15];
502*5f39d1b3SJooyung Han       const auto transpose_bottom_right = Transpose(bottom_right);
503*5f39d1b3SJooyung Han       for (int i = 0; i < 4; i++) {
504*5f39d1b3SJooyung Han         vst1q_s32(dst_ptr + (i + 4) * row_stride + 4,
505*5f39d1b3SJooyung Han                   transpose_bottom_right.buf.reg[i]);
506*5f39d1b3SJooyung Han       }
507*5f39d1b3SJooyung Han     }
508*5f39d1b3SJooyung Han   }
509*5f39d1b3SJooyung Han };
510*5f39d1b3SJooyung Han 
511*5f39d1b3SJooyung Han template <typename DstType>
512*5f39d1b3SJooyung Han struct StoreFinalOutputImpl<RegBlockInt32<4, 1>, DstType> {
513*5f39d1b3SJooyung Han   static void Run(const RegBlockInt32<4, 1>& src, DstType* dst, int row,
514*5f39d1b3SJooyung Han                   int col) {
515*5f39d1b3SJooyung Han     std::int32_t* dst_ptr = dst->data(row, col);
516*5f39d1b3SJooyung Han     if (DstType::kOrder == MapOrder::ColMajor) {
517*5f39d1b3SJooyung Han       vst1q_s32(dst_ptr, src.buf.reg[0]);
518*5f39d1b3SJooyung Han     } else {
519*5f39d1b3SJooyung Han       int row_stride = dst->rows_stride();
520*5f39d1b3SJooyung Han       vst1q_lane_s32(dst_ptr + 0 * row_stride, src.buf.reg[0], 0);
521*5f39d1b3SJooyung Han       vst1q_lane_s32(dst_ptr + 1 * row_stride, src.buf.reg[0], 1);
522*5f39d1b3SJooyung Han       vst1q_lane_s32(dst_ptr + 2 * row_stride, src.buf.reg[0], 2);
523*5f39d1b3SJooyung Han       vst1q_lane_s32(dst_ptr + 3 * row_stride, src.buf.reg[0], 3);
524*5f39d1b3SJooyung Han     }
525*5f39d1b3SJooyung Han   }
526*5f39d1b3SJooyung Han };
527*5f39d1b3SJooyung Han 
528*5f39d1b3SJooyung Han template <typename DstType>
529*5f39d1b3SJooyung Han struct StoreFinalOutputImpl<RegBlockInt32<1, 4>, DstType> {
530*5f39d1b3SJooyung Han   static void Run(const RegBlockInt32<1, 4>& src, DstType* dst, int row,
531*5f39d1b3SJooyung Han                   int col) {
532*5f39d1b3SJooyung Han     std::int32_t* dst_ptr = dst->data(row, col);
533*5f39d1b3SJooyung Han     if (DstType::kOrder == MapOrder::RowMajor) {
534*5f39d1b3SJooyung Han       vst1q_s32(dst_ptr, src.buf.reg[0]);
535*5f39d1b3SJooyung Han     } else {
536*5f39d1b3SJooyung Han       int col_stride = dst->cols_stride();
537*5f39d1b3SJooyung Han       vst1q_lane_s32(dst_ptr + 0 * col_stride, src.buf.reg[0], 0);
538*5f39d1b3SJooyung Han       vst1q_lane_s32(dst_ptr + 1 * col_stride, src.buf.reg[0], 1);
539*5f39d1b3SJooyung Han       vst1q_lane_s32(dst_ptr + 2 * col_stride, src.buf.reg[0], 2);
540*5f39d1b3SJooyung Han       vst1q_lane_s32(dst_ptr + 3 * col_stride, src.buf.reg[0], 3);
541*5f39d1b3SJooyung Han     }
542*5f39d1b3SJooyung Han   }
543*5f39d1b3SJooyung Han };
544*5f39d1b3SJooyung Han 
545*5f39d1b3SJooyung Han template <typename DstType>
546*5f39d1b3SJooyung Han struct StoreFinalOutputImpl<RegBlockInt16<1, 4>, DstType> {
547*5f39d1b3SJooyung Han   static void Run(const RegBlockInt16<1, 4>& src, DstType* dst, int row,
548*5f39d1b3SJooyung Han                   int col) {
549*5f39d1b3SJooyung Han     std::int16_t* dst_ptr = dst->data(row, col);
550*5f39d1b3SJooyung Han     if (DstType::kOrder == MapOrder::RowMajor) {
551*5f39d1b3SJooyung Han       vst1_s16(dst_ptr, src.buf.reg[0]);
552*5f39d1b3SJooyung Han     } else {
553*5f39d1b3SJooyung Han       int col_stride = dst->cols_stride();
554*5f39d1b3SJooyung Han       vst1_lane_s16(dst_ptr + 0 * col_stride, src.buf.reg[0], 0);
555*5f39d1b3SJooyung Han       vst1_lane_s16(dst_ptr + 1 * col_stride, src.buf.reg[0], 1);
556*5f39d1b3SJooyung Han       vst1_lane_s16(dst_ptr + 2 * col_stride, src.buf.reg[0], 2);
557*5f39d1b3SJooyung Han       vst1_lane_s16(dst_ptr + 3 * col_stride, src.buf.reg[0], 3);
558*5f39d1b3SJooyung Han     }
559*5f39d1b3SJooyung Han   }
560*5f39d1b3SJooyung Han };
561*5f39d1b3SJooyung Han 
562*5f39d1b3SJooyung Han template <typename DstType>
563*5f39d1b3SJooyung Han struct StoreFinalOutputImpl<RegBlockUint8<4, 1>, DstType> {
564*5f39d1b3SJooyung Han   static void Run(const RegBlockUint8<4, 1>& src, DstType* dst, int row,
565*5f39d1b3SJooyung Han                   int col) {
566*5f39d1b3SJooyung Han     const std::uint32_t src_reg = src.buf.reg[0];
567*5f39d1b3SJooyung Han     for (int i = 0; i < 4; i++) {
568*5f39d1b3SJooyung Han       *dst->data(row + i, col) = (src_reg >> (8 * i));
569*5f39d1b3SJooyung Han     }
570*5f39d1b3SJooyung Han   }
571*5f39d1b3SJooyung Han };
572*5f39d1b3SJooyung Han 
573*5f39d1b3SJooyung Han template <typename DstType>
574*5f39d1b3SJooyung Han struct StoreFinalOutputImpl<RegBlockUint8<1, 4>, DstType> {
575*5f39d1b3SJooyung Han   static void Run(const RegBlockUint8<1, 4>& src, DstType* dst, int row,
576*5f39d1b3SJooyung Han                   int col) {
577*5f39d1b3SJooyung Han     for (int i = 0; i < 4; i++) {
578*5f39d1b3SJooyung Han       *dst->data(row, col + i) = (src.buf.reg[0] >> (8 * i));
579*5f39d1b3SJooyung Han     }
580*5f39d1b3SJooyung Han   }
581*5f39d1b3SJooyung Han };
582*5f39d1b3SJooyung Han 
583*5f39d1b3SJooyung Han template <typename DstType>
584*5f39d1b3SJooyung Han struct StoreFinalOutputImpl<RegBlockUint8<8, 1>, DstType> {
585*5f39d1b3SJooyung Han   static void Run(const RegBlockUint8<8, 1>& src, DstType* dst, int row,
586*5f39d1b3SJooyung Han                   int col) {
587*5f39d1b3SJooyung Han     std::uint8_t* dst_ptr = dst->data(row, col);
588*5f39d1b3SJooyung Han     if (DstType::kOrder == MapOrder::ColMajor) {
589*5f39d1b3SJooyung Han       vst1_u8(dst_ptr, src.buf.reg[0]);
590*5f39d1b3SJooyung Han     } else {
591*5f39d1b3SJooyung Han       const int row_stride = dst->rows_stride();
592*5f39d1b3SJooyung Han       vst1_lane_u8(dst_ptr + 0 * row_stride, src.buf.reg[0], 0);
593*5f39d1b3SJooyung Han       vst1_lane_u8(dst_ptr + 1 * row_stride, src.buf.reg[0], 1);
594*5f39d1b3SJooyung Han       vst1_lane_u8(dst_ptr + 2 * row_stride, src.buf.reg[0], 2);
595*5f39d1b3SJooyung Han       vst1_lane_u8(dst_ptr + 3 * row_stride, src.buf.reg[0], 3);
596*5f39d1b3SJooyung Han       vst1_lane_u8(dst_ptr + 4 * row_stride, src.buf.reg[0], 4);
597*5f39d1b3SJooyung Han       vst1_lane_u8(dst_ptr + 5 * row_stride, src.buf.reg[0], 5);
598*5f39d1b3SJooyung Han       vst1_lane_u8(dst_ptr + 6 * row_stride, src.buf.reg[0], 6);
599*5f39d1b3SJooyung Han       vst1_lane_u8(dst_ptr + 7 * row_stride, src.buf.reg[0], 7);
600*5f39d1b3SJooyung Han     }
601*5f39d1b3SJooyung Han   }
602*5f39d1b3SJooyung Han };
603*5f39d1b3SJooyung Han 
604*5f39d1b3SJooyung Han template <typename DstType>
605*5f39d1b3SJooyung Han struct StoreFinalOutputImpl<RegBlockUint8<4, 4>, DstType> {
606*5f39d1b3SJooyung Han   static void Run(const RegBlockUint8<4, 4>& src, DstType* dst, int row,
607*5f39d1b3SJooyung Han                   int col) {
608*5f39d1b3SJooyung Han     std::uint8_t* dst_ptr = dst->data(row, col);
609*5f39d1b3SJooyung Han     const int row_stride = dst->rows_stride();
610*5f39d1b3SJooyung Han     const int col_stride = dst->cols_stride();
611*5f39d1b3SJooyung Han     for (int i = 0; i < 2; i++) {
612*5f39d1b3SJooyung Han       vst1_lane_u8(dst_ptr + 0 * row_stride + (2 * i + 0) * col_stride,
613*5f39d1b3SJooyung Han                    src.buf.reg[i], 0);
614*5f39d1b3SJooyung Han       vst1_lane_u8(dst_ptr + 1 * row_stride + (2 * i + 0) * col_stride,
615*5f39d1b3SJooyung Han                    src.buf.reg[i], 1);
616*5f39d1b3SJooyung Han       vst1_lane_u8(dst_ptr + 2 * row_stride + (2 * i + 0) * col_stride,
617*5f39d1b3SJooyung Han                    src.buf.reg[i], 2);
618*5f39d1b3SJooyung Han       vst1_lane_u8(dst_ptr + 3 * row_stride + (2 * i + 0) * col_stride,
619*5f39d1b3SJooyung Han                    src.buf.reg[i], 3);
620*5f39d1b3SJooyung Han       vst1_lane_u8(dst_ptr + 0 * row_stride + (2 * i + 1) * col_stride,
621*5f39d1b3SJooyung Han                    src.buf.reg[i], 4);
622*5f39d1b3SJooyung Han       vst1_lane_u8(dst_ptr + 1 * row_stride + (2 * i + 1) * col_stride,
623*5f39d1b3SJooyung Han                    src.buf.reg[i], 5);
624*5f39d1b3SJooyung Han       vst1_lane_u8(dst_ptr + 2 * row_stride + (2 * i + 1) * col_stride,
625*5f39d1b3SJooyung Han                    src.buf.reg[i], 6);
626*5f39d1b3SJooyung Han       vst1_lane_u8(dst_ptr + 3 * row_stride + (2 * i + 1) * col_stride,
627*5f39d1b3SJooyung Han                    src.buf.reg[i], 7);
628*5f39d1b3SJooyung Han     }
629*5f39d1b3SJooyung Han   }
630*5f39d1b3SJooyung Han };
631*5f39d1b3SJooyung Han 
632*5f39d1b3SJooyung Han template <typename DstType>
633*5f39d1b3SJooyung Han struct StoreFinalOutputImpl<RegBlockUint8<8, 4>, DstType> {
634*5f39d1b3SJooyung Han   static void Run(const RegBlockUint8<8, 4>& src, DstType* dst, int row,
635*5f39d1b3SJooyung Han                   int col) {
636*5f39d1b3SJooyung Han     std::uint8_t* dst_ptr = dst->data(row, col);
637*5f39d1b3SJooyung Han     if (DstType::kOrder == MapOrder::ColMajor) {
638*5f39d1b3SJooyung Han       int col_stride = dst->cols_stride();
639*5f39d1b3SJooyung Han       for (int i = 0; i < 4; i++) {
640*5f39d1b3SJooyung Han         vst1_u8(dst_ptr + i * col_stride, src.buf.reg[i]);
641*5f39d1b3SJooyung Han       }
642*5f39d1b3SJooyung Han     } else {
643*5f39d1b3SJooyung Han       int row_stride = dst->rows_stride();
644*5f39d1b3SJooyung Han       for (int i = 0; i < 4; i++) {
645*5f39d1b3SJooyung Han         std::uint8_t* col_ptr = dst_ptr + i;
646*5f39d1b3SJooyung Han         vst1_lane_u8(col_ptr + 0 * row_stride, src.buf.reg[i], 0);
647*5f39d1b3SJooyung Han         vst1_lane_u8(col_ptr + 1 * row_stride, src.buf.reg[i], 1);
648*5f39d1b3SJooyung Han         vst1_lane_u8(col_ptr + 2 * row_stride, src.buf.reg[i], 2);
649*5f39d1b3SJooyung Han         vst1_lane_u8(col_ptr + 3 * row_stride, src.buf.reg[i], 3);
650*5f39d1b3SJooyung Han         vst1_lane_u8(col_ptr + 4 * row_stride, src.buf.reg[i], 4);
651*5f39d1b3SJooyung Han         vst1_lane_u8(col_ptr + 5 * row_stride, src.buf.reg[i], 5);
652*5f39d1b3SJooyung Han         vst1_lane_u8(col_ptr + 6 * row_stride, src.buf.reg[i], 6);
653*5f39d1b3SJooyung Han         vst1_lane_u8(col_ptr + 7 * row_stride, src.buf.reg[i], 7);
654*5f39d1b3SJooyung Han       }
655*5f39d1b3SJooyung Han     }
656*5f39d1b3SJooyung Han   }
657*5f39d1b3SJooyung Han };
658*5f39d1b3SJooyung Han 
659*5f39d1b3SJooyung Han inline RegBlockUint8<8, 8> Transpose(const RegBlockUint8<8, 8>& src) {
660*5f39d1b3SJooyung Han   uint8x8x2_t a[4];
661*5f39d1b3SJooyung Han   a[0] = vtrn_u8(src.buf.reg[0], src.buf.reg[1]);
662*5f39d1b3SJooyung Han   a[1] = vtrn_u8(src.buf.reg[2], src.buf.reg[3]);
663*5f39d1b3SJooyung Han   a[2] = vtrn_u8(src.buf.reg[4], src.buf.reg[5]);
664*5f39d1b3SJooyung Han   a[3] = vtrn_u8(src.buf.reg[6], src.buf.reg[7]);
665*5f39d1b3SJooyung Han   uint16x4x2_t b[4];
666*5f39d1b3SJooyung Han   b[0] = vtrn_u16(vreinterpret_u16_u8(a[0].val[0]),
667*5f39d1b3SJooyung Han                   vreinterpret_u16_u8(a[1].val[0]));
668*5f39d1b3SJooyung Han   b[1] = vtrn_u16(vreinterpret_u16_u8(a[0].val[1]),
669*5f39d1b3SJooyung Han                   vreinterpret_u16_u8(a[1].val[1]));
670*5f39d1b3SJooyung Han   b[2] = vtrn_u16(vreinterpret_u16_u8(a[2].val[0]),
671*5f39d1b3SJooyung Han                   vreinterpret_u16_u8(a[3].val[0]));
672*5f39d1b3SJooyung Han   b[3] = vtrn_u16(vreinterpret_u16_u8(a[2].val[1]),
673*5f39d1b3SJooyung Han                   vreinterpret_u16_u8(a[3].val[1]));
674*5f39d1b3SJooyung Han   uint32x2x2_t c[4];
675*5f39d1b3SJooyung Han   c[0] = vtrn_u32(vreinterpret_u32_u16(b[0].val[0]),
676*5f39d1b3SJooyung Han                   vreinterpret_u32_u16(b[2].val[0]));
677*5f39d1b3SJooyung Han   c[1] = vtrn_u32(vreinterpret_u32_u16(b[1].val[0]),
678*5f39d1b3SJooyung Han                   vreinterpret_u32_u16(b[3].val[0]));
679*5f39d1b3SJooyung Han   c[2] = vtrn_u32(vreinterpret_u32_u16(b[0].val[1]),
680*5f39d1b3SJooyung Han                   vreinterpret_u32_u16(b[2].val[1]));
681*5f39d1b3SJooyung Han   c[3] = vtrn_u32(vreinterpret_u32_u16(b[1].val[1]),
682*5f39d1b3SJooyung Han                   vreinterpret_u32_u16(b[3].val[1]));
683*5f39d1b3SJooyung Han   RegBlockUint8<8, 8> result;
684*5f39d1b3SJooyung Han   result.buf.reg[0] = vreinterpret_u8_u32(c[0].val[0]);
685*5f39d1b3SJooyung Han   result.buf.reg[1] = vreinterpret_u8_u32(c[1].val[0]);
686*5f39d1b3SJooyung Han   result.buf.reg[2] = vreinterpret_u8_u32(c[2].val[0]);
687*5f39d1b3SJooyung Han   result.buf.reg[3] = vreinterpret_u8_u32(c[3].val[0]);
688*5f39d1b3SJooyung Han   result.buf.reg[4] = vreinterpret_u8_u32(c[0].val[1]);
689*5f39d1b3SJooyung Han   result.buf.reg[5] = vreinterpret_u8_u32(c[1].val[1]);
690*5f39d1b3SJooyung Han   result.buf.reg[6] = vreinterpret_u8_u32(c[2].val[1]);
691*5f39d1b3SJooyung Han   result.buf.reg[7] = vreinterpret_u8_u32(c[3].val[1]);
692*5f39d1b3SJooyung Han   return result;
693*5f39d1b3SJooyung Han }
694*5f39d1b3SJooyung Han 
695*5f39d1b3SJooyung Han template <typename DstType>
696*5f39d1b3SJooyung Han struct StoreFinalOutputImpl<RegBlockUint8<8, 8>, DstType> {
697*5f39d1b3SJooyung Han   static void Run(const RegBlockUint8<8, 8>& src, DstType* dst, int row,
698*5f39d1b3SJooyung Han                   int col) {
699*5f39d1b3SJooyung Han     const auto& block =
700*5f39d1b3SJooyung Han         DstType::kOrder == MapOrder::ColMajor ? src : Transpose(src);
701*5f39d1b3SJooyung Han     std::uint8_t* dst_ptr = dst->data(row, col);
702*5f39d1b3SJooyung Han     int stride = dst->stride();
703*5f39d1b3SJooyung Han     for (int i = 0; i < 8; i++) {
704*5f39d1b3SJooyung Han       vst1_u8(dst_ptr + i * stride, block.buf.reg[i]);
705*5f39d1b3SJooyung Han     }
706*5f39d1b3SJooyung Han   }
707*5f39d1b3SJooyung Han };
708*5f39d1b3SJooyung Han 
709*5f39d1b3SJooyung Han template <typename DstType>
710*5f39d1b3SJooyung Han struct StoreFinalOutputImpl<RegBlockInt8<4, 1>, DstType> {
711*5f39d1b3SJooyung Han   static void Run(const RegBlockInt8<4, 1>& src, DstType* dst, int row,
712*5f39d1b3SJooyung Han                   int col) {
713*5f39d1b3SJooyung Han     const std::int32_t src_reg = src.buf.reg[0];
714*5f39d1b3SJooyung Han     for (int i = 0; i < 4; i++) {
715*5f39d1b3SJooyung Han       *dst->data(row + i, col) = (src_reg >> (8 * i));
716*5f39d1b3SJooyung Han     }
717*5f39d1b3SJooyung Han   }
718*5f39d1b3SJooyung Han };
719*5f39d1b3SJooyung Han 
720*5f39d1b3SJooyung Han template <typename DstType>
721*5f39d1b3SJooyung Han struct StoreFinalOutputImpl<RegBlockInt8<1, 4>, DstType> {
722*5f39d1b3SJooyung Han   static void Run(const RegBlockInt8<1, 4>& src, DstType* dst, int row,
723*5f39d1b3SJooyung Han                   int col) {
724*5f39d1b3SJooyung Han     for (int i = 0; i < 4; i++) {
725*5f39d1b3SJooyung Han       *dst->data(row, col + i) = (src.buf.reg[0] >> (8 * i));
726*5f39d1b3SJooyung Han     }
727*5f39d1b3SJooyung Han   }
728*5f39d1b3SJooyung Han };
729*5f39d1b3SJooyung Han 
730*5f39d1b3SJooyung Han template <typename DstType>
731*5f39d1b3SJooyung Han struct StoreFinalOutputImpl<RegBlockInt8<8, 1>, DstType> {
732*5f39d1b3SJooyung Han   static void Run(const RegBlockInt8<8, 1>& src, DstType* dst, int row,
733*5f39d1b3SJooyung Han                   int col) {
734*5f39d1b3SJooyung Han     std::int8_t* dst_ptr = dst->data(row, col);
735*5f39d1b3SJooyung Han     if (DstType::kOrder == MapOrder::ColMajor) {
736*5f39d1b3SJooyung Han       vst1_s8(dst_ptr, src.buf.reg[0]);
737*5f39d1b3SJooyung Han     } else {
738*5f39d1b3SJooyung Han       const int row_stride = dst->rows_stride();
739*5f39d1b3SJooyung Han       vst1_lane_s8(dst_ptr + 0 * row_stride, src.buf.reg[0], 0);
740*5f39d1b3SJooyung Han       vst1_lane_s8(dst_ptr + 1 * row_stride, src.buf.reg[0], 1);
741*5f39d1b3SJooyung Han       vst1_lane_s8(dst_ptr + 2 * row_stride, src.buf.reg[0], 2);
742*5f39d1b3SJooyung Han       vst1_lane_s8(dst_ptr + 3 * row_stride, src.buf.reg[0], 3);
743*5f39d1b3SJooyung Han       vst1_lane_s8(dst_ptr + 4 * row_stride, src.buf.reg[0], 4);
744*5f39d1b3SJooyung Han       vst1_lane_s8(dst_ptr + 5 * row_stride, src.buf.reg[0], 5);
745*5f39d1b3SJooyung Han       vst1_lane_s8(dst_ptr + 6 * row_stride, src.buf.reg[0], 6);
746*5f39d1b3SJooyung Han       vst1_lane_s8(dst_ptr + 7 * row_stride, src.buf.reg[0], 7);
747*5f39d1b3SJooyung Han     }
748*5f39d1b3SJooyung Han   }
749*5f39d1b3SJooyung Han };
750*5f39d1b3SJooyung Han 
751*5f39d1b3SJooyung Han template <typename DstType>
752*5f39d1b3SJooyung Han struct StoreFinalOutputImpl<RegBlockInt8<4, 4>, DstType> {
753*5f39d1b3SJooyung Han   static void Run(const RegBlockInt8<4, 4>& src, DstType* dst, int row,
754*5f39d1b3SJooyung Han                   int col) {
755*5f39d1b3SJooyung Han     std::int8_t* dst_ptr = dst->data(row, col);
756*5f39d1b3SJooyung Han     const int row_stride = dst->rows_stride();
757*5f39d1b3SJooyung Han     const int col_stride = dst->cols_stride();
758*5f39d1b3SJooyung Han     for (int i = 0; i < 2; i++) {
759*5f39d1b3SJooyung Han       vst1_lane_s8(dst_ptr + 0 * row_stride + (2 * i + 0) * col_stride,
760*5f39d1b3SJooyung Han                    src.buf.reg[i], 0);
761*5f39d1b3SJooyung Han       vst1_lane_s8(dst_ptr + 1 * row_stride + (2 * i + 0) * col_stride,
762*5f39d1b3SJooyung Han                    src.buf.reg[i], 1);
763*5f39d1b3SJooyung Han       vst1_lane_s8(dst_ptr + 2 * row_stride + (2 * i + 0) * col_stride,
764*5f39d1b3SJooyung Han                    src.buf.reg[i], 2);
765*5f39d1b3SJooyung Han       vst1_lane_s8(dst_ptr + 3 * row_stride + (2 * i + 0) * col_stride,
766*5f39d1b3SJooyung Han                    src.buf.reg[i], 3);
767*5f39d1b3SJooyung Han       vst1_lane_s8(dst_ptr + 0 * row_stride + (2 * i + 1) * col_stride,
768*5f39d1b3SJooyung Han                    src.buf.reg[i], 4);
769*5f39d1b3SJooyung Han       vst1_lane_s8(dst_ptr + 1 * row_stride + (2 * i + 1) * col_stride,
770*5f39d1b3SJooyung Han                    src.buf.reg[i], 5);
771*5f39d1b3SJooyung Han       vst1_lane_s8(dst_ptr + 2 * row_stride + (2 * i + 1) * col_stride,
772*5f39d1b3SJooyung Han                    src.buf.reg[i], 6);
773*5f39d1b3SJooyung Han       vst1_lane_s8(dst_ptr + 3 * row_stride + (2 * i + 1) * col_stride,
774*5f39d1b3SJooyung Han                    src.buf.reg[i], 7);
775*5f39d1b3SJooyung Han     }
776*5f39d1b3SJooyung Han   }
777*5f39d1b3SJooyung Han };
778*5f39d1b3SJooyung Han 
779*5f39d1b3SJooyung Han template <typename DstType>
780*5f39d1b3SJooyung Han struct StoreFinalOutputImpl<RegBlockInt8<8, 4>, DstType> {
781*5f39d1b3SJooyung Han   static void Run(const RegBlockInt8<8, 4>& src, DstType* dst, int row,
782*5f39d1b3SJooyung Han                   int col) {
783*5f39d1b3SJooyung Han     std::int8_t* dst_ptr = dst->data(row, col);
784*5f39d1b3SJooyung Han     if (DstType::kOrder == MapOrder::ColMajor) {
785*5f39d1b3SJooyung Han       int col_stride = dst->cols_stride();
786*5f39d1b3SJooyung Han       for (int i = 0; i < 4; i++) {
787*5f39d1b3SJooyung Han         vst1_s8(dst_ptr + i * col_stride, src.buf.reg[i]);
788*5f39d1b3SJooyung Han       }
789*5f39d1b3SJooyung Han     } else {
790*5f39d1b3SJooyung Han       int row_stride = dst->rows_stride();
791*5f39d1b3SJooyung Han       for (int i = 0; i < 4; i++) {
792*5f39d1b3SJooyung Han         std::int8_t* col_ptr = dst_ptr + i;
793*5f39d1b3SJooyung Han         vst1_lane_s8(col_ptr + 0 * row_stride, src.buf.reg[i], 0);
794*5f39d1b3SJooyung Han         vst1_lane_s8(col_ptr + 1 * row_stride, src.buf.reg[i], 1);
795*5f39d1b3SJooyung Han         vst1_lane_s8(col_ptr + 2 * row_stride, src.buf.reg[i], 2);
796*5f39d1b3SJooyung Han         vst1_lane_s8(col_ptr + 3 * row_stride, src.buf.reg[i], 3);
797*5f39d1b3SJooyung Han         vst1_lane_s8(col_ptr + 4 * row_stride, src.buf.reg[i], 4);
798*5f39d1b3SJooyung Han         vst1_lane_s8(col_ptr + 5 * row_stride, src.buf.reg[i], 5);
799*5f39d1b3SJooyung Han         vst1_lane_s8(col_ptr + 6 * row_stride, src.buf.reg[i], 6);
800*5f39d1b3SJooyung Han         vst1_lane_s8(col_ptr + 7 * row_stride, src.buf.reg[i], 7);
801*5f39d1b3SJooyung Han       }
802*5f39d1b3SJooyung Han     }
803*5f39d1b3SJooyung Han   }
804*5f39d1b3SJooyung Han };
805*5f39d1b3SJooyung Han 
806*5f39d1b3SJooyung Han inline RegBlockInt8<8, 8> Transpose(const RegBlockInt8<8, 8>& src) {
807*5f39d1b3SJooyung Han   int8x8x2_t a[4];
808*5f39d1b3SJooyung Han   a[0] = vtrn_s8(src.buf.reg[0], src.buf.reg[1]);
809*5f39d1b3SJooyung Han   a[1] = vtrn_s8(src.buf.reg[2], src.buf.reg[3]);
810*5f39d1b3SJooyung Han   a[2] = vtrn_s8(src.buf.reg[4], src.buf.reg[5]);
811*5f39d1b3SJooyung Han   a[3] = vtrn_s8(src.buf.reg[6], src.buf.reg[7]);
812*5f39d1b3SJooyung Han   int16x4x2_t b[4];
813*5f39d1b3SJooyung Han   b[0] = vtrn_s16(vreinterpret_s16_s8(a[0].val[0]),
814*5f39d1b3SJooyung Han                   vreinterpret_s16_s8(a[1].val[0]));
815*5f39d1b3SJooyung Han   b[1] = vtrn_s16(vreinterpret_s16_s8(a[0].val[1]),
816*5f39d1b3SJooyung Han                   vreinterpret_s16_s8(a[1].val[1]));
817*5f39d1b3SJooyung Han   b[2] = vtrn_s16(vreinterpret_s16_s8(a[2].val[0]),
818*5f39d1b3SJooyung Han                   vreinterpret_s16_s8(a[3].val[0]));
819*5f39d1b3SJooyung Han   b[3] = vtrn_s16(vreinterpret_s16_s8(a[2].val[1]),
820*5f39d1b3SJooyung Han                   vreinterpret_s16_s8(a[3].val[1]));
821*5f39d1b3SJooyung Han   int32x2x2_t c[4];
822*5f39d1b3SJooyung Han   c[0] = vtrn_s32(vreinterpret_s32_s16(b[0].val[0]),
823*5f39d1b3SJooyung Han                   vreinterpret_s32_s16(b[2].val[0]));
824*5f39d1b3SJooyung Han   c[1] = vtrn_s32(vreinterpret_s32_s16(b[1].val[0]),
825*5f39d1b3SJooyung Han                   vreinterpret_s32_s16(b[3].val[0]));
826*5f39d1b3SJooyung Han   c[2] = vtrn_s32(vreinterpret_s32_s16(b[0].val[1]),
827*5f39d1b3SJooyung Han                   vreinterpret_s32_s16(b[2].val[1]));
828*5f39d1b3SJooyung Han   c[3] = vtrn_s32(vreinterpret_s32_s16(b[1].val[1]),
829*5f39d1b3SJooyung Han                   vreinterpret_s32_s16(b[3].val[1]));
830*5f39d1b3SJooyung Han   RegBlockInt8<8, 8> result;
831*5f39d1b3SJooyung Han   result.buf.reg[0] = vreinterpret_s8_s32(c[0].val[0]);
832*5f39d1b3SJooyung Han   result.buf.reg[1] = vreinterpret_s8_s32(c[1].val[0]);
833*5f39d1b3SJooyung Han   result.buf.reg[2] = vreinterpret_s8_s32(c[2].val[0]);
834*5f39d1b3SJooyung Han   result.buf.reg[3] = vreinterpret_s8_s32(c[3].val[0]);
835*5f39d1b3SJooyung Han   result.buf.reg[4] = vreinterpret_s8_s32(c[0].val[1]);
836*5f39d1b3SJooyung Han   result.buf.reg[5] = vreinterpret_s8_s32(c[1].val[1]);
837*5f39d1b3SJooyung Han   result.buf.reg[6] = vreinterpret_s8_s32(c[2].val[1]);
838*5f39d1b3SJooyung Han   result.buf.reg[7] = vreinterpret_s8_s32(c[3].val[1]);
839*5f39d1b3SJooyung Han   return result;
840*5f39d1b3SJooyung Han }
841*5f39d1b3SJooyung Han 
842*5f39d1b3SJooyung Han template <typename DstType>
843*5f39d1b3SJooyung Han struct StoreFinalOutputImpl<RegBlockInt8<8, 8>, DstType> {
844*5f39d1b3SJooyung Han   static void Run(const RegBlockInt8<8, 8>& src, DstType* dst, int row,
845*5f39d1b3SJooyung Han                   int col) {
846*5f39d1b3SJooyung Han     const auto& block =
847*5f39d1b3SJooyung Han         DstType::kOrder == MapOrder::ColMajor ? src : Transpose(src);
848*5f39d1b3SJooyung Han     std::int8_t* dst_ptr = dst->data(row, col);
849*5f39d1b3SJooyung Han     int stride = dst->stride();
850*5f39d1b3SJooyung Han     for (int i = 0; i < 8; i++) {
851*5f39d1b3SJooyung Han       vst1_s8(dst_ptr + i * stride, block.buf.reg[i]);
852*5f39d1b3SJooyung Han     }
853*5f39d1b3SJooyung Han   }
854*5f39d1b3SJooyung Han };
855*5f39d1b3SJooyung Han 
856*5f39d1b3SJooyung Han template <typename DstType>
857*5f39d1b3SJooyung Han struct StoreFinalOutputImpl<RegBlockInt16<8, 8>, DstType> {
858*5f39d1b3SJooyung Han   static void Run(const RegBlockInt16<8, 8>& src, DstType* dst, int row,
859*5f39d1b3SJooyung Han                   int col) {
860*5f39d1b3SJooyung Han     if (DstType::kOrder == MapOrder::ColMajor) {
861*5f39d1b3SJooyung Han       vst1q_s16(dst->data(row, col + 0), src.buf.reg[0]);
862*5f39d1b3SJooyung Han       vst1q_s16(dst->data(row, col + 1), src.buf.reg[1]);
863*5f39d1b3SJooyung Han       vst1q_s16(dst->data(row, col + 2), src.buf.reg[2]);
864*5f39d1b3SJooyung Han       vst1q_s16(dst->data(row, col + 3), src.buf.reg[3]);
865*5f39d1b3SJooyung Han       vst1q_s16(dst->data(row, col + 4), src.buf.reg[4]);
866*5f39d1b3SJooyung Han       vst1q_s16(dst->data(row, col + 5), src.buf.reg[5]);
867*5f39d1b3SJooyung Han       vst1q_s16(dst->data(row, col + 6), src.buf.reg[6]);
868*5f39d1b3SJooyung Han       vst1q_s16(dst->data(row, col + 7), src.buf.reg[7]);
869*5f39d1b3SJooyung Han     } else {
870*5f39d1b3SJooyung Han       int16x8x2_t a[4];
871*5f39d1b3SJooyung Han       a[0] = vtrnq_s16(src.buf.reg[0], src.buf.reg[1]);
872*5f39d1b3SJooyung Han       a[1] = vtrnq_s16(src.buf.reg[2], src.buf.reg[3]);
873*5f39d1b3SJooyung Han       a[2] = vtrnq_s16(src.buf.reg[4], src.buf.reg[5]);
874*5f39d1b3SJooyung Han       a[3] = vtrnq_s16(src.buf.reg[6], src.buf.reg[7]);
875*5f39d1b3SJooyung Han       int32x4x2_t b[4];
876*5f39d1b3SJooyung Han       b[0] = vtrnq_s32(vreinterpretq_s32_s16(a[0].val[0]),
877*5f39d1b3SJooyung Han                        vreinterpretq_s32_s16(a[1].val[0]));
878*5f39d1b3SJooyung Han       b[1] = vtrnq_s32(vreinterpretq_s32_s16(a[0].val[1]),
879*5f39d1b3SJooyung Han                        vreinterpretq_s32_s16(a[1].val[1]));
880*5f39d1b3SJooyung Han       b[2] = vtrnq_s32(vreinterpretq_s32_s16(a[2].val[0]),
881*5f39d1b3SJooyung Han                        vreinterpretq_s32_s16(a[3].val[0]));
882*5f39d1b3SJooyung Han       b[3] = vtrnq_s32(vreinterpretq_s32_s16(a[2].val[1]),
883*5f39d1b3SJooyung Han                        vreinterpretq_s32_s16(a[3].val[1]));
884*5f39d1b3SJooyung Han       vst1_s16(dst->data(row + 0, col + 0),
885*5f39d1b3SJooyung Han                vget_low_s16(vreinterpretq_s16_s32(b[0].val[0])));
886*5f39d1b3SJooyung Han       vst1_s16(dst->data(row + 0, col + 4),
887*5f39d1b3SJooyung Han                vget_low_s16(vreinterpretq_s16_s32(b[2].val[0])));
888*5f39d1b3SJooyung Han       vst1_s16(dst->data(row + 1, col + 0),
889*5f39d1b3SJooyung Han                vget_low_s16(vreinterpretq_s16_s32(b[1].val[0])));
890*5f39d1b3SJooyung Han       vst1_s16(dst->data(row + 1, col + 4),
891*5f39d1b3SJooyung Han                vget_low_s16(vreinterpretq_s16_s32(b[3].val[0])));
892*5f39d1b3SJooyung Han       vst1_s16(dst->data(row + 2, col + 0),
893*5f39d1b3SJooyung Han                vget_low_s16(vreinterpretq_s16_s32(b[0].val[1])));
894*5f39d1b3SJooyung Han       vst1_s16(dst->data(row + 2, col + 4),
895*5f39d1b3SJooyung Han                vget_low_s16(vreinterpretq_s16_s32(b[2].val[1])));
896*5f39d1b3SJooyung Han       vst1_s16(dst->data(row + 3, col + 0),
897*5f39d1b3SJooyung Han                vget_low_s16(vreinterpretq_s16_s32(b[1].val[1])));
898*5f39d1b3SJooyung Han       vst1_s16(dst->data(row + 3, col + 4),
899*5f39d1b3SJooyung Han                vget_low_s16(vreinterpretq_s16_s32(b[3].val[1])));
900*5f39d1b3SJooyung Han       vst1_s16(dst->data(row + 4, col + 0),
901*5f39d1b3SJooyung Han                vget_high_s16(vreinterpretq_s16_s32(b[0].val[0])));
902*5f39d1b3SJooyung Han       vst1_s16(dst->data(row + 4, col + 4),
903*5f39d1b3SJooyung Han                vget_high_s16(vreinterpretq_s16_s32(b[2].val[0])));
904*5f39d1b3SJooyung Han       vst1_s16(dst->data(row + 5, col + 0),
905*5f39d1b3SJooyung Han                vget_high_s16(vreinterpretq_s16_s32(b[1].val[0])));
906*5f39d1b3SJooyung Han       vst1_s16(dst->data(row + 5, col + 4),
907*5f39d1b3SJooyung Han                vget_high_s16(vreinterpretq_s16_s32(b[3].val[0])));
908*5f39d1b3SJooyung Han       vst1_s16(dst->data(row + 6, col + 0),
909*5f39d1b3SJooyung Han                vget_high_s16(vreinterpretq_s16_s32(b[0].val[1])));
910*5f39d1b3SJooyung Han       vst1_s16(dst->data(row + 6, col + 4),
911*5f39d1b3SJooyung Han                vget_high_s16(vreinterpretq_s16_s32(b[2].val[1])));
912*5f39d1b3SJooyung Han       vst1_s16(dst->data(row + 7, col + 0),
913*5f39d1b3SJooyung Han                vget_high_s16(vreinterpretq_s16_s32(b[1].val[1])));
914*5f39d1b3SJooyung Han       vst1_s16(dst->data(row + 7, col + 4),
915*5f39d1b3SJooyung Han                vget_high_s16(vreinterpretq_s16_s32(b[3].val[1])));
916*5f39d1b3SJooyung Han     }
917*5f39d1b3SJooyung Han   }
918*5f39d1b3SJooyung Han };
919*5f39d1b3SJooyung Han 
920*5f39d1b3SJooyung Han }  // namespace gemmlowp
921*5f39d1b3SJooyung Han 
922*5f39d1b3SJooyung Han #endif  // GEMMLOWP_INTERNAL_OUTPUT_NEON_H_
923