xref: /aosp_15_r20/external/gemmlowp/internal/output_msa.h (revision 5f39d1b313f0528e11bae88b3029b54b9e1033e7)
1*5f39d1b3SJooyung Han // Copyright 2018 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_msa.h: optimized MSA specializations of the templates in output.h.
16*5f39d1b3SJooyung Han 
17*5f39d1b3SJooyung Han #ifndef GEMMLOWP_INTERNAL_OUTPUT_MSA_H_
18*5f39d1b3SJooyung Han #define GEMMLOWP_INTERNAL_OUTPUT_MSA_H_
19*5f39d1b3SJooyung Han 
20*5f39d1b3SJooyung Han #include "output.h"
21*5f39d1b3SJooyung Han 
22*5f39d1b3SJooyung Han #include <msa.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     // Signed saturate each 32-bit element to 9 bits
39*5f39d1b3SJooyung Han     // (this takes full care of non-negative elements).
40*5f39d1b3SJooyung Han     v4i32 tmp = __builtin_msa_sat_s_w(input.reg[0], 8);
41*5f39d1b3SJooyung Han     // Zero out negative elements.
42*5f39d1b3SJooyung Han     tmp = __builtin_msa_maxi_s_w(tmp, 0);
43*5f39d1b3SJooyung Han     // Pack every 32-bit element into 16 bits.
44*5f39d1b3SJooyung Han     tmp = reinterpret_cast<v4i32>(__builtin_msa_pckev_h(
45*5f39d1b3SJooyung Han         reinterpret_cast<v8i16>(tmp), reinterpret_cast<v8i16>(tmp)));
46*5f39d1b3SJooyung Han     // Pack every element into 8 bits.
47*5f39d1b3SJooyung Han     tmp = reinterpret_cast<v4i32>(__builtin_msa_pckev_b(
48*5f39d1b3SJooyung Han         reinterpret_cast<v16i8>(tmp), reinterpret_cast<v16i8>(tmp)));
49*5f39d1b3SJooyung Han     // Return 4 uint8_t elements as uint32_t.
50*5f39d1b3SJooyung Han     output.reg[0] = __builtin_msa_copy_s_w(tmp, 0);
51*5f39d1b3SJooyung Han     return output;
52*5f39d1b3SJooyung Han   }
53*5f39d1b3SJooyung Han };
54*5f39d1b3SJooyung Han 
55*5f39d1b3SJooyung Han template <>
56*5f39d1b3SJooyung Han struct OutputStageEvalBufferImpl<OutputStageSaturatingCastToUint8,
57*5f39d1b3SJooyung Han                                  RegBufferInt32<8>> {
58*5f39d1b3SJooyung Han   typedef RegBufferInt32<8> InputType;
59*5f39d1b3SJooyung Han   typedef RegBufferUint8<8> OutputType;
60*5f39d1b3SJooyung Han 
61*5f39d1b3SJooyung Han   typedef OutputStageSaturatingCastToUint8 OutputStage;
62*5f39d1b3SJooyung Han 
63*5f39d1b3SJooyung Han   OutputStageEvalBufferImpl(const OutputStage&) {}
64*5f39d1b3SJooyung Han 
65*5f39d1b3SJooyung Han   OutputType Eval(InputType input) const {
66*5f39d1b3SJooyung Han     OutputType output;
67*5f39d1b3SJooyung Han     // Signed saturate each 32-bit element to 9 bits
68*5f39d1b3SJooyung Han     // (this takes full care of non-negative elements).
69*5f39d1b3SJooyung Han     v4i32 tmp_lo = __builtin_msa_sat_s_w(input.reg[0], 8);
70*5f39d1b3SJooyung Han     v4i32 tmp_hi = __builtin_msa_sat_s_w(input.reg[1], 8);
71*5f39d1b3SJooyung Han     // Pack every 32-bit element into 16 bits,
72*5f39d1b3SJooyung Han     // combining all 8 elements into one vector.
73*5f39d1b3SJooyung Han     tmp_lo = reinterpret_cast<v4i32>(__builtin_msa_pckev_h(
74*5f39d1b3SJooyung Han         reinterpret_cast<v8i16>(tmp_hi), reinterpret_cast<v8i16>(tmp_lo)));
75*5f39d1b3SJooyung Han     // Zero out negative elements.
76*5f39d1b3SJooyung Han     tmp_lo = reinterpret_cast<v4i32>(__builtin_msa_maxi_s_h(
77*5f39d1b3SJooyung Han         reinterpret_cast<v8i16>(tmp_lo), 0));
78*5f39d1b3SJooyung Han     // Pack every element into 8 bits.
79*5f39d1b3SJooyung Han     tmp_lo = reinterpret_cast<v4i32>(__builtin_msa_pckev_b(
80*5f39d1b3SJooyung Han         reinterpret_cast<v16i8>(tmp_lo), reinterpret_cast<v16i8>(tmp_lo)));
81*5f39d1b3SJooyung Han     // Return 8 uint8_t elements as 2 uint32_t's.
82*5f39d1b3SJooyung Han     output.reg[0] = __builtin_msa_copy_s_w(tmp_lo, 0);
83*5f39d1b3SJooyung Han     output.reg[1] = __builtin_msa_copy_s_w(tmp_lo, 1);
84*5f39d1b3SJooyung Han     return output;
85*5f39d1b3SJooyung Han   }
86*5f39d1b3SJooyung Han };
87*5f39d1b3SJooyung Han 
88*5f39d1b3SJooyung Han #define GEMMLOWP_MIPS_SAT_U8_16(out, in0, in1, in2, in3)                     \
89*5f39d1b3SJooyung Han   {                                                                          \
90*5f39d1b3SJooyung Han     v4i32 tmp0 = __builtin_msa_sat_s_w(in0, 8);                              \
91*5f39d1b3SJooyung Han     v4i32 tmp1 = __builtin_msa_sat_s_w(in1, 8);                              \
92*5f39d1b3SJooyung Han     v4i32 tmp2 = __builtin_msa_sat_s_w(in2, 8);                              \
93*5f39d1b3SJooyung Han     v4i32 tmp3 = __builtin_msa_sat_s_w(in3, 8);                              \
94*5f39d1b3SJooyung Han     tmp0 = reinterpret_cast<v4i32>(__builtin_msa_pckev_h(                    \
95*5f39d1b3SJooyung Han         reinterpret_cast<v8i16>(tmp1), reinterpret_cast<v8i16>(tmp0)));      \
96*5f39d1b3SJooyung Han     tmp2 = reinterpret_cast<v4i32>(__builtin_msa_pckev_h(                    \
97*5f39d1b3SJooyung Han         reinterpret_cast<v8i16>(tmp3), reinterpret_cast<v8i16>(tmp2)));      \
98*5f39d1b3SJooyung Han     tmp0 = reinterpret_cast<v4i32>(__builtin_msa_maxi_s_h(                   \
99*5f39d1b3SJooyung Han         reinterpret_cast<v8i16>(tmp0), 0));                                  \
100*5f39d1b3SJooyung Han     tmp2 = reinterpret_cast<v4i32>(__builtin_msa_maxi_s_h(                   \
101*5f39d1b3SJooyung Han         reinterpret_cast<v8i16>(tmp2), 0));                                  \
102*5f39d1b3SJooyung Han     tmp0 = reinterpret_cast<v4i32>(__builtin_msa_pckev_b(                    \
103*5f39d1b3SJooyung Han         reinterpret_cast<v16i8>(tmp2), reinterpret_cast<v16i8>(tmp0)));      \
104*5f39d1b3SJooyung Han     out = reinterpret_cast<v16i8>(tmp0);                                     \
105*5f39d1b3SJooyung Han   }
106*5f39d1b3SJooyung Han 
107*5f39d1b3SJooyung Han template <>
108*5f39d1b3SJooyung Han struct OutputStageEvalBufferImpl<OutputStageSaturatingCastToUint8,
109*5f39d1b3SJooyung Han                                  RegBufferInt32<16>> {
110*5f39d1b3SJooyung Han   typedef RegBufferInt32<16> InputType;
111*5f39d1b3SJooyung Han   typedef RegBufferUint8<16> OutputType;
112*5f39d1b3SJooyung Han 
113*5f39d1b3SJooyung Han   typedef OutputStageSaturatingCastToUint8 OutputStage;
114*5f39d1b3SJooyung Han 
115*5f39d1b3SJooyung Han   OutputStageEvalBufferImpl(const OutputStage&) {}
116*5f39d1b3SJooyung Han 
117*5f39d1b3SJooyung Han   OutputType Eval(InputType input) const {
118*5f39d1b3SJooyung Han     OutputType output;
119*5f39d1b3SJooyung Han     GEMMLOWP_MIPS_SAT_U8_16(output.reg[0], input.reg[0], input.reg[1],
120*5f39d1b3SJooyung Han                             input.reg[2], input.reg[3]);
121*5f39d1b3SJooyung Han     return output;
122*5f39d1b3SJooyung Han   }
123*5f39d1b3SJooyung Han };
124*5f39d1b3SJooyung Han 
125*5f39d1b3SJooyung Han template <>
126*5f39d1b3SJooyung Han struct OutputStageEvalBufferImpl<OutputStageSaturatingCastToUint8,
127*5f39d1b3SJooyung Han                                  RegBufferInt32<32>> {
128*5f39d1b3SJooyung Han   typedef RegBufferInt32<32> InputType;
129*5f39d1b3SJooyung Han   typedef RegBufferUint8<32> OutputType;
130*5f39d1b3SJooyung Han 
131*5f39d1b3SJooyung Han   typedef OutputStageSaturatingCastToUint8 OutputStage;
132*5f39d1b3SJooyung Han 
133*5f39d1b3SJooyung Han   OutputStageEvalBufferImpl(const OutputStage&) {}
134*5f39d1b3SJooyung Han 
135*5f39d1b3SJooyung Han   OutputType Eval(InputType input) const {
136*5f39d1b3SJooyung Han     OutputType output;
137*5f39d1b3SJooyung Han     GEMMLOWP_MIPS_SAT_U8_16(output.reg[0], input.reg[0], input.reg[1],
138*5f39d1b3SJooyung Han                             input.reg[2], input.reg[3]);
139*5f39d1b3SJooyung Han     GEMMLOWP_MIPS_SAT_U8_16(output.reg[1], input.reg[4], input.reg[5],
140*5f39d1b3SJooyung Han                             input.reg[6], input.reg[7]);
141*5f39d1b3SJooyung Han     return output;
142*5f39d1b3SJooyung Han   }
143*5f39d1b3SJooyung Han };
144*5f39d1b3SJooyung Han 
145*5f39d1b3SJooyung Han #undef GEMMLOWP_MIPS_SAT_U8_16
146*5f39d1b3SJooyung Han 
147*5f39d1b3SJooyung Han template <>
148*5f39d1b3SJooyung Han struct OutputStageEvalBufferImpl<OutputStageSaturatingCastToInt16,
149*5f39d1b3SJooyung Han                                  RegBufferInt32<4>> {
150*5f39d1b3SJooyung Han   typedef RegBufferInt32<4> InputType;
151*5f39d1b3SJooyung Han   typedef RegBufferInt16<4> OutputType;
152*5f39d1b3SJooyung Han 
153*5f39d1b3SJooyung Han   typedef OutputStageSaturatingCastToInt16 OutputStage;
154*5f39d1b3SJooyung Han 
155*5f39d1b3SJooyung Han   OutputStageEvalBufferImpl(const OutputStage&) {}
156*5f39d1b3SJooyung Han 
157*5f39d1b3SJooyung Han   OutputType Eval(InputType input) const {
158*5f39d1b3SJooyung Han     OutputType output;
159*5f39d1b3SJooyung Han     // Signed saturate each 32-bit element to 16 bits.
160*5f39d1b3SJooyung Han     v8i16 tmp =
161*5f39d1b3SJooyung Han         reinterpret_cast<v8i16>(__builtin_msa_sat_s_w(input.reg[0], 15));
162*5f39d1b3SJooyung Han     output.reg[0] = __builtin_msa_copy_s_h(tmp, 0);
163*5f39d1b3SJooyung Han     output.reg[1] = __builtin_msa_copy_s_h(tmp, 2);
164*5f39d1b3SJooyung Han     output.reg[2] = __builtin_msa_copy_s_h(tmp, 4);
165*5f39d1b3SJooyung Han     output.reg[3] = __builtin_msa_copy_s_h(tmp, 6);
166*5f39d1b3SJooyung Han     return output;
167*5f39d1b3SJooyung Han   }
168*5f39d1b3SJooyung Han };
169*5f39d1b3SJooyung Han 
170*5f39d1b3SJooyung Han #define GEMMLOWP_MIPS_SAT_I16_8(out, in0, in1)                  \
171*5f39d1b3SJooyung Han   {                                                             \
172*5f39d1b3SJooyung Han     v4i32 tmp0 = __builtin_msa_sat_s_w(in0, 15);                \
173*5f39d1b3SJooyung Han     v4i32 tmp1 = __builtin_msa_sat_s_w(in1, 15);                \
174*5f39d1b3SJooyung Han     out = __builtin_msa_pckev_h(reinterpret_cast<v8i16>(tmp1),  \
175*5f39d1b3SJooyung Han                                 reinterpret_cast<v8i16>(tmp0)); \
176*5f39d1b3SJooyung Han   }
177*5f39d1b3SJooyung Han 
178*5f39d1b3SJooyung Han template <>
179*5f39d1b3SJooyung Han struct OutputStageEvalBufferImpl<OutputStageSaturatingCastToInt16,
180*5f39d1b3SJooyung Han                                  RegBufferInt32<8>> {
181*5f39d1b3SJooyung Han   typedef RegBufferInt32<8> InputType;
182*5f39d1b3SJooyung Han   typedef RegBufferInt16<8> OutputType;
183*5f39d1b3SJooyung Han 
184*5f39d1b3SJooyung Han   typedef OutputStageSaturatingCastToInt16 OutputStage;
185*5f39d1b3SJooyung Han 
186*5f39d1b3SJooyung Han   OutputStageEvalBufferImpl(const OutputStage&) {}
187*5f39d1b3SJooyung Han 
188*5f39d1b3SJooyung Han   OutputType Eval(InputType input) const {
189*5f39d1b3SJooyung Han     OutputType output;
190*5f39d1b3SJooyung Han     GEMMLOWP_MIPS_SAT_I16_8(output.reg[0], input.reg[0], input.reg[1]);
191*5f39d1b3SJooyung Han     return output;
192*5f39d1b3SJooyung Han   }
193*5f39d1b3SJooyung Han };
194*5f39d1b3SJooyung Han 
195*5f39d1b3SJooyung Han template <>
196*5f39d1b3SJooyung Han struct OutputStageEvalBufferImpl<OutputStageSaturatingCastToInt16,
197*5f39d1b3SJooyung Han                                  RegBufferInt32<16>> {
198*5f39d1b3SJooyung Han   typedef RegBufferInt32<16> InputType;
199*5f39d1b3SJooyung Han   typedef RegBufferInt16<16> OutputType;
200*5f39d1b3SJooyung Han 
201*5f39d1b3SJooyung Han   typedef OutputStageSaturatingCastToInt16 OutputStage;
202*5f39d1b3SJooyung Han 
203*5f39d1b3SJooyung Han   OutputStageEvalBufferImpl(const OutputStage&) {}
204*5f39d1b3SJooyung Han 
205*5f39d1b3SJooyung Han   OutputType Eval(InputType input) const {
206*5f39d1b3SJooyung Han     OutputType output;
207*5f39d1b3SJooyung Han     GEMMLOWP_MIPS_SAT_I16_8(output.reg[0], input.reg[0], input.reg[1]);
208*5f39d1b3SJooyung Han     GEMMLOWP_MIPS_SAT_I16_8(output.reg[1], input.reg[2], input.reg[3]);
209*5f39d1b3SJooyung Han     return output;
210*5f39d1b3SJooyung Han   }
211*5f39d1b3SJooyung Han };
212*5f39d1b3SJooyung Han 
213*5f39d1b3SJooyung Han template <>
214*5f39d1b3SJooyung Han struct OutputStageEvalBufferImpl<OutputStageSaturatingCastToInt16,
215*5f39d1b3SJooyung Han                                  RegBufferInt32<32>> {
216*5f39d1b3SJooyung Han   typedef RegBufferInt32<32> InputType;
217*5f39d1b3SJooyung Han   typedef RegBufferInt16<32> OutputType;
218*5f39d1b3SJooyung Han 
219*5f39d1b3SJooyung Han   typedef OutputStageSaturatingCastToInt16 OutputStage;
220*5f39d1b3SJooyung Han 
221*5f39d1b3SJooyung Han   OutputStageEvalBufferImpl(const OutputStage&) {}
222*5f39d1b3SJooyung Han 
223*5f39d1b3SJooyung Han   OutputType Eval(InputType input) const {
224*5f39d1b3SJooyung Han     OutputType output;
225*5f39d1b3SJooyung Han     GEMMLOWP_MIPS_SAT_I16_8(output.reg[0], input.reg[0], input.reg[1]);
226*5f39d1b3SJooyung Han     GEMMLOWP_MIPS_SAT_I16_8(output.reg[1], input.reg[2], input.reg[3]);
227*5f39d1b3SJooyung Han     GEMMLOWP_MIPS_SAT_I16_8(output.reg[2], input.reg[4], input.reg[5]);
228*5f39d1b3SJooyung Han     GEMMLOWP_MIPS_SAT_I16_8(output.reg[3], input.reg[6], input.reg[7]);
229*5f39d1b3SJooyung Han     return output;
230*5f39d1b3SJooyung Han   }
231*5f39d1b3SJooyung Han };
232*5f39d1b3SJooyung Han 
233*5f39d1b3SJooyung Han #undef GEMMLOWP_MIPS_SAT_I16_8
234*5f39d1b3SJooyung Han 
235*5f39d1b3SJooyung Han template <>
236*5f39d1b3SJooyung Han struct OutputStageEvalBufferImpl<OutputStageTruncatingCastToUint8,
237*5f39d1b3SJooyung Han                                  RegBufferInt32<4>> {
238*5f39d1b3SJooyung Han   typedef RegBufferInt32<4> InputType;
239*5f39d1b3SJooyung Han   typedef RegBufferUint8<4> OutputType;
240*5f39d1b3SJooyung Han 
241*5f39d1b3SJooyung Han   typedef OutputStageTruncatingCastToUint8 OutputStage;
242*5f39d1b3SJooyung Han 
243*5f39d1b3SJooyung Han   OutputStageEvalBufferImpl(const OutputStage&) {}
244*5f39d1b3SJooyung Han 
245*5f39d1b3SJooyung Han   OutputType Eval(InputType input) const {
246*5f39d1b3SJooyung Han     OutputType output;
247*5f39d1b3SJooyung Han     // Pack every 32-bit element into 16 bits.
248*5f39d1b3SJooyung Han     v4i32 tmp = reinterpret_cast<v4i32>(__builtin_msa_pckev_h(
249*5f39d1b3SJooyung Han         reinterpret_cast<v8i16>(input.reg[0]),
250*5f39d1b3SJooyung Han         reinterpret_cast<v8i16>(input.reg[0])));
251*5f39d1b3SJooyung Han     // Pack every element into 8 bits.
252*5f39d1b3SJooyung Han     tmp = reinterpret_cast<v4i32>(__builtin_msa_pckev_b(
253*5f39d1b3SJooyung Han         reinterpret_cast<v16i8>(tmp), reinterpret_cast<v16i8>(tmp)));
254*5f39d1b3SJooyung Han     // Return 4 uint8_t elements as uint32_t.
255*5f39d1b3SJooyung Han     output.reg[0] = __builtin_msa_copy_s_w(tmp, 0);
256*5f39d1b3SJooyung Han     return output;
257*5f39d1b3SJooyung Han   }
258*5f39d1b3SJooyung Han };
259*5f39d1b3SJooyung Han 
260*5f39d1b3SJooyung Han template <>
261*5f39d1b3SJooyung Han struct OutputStageEvalBufferImpl<OutputStageTruncatingCastToUint8,
262*5f39d1b3SJooyung Han                                  RegBufferInt32<8>> {
263*5f39d1b3SJooyung Han   typedef RegBufferInt32<8> InputType;
264*5f39d1b3SJooyung Han   typedef RegBufferUint8<8> OutputType;
265*5f39d1b3SJooyung Han 
266*5f39d1b3SJooyung Han   typedef OutputStageTruncatingCastToUint8 OutputStage;
267*5f39d1b3SJooyung Han 
268*5f39d1b3SJooyung Han   OutputStageEvalBufferImpl(const OutputStage&) {}
269*5f39d1b3SJooyung Han 
270*5f39d1b3SJooyung Han   OutputType Eval(InputType input) const {
271*5f39d1b3SJooyung Han     OutputType output;
272*5f39d1b3SJooyung Han     // Pack every 32-bit element into 16 bits.
273*5f39d1b3SJooyung Han     v4i32 tmp = reinterpret_cast<v4i32>(__builtin_msa_pckev_h(
274*5f39d1b3SJooyung Han         reinterpret_cast<v8i16>(input.reg[1]),
275*5f39d1b3SJooyung Han         reinterpret_cast<v8i16>(input.reg[0])));
276*5f39d1b3SJooyung Han     // Pack every element into 8 bits.
277*5f39d1b3SJooyung Han     tmp = reinterpret_cast<v4i32>(__builtin_msa_pckev_b(
278*5f39d1b3SJooyung Han         reinterpret_cast<v16i8>(tmp), reinterpret_cast<v16i8>(tmp)));
279*5f39d1b3SJooyung Han     // Return 8 uint8_t elements as 2 uint32_t's.
280*5f39d1b3SJooyung Han     output.reg[0] = __builtin_msa_copy_s_w(tmp, 0);
281*5f39d1b3SJooyung Han     output.reg[1] = __builtin_msa_copy_s_w(tmp, 1);
282*5f39d1b3SJooyung Han     return output;
283*5f39d1b3SJooyung Han   }
284*5f39d1b3SJooyung Han };
285*5f39d1b3SJooyung Han 
286*5f39d1b3SJooyung Han template <>
287*5f39d1b3SJooyung Han struct OutputStageEvalBufferImpl<OutputStageTruncatingCastToUint8,
288*5f39d1b3SJooyung Han                                  RegBufferInt32<16>> {
289*5f39d1b3SJooyung Han   typedef RegBufferInt32<16> InputType;
290*5f39d1b3SJooyung Han   typedef RegBufferUint8<16> OutputType;
291*5f39d1b3SJooyung Han 
292*5f39d1b3SJooyung Han   typedef OutputStageTruncatingCastToUint8 OutputStage;
293*5f39d1b3SJooyung Han 
294*5f39d1b3SJooyung Han   OutputStageEvalBufferImpl(const OutputStage&) {}
295*5f39d1b3SJooyung Han 
296*5f39d1b3SJooyung Han   OutputType Eval(InputType input) const {
297*5f39d1b3SJooyung Han     OutputType output;
298*5f39d1b3SJooyung Han     // Pack every 32-bit element into 16 bits.
299*5f39d1b3SJooyung Han     v8i16 tmp0 = __builtin_msa_pckev_h(
300*5f39d1b3SJooyung Han         reinterpret_cast<v8i16>(input.reg[1]),
301*5f39d1b3SJooyung Han         reinterpret_cast<v8i16>(input.reg[0]));
302*5f39d1b3SJooyung Han     v8i16 tmp1 = __builtin_msa_pckev_h(
303*5f39d1b3SJooyung Han         reinterpret_cast<v8i16>(input.reg[3]),
304*5f39d1b3SJooyung Han         reinterpret_cast<v8i16>(input.reg[2]));
305*5f39d1b3SJooyung Han     // Pack every element into 8 bits.
306*5f39d1b3SJooyung Han     output.reg[0] = __builtin_msa_pckev_b(
307*5f39d1b3SJooyung Han         reinterpret_cast<v16i8>(tmp1), reinterpret_cast<v16i8>(tmp0));
308*5f39d1b3SJooyung Han     return output;
309*5f39d1b3SJooyung Han   }
310*5f39d1b3SJooyung Han };
311*5f39d1b3SJooyung Han 
312*5f39d1b3SJooyung Han template <>
313*5f39d1b3SJooyung Han struct OutputStageEvalBufferImpl<OutputStageTruncatingCastToUint8,
314*5f39d1b3SJooyung Han                                  RegBufferInt32<32>> {
315*5f39d1b3SJooyung Han   typedef RegBufferInt32<32> InputType;
316*5f39d1b3SJooyung Han   typedef RegBufferUint8<32> OutputType;
317*5f39d1b3SJooyung Han 
318*5f39d1b3SJooyung Han   typedef OutputStageTruncatingCastToUint8 OutputStage;
319*5f39d1b3SJooyung Han 
320*5f39d1b3SJooyung Han   OutputStageEvalBufferImpl(const OutputStage&) {}
321*5f39d1b3SJooyung Han 
322*5f39d1b3SJooyung Han   OutputType Eval(InputType input) const {
323*5f39d1b3SJooyung Han     OutputType output;
324*5f39d1b3SJooyung Han     // Pack every 32-bit element into 16 bits.
325*5f39d1b3SJooyung Han     v8i16 tmp0 = __builtin_msa_pckev_h(
326*5f39d1b3SJooyung Han         reinterpret_cast<v8i16>(input.reg[1]),
327*5f39d1b3SJooyung Han         reinterpret_cast<v8i16>(input.reg[0]));
328*5f39d1b3SJooyung Han     v8i16 tmp1 = __builtin_msa_pckev_h(
329*5f39d1b3SJooyung Han         reinterpret_cast<v8i16>(input.reg[3]),
330*5f39d1b3SJooyung Han         reinterpret_cast<v8i16>(input.reg[2]));
331*5f39d1b3SJooyung Han     v8i16 tmp2 = __builtin_msa_pckev_h(
332*5f39d1b3SJooyung Han         reinterpret_cast<v8i16>(input.reg[5]),
333*5f39d1b3SJooyung Han         reinterpret_cast<v8i16>(input.reg[4]));
334*5f39d1b3SJooyung Han     v8i16 tmp3 = __builtin_msa_pckev_h(
335*5f39d1b3SJooyung Han         reinterpret_cast<v8i16>(input.reg[7]),
336*5f39d1b3SJooyung Han         reinterpret_cast<v8i16>(input.reg[6]));
337*5f39d1b3SJooyung Han     // Pack every element into 8 bits.
338*5f39d1b3SJooyung Han     output.reg[0] = __builtin_msa_pckev_b(
339*5f39d1b3SJooyung Han         reinterpret_cast<v16i8>(tmp1), reinterpret_cast<v16i8>(tmp0));
340*5f39d1b3SJooyung Han     output.reg[1] = __builtin_msa_pckev_b(
341*5f39d1b3SJooyung Han         reinterpret_cast<v16i8>(tmp3), reinterpret_cast<v16i8>(tmp2));
342*5f39d1b3SJooyung Han     return output;
343*5f39d1b3SJooyung Han   }
344*5f39d1b3SJooyung Han };
345*5f39d1b3SJooyung Han 
346*5f39d1b3SJooyung Han template <typename DstType>
347*5f39d1b3SJooyung Han struct StoreFinalOutputImpl<RegBlockInt32<4, 1>, DstType> {
348*5f39d1b3SJooyung Han   static void Run(const RegBlockInt32<4, 1>& src, DstType* dst, int row,
349*5f39d1b3SJooyung Han                   int col) {
350*5f39d1b3SJooyung Han     if (DstType::kOrder == MapOrder::ColMajor) {
351*5f39d1b3SJooyung Han       StoreInt32x4(dst->data(row, col), src.buf.reg[0]);
352*5f39d1b3SJooyung Han     } else {
353*5f39d1b3SJooyung Han       *dst->data(row + 0, col) = GetLane<0>(src.buf.reg[0]);
354*5f39d1b3SJooyung Han       *dst->data(row + 1, col) = GetLane<1>(src.buf.reg[0]);
355*5f39d1b3SJooyung Han       *dst->data(row + 2, col) = GetLane<2>(src.buf.reg[0]);
356*5f39d1b3SJooyung Han       *dst->data(row + 3, col) = GetLane<3>(src.buf.reg[0]);
357*5f39d1b3SJooyung Han     }
358*5f39d1b3SJooyung Han   }
359*5f39d1b3SJooyung Han };
360*5f39d1b3SJooyung Han 
361*5f39d1b3SJooyung Han template <typename DstType>
362*5f39d1b3SJooyung Han struct StoreFinalOutputImpl<RegBlockInt32<8, 1>, DstType> {
363*5f39d1b3SJooyung Han   static void Run(const RegBlockInt32<8, 1>& src, DstType* dst, int row,
364*5f39d1b3SJooyung Han                   int col) {
365*5f39d1b3SJooyung Han     if (DstType::kOrder == MapOrder::ColMajor) {
366*5f39d1b3SJooyung Han       StoreInt32x4(dst->data(row, col), src.buf.reg[0]);
367*5f39d1b3SJooyung Han       StoreInt32x4(dst->data(row + 4, col), src.buf.reg[1]);
368*5f39d1b3SJooyung Han     } else {
369*5f39d1b3SJooyung Han       *dst->data(row + 0, col) = GetLane<0>(src.buf.reg[0]);
370*5f39d1b3SJooyung Han       *dst->data(row + 1, col) = GetLane<1>(src.buf.reg[0]);
371*5f39d1b3SJooyung Han       *dst->data(row + 2, col) = GetLane<2>(src.buf.reg[0]);
372*5f39d1b3SJooyung Han       *dst->data(row + 3, col) = GetLane<3>(src.buf.reg[0]);
373*5f39d1b3SJooyung Han       *dst->data(row + 4, col) = GetLane<0>(src.buf.reg[1]);
374*5f39d1b3SJooyung Han       *dst->data(row + 5, col) = GetLane<1>(src.buf.reg[1]);
375*5f39d1b3SJooyung Han       *dst->data(row + 6, col) = GetLane<2>(src.buf.reg[1]);
376*5f39d1b3SJooyung Han       *dst->data(row + 7, col) = GetLane<3>(src.buf.reg[1]);
377*5f39d1b3SJooyung Han     }
378*5f39d1b3SJooyung Han   }
379*5f39d1b3SJooyung Han };
380*5f39d1b3SJooyung Han 
381*5f39d1b3SJooyung Han template <typename DstType>
382*5f39d1b3SJooyung Han struct StoreFinalOutputImpl<RegBlockInt16<4, 1>, DstType> {
383*5f39d1b3SJooyung Han   static void Run(const RegBlockInt16<4, 1>& src, DstType* dst, int row,
384*5f39d1b3SJooyung Han                   int col) {
385*5f39d1b3SJooyung Han     *dst->data(row + 0, col) = src.buf.reg[0];
386*5f39d1b3SJooyung Han     *dst->data(row + 1, col) = src.buf.reg[1];
387*5f39d1b3SJooyung Han     *dst->data(row + 2, col) = src.buf.reg[2];
388*5f39d1b3SJooyung Han     *dst->data(row + 3, col) = src.buf.reg[3];
389*5f39d1b3SJooyung Han   }
390*5f39d1b3SJooyung Han };
391*5f39d1b3SJooyung Han 
392*5f39d1b3SJooyung Han template <typename DstType>
393*5f39d1b3SJooyung Han struct StoreFinalOutputImpl<RegBlockInt16<8, 1>, DstType> {
394*5f39d1b3SJooyung Han   static void Run(const RegBlockInt16<8, 1>& src, DstType* dst, int row,
395*5f39d1b3SJooyung Han                   int col) {
396*5f39d1b3SJooyung Han     if (DstType::kOrder == MapOrder::ColMajor) {
397*5f39d1b3SJooyung Han       StoreInt16x8(dst->data(row, col), src.buf.reg[0]);
398*5f39d1b3SJooyung Han     } else {
399*5f39d1b3SJooyung Han       *dst->data(row + 0, col) = __builtin_msa_copy_s_h(src.buf.reg[0], 0);
400*5f39d1b3SJooyung Han       *dst->data(row + 1, col) = __builtin_msa_copy_s_h(src.buf.reg[0], 1);
401*5f39d1b3SJooyung Han       *dst->data(row + 2, col) = __builtin_msa_copy_s_h(src.buf.reg[0], 2);
402*5f39d1b3SJooyung Han       *dst->data(row + 3, col) = __builtin_msa_copy_s_h(src.buf.reg[0], 3);
403*5f39d1b3SJooyung Han       *dst->data(row + 4, col) = __builtin_msa_copy_s_h(src.buf.reg[0], 4);
404*5f39d1b3SJooyung Han       *dst->data(row + 5, col) = __builtin_msa_copy_s_h(src.buf.reg[0], 5);
405*5f39d1b3SJooyung Han       *dst->data(row + 6, col) = __builtin_msa_copy_s_h(src.buf.reg[0], 6);
406*5f39d1b3SJooyung Han       *dst->data(row + 7, col) = __builtin_msa_copy_s_h(src.buf.reg[0], 7);
407*5f39d1b3SJooyung Han     }
408*5f39d1b3SJooyung Han   }
409*5f39d1b3SJooyung Han };
410*5f39d1b3SJooyung Han 
411*5f39d1b3SJooyung Han inline RegBlockInt32<4, 4> Transpose(const RegBlockInt32<4, 4>& src) {
412*5f39d1b3SJooyung Han   RegBlockInt32<4, 4> result;
413*5f39d1b3SJooyung Han   v4i32 tmp0, tmp1;
414*5f39d1b3SJooyung Han   tmp0 = __builtin_msa_ilvr_w(src.buf.reg[1], src.buf.reg[0]);
415*5f39d1b3SJooyung Han   tmp1 = __builtin_msa_ilvr_w(src.buf.reg[3], src.buf.reg[2]);
416*5f39d1b3SJooyung Han   result.buf.reg[0] = reinterpret_cast<v4i32>(__builtin_msa_ilvr_d(
417*5f39d1b3SJooyung Han       reinterpret_cast<v2i64>(tmp1), reinterpret_cast<v2i64>(tmp0)));
418*5f39d1b3SJooyung Han   result.buf.reg[1] = reinterpret_cast<v4i32>(__builtin_msa_ilvl_d(
419*5f39d1b3SJooyung Han       reinterpret_cast<v2i64>(tmp1), reinterpret_cast<v2i64>(tmp0)));
420*5f39d1b3SJooyung Han   tmp0 = __builtin_msa_ilvl_w(src.buf.reg[1], src.buf.reg[0]);
421*5f39d1b3SJooyung Han   tmp1 = __builtin_msa_ilvl_w(src.buf.reg[3], src.buf.reg[2]);
422*5f39d1b3SJooyung Han   result.buf.reg[2] = reinterpret_cast<v4i32>(__builtin_msa_ilvr_d(
423*5f39d1b3SJooyung Han       reinterpret_cast<v2i64>(tmp1), reinterpret_cast<v2i64>(tmp0)));
424*5f39d1b3SJooyung Han   result.buf.reg[3] = reinterpret_cast<v4i32>(__builtin_msa_ilvl_d(
425*5f39d1b3SJooyung Han       reinterpret_cast<v2i64>(tmp1), reinterpret_cast<v2i64>(tmp0)));
426*5f39d1b3SJooyung Han   return result;
427*5f39d1b3SJooyung Han }
428*5f39d1b3SJooyung Han 
429*5f39d1b3SJooyung Han template <typename DstType>
430*5f39d1b3SJooyung Han struct StoreFinalOutputImpl<RegBlockInt32<4, 4>, DstType> {
431*5f39d1b3SJooyung Han   static void Run(const RegBlockInt32<4, 4>& src, DstType* dst, int row,
432*5f39d1b3SJooyung Han                   int col) {
433*5f39d1b3SJooyung Han     if (DstType::kOrder == MapOrder::ColMajor) {
434*5f39d1b3SJooyung Han       for (int i = 0; i < 4; i++) {
435*5f39d1b3SJooyung Han         StoreInt32x4(dst->data(row, col + i), src.buf.reg[i]);
436*5f39d1b3SJooyung Han       }
437*5f39d1b3SJooyung Han     } else {
438*5f39d1b3SJooyung Han       const auto transpose = Transpose(src);
439*5f39d1b3SJooyung Han       for (int i = 0; i < 4; i++) {
440*5f39d1b3SJooyung Han         StoreInt32x4(dst->data(row + i, col), transpose.buf.reg[i]);
441*5f39d1b3SJooyung Han       }
442*5f39d1b3SJooyung Han     }
443*5f39d1b3SJooyung Han   }
444*5f39d1b3SJooyung Han };
445*5f39d1b3SJooyung Han 
446*5f39d1b3SJooyung Han template <typename DstType>
447*5f39d1b3SJooyung Han struct StoreFinalOutputImpl<RegBlockInt16<4, 4>, DstType> {
448*5f39d1b3SJooyung Han   static void Run(const RegBlockInt16<4, 4>& src, DstType* dst, int row,
449*5f39d1b3SJooyung Han                   int col) {
450*5f39d1b3SJooyung Han     std::int16_t buf[16];
451*5f39d1b3SJooyung Han     StoreInt16x8(buf + 0, src.buf.reg[0]);
452*5f39d1b3SJooyung Han     StoreInt16x8(buf + 8, src.buf.reg[1]);
453*5f39d1b3SJooyung Han     for (int i = 0; i < 4; i++) {
454*5f39d1b3SJooyung Han       for (int j = 0; j < 4; j++) {
455*5f39d1b3SJooyung Han         *dst->data(row + i, col + j) = buf[i + 4 * j];
456*5f39d1b3SJooyung Han       }
457*5f39d1b3SJooyung Han     }
458*5f39d1b3SJooyung Han   }
459*5f39d1b3SJooyung Han };
460*5f39d1b3SJooyung Han 
461*5f39d1b3SJooyung Han template <typename DstType>
462*5f39d1b3SJooyung Han struct StoreFinalOutputImpl<RegBlockInt32<8, 4>, DstType> {
463*5f39d1b3SJooyung Han   static void Run(const RegBlockInt32<8, 4>& src, DstType* dst, int row,
464*5f39d1b3SJooyung Han                   int col) {
465*5f39d1b3SJooyung Han     if (DstType::kOrder == MapOrder::ColMajor) {
466*5f39d1b3SJooyung Han       for (int i = 0; i < 4; i++) {
467*5f39d1b3SJooyung Han         StoreInt32x4(dst->data(row, col + i), src.buf.reg[2 * i]);
468*5f39d1b3SJooyung Han         StoreInt32x4(dst->data(row + 4, col + i), src.buf.reg[2 * i + 1]);
469*5f39d1b3SJooyung Han       }
470*5f39d1b3SJooyung Han     } else {
471*5f39d1b3SJooyung Han       RegBlockInt32<4, 4> top;
472*5f39d1b3SJooyung Han       top.buf.reg[0] = src.buf.reg[0];
473*5f39d1b3SJooyung Han       top.buf.reg[1] = src.buf.reg[2];
474*5f39d1b3SJooyung Han       top.buf.reg[2] = src.buf.reg[4];
475*5f39d1b3SJooyung Han       top.buf.reg[3] = src.buf.reg[6];
476*5f39d1b3SJooyung Han       const auto transpose_top = Transpose(top);
477*5f39d1b3SJooyung Han       for (int i = 0; i < 4; i++) {
478*5f39d1b3SJooyung Han         StoreInt32x4(dst->data(row + i, col), transpose_top.buf.reg[i]);
479*5f39d1b3SJooyung Han       }
480*5f39d1b3SJooyung Han       RegBlockInt32<4, 4> bottom;
481*5f39d1b3SJooyung Han       bottom.buf.reg[0] = src.buf.reg[1];
482*5f39d1b3SJooyung Han       bottom.buf.reg[1] = src.buf.reg[3];
483*5f39d1b3SJooyung Han       bottom.buf.reg[2] = src.buf.reg[5];
484*5f39d1b3SJooyung Han       bottom.buf.reg[3] = src.buf.reg[7];
485*5f39d1b3SJooyung Han       const auto transpose_bottom = Transpose(bottom);
486*5f39d1b3SJooyung Han       for (int i = 0; i < 4; i++) {
487*5f39d1b3SJooyung Han         StoreInt32x4(dst->data(row + 4 + i, col), transpose_bottom.buf.reg[i]);
488*5f39d1b3SJooyung Han       }
489*5f39d1b3SJooyung Han     }
490*5f39d1b3SJooyung Han   }
491*5f39d1b3SJooyung Han };
492*5f39d1b3SJooyung Han 
493*5f39d1b3SJooyung Han template <typename DstType>
494*5f39d1b3SJooyung Han struct StoreFinalOutputImpl<RegBlockInt16<8, 4>, DstType> {
495*5f39d1b3SJooyung Han   static void Run(const RegBlockInt16<8, 4>& src, DstType* dst, int row,
496*5f39d1b3SJooyung Han                   int col) {
497*5f39d1b3SJooyung Han     if (DstType::kOrder == MapOrder::ColMajor) {
498*5f39d1b3SJooyung Han       for (int i = 0; i < 4; i++) {
499*5f39d1b3SJooyung Han         StoreInt16x8(dst->data(row, col + i), src.buf.reg[i]);
500*5f39d1b3SJooyung Han       }
501*5f39d1b3SJooyung Han     } else {
502*5f39d1b3SJooyung Han       std::int16_t buf[32];
503*5f39d1b3SJooyung Han       StoreInt16x8(buf + 0, src.buf.reg[0]);
504*5f39d1b3SJooyung Han       StoreInt16x8(buf + 8, src.buf.reg[1]);
505*5f39d1b3SJooyung Han       StoreInt16x8(buf + 16, src.buf.reg[2]);
506*5f39d1b3SJooyung Han       StoreInt16x8(buf + 24, src.buf.reg[3]);
507*5f39d1b3SJooyung Han       for (int i = 0; i < 8; i++) {
508*5f39d1b3SJooyung Han         for (int j = 0; j < 4; j++) {
509*5f39d1b3SJooyung Han           *dst->data(row + i, col + j) = buf[i + 8 * j];
510*5f39d1b3SJooyung Han         }
511*5f39d1b3SJooyung Han       }
512*5f39d1b3SJooyung Han     }
513*5f39d1b3SJooyung Han   }
514*5f39d1b3SJooyung Han };
515*5f39d1b3SJooyung Han 
516*5f39d1b3SJooyung Han template <typename DstType>
517*5f39d1b3SJooyung Han struct StoreFinalOutputImpl<RegBlockInt32<8, 8>, DstType> {
518*5f39d1b3SJooyung Han   static void Run(const RegBlockInt32<8, 8>& src, DstType* dst, int row,
519*5f39d1b3SJooyung Han                   int col) {
520*5f39d1b3SJooyung Han     if (DstType::kOrder == MapOrder::ColMajor) {
521*5f39d1b3SJooyung Han       for (int i = 0; i < 8; i++) {
522*5f39d1b3SJooyung Han         StoreInt32x4(dst->data(row, col + i), src.buf.reg[2 * i]);
523*5f39d1b3SJooyung Han         StoreInt32x4(dst->data(row + 4, col + i), src.buf.reg[2 * i + 1]);
524*5f39d1b3SJooyung Han       }
525*5f39d1b3SJooyung Han     } else {
526*5f39d1b3SJooyung Han       RegBlockInt32<4, 4> top_left;
527*5f39d1b3SJooyung Han       top_left.buf.reg[0] = src.buf.reg[0];
528*5f39d1b3SJooyung Han       top_left.buf.reg[1] = src.buf.reg[2];
529*5f39d1b3SJooyung Han       top_left.buf.reg[2] = src.buf.reg[4];
530*5f39d1b3SJooyung Han       top_left.buf.reg[3] = src.buf.reg[6];
531*5f39d1b3SJooyung Han       const auto transpose_top_left = Transpose(top_left);
532*5f39d1b3SJooyung Han       for (int i = 0; i < 4; i++) {
533*5f39d1b3SJooyung Han         StoreInt32x4(dst->data(row + i, col), transpose_top_left.buf.reg[i]);
534*5f39d1b3SJooyung Han       }
535*5f39d1b3SJooyung Han       RegBlockInt32<4, 4> bottom_left;
536*5f39d1b3SJooyung Han       bottom_left.buf.reg[0] = src.buf.reg[1];
537*5f39d1b3SJooyung Han       bottom_left.buf.reg[1] = src.buf.reg[3];
538*5f39d1b3SJooyung Han       bottom_left.buf.reg[2] = src.buf.reg[5];
539*5f39d1b3SJooyung Han       bottom_left.buf.reg[3] = src.buf.reg[7];
540*5f39d1b3SJooyung Han       const auto transpose_bottom_left = Transpose(bottom_left);
541*5f39d1b3SJooyung Han       for (int i = 0; i < 4; i++) {
542*5f39d1b3SJooyung Han         StoreInt32x4(dst->data(row + 4 + i, col),
543*5f39d1b3SJooyung Han                      transpose_bottom_left.buf.reg[i]);
544*5f39d1b3SJooyung Han       }
545*5f39d1b3SJooyung Han       RegBlockInt32<4, 4> top_right;
546*5f39d1b3SJooyung Han       top_right.buf.reg[0] = src.buf.reg[8];
547*5f39d1b3SJooyung Han       top_right.buf.reg[1] = src.buf.reg[10];
548*5f39d1b3SJooyung Han       top_right.buf.reg[2] = src.buf.reg[12];
549*5f39d1b3SJooyung Han       top_right.buf.reg[3] = src.buf.reg[14];
550*5f39d1b3SJooyung Han       const auto transpose_top_right = Transpose(top_right);
551*5f39d1b3SJooyung Han       for (int i = 0; i < 4; i++) {
552*5f39d1b3SJooyung Han         StoreInt32x4(dst->data(row + i, col + 4),
553*5f39d1b3SJooyung Han                      transpose_top_right.buf.reg[i]);
554*5f39d1b3SJooyung Han       }
555*5f39d1b3SJooyung Han       RegBlockInt32<4, 4> bottom_right;
556*5f39d1b3SJooyung Han       bottom_right.buf.reg[0] = src.buf.reg[9];
557*5f39d1b3SJooyung Han       bottom_right.buf.reg[1] = src.buf.reg[11];
558*5f39d1b3SJooyung Han       bottom_right.buf.reg[2] = src.buf.reg[13];
559*5f39d1b3SJooyung Han       bottom_right.buf.reg[3] = src.buf.reg[15];
560*5f39d1b3SJooyung Han       const auto transpose_bottom_right = Transpose(bottom_right);
561*5f39d1b3SJooyung Han       for (int i = 0; i < 4; i++) {
562*5f39d1b3SJooyung Han         StoreInt32x4(dst->data(row + 4 + i, col + 4),
563*5f39d1b3SJooyung Han                      transpose_bottom_right.buf.reg[i]);
564*5f39d1b3SJooyung Han       }
565*5f39d1b3SJooyung Han     }
566*5f39d1b3SJooyung Han   }
567*5f39d1b3SJooyung Han };
568*5f39d1b3SJooyung Han 
569*5f39d1b3SJooyung Han template <typename DstType>
570*5f39d1b3SJooyung Han struct StoreFinalOutputImpl<RegBlockInt16<8, 8>, DstType> {
571*5f39d1b3SJooyung Han   static void Run(const RegBlockInt16<8, 8>& src, DstType* dst, int row,
572*5f39d1b3SJooyung Han                   int col) {
573*5f39d1b3SJooyung Han     if (DstType::kOrder == MapOrder::ColMajor) {
574*5f39d1b3SJooyung Han       for (int i = 0; i < 8; i++) {
575*5f39d1b3SJooyung Han         StoreInt16x8(dst->data(row, col + i), src.buf.reg[i]);
576*5f39d1b3SJooyung Han       }
577*5f39d1b3SJooyung Han     } else {
578*5f39d1b3SJooyung Han       // top-left 4x4
579*5f39d1b3SJooyung Han       v4i32 t0 = reinterpret_cast<v4i32>(
580*5f39d1b3SJooyung Han           __builtin_msa_ilvr_h(src.buf.reg[1], src.buf.reg[0]));
581*5f39d1b3SJooyung Han       v4i32 t1 = reinterpret_cast<v4i32>(
582*5f39d1b3SJooyung Han           __builtin_msa_ilvr_h(src.buf.reg[3], src.buf.reg[2]));
583*5f39d1b3SJooyung Han       v2i64 u0 = reinterpret_cast<v2i64>(__builtin_msa_ilvr_w(t1, t0));
584*5f39d1b3SJooyung Han       v2i64 u1 = reinterpret_cast<v2i64>(__builtin_msa_ilvl_w(t1, t0));
585*5f39d1b3SJooyung Han       // top-right 4x4
586*5f39d1b3SJooyung Han       v4i32 t2 = reinterpret_cast<v4i32>(
587*5f39d1b3SJooyung Han           __builtin_msa_ilvr_h(src.buf.reg[5], src.buf.reg[4]));
588*5f39d1b3SJooyung Han       v4i32 t3 = reinterpret_cast<v4i32>(
589*5f39d1b3SJooyung Han           __builtin_msa_ilvr_h(src.buf.reg[7], src.buf.reg[6]));
590*5f39d1b3SJooyung Han       v2i64 u2 = reinterpret_cast<v2i64>(__builtin_msa_ilvr_w(t3, t2));
591*5f39d1b3SJooyung Han       v2i64 u3 = reinterpret_cast<v2i64>(__builtin_msa_ilvl_w(t3, t2));
592*5f39d1b3SJooyung Han       // bottom-left 4x4
593*5f39d1b3SJooyung Han       v4i32 t4 = reinterpret_cast<v4i32>(
594*5f39d1b3SJooyung Han           __builtin_msa_ilvl_h(src.buf.reg[1], src.buf.reg[0]));
595*5f39d1b3SJooyung Han       v4i32 t5 = reinterpret_cast<v4i32>(
596*5f39d1b3SJooyung Han           __builtin_msa_ilvl_h(src.buf.reg[3], src.buf.reg[2]));
597*5f39d1b3SJooyung Han       v2i64 u4 = reinterpret_cast<v2i64>(__builtin_msa_ilvr_w(t5, t4));
598*5f39d1b3SJooyung Han       v2i64 u5 = reinterpret_cast<v2i64>(__builtin_msa_ilvl_w(t5, t4));
599*5f39d1b3SJooyung Han       // bottom-right 4x4
600*5f39d1b3SJooyung Han       v4i32 t6 = reinterpret_cast<v4i32>(
601*5f39d1b3SJooyung Han           __builtin_msa_ilvl_h(src.buf.reg[5], src.buf.reg[4]));
602*5f39d1b3SJooyung Han       v4i32 t7 = reinterpret_cast<v4i32>(
603*5f39d1b3SJooyung Han           __builtin_msa_ilvl_h(src.buf.reg[7], src.buf.reg[6]));
604*5f39d1b3SJooyung Han       v2i64 u6 = reinterpret_cast<v2i64>(__builtin_msa_ilvr_w(t7, t6));
605*5f39d1b3SJooyung Han       v2i64 u7 = reinterpret_cast<v2i64>(__builtin_msa_ilvl_w(t7, t6));
606*5f39d1b3SJooyung Han 
607*5f39d1b3SJooyung Han       StoreInt16x8(dst->data(row + 0, col),
608*5f39d1b3SJooyung Han                    reinterpret_cast<v8i16>(__builtin_msa_ilvr_d(u2, u0)));
609*5f39d1b3SJooyung Han       StoreInt16x8(dst->data(row + 1, col),
610*5f39d1b3SJooyung Han                    reinterpret_cast<v8i16>(__builtin_msa_ilvl_d(u2, u0)));
611*5f39d1b3SJooyung Han       StoreInt16x8(dst->data(row + 2, col),
612*5f39d1b3SJooyung Han                    reinterpret_cast<v8i16>(__builtin_msa_ilvr_d(u3, u1)));
613*5f39d1b3SJooyung Han       StoreInt16x8(dst->data(row + 3, col),
614*5f39d1b3SJooyung Han                    reinterpret_cast<v8i16>(__builtin_msa_ilvl_d(u3, u1)));
615*5f39d1b3SJooyung Han       StoreInt16x8(dst->data(row + 4, col),
616*5f39d1b3SJooyung Han                    reinterpret_cast<v8i16>(__builtin_msa_ilvr_d(u6, u4)));
617*5f39d1b3SJooyung Han       StoreInt16x8(dst->data(row + 5, col),
618*5f39d1b3SJooyung Han                    reinterpret_cast<v8i16>(__builtin_msa_ilvl_d(u6, u4)));
619*5f39d1b3SJooyung Han       StoreInt16x8(dst->data(row + 6, col),
620*5f39d1b3SJooyung Han                    reinterpret_cast<v8i16>(__builtin_msa_ilvr_d(u7, u5)));
621*5f39d1b3SJooyung Han       StoreInt16x8(dst->data(row + 7, col),
622*5f39d1b3SJooyung Han                    reinterpret_cast<v8i16>(__builtin_msa_ilvl_d(u7, u5)));
623*5f39d1b3SJooyung Han     }
624*5f39d1b3SJooyung Han   }
625*5f39d1b3SJooyung Han };
626*5f39d1b3SJooyung Han 
627*5f39d1b3SJooyung Han template <typename DstType>
628*5f39d1b3SJooyung Han struct StoreFinalOutputImpl<RegBlockInt32<1, 4>, DstType> {
629*5f39d1b3SJooyung Han   static void Run(const RegBlockInt32<1, 4>& src, DstType* dst, int row,
630*5f39d1b3SJooyung Han                   int col) {
631*5f39d1b3SJooyung Han     if (DstType::kOrder == MapOrder::ColMajor) {
632*5f39d1b3SJooyung Han       *dst->data(row, col + 0) = GetLane<0>(src.buf.reg[0]);
633*5f39d1b3SJooyung Han       *dst->data(row, col + 1) = GetLane<1>(src.buf.reg[0]);
634*5f39d1b3SJooyung Han       *dst->data(row, col + 2) = GetLane<2>(src.buf.reg[0]);
635*5f39d1b3SJooyung Han       *dst->data(row, col + 3) = GetLane<3>(src.buf.reg[0]);
636*5f39d1b3SJooyung Han     } else {
637*5f39d1b3SJooyung Han       StoreInt32x4(dst->data(row, col), src.buf.reg[0]);
638*5f39d1b3SJooyung Han     }
639*5f39d1b3SJooyung Han   }
640*5f39d1b3SJooyung Han };
641*5f39d1b3SJooyung Han 
642*5f39d1b3SJooyung Han template <typename DstType>
643*5f39d1b3SJooyung Han struct StoreFinalOutputImpl<RegBlockUint8<4, 1>, DstType> {
644*5f39d1b3SJooyung Han   static void Run(const RegBlockUint8<4, 1>& src, DstType* dst, int row,
645*5f39d1b3SJooyung Han                   int col) {
646*5f39d1b3SJooyung Han     const std::uint32_t src_reg = src.buf.reg[0];
647*5f39d1b3SJooyung Han     for (int i = 0; i < 4; i++) {
648*5f39d1b3SJooyung Han       *dst->data(row + i, col) = (src_reg >> (8 * i));
649*5f39d1b3SJooyung Han     }
650*5f39d1b3SJooyung Han   }
651*5f39d1b3SJooyung Han };
652*5f39d1b3SJooyung Han 
653*5f39d1b3SJooyung Han template <typename DstType>
654*5f39d1b3SJooyung Han struct StoreFinalOutputImpl<RegBlockUint8<8, 1>, DstType> {
655*5f39d1b3SJooyung Han   static void Run(const RegBlockUint8<8, 1>& src, DstType* dst, int row,
656*5f39d1b3SJooyung Han                   int col) {
657*5f39d1b3SJooyung Han     for (int i = 0; i < 4; i++) {
658*5f39d1b3SJooyung Han       *dst->data(row + i, col) = (src.buf.reg[0] >> (8 * i));
659*5f39d1b3SJooyung Han     }
660*5f39d1b3SJooyung Han     for (int i = 0; i < 4; i++) {
661*5f39d1b3SJooyung Han       *dst->data(row + 4 + i, col) = (src.buf.reg[1] >> (8 * i));
662*5f39d1b3SJooyung Han     }
663*5f39d1b3SJooyung Han   }
664*5f39d1b3SJooyung Han };
665*5f39d1b3SJooyung Han 
666*5f39d1b3SJooyung Han template <typename DstType>
667*5f39d1b3SJooyung Han struct StoreFinalOutputImpl<RegBlockUint8<1, 4>, DstType> {
668*5f39d1b3SJooyung Han   static void Run(const RegBlockUint8<1, 4>& src, DstType* dst, int row,
669*5f39d1b3SJooyung Han                   int col) {
670*5f39d1b3SJooyung Han     for (int i = 0; i < 4; i++) {
671*5f39d1b3SJooyung Han       *dst->data(row, col + i) = (src.buf.reg[0] >> (8 * i));
672*5f39d1b3SJooyung Han     }
673*5f39d1b3SJooyung Han   }
674*5f39d1b3SJooyung Han };
675*5f39d1b3SJooyung Han 
676*5f39d1b3SJooyung Han template <typename DstType>
677*5f39d1b3SJooyung Han struct StoreFinalOutputImpl<RegBlockUint8<4, 4>, DstType> {
678*5f39d1b3SJooyung Han   static void Run(const RegBlockUint8<4, 4>& src, DstType* dst, int row,
679*5f39d1b3SJooyung Han                   int col) {
680*5f39d1b3SJooyung Han     std::uint8_t buf[16];
681*5f39d1b3SJooyung Han     StoreUint8x16(buf, src.buf.reg[0]);
682*5f39d1b3SJooyung Han     for (int c = 0; c < 4; c++) {
683*5f39d1b3SJooyung Han       for (int r = 0; r < 4; r++) {
684*5f39d1b3SJooyung Han         *dst->data(row + r, col + c) = buf[r + 4 * c];
685*5f39d1b3SJooyung Han       }
686*5f39d1b3SJooyung Han     }
687*5f39d1b3SJooyung Han   }
688*5f39d1b3SJooyung Han };
689*5f39d1b3SJooyung Han 
690*5f39d1b3SJooyung Han // There's no way to express in C++ the desired machine code for
691*5f39d1b3SJooyung Han // StoreFinalOutputImpl<RegBlockUint8<8, 4>, DstType> and
692*5f39d1b3SJooyung Han // StoreFinalOutputImpl<RegBlockUint8<8, 8>, DstType>.
693*5f39d1b3SJooyung Han // Hence, if we can, we use inline assembly, which takes advantage
694*5f39d1b3SJooyung Han // of little-endian byte order and specifics of different CPU revisions.
695*5f39d1b3SJooyung Han // Note, clang currently can't derive MSA register names from floating-
696*5f39d1b3SJooyung Han // point register names and vice versa in inline assembly.
697*5f39d1b3SJooyung Han #if defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) && \
698*5f39d1b3SJooyung Han     !defined(__clang__)
699*5f39d1b3SJooyung Han 
700*5f39d1b3SJooyung Han // Instructions for pointer-sized operands.
701*5f39d1b3SJooyung Han #ifdef GEMMLOWP_MIPS_64
702*5f39d1b3SJooyung Han #define GEMMLOWP_MIPS_XADDU "daddu"
703*5f39d1b3SJooyung Han #define GEMMLOWP_MIPS_XLSA "dlsa"
704*5f39d1b3SJooyung Han #else
705*5f39d1b3SJooyung Han #define GEMMLOWP_MIPS_XADDU "addu"
706*5f39d1b3SJooyung Han #define GEMMLOWP_MIPS_XLSA "lsa"
707*5f39d1b3SJooyung Han #endif
708*5f39d1b3SJooyung Han 
709*5f39d1b3SJooyung Han // Stores 4 8-byte half-vectors with a stride.
710*5f39d1b3SJooyung Han inline void MipsMsaStore4x8(const RegBlockUint8<8, 4>& src,
711*5f39d1b3SJooyung Han                             std::uint8_t* dst_ptr, int stride) {
712*5f39d1b3SJooyung Han #if (__mips_isa_rev >= 6)
713*5f39d1b3SJooyung Han   // Assembly temporaries that will be handily referred to by their names.
714*5f39d1b3SJooyung Han   std::uint8_t *dst_ptr1, *dst_ptr2, *dst_ptr3;
715*5f39d1b3SJooyung Han   v16i8 vtmp0, vtmp1;
716*5f39d1b3SJooyung Han   asm volatile(
717*5f39d1b3SJooyung Han     GEMMLOWP_MIPS_XADDU " %[dst_ptr1], %[dst_ptr0], %[stride]\n"
718*5f39d1b3SJooyung Han     "ilvl.d               %w[vtmp0], %w[src0], %w[src0]\n"
719*5f39d1b3SJooyung Han     GEMMLOWP_MIPS_XLSA  " %[dst_ptr2], %[stride], %[dst_ptr0], 1\n"
720*5f39d1b3SJooyung Han     "ilvl.d               %w[vtmp1], %w[src1], %w[src1]\n"
721*5f39d1b3SJooyung Han     GEMMLOWP_MIPS_XLSA  " %[dst_ptr3], %[stride], %[dst_ptr1], 1\n"
722*5f39d1b3SJooyung Han     "sdc1                 %[src0], 0(%[dst_ptr0])\n"
723*5f39d1b3SJooyung Han     "sdc1                 %[vtmp0], 0(%[dst_ptr1])\n"
724*5f39d1b3SJooyung Han     "sdc1                 %[src1], 0(%[dst_ptr2])\n"
725*5f39d1b3SJooyung Han     "sdc1                 %[vtmp1], 0(%[dst_ptr3])\n"
726*5f39d1b3SJooyung Han     :
727*5f39d1b3SJooyung Han     // Outputs.
728*5f39d1b3SJooyung Han     [dst_ptr0] "+r"(dst_ptr), [dst_ptr1] "=&r"(dst_ptr1),
729*5f39d1b3SJooyung Han     [dst_ptr2] "=&r"(dst_ptr2), [dst_ptr3] "=&r"(dst_ptr3),
730*5f39d1b3SJooyung Han     [vtmp0] "=&f"(vtmp0), [vtmp1] "=&f"(vtmp1)
731*5f39d1b3SJooyung Han     :
732*5f39d1b3SJooyung Han     // Inputs.
733*5f39d1b3SJooyung Han     [src0] "f"(src.buf.reg[0]), [src1] "f"(src.buf.reg[1]),
734*5f39d1b3SJooyung Han     [stride] "r"(stride)
735*5f39d1b3SJooyung Han     :
736*5f39d1b3SJooyung Han     // Clobbers.
737*5f39d1b3SJooyung Han     "memory");
738*5f39d1b3SJooyung Han #else
739*5f39d1b3SJooyung Han   // Assembly temporaries that will be handily referred to by their names.
740*5f39d1b3SJooyung Han   std::uint8_t *dst_ptr1, *dst_ptr2, *dst_ptr3;
741*5f39d1b3SJooyung Han   int tmp0, tmp1, tmp2, tmp3;
742*5f39d1b3SJooyung Han   asm volatile(
743*5f39d1b3SJooyung Han     GEMMLOWP_MIPS_XADDU " %[dst_ptr1], %[dst_ptr0], %[stride]\n"
744*5f39d1b3SJooyung Han     GEMMLOWP_MIPS_XLSA  " %[dst_ptr2], %[stride], %[dst_ptr0], 1\n"
745*5f39d1b3SJooyung Han     GEMMLOWP_MIPS_XLSA  " %[dst_ptr3], %[stride], %[dst_ptr1], 1\n"
746*5f39d1b3SJooyung Han     "copy_s.w             %[tmp0], %w[src0][0]\n"
747*5f39d1b3SJooyung Han     "copy_s.w             %[tmp1], %w[src0][1]\n"
748*5f39d1b3SJooyung Han     "copy_s.w             %[tmp2], %w[src0][2]\n"
749*5f39d1b3SJooyung Han     "copy_s.w             %[tmp3], %w[src0][3]\n"
750*5f39d1b3SJooyung Han     "swr                  %[tmp0], 0(%[dst_ptr0])\n"
751*5f39d1b3SJooyung Han     "swl                  %[tmp0], 3(%[dst_ptr0])\n"
752*5f39d1b3SJooyung Han     "swr                  %[tmp1], 4(%[dst_ptr0])\n"
753*5f39d1b3SJooyung Han     "swl                  %[tmp1], 7(%[dst_ptr0])\n"
754*5f39d1b3SJooyung Han     "swr                  %[tmp2], 0(%[dst_ptr1])\n"
755*5f39d1b3SJooyung Han     "swl                  %[tmp2], 3(%[dst_ptr1])\n"
756*5f39d1b3SJooyung Han     "swr                  %[tmp3], 4(%[dst_ptr1])\n"
757*5f39d1b3SJooyung Han     "swl                  %[tmp3], 7(%[dst_ptr1])\n"
758*5f39d1b3SJooyung Han     "copy_s.w             %[tmp0], %w[src1][0]\n"
759*5f39d1b3SJooyung Han     "copy_s.w             %[tmp1], %w[src1][1]\n"
760*5f39d1b3SJooyung Han     "copy_s.w             %[tmp2], %w[src1][2]\n"
761*5f39d1b3SJooyung Han     "copy_s.w             %[tmp3], %w[src1][3]\n"
762*5f39d1b3SJooyung Han     "swr                  %[tmp0], 0(%[dst_ptr2])\n"
763*5f39d1b3SJooyung Han     "swl                  %[tmp0], 3(%[dst_ptr2])\n"
764*5f39d1b3SJooyung Han     "swr                  %[tmp1], 4(%[dst_ptr2])\n"
765*5f39d1b3SJooyung Han     "swl                  %[tmp1], 7(%[dst_ptr2])\n"
766*5f39d1b3SJooyung Han     "swr                  %[tmp2], 0(%[dst_ptr3])\n"
767*5f39d1b3SJooyung Han     "swl                  %[tmp2], 3(%[dst_ptr3])\n"
768*5f39d1b3SJooyung Han     "swr                  %[tmp3], 4(%[dst_ptr3])\n"
769*5f39d1b3SJooyung Han     "swl                  %[tmp3], 7(%[dst_ptr3])\n"
770*5f39d1b3SJooyung Han     :
771*5f39d1b3SJooyung Han     // Outputs.
772*5f39d1b3SJooyung Han     [dst_ptr0] "+r"(dst_ptr), [dst_ptr1] "=&r"(dst_ptr1),
773*5f39d1b3SJooyung Han     [dst_ptr2] "=&r"(dst_ptr2), [dst_ptr3] "=&r"(dst_ptr3), [tmp0] "=&r"(tmp0),
774*5f39d1b3SJooyung Han     [tmp1] "=&r"(tmp1), [tmp2] "=&r"(tmp2), [tmp3] "=&r"(tmp3)
775*5f39d1b3SJooyung Han     :
776*5f39d1b3SJooyung Han     // Inputs.
777*5f39d1b3SJooyung Han     [src0] "f"(src.buf.reg[0]), [src1] "f"(src.buf.reg[1]),
778*5f39d1b3SJooyung Han     [stride] "r"(stride)
779*5f39d1b3SJooyung Han     :
780*5f39d1b3SJooyung Han     // Clobbers.
781*5f39d1b3SJooyung Han     "memory");
782*5f39d1b3SJooyung Han #endif
783*5f39d1b3SJooyung Han }
784*5f39d1b3SJooyung Han 
785*5f39d1b3SJooyung Han // Stores 8 4-byte quarter-vectors with a stride.
786*5f39d1b3SJooyung Han inline void MipsMsaStore8x4(const RegBlockUint8<4, 8>& src,
787*5f39d1b3SJooyung Han                             std::uint8_t* dst_ptr, int stride) {
788*5f39d1b3SJooyung Han #if (__mips_isa_rev >= 6)
789*5f39d1b3SJooyung Han   // Assembly temporaries that will be handily referred to by their names.
790*5f39d1b3SJooyung Han   std::uint8_t *dst_ptr1, *dst_ptr2, *dst_ptr3, *dst_ptr4, *dst_ptr5,
791*5f39d1b3SJooyung Han       *dst_ptr6, *dst_ptr7;
792*5f39d1b3SJooyung Han   int tmp1, tmp2, tmp3;
793*5f39d1b3SJooyung Han   asm volatile(
794*5f39d1b3SJooyung Han     GEMMLOWP_MIPS_XADDU " %[dst_ptr1], %[dst_ptr0], %[stride]\n"
795*5f39d1b3SJooyung Han     GEMMLOWP_MIPS_XLSA  " %[dst_ptr2], %[stride], %[dst_ptr0], 1\n"
796*5f39d1b3SJooyung Han     GEMMLOWP_MIPS_XLSA  " %[dst_ptr4], %[stride], %[dst_ptr0], 2\n"
797*5f39d1b3SJooyung Han     GEMMLOWP_MIPS_XLSA  " %[dst_ptr3], %[stride], %[dst_ptr1], 1\n"
798*5f39d1b3SJooyung Han     GEMMLOWP_MIPS_XLSA  " %[dst_ptr5], %[stride], %[dst_ptr1], 2\n"
799*5f39d1b3SJooyung Han     GEMMLOWP_MIPS_XLSA  " %[dst_ptr6], %[stride], %[dst_ptr2], 2\n"
800*5f39d1b3SJooyung Han     GEMMLOWP_MIPS_XLSA  " %[dst_ptr7], %[stride], %[dst_ptr3], 2\n"
801*5f39d1b3SJooyung Han     "copy_s.w             %[tmp1], %w[src0][1]\n"
802*5f39d1b3SJooyung Han     "copy_s.w             %[tmp2], %w[src0][2]\n"
803*5f39d1b3SJooyung Han     "copy_s.w             %[tmp3], %w[src0][3]\n"
804*5f39d1b3SJooyung Han     "swc1                 %[src0], 0(%[dst_ptr0])\n"
805*5f39d1b3SJooyung Han     "sw                   %[tmp1], 0(%[dst_ptr1])\n"
806*5f39d1b3SJooyung Han     "sw                   %[tmp2], 0(%[dst_ptr2])\n"
807*5f39d1b3SJooyung Han     "sw                   %[tmp3], 0(%[dst_ptr3])\n"
808*5f39d1b3SJooyung Han     "copy_s.w             %[tmp1], %w[src1][1]\n"
809*5f39d1b3SJooyung Han     "copy_s.w             %[tmp2], %w[src1][2]\n"
810*5f39d1b3SJooyung Han     "copy_s.w             %[tmp3], %w[src1][3]\n"
811*5f39d1b3SJooyung Han     "swc1                 %[src1], 0(%[dst_ptr4])\n"
812*5f39d1b3SJooyung Han     "sw                   %[tmp1], 0(%[dst_ptr5])\n"
813*5f39d1b3SJooyung Han     "sw                   %[tmp2], 0(%[dst_ptr6])\n"
814*5f39d1b3SJooyung Han     "sw                   %[tmp3], 0(%[dst_ptr7])\n"
815*5f39d1b3SJooyung Han     :
816*5f39d1b3SJooyung Han     // Outputs.
817*5f39d1b3SJooyung Han     [dst_ptr0] "+r"(dst_ptr), [dst_ptr1] "=&r"(dst_ptr1),
818*5f39d1b3SJooyung Han     [dst_ptr2] "=&r"(dst_ptr2), [dst_ptr3] "=&r"(dst_ptr3),
819*5f39d1b3SJooyung Han     [dst_ptr4] "=&r"(dst_ptr4), [dst_ptr5] "=&r"(dst_ptr5),
820*5f39d1b3SJooyung Han     [dst_ptr6] "=&r"(dst_ptr6), [dst_ptr7] "=&r"(dst_ptr7),
821*5f39d1b3SJooyung Han     [tmp1] "=&r"(tmp1), [tmp2] "=&r"(tmp2), [tmp3] "=&r"(tmp3)
822*5f39d1b3SJooyung Han     :
823*5f39d1b3SJooyung Han     // Inputs.
824*5f39d1b3SJooyung Han     [src0] "f"(src.buf.reg[0]), [src1] "f"(src.buf.reg[1]),
825*5f39d1b3SJooyung Han     [stride] "r"(stride)
826*5f39d1b3SJooyung Han     :
827*5f39d1b3SJooyung Han     // Clobbers.
828*5f39d1b3SJooyung Han     "memory");
829*5f39d1b3SJooyung Han #else
830*5f39d1b3SJooyung Han   // Assembly temporaries that will be handily referred to by their names.
831*5f39d1b3SJooyung Han   std::uint8_t *dst_ptr1, *dst_ptr2, *dst_ptr3, *dst_ptr4, *dst_ptr5,
832*5f39d1b3SJooyung Han       *dst_ptr6, *dst_ptr7;
833*5f39d1b3SJooyung Han   int tmp0, tmp1, tmp2, tmp3;
834*5f39d1b3SJooyung Han   asm volatile(
835*5f39d1b3SJooyung Han     GEMMLOWP_MIPS_XADDU " %[dst_ptr1], %[dst_ptr0], %[stride]\n"
836*5f39d1b3SJooyung Han     GEMMLOWP_MIPS_XLSA  " %[dst_ptr2], %[stride], %[dst_ptr0], 1\n"
837*5f39d1b3SJooyung Han     GEMMLOWP_MIPS_XLSA  " %[dst_ptr4], %[stride], %[dst_ptr0], 2\n"
838*5f39d1b3SJooyung Han     GEMMLOWP_MIPS_XLSA  " %[dst_ptr3], %[stride], %[dst_ptr1], 1\n"
839*5f39d1b3SJooyung Han     GEMMLOWP_MIPS_XLSA  " %[dst_ptr5], %[stride], %[dst_ptr1], 2\n"
840*5f39d1b3SJooyung Han     GEMMLOWP_MIPS_XLSA  " %[dst_ptr6], %[stride], %[dst_ptr2], 2\n"
841*5f39d1b3SJooyung Han     GEMMLOWP_MIPS_XLSA  " %[dst_ptr7], %[stride], %[dst_ptr3], 2\n"
842*5f39d1b3SJooyung Han     "copy_s.w             %[tmp0], %w[src0][0]\n"
843*5f39d1b3SJooyung Han     "copy_s.w             %[tmp1], %w[src0][1]\n"
844*5f39d1b3SJooyung Han     "copy_s.w             %[tmp2], %w[src0][2]\n"
845*5f39d1b3SJooyung Han     "copy_s.w             %[tmp3], %w[src0][3]\n"
846*5f39d1b3SJooyung Han     "swr                  %[tmp0], 0(%[dst_ptr0])\n"
847*5f39d1b3SJooyung Han     "swl                  %[tmp0], 3(%[dst_ptr0])\n"
848*5f39d1b3SJooyung Han     "swr                  %[tmp1], 0(%[dst_ptr1])\n"
849*5f39d1b3SJooyung Han     "swl                  %[tmp1], 3(%[dst_ptr1])\n"
850*5f39d1b3SJooyung Han     "swr                  %[tmp2], 0(%[dst_ptr2])\n"
851*5f39d1b3SJooyung Han     "swl                  %[tmp2], 3(%[dst_ptr2])\n"
852*5f39d1b3SJooyung Han     "swr                  %[tmp3], 0(%[dst_ptr3])\n"
853*5f39d1b3SJooyung Han     "swl                  %[tmp3], 3(%[dst_ptr3])\n"
854*5f39d1b3SJooyung Han     "copy_s.w             %[tmp0], %w[src1][0]\n"
855*5f39d1b3SJooyung Han     "copy_s.w             %[tmp1], %w[src1][1]\n"
856*5f39d1b3SJooyung Han     "copy_s.w             %[tmp2], %w[src1][2]\n"
857*5f39d1b3SJooyung Han     "copy_s.w             %[tmp3], %w[src1][3]\n"
858*5f39d1b3SJooyung Han     "swr                  %[tmp0], 0(%[dst_ptr4])\n"
859*5f39d1b3SJooyung Han     "swl                  %[tmp0], 3(%[dst_ptr4])\n"
860*5f39d1b3SJooyung Han     "swr                  %[tmp1], 0(%[dst_ptr5])\n"
861*5f39d1b3SJooyung Han     "swl                  %[tmp1], 3(%[dst_ptr5])\n"
862*5f39d1b3SJooyung Han     "swr                  %[tmp2], 0(%[dst_ptr6])\n"
863*5f39d1b3SJooyung Han     "swl                  %[tmp2], 3(%[dst_ptr6])\n"
864*5f39d1b3SJooyung Han     "swr                  %[tmp3], 0(%[dst_ptr7])\n"
865*5f39d1b3SJooyung Han     "swl                  %[tmp3], 3(%[dst_ptr7])\n"
866*5f39d1b3SJooyung Han     :
867*5f39d1b3SJooyung Han     // Outputs.
868*5f39d1b3SJooyung Han     [dst_ptr0] "+r"(dst_ptr), [dst_ptr1] "=&r"(dst_ptr1),
869*5f39d1b3SJooyung Han     [dst_ptr2] "=&r"(dst_ptr2), [dst_ptr3] "=&r"(dst_ptr3),
870*5f39d1b3SJooyung Han     [dst_ptr4] "=&r"(dst_ptr4), [dst_ptr5] "=&r"(dst_ptr5),
871*5f39d1b3SJooyung Han     [dst_ptr6] "=&r"(dst_ptr6), [dst_ptr7] "=&r"(dst_ptr7),
872*5f39d1b3SJooyung Han     [tmp0] "=&r"(tmp0), [tmp1] "=&r"(tmp1), [tmp2] "=&r"(tmp2),
873*5f39d1b3SJooyung Han     [tmp3] "=&r"(tmp3)
874*5f39d1b3SJooyung Han     :
875*5f39d1b3SJooyung Han     // Inputs.
876*5f39d1b3SJooyung Han     [src0] "f"(src.buf.reg[0]), [src1] "f"(src.buf.reg[1]),
877*5f39d1b3SJooyung Han     [stride] "r"(stride)
878*5f39d1b3SJooyung Han     :
879*5f39d1b3SJooyung Han     // Clobbers.
880*5f39d1b3SJooyung Han     "memory");
881*5f39d1b3SJooyung Han #endif
882*5f39d1b3SJooyung Han }
883*5f39d1b3SJooyung Han 
884*5f39d1b3SJooyung Han // Stores 8 8-byte half-vectors with a stride.
885*5f39d1b3SJooyung Han inline void MipsMsaStore8x8(const RegBlockUint8<8, 8>& src,
886*5f39d1b3SJooyung Han                             std::uint8_t* dst_ptr, int stride) {
887*5f39d1b3SJooyung Han #if (__mips_isa_rev >= 6)
888*5f39d1b3SJooyung Han   // Assembly temporaries that will be handily referred to by their names.
889*5f39d1b3SJooyung Han   std::uint8_t *dst_ptr1, *dst_ptr2, *dst_ptr3, *dst_ptr4, *dst_ptr5,
890*5f39d1b3SJooyung Han       *dst_ptr6, *dst_ptr7;
891*5f39d1b3SJooyung Han   v16i8 vtmp0, vtmp1, vtmp2, vtmp3;
892*5f39d1b3SJooyung Han   asm volatile(
893*5f39d1b3SJooyung Han     "ilvl.d               %w[vtmp0], %w[src0], %w[src0]\n"
894*5f39d1b3SJooyung Han     GEMMLOWP_MIPS_XADDU " %[dst_ptr1], %[dst_ptr0], %[stride]\n"
895*5f39d1b3SJooyung Han     GEMMLOWP_MIPS_XLSA  " %[dst_ptr2], %[stride], %[dst_ptr0], 1\n"
896*5f39d1b3SJooyung Han     "ilvl.d               %w[vtmp1], %w[src1], %w[src1]\n"
897*5f39d1b3SJooyung Han     GEMMLOWP_MIPS_XLSA  " %[dst_ptr4], %[stride], %[dst_ptr0], 2\n"
898*5f39d1b3SJooyung Han     GEMMLOWP_MIPS_XLSA  " %[dst_ptr3], %[stride], %[dst_ptr1], 1\n"
899*5f39d1b3SJooyung Han     "ilvl.d               %w[vtmp2], %w[src2], %w[src2]\n"
900*5f39d1b3SJooyung Han     GEMMLOWP_MIPS_XLSA  " %[dst_ptr5], %[stride], %[dst_ptr1], 2\n"
901*5f39d1b3SJooyung Han     GEMMLOWP_MIPS_XLSA  " %[dst_ptr6], %[stride], %[dst_ptr2], 2\n"
902*5f39d1b3SJooyung Han     "ilvl.d               %w[vtmp3], %w[src3], %w[src3]\n"
903*5f39d1b3SJooyung Han     GEMMLOWP_MIPS_XLSA  " %[dst_ptr7], %[stride], %[dst_ptr3], 2\n"
904*5f39d1b3SJooyung Han     "sdc1                 %[src0], 0(%[dst_ptr0])\n"
905*5f39d1b3SJooyung Han     "sdc1                 %[vtmp0], 0(%[dst_ptr1])\n"
906*5f39d1b3SJooyung Han     "sdc1                 %[src1], 0(%[dst_ptr2])\n"
907*5f39d1b3SJooyung Han     "sdc1                 %[vtmp1], 0(%[dst_ptr3])\n"
908*5f39d1b3SJooyung Han     "sdc1                 %[src2], 0(%[dst_ptr4])\n"
909*5f39d1b3SJooyung Han     "sdc1                 %[vtmp2], 0(%[dst_ptr5])\n"
910*5f39d1b3SJooyung Han     "sdc1                 %[src3], 0(%[dst_ptr6])\n"
911*5f39d1b3SJooyung Han     "sdc1                 %[vtmp3], 0(%[dst_ptr7])\n"
912*5f39d1b3SJooyung Han     :
913*5f39d1b3SJooyung Han     // Outputs.
914*5f39d1b3SJooyung Han     [dst_ptr0] "+r"(dst_ptr), [dst_ptr1] "=&r"(dst_ptr1),
915*5f39d1b3SJooyung Han     [dst_ptr2] "=&r"(dst_ptr2), [dst_ptr3] "=&r"(dst_ptr3),
916*5f39d1b3SJooyung Han     [dst_ptr4] "=&r"(dst_ptr4), [dst_ptr5] "=&r"(dst_ptr5),
917*5f39d1b3SJooyung Han     [dst_ptr6] "=&r"(dst_ptr6), [dst_ptr7] "=&r"(dst_ptr7),
918*5f39d1b3SJooyung Han     [vtmp0] "=&f"(vtmp0), [vtmp1] "=&f"(vtmp1), [vtmp2] "=&f"(vtmp2),
919*5f39d1b3SJooyung Han     [vtmp3] "=&f"(vtmp3)
920*5f39d1b3SJooyung Han     :
921*5f39d1b3SJooyung Han     // Inputs.
922*5f39d1b3SJooyung Han     [src0] "f"(src.buf.reg[0]), [src1] "f"(src.buf.reg[1]),
923*5f39d1b3SJooyung Han     [src2] "f"(src.buf.reg[2]), [src3] "f"(src.buf.reg[3]),
924*5f39d1b3SJooyung Han     [stride] "r"(stride)
925*5f39d1b3SJooyung Han     :
926*5f39d1b3SJooyung Han     // Clobbers.
927*5f39d1b3SJooyung Han     "memory");
928*5f39d1b3SJooyung Han #else
929*5f39d1b3SJooyung Han   // Assembly temporaries that will be handily referred to by their names.
930*5f39d1b3SJooyung Han   std::uint8_t *dst_ptr1, *dst_ptr2, *dst_ptr3, *dst_ptr4, *dst_ptr5,
931*5f39d1b3SJooyung Han       *dst_ptr6, *dst_ptr7;
932*5f39d1b3SJooyung Han   int tmp0, tmp1, tmp2, tmp3;
933*5f39d1b3SJooyung Han   asm volatile(
934*5f39d1b3SJooyung Han     GEMMLOWP_MIPS_XADDU " %[dst_ptr1], %[dst_ptr0], %[stride]\n"
935*5f39d1b3SJooyung Han     GEMMLOWP_MIPS_XLSA  " %[dst_ptr2], %[stride], %[dst_ptr0], 1\n"
936*5f39d1b3SJooyung Han     GEMMLOWP_MIPS_XLSA  " %[dst_ptr4], %[stride], %[dst_ptr0], 2\n"
937*5f39d1b3SJooyung Han     GEMMLOWP_MIPS_XLSA  " %[dst_ptr3], %[stride], %[dst_ptr1], 1\n"
938*5f39d1b3SJooyung Han     GEMMLOWP_MIPS_XLSA  " %[dst_ptr5], %[stride], %[dst_ptr1], 2\n"
939*5f39d1b3SJooyung Han     GEMMLOWP_MIPS_XLSA  " %[dst_ptr6], %[stride], %[dst_ptr2], 2\n"
940*5f39d1b3SJooyung Han     GEMMLOWP_MIPS_XLSA  " %[dst_ptr7], %[stride], %[dst_ptr3], 2\n"
941*5f39d1b3SJooyung Han     "copy_s.w             %[tmp0], %w[src0][0]\n"
942*5f39d1b3SJooyung Han     "copy_s.w             %[tmp1], %w[src0][1]\n"
943*5f39d1b3SJooyung Han     "copy_s.w             %[tmp2], %w[src0][2]\n"
944*5f39d1b3SJooyung Han     "copy_s.w             %[tmp3], %w[src0][3]\n"
945*5f39d1b3SJooyung Han     "swr                  %[tmp0], 0(%[dst_ptr0])\n"
946*5f39d1b3SJooyung Han     "swl                  %[tmp0], 3(%[dst_ptr0])\n"
947*5f39d1b3SJooyung Han     "swr                  %[tmp1], 4(%[dst_ptr0])\n"
948*5f39d1b3SJooyung Han     "swl                  %[tmp1], 7(%[dst_ptr0])\n"
949*5f39d1b3SJooyung Han     "swr                  %[tmp2], 0(%[dst_ptr1])\n"
950*5f39d1b3SJooyung Han     "swl                  %[tmp2], 3(%[dst_ptr1])\n"
951*5f39d1b3SJooyung Han     "swr                  %[tmp3], 4(%[dst_ptr1])\n"
952*5f39d1b3SJooyung Han     "swl                  %[tmp3], 7(%[dst_ptr1])\n"
953*5f39d1b3SJooyung Han     "copy_s.w             %[tmp0], %w[src1][0]\n"
954*5f39d1b3SJooyung Han     "copy_s.w             %[tmp1], %w[src1][1]\n"
955*5f39d1b3SJooyung Han     "copy_s.w             %[tmp2], %w[src1][2]\n"
956*5f39d1b3SJooyung Han     "copy_s.w             %[tmp3], %w[src1][3]\n"
957*5f39d1b3SJooyung Han     "swr                  %[tmp0], 0(%[dst_ptr2])\n"
958*5f39d1b3SJooyung Han     "swl                  %[tmp0], 3(%[dst_ptr2])\n"
959*5f39d1b3SJooyung Han     "swr                  %[tmp1], 4(%[dst_ptr2])\n"
960*5f39d1b3SJooyung Han     "swl                  %[tmp1], 7(%[dst_ptr2])\n"
961*5f39d1b3SJooyung Han     "swr                  %[tmp2], 0(%[dst_ptr3])\n"
962*5f39d1b3SJooyung Han     "swl                  %[tmp2], 3(%[dst_ptr3])\n"
963*5f39d1b3SJooyung Han     "swr                  %[tmp3], 4(%[dst_ptr3])\n"
964*5f39d1b3SJooyung Han     "swl                  %[tmp3], 7(%[dst_ptr3])\n"
965*5f39d1b3SJooyung Han     "copy_s.w             %[tmp0], %w[src2][0]\n"
966*5f39d1b3SJooyung Han     "copy_s.w             %[tmp1], %w[src2][1]\n"
967*5f39d1b3SJooyung Han     "copy_s.w             %[tmp2], %w[src2][2]\n"
968*5f39d1b3SJooyung Han     "copy_s.w             %[tmp3], %w[src2][3]\n"
969*5f39d1b3SJooyung Han     "swr                  %[tmp0], 0(%[dst_ptr4])\n"
970*5f39d1b3SJooyung Han     "swl                  %[tmp0], 3(%[dst_ptr4])\n"
971*5f39d1b3SJooyung Han     "swr                  %[tmp1], 4(%[dst_ptr4])\n"
972*5f39d1b3SJooyung Han     "swl                  %[tmp1], 7(%[dst_ptr4])\n"
973*5f39d1b3SJooyung Han     "swr                  %[tmp2], 0(%[dst_ptr5])\n"
974*5f39d1b3SJooyung Han     "swl                  %[tmp2], 3(%[dst_ptr5])\n"
975*5f39d1b3SJooyung Han     "swr                  %[tmp3], 4(%[dst_ptr5])\n"
976*5f39d1b3SJooyung Han     "swl                  %[tmp3], 7(%[dst_ptr5])\n"
977*5f39d1b3SJooyung Han     "copy_s.w             %[tmp0], %w[src3][0]\n"
978*5f39d1b3SJooyung Han     "copy_s.w             %[tmp1], %w[src3][1]\n"
979*5f39d1b3SJooyung Han     "copy_s.w             %[tmp2], %w[src3][2]\n"
980*5f39d1b3SJooyung Han     "copy_s.w             %[tmp3], %w[src3][3]\n"
981*5f39d1b3SJooyung Han     "swr                  %[tmp0], 0(%[dst_ptr6])\n"
982*5f39d1b3SJooyung Han     "swl                  %[tmp0], 3(%[dst_ptr6])\n"
983*5f39d1b3SJooyung Han     "swr                  %[tmp1], 4(%[dst_ptr6])\n"
984*5f39d1b3SJooyung Han     "swl                  %[tmp1], 7(%[dst_ptr6])\n"
985*5f39d1b3SJooyung Han     "swr                  %[tmp2], 0(%[dst_ptr7])\n"
986*5f39d1b3SJooyung Han     "swl                  %[tmp2], 3(%[dst_ptr7])\n"
987*5f39d1b3SJooyung Han     "swr                  %[tmp3], 4(%[dst_ptr7])\n"
988*5f39d1b3SJooyung Han     "swl                  %[tmp3], 7(%[dst_ptr7])\n"
989*5f39d1b3SJooyung Han     :
990*5f39d1b3SJooyung Han     // Outputs.
991*5f39d1b3SJooyung Han     [dst_ptr0] "+r"(dst_ptr), [dst_ptr1] "=&r"(dst_ptr1),
992*5f39d1b3SJooyung Han     [dst_ptr2] "=&r"(dst_ptr2), [dst_ptr3] "=&r"(dst_ptr3),
993*5f39d1b3SJooyung Han     [dst_ptr4] "=&r"(dst_ptr4), [dst_ptr5] "=&r"(dst_ptr5),
994*5f39d1b3SJooyung Han     [dst_ptr6] "=&r"(dst_ptr6), [dst_ptr7] "=&r"(dst_ptr7),
995*5f39d1b3SJooyung Han     [tmp0] "=&r"(tmp0), [tmp1] "=&r"(tmp1), [tmp2] "=&r"(tmp2),
996*5f39d1b3SJooyung Han     [tmp3] "=&r"(tmp3)
997*5f39d1b3SJooyung Han     :
998*5f39d1b3SJooyung Han     // Inputs.
999*5f39d1b3SJooyung Han     [src0] "f"(src.buf.reg[0]), [src1] "f"(src.buf.reg[1]),
1000*5f39d1b3SJooyung Han     [src2] "f"(src.buf.reg[2]), [src3] "f"(src.buf.reg[3]),
1001*5f39d1b3SJooyung Han     [stride] "r"(stride)
1002*5f39d1b3SJooyung Han     :
1003*5f39d1b3SJooyung Han     // Clobbers.
1004*5f39d1b3SJooyung Han     "memory");
1005*5f39d1b3SJooyung Han #endif
1006*5f39d1b3SJooyung Han }
1007*5f39d1b3SJooyung Han 
1008*5f39d1b3SJooyung Han #undef GEMMLOWP_MIPS_XADDU
1009*5f39d1b3SJooyung Han #undef GEMMLOWP_MIPS_XLSA
1010*5f39d1b3SJooyung Han 
1011*5f39d1b3SJooyung Han // Transposes a column-major 8x4 block for storage into a row-major matrix.
1012*5f39d1b3SJooyung Han inline RegBlockUint8<4, 8> Transpose(const RegBlockUint8<8, 4>& src) {
1013*5f39d1b3SJooyung Han   v16i8 tmp0 = __builtin_msa_ilvr_b(src.buf.reg[1], src.buf.reg[0]);
1014*5f39d1b3SJooyung Han   v16i8 tmp1 = __builtin_msa_ilvl_b(src.buf.reg[1], src.buf.reg[0]);
1015*5f39d1b3SJooyung Han   RegBlockUint8<4, 8> result;
1016*5f39d1b3SJooyung Han   result.buf.reg[0] = __builtin_msa_ilvr_b(tmp1, tmp0);
1017*5f39d1b3SJooyung Han   result.buf.reg[1] = __builtin_msa_ilvl_b(tmp1, tmp0);
1018*5f39d1b3SJooyung Han   return result;
1019*5f39d1b3SJooyung Han }
1020*5f39d1b3SJooyung Han 
1021*5f39d1b3SJooyung Han inline RegBlockUint8<8, 8> Transpose(const RegBlockUint8<8, 8>& src) {
1022*5f39d1b3SJooyung Han   v16i8 tmp0[4];
1023*5f39d1b3SJooyung Han   tmp0[0] = __builtin_msa_ilvr_b(src.buf.reg[1], src.buf.reg[0]);
1024*5f39d1b3SJooyung Han   tmp0[1] = __builtin_msa_ilvl_b(src.buf.reg[1], src.buf.reg[0]);
1025*5f39d1b3SJooyung Han   tmp0[2] = __builtin_msa_ilvr_b(src.buf.reg[3], src.buf.reg[2]);
1026*5f39d1b3SJooyung Han   tmp0[3] = __builtin_msa_ilvl_b(src.buf.reg[3], src.buf.reg[2]);
1027*5f39d1b3SJooyung Han   v16i8 tmp1[4];
1028*5f39d1b3SJooyung Han   tmp1[0] = __builtin_msa_ilvr_b(tmp0[1], tmp0[0]);
1029*5f39d1b3SJooyung Han   tmp1[1] = __builtin_msa_ilvl_b(tmp0[1], tmp0[0]);
1030*5f39d1b3SJooyung Han   tmp1[2] = __builtin_msa_ilvr_b(tmp0[3], tmp0[2]);
1031*5f39d1b3SJooyung Han   tmp1[3] = __builtin_msa_ilvl_b(tmp0[3], tmp0[2]);
1032*5f39d1b3SJooyung Han   RegBlockUint8<8, 8> result;
1033*5f39d1b3SJooyung Han   result.buf.reg[0] = reinterpret_cast<v16i8>(__builtin_msa_ilvr_w(
1034*5f39d1b3SJooyung Han       reinterpret_cast<v4i32>(tmp1[2]), reinterpret_cast<v4i32>(tmp1[0])));
1035*5f39d1b3SJooyung Han   result.buf.reg[1] = reinterpret_cast<v16i8>(__builtin_msa_ilvl_w(
1036*5f39d1b3SJooyung Han       reinterpret_cast<v4i32>(tmp1[2]), reinterpret_cast<v4i32>(tmp1[0])));
1037*5f39d1b3SJooyung Han   result.buf.reg[2] = reinterpret_cast<v16i8>(__builtin_msa_ilvr_w(
1038*5f39d1b3SJooyung Han       reinterpret_cast<v4i32>(tmp1[3]), reinterpret_cast<v4i32>(tmp1[1])));
1039*5f39d1b3SJooyung Han   result.buf.reg[3] = reinterpret_cast<v16i8>(__builtin_msa_ilvl_w(
1040*5f39d1b3SJooyung Han       reinterpret_cast<v4i32>(tmp1[3]), reinterpret_cast<v4i32>(tmp1[1])));
1041*5f39d1b3SJooyung Han   return result;
1042*5f39d1b3SJooyung Han }
1043*5f39d1b3SJooyung Han 
1044*5f39d1b3SJooyung Han template <typename DstType>
1045*5f39d1b3SJooyung Han struct StoreFinalOutputImpl<RegBlockUint8<8, 4>, DstType> {
1046*5f39d1b3SJooyung Han   static void Run(const RegBlockUint8<8, 4>& src, DstType* dst, int row,
1047*5f39d1b3SJooyung Han                   int col) {
1048*5f39d1b3SJooyung Han     if (DstType::kOrder == MapOrder::ColMajor) {
1049*5f39d1b3SJooyung Han       std::uint8_t* dst_ptr = dst->data(row, col);
1050*5f39d1b3SJooyung Han       int col_stride = dst->cols_stride();
1051*5f39d1b3SJooyung Han       MipsMsaStore4x8(src, dst_ptr, col_stride);
1052*5f39d1b3SJooyung Han     } else {
1053*5f39d1b3SJooyung Han       const auto& block = Transpose(src);
1054*5f39d1b3SJooyung Han       std::uint8_t* dst_ptr = dst->data(row, col);
1055*5f39d1b3SJooyung Han       int row_stride = dst->rows_stride();
1056*5f39d1b3SJooyung Han       MipsMsaStore8x4(block, dst_ptr, row_stride);
1057*5f39d1b3SJooyung Han     }
1058*5f39d1b3SJooyung Han   }
1059*5f39d1b3SJooyung Han };
1060*5f39d1b3SJooyung Han 
1061*5f39d1b3SJooyung Han template <typename DstType>
1062*5f39d1b3SJooyung Han struct StoreFinalOutputImpl<RegBlockUint8<8, 8>, DstType> {
1063*5f39d1b3SJooyung Han   static void Run(const RegBlockUint8<8, 8>& src, DstType* dst, int row,
1064*5f39d1b3SJooyung Han                   int col) {
1065*5f39d1b3SJooyung Han     const auto& block =
1066*5f39d1b3SJooyung Han         (DstType::kOrder == MapOrder::ColMajor) ? src : Transpose(src);
1067*5f39d1b3SJooyung Han     std::uint8_t* dst_ptr = dst->data(row, col);
1068*5f39d1b3SJooyung Han     int stride = dst->stride();
1069*5f39d1b3SJooyung Han     MipsMsaStore8x8(block, dst_ptr, stride);
1070*5f39d1b3SJooyung Han   }
1071*5f39d1b3SJooyung Han };
1072*5f39d1b3SJooyung Han 
1073*5f39d1b3SJooyung Han #else
1074*5f39d1b3SJooyung Han 
1075*5f39d1b3SJooyung Han template <typename DstType>
1076*5f39d1b3SJooyung Han struct StoreFinalOutputImpl<RegBlockUint8<8, 4>, DstType> {
1077*5f39d1b3SJooyung Han   static void Run(const RegBlockUint8<8, 4>& src, DstType* dst, int row,
1078*5f39d1b3SJooyung Han                   int col) {
1079*5f39d1b3SJooyung Han     std::uint8_t buf[32];
1080*5f39d1b3SJooyung Han     StoreUint8x16(buf, src.buf.reg[0]);
1081*5f39d1b3SJooyung Han     StoreUint8x16(buf + 16, src.buf.reg[1]);
1082*5f39d1b3SJooyung Han     for (int c = 0; c < 4; c++) {
1083*5f39d1b3SJooyung Han       for (int r = 0; r < 8; r++) {
1084*5f39d1b3SJooyung Han         *dst->data(row + r, col + c) = buf[r + 8 * c];
1085*5f39d1b3SJooyung Han       }
1086*5f39d1b3SJooyung Han     }
1087*5f39d1b3SJooyung Han   }
1088*5f39d1b3SJooyung Han };
1089*5f39d1b3SJooyung Han 
1090*5f39d1b3SJooyung Han template <typename DstType>
1091*5f39d1b3SJooyung Han struct StoreFinalOutputImpl<RegBlockUint8<8, 8>, DstType> {
1092*5f39d1b3SJooyung Han   static void Run(const RegBlockUint8<8, 8>& src, DstType* dst, int row,
1093*5f39d1b3SJooyung Han                   int col) {
1094*5f39d1b3SJooyung Han     std::uint8_t buf[64];
1095*5f39d1b3SJooyung Han     StoreUint8x16(buf, src.buf.reg[0]);
1096*5f39d1b3SJooyung Han     StoreUint8x16(buf + 16, src.buf.reg[1]);
1097*5f39d1b3SJooyung Han     StoreUint8x16(buf + 32, src.buf.reg[2]);
1098*5f39d1b3SJooyung Han     StoreUint8x16(buf + 48, src.buf.reg[3]);
1099*5f39d1b3SJooyung Han     for (int c = 0; c < 8; c++) {
1100*5f39d1b3SJooyung Han       for (int r = 0; r < 8; r++) {
1101*5f39d1b3SJooyung Han         *dst->data(row + r, col + c) = buf[r + 8 * c];
1102*5f39d1b3SJooyung Han       }
1103*5f39d1b3SJooyung Han     }
1104*5f39d1b3SJooyung Han   }
1105*5f39d1b3SJooyung Han };
1106*5f39d1b3SJooyung Han 
1107*5f39d1b3SJooyung Han #endif  // Endianness, compiler.
1108*5f39d1b3SJooyung Han 
1109*5f39d1b3SJooyung Han }  // namespace gemmlowp
1110*5f39d1b3SJooyung Han 
1111*5f39d1b3SJooyung Han #endif  // GEMMLOWP_INTERNAL_OUTPUT_MSA_H_
1112