xref: /aosp_15_r20/external/gemmlowp/fixedpoint/fixedpoint_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 // fixedpoint_msa.h: optimized MSA specializations of the templates
16*5f39d1b3SJooyung Han // in fixedpoint.h.
17*5f39d1b3SJooyung Han 
18*5f39d1b3SJooyung Han #ifndef GEMMLOWP_INTERNAL_FIXEDPOINT_MSA_H_
19*5f39d1b3SJooyung Han #define GEMMLOWP_INTERNAL_FIXEDPOINT_MSA_H_
20*5f39d1b3SJooyung Han 
21*5f39d1b3SJooyung Han #include <msa.h>
22*5f39d1b3SJooyung Han 
23*5f39d1b3SJooyung Han namespace gemmlowp {
24*5f39d1b3SJooyung Han 
25*5f39d1b3SJooyung Han template <>
26*5f39d1b3SJooyung Han struct FixedPointRawTypeTraits<v4i32> {
27*5f39d1b3SJooyung Han   typedef std::int32_t ScalarRawType;
28*5f39d1b3SJooyung Han   static constexpr int kLanes = 4;
29*5f39d1b3SJooyung Han };
30*5f39d1b3SJooyung Han 
31*5f39d1b3SJooyung Han template <>
32*5f39d1b3SJooyung Han struct FixedPointRawTypeTraits<v8i16> {
33*5f39d1b3SJooyung Han   typedef std::int16_t ScalarRawType;
34*5f39d1b3SJooyung Han   static constexpr int kLanes = 8;
35*5f39d1b3SJooyung Han };
36*5f39d1b3SJooyung Han 
37*5f39d1b3SJooyung Han template <>
38*5f39d1b3SJooyung Han inline v4i32 BitAnd(v4i32 a, v4i32 b) {
39*5f39d1b3SJooyung Han   return reinterpret_cast<v4i32>(__builtin_msa_and_v(reinterpret_cast<v16u8>(a),
40*5f39d1b3SJooyung Han                                                      reinterpret_cast<v16u8>(b)));
41*5f39d1b3SJooyung Han }
42*5f39d1b3SJooyung Han 
43*5f39d1b3SJooyung Han template <>
44*5f39d1b3SJooyung Han inline v8i16 BitAnd(v8i16 a, v8i16 b) {
45*5f39d1b3SJooyung Han   return reinterpret_cast<v8i16>(__builtin_msa_and_v(reinterpret_cast<v16u8>(a),
46*5f39d1b3SJooyung Han                                                      reinterpret_cast<v16u8>(b)));
47*5f39d1b3SJooyung Han }
48*5f39d1b3SJooyung Han 
49*5f39d1b3SJooyung Han template <>
50*5f39d1b3SJooyung Han inline v4i32 BitOr(v4i32 a, v4i32 b) {
51*5f39d1b3SJooyung Han   return reinterpret_cast<v4i32>(__builtin_msa_or_v(reinterpret_cast<v16u8>(a),
52*5f39d1b3SJooyung Han                                                     reinterpret_cast<v16u8>(b)));
53*5f39d1b3SJooyung Han }
54*5f39d1b3SJooyung Han 
55*5f39d1b3SJooyung Han template <>
56*5f39d1b3SJooyung Han inline v8i16 BitOr(v8i16 a, v8i16 b) {
57*5f39d1b3SJooyung Han   return reinterpret_cast<v8i16>(__builtin_msa_or_v(reinterpret_cast<v16u8>(a),
58*5f39d1b3SJooyung Han                                                     reinterpret_cast<v16u8>(b)));
59*5f39d1b3SJooyung Han }
60*5f39d1b3SJooyung Han 
61*5f39d1b3SJooyung Han template <>
62*5f39d1b3SJooyung Han inline v4i32 BitXor(v4i32 a, v4i32 b) {
63*5f39d1b3SJooyung Han   return reinterpret_cast<v4i32>(__builtin_msa_xor_v(reinterpret_cast<v16u8>(a),
64*5f39d1b3SJooyung Han                                                      reinterpret_cast<v16u8>(b)));
65*5f39d1b3SJooyung Han }
66*5f39d1b3SJooyung Han 
67*5f39d1b3SJooyung Han template <>
68*5f39d1b3SJooyung Han inline v8i16 BitXor(v8i16 a, v8i16 b) {
69*5f39d1b3SJooyung Han   return reinterpret_cast<v8i16>(__builtin_msa_xor_v(reinterpret_cast<v16u8>(a),
70*5f39d1b3SJooyung Han                                                      reinterpret_cast<v16u8>(b)));
71*5f39d1b3SJooyung Han }
72*5f39d1b3SJooyung Han 
73*5f39d1b3SJooyung Han template <>
74*5f39d1b3SJooyung Han inline v4i32 BitNot(v4i32 a) {
75*5f39d1b3SJooyung Han   return reinterpret_cast<v4i32>(__builtin_msa_nor_v(reinterpret_cast<v16u8>(a),
76*5f39d1b3SJooyung Han                                                      reinterpret_cast<v16u8>(a)));
77*5f39d1b3SJooyung Han }
78*5f39d1b3SJooyung Han 
79*5f39d1b3SJooyung Han template <>
80*5f39d1b3SJooyung Han inline v8i16 BitNot(v8i16 a) {
81*5f39d1b3SJooyung Han   return reinterpret_cast<v8i16>(__builtin_msa_nor_v(reinterpret_cast<v16u8>(a),
82*5f39d1b3SJooyung Han                                                      reinterpret_cast<v16u8>(a)));
83*5f39d1b3SJooyung Han }
84*5f39d1b3SJooyung Han 
85*5f39d1b3SJooyung Han template <>
86*5f39d1b3SJooyung Han inline v4i32 Add(v4i32 a, v4i32 b) {
87*5f39d1b3SJooyung Han   return __builtin_msa_addv_w(a, b);
88*5f39d1b3SJooyung Han }
89*5f39d1b3SJooyung Han 
90*5f39d1b3SJooyung Han template <>
91*5f39d1b3SJooyung Han inline v8i16 Add(v8i16 a, v8i16 b) {
92*5f39d1b3SJooyung Han   return __builtin_msa_addv_h(a, b);
93*5f39d1b3SJooyung Han }
94*5f39d1b3SJooyung Han 
95*5f39d1b3SJooyung Han template <>
96*5f39d1b3SJooyung Han inline v4i32 Sub(v4i32 a, v4i32 b) {
97*5f39d1b3SJooyung Han   return __builtin_msa_subv_w(a, b);
98*5f39d1b3SJooyung Han }
99*5f39d1b3SJooyung Han 
100*5f39d1b3SJooyung Han template <>
101*5f39d1b3SJooyung Han inline v8i16 Sub(v8i16 a, v8i16 b) {
102*5f39d1b3SJooyung Han   return __builtin_msa_subv_h(a, b);
103*5f39d1b3SJooyung Han }
104*5f39d1b3SJooyung Han 
105*5f39d1b3SJooyung Han template <>
106*5f39d1b3SJooyung Han inline v4i32 Neg(v4i32 a) {
107*5f39d1b3SJooyung Han   v4i32 zeroes = __builtin_msa_ldi_w(0);
108*5f39d1b3SJooyung Han   return __builtin_msa_subv_w(zeroes, a);
109*5f39d1b3SJooyung Han }
110*5f39d1b3SJooyung Han 
111*5f39d1b3SJooyung Han template <>
112*5f39d1b3SJooyung Han inline v8i16 Neg(v8i16 a) {
113*5f39d1b3SJooyung Han   v8i16 zeroes = __builtin_msa_ldi_h(0);
114*5f39d1b3SJooyung Han   return __builtin_msa_subv_h(zeroes, a);
115*5f39d1b3SJooyung Han }
116*5f39d1b3SJooyung Han 
117*5f39d1b3SJooyung Han template <>
118*5f39d1b3SJooyung Han inline v4i32 ShiftLeft(v4i32 a, int offset) {
119*5f39d1b3SJooyung Han   return __builtin_msa_sll_w(a, __builtin_msa_fill_w(offset));
120*5f39d1b3SJooyung Han }
121*5f39d1b3SJooyung Han 
122*5f39d1b3SJooyung Han template <>
123*5f39d1b3SJooyung Han inline v8i16 ShiftLeft(v8i16 a, int offset) {
124*5f39d1b3SJooyung Han   return __builtin_msa_sll_h(a, __builtin_msa_fill_h(offset));
125*5f39d1b3SJooyung Han }
126*5f39d1b3SJooyung Han 
127*5f39d1b3SJooyung Han template <>
128*5f39d1b3SJooyung Han inline v4i32 ShiftRight(v4i32 a, int offset) {
129*5f39d1b3SJooyung Han   return __builtin_msa_sra_w(a, __builtin_msa_fill_w(offset));
130*5f39d1b3SJooyung Han }
131*5f39d1b3SJooyung Han 
132*5f39d1b3SJooyung Han template <>
133*5f39d1b3SJooyung Han inline v8i16 ShiftRight(v8i16 a, int offset) {
134*5f39d1b3SJooyung Han   return __builtin_msa_sra_h(a, __builtin_msa_fill_h(offset));
135*5f39d1b3SJooyung Han }
136*5f39d1b3SJooyung Han 
137*5f39d1b3SJooyung Han template <>
138*5f39d1b3SJooyung Han inline v4i32 SelectUsingMask(v4i32 if_mask, v4i32 then_val, v4i32 else_val) {
139*5f39d1b3SJooyung Han   if_mask = reinterpret_cast<v4i32>(__builtin_msa_bsel_v(reinterpret_cast<v16u8>(if_mask),
140*5f39d1b3SJooyung Han                                                          reinterpret_cast<v16u8>(else_val),
141*5f39d1b3SJooyung Han                                                          reinterpret_cast<v16u8>(then_val)));
142*5f39d1b3SJooyung Han   return if_mask;
143*5f39d1b3SJooyung Han }
144*5f39d1b3SJooyung Han 
145*5f39d1b3SJooyung Han template <>
146*5f39d1b3SJooyung Han inline v8i16 SelectUsingMask(v8i16 if_mask, v8i16 then_val, v8i16 else_val) {
147*5f39d1b3SJooyung Han   if_mask = reinterpret_cast<v8i16>(__builtin_msa_bsel_v(reinterpret_cast<v16u8>(if_mask),
148*5f39d1b3SJooyung Han                                                          reinterpret_cast<v16u8>(else_val),
149*5f39d1b3SJooyung Han                                                          reinterpret_cast<v16u8>(then_val)));
150*5f39d1b3SJooyung Han   return if_mask;
151*5f39d1b3SJooyung Han }
152*5f39d1b3SJooyung Han 
153*5f39d1b3SJooyung Han template <>
154*5f39d1b3SJooyung Han inline v4i32 MaskIfEqual(v4i32 a, v4i32 b) {
155*5f39d1b3SJooyung Han   return __builtin_msa_ceq_w(a, b);
156*5f39d1b3SJooyung Han }
157*5f39d1b3SJooyung Han 
158*5f39d1b3SJooyung Han template <>
159*5f39d1b3SJooyung Han inline v8i16 MaskIfEqual(v8i16 a, v8i16 b) {
160*5f39d1b3SJooyung Han   return __builtin_msa_ceq_h(a, b);
161*5f39d1b3SJooyung Han }
162*5f39d1b3SJooyung Han 
163*5f39d1b3SJooyung Han template <>
164*5f39d1b3SJooyung Han inline v4i32 MaskIfNotEqual(v4i32 a, v4i32 b) {
165*5f39d1b3SJooyung Han   return BitNot(MaskIfEqual(a, b));
166*5f39d1b3SJooyung Han }
167*5f39d1b3SJooyung Han 
168*5f39d1b3SJooyung Han template <>
169*5f39d1b3SJooyung Han inline v8i16 MaskIfNotEqual(v8i16 a, v8i16 b) {
170*5f39d1b3SJooyung Han   return BitNot(MaskIfEqual(a, b));
171*5f39d1b3SJooyung Han }
172*5f39d1b3SJooyung Han 
173*5f39d1b3SJooyung Han template <>
174*5f39d1b3SJooyung Han inline v4i32 MaskIfZero(v4i32 a) {
175*5f39d1b3SJooyung Han   return __builtin_msa_ceqi_w(a, 0);
176*5f39d1b3SJooyung Han }
177*5f39d1b3SJooyung Han 
178*5f39d1b3SJooyung Han template <>
179*5f39d1b3SJooyung Han inline v8i16 MaskIfZero(v8i16 a) {
180*5f39d1b3SJooyung Han   return __builtin_msa_ceqi_h(a, 0);
181*5f39d1b3SJooyung Han }
182*5f39d1b3SJooyung Han 
183*5f39d1b3SJooyung Han template <>
184*5f39d1b3SJooyung Han inline v4i32 MaskIfNonZero(v4i32 a) {
185*5f39d1b3SJooyung Han   return BitNot(MaskIfZero(a));
186*5f39d1b3SJooyung Han }
187*5f39d1b3SJooyung Han 
188*5f39d1b3SJooyung Han template <>
189*5f39d1b3SJooyung Han inline v8i16 MaskIfNonZero(v8i16 a) {
190*5f39d1b3SJooyung Han   return BitNot(MaskIfZero(a));
191*5f39d1b3SJooyung Han }
192*5f39d1b3SJooyung Han 
193*5f39d1b3SJooyung Han template <>
194*5f39d1b3SJooyung Han inline v4i32 MaskIfGreaterThan(v4i32 a, v4i32 b) {
195*5f39d1b3SJooyung Han   return __builtin_msa_clt_s_w(b, a);
196*5f39d1b3SJooyung Han }
197*5f39d1b3SJooyung Han 
198*5f39d1b3SJooyung Han template <>
199*5f39d1b3SJooyung Han inline v8i16 MaskIfGreaterThan(v8i16 a, v8i16 b) {
200*5f39d1b3SJooyung Han   return __builtin_msa_clt_s_h(b, a);
201*5f39d1b3SJooyung Han }
202*5f39d1b3SJooyung Han 
203*5f39d1b3SJooyung Han template <>
204*5f39d1b3SJooyung Han inline v4i32 MaskIfGreaterThanOrEqual(v4i32 a, v4i32 b) {
205*5f39d1b3SJooyung Han   return __builtin_msa_cle_s_w(b, a);
206*5f39d1b3SJooyung Han }
207*5f39d1b3SJooyung Han 
208*5f39d1b3SJooyung Han template <>
209*5f39d1b3SJooyung Han inline v8i16 MaskIfGreaterThanOrEqual(v8i16 a, v8i16 b) {
210*5f39d1b3SJooyung Han   return __builtin_msa_cle_s_h(b, a);
211*5f39d1b3SJooyung Han }
212*5f39d1b3SJooyung Han 
213*5f39d1b3SJooyung Han template <>
214*5f39d1b3SJooyung Han inline v4i32 MaskIfLessThan(v4i32 a, v4i32 b) {
215*5f39d1b3SJooyung Han   return __builtin_msa_clt_s_w(a, b);
216*5f39d1b3SJooyung Han }
217*5f39d1b3SJooyung Han 
218*5f39d1b3SJooyung Han template <>
219*5f39d1b3SJooyung Han inline v8i16 MaskIfLessThan(v8i16 a, v8i16 b) {
220*5f39d1b3SJooyung Han   return __builtin_msa_clt_s_h(a, b);
221*5f39d1b3SJooyung Han }
222*5f39d1b3SJooyung Han 
223*5f39d1b3SJooyung Han template <>
224*5f39d1b3SJooyung Han inline v4i32 MaskIfLessThanOrEqual(v4i32 a, v4i32 b) {
225*5f39d1b3SJooyung Han   return __builtin_msa_cle_s_w(a, b);
226*5f39d1b3SJooyung Han }
227*5f39d1b3SJooyung Han 
228*5f39d1b3SJooyung Han template <>
229*5f39d1b3SJooyung Han inline v8i16 MaskIfLessThanOrEqual(v8i16 a, v8i16 b) {
230*5f39d1b3SJooyung Han   return __builtin_msa_cle_s_h(a, b);
231*5f39d1b3SJooyung Han }
232*5f39d1b3SJooyung Han 
233*5f39d1b3SJooyung Han template <>
234*5f39d1b3SJooyung Han inline bool All(v4i32 a) {
235*5f39d1b3SJooyung Han   return __builtin_msa_bz_v(reinterpret_cast<v16u8>(BitNot(a)));
236*5f39d1b3SJooyung Han }
237*5f39d1b3SJooyung Han 
238*5f39d1b3SJooyung Han template <>
239*5f39d1b3SJooyung Han inline bool All(v8i16 a) {
240*5f39d1b3SJooyung Han   return __builtin_msa_bz_v(reinterpret_cast<v16u8>(BitNot(a)));
241*5f39d1b3SJooyung Han }
242*5f39d1b3SJooyung Han 
243*5f39d1b3SJooyung Han template <>
244*5f39d1b3SJooyung Han inline bool Any(v4i32 a) {
245*5f39d1b3SJooyung Han   return __builtin_msa_bnz_v(reinterpret_cast<v16u8>(a));
246*5f39d1b3SJooyung Han }
247*5f39d1b3SJooyung Han 
248*5f39d1b3SJooyung Han template <>
249*5f39d1b3SJooyung Han inline bool Any(v8i16 a) {
250*5f39d1b3SJooyung Han   return __builtin_msa_bnz_v(reinterpret_cast<v16u8>(a));
251*5f39d1b3SJooyung Han }
252*5f39d1b3SJooyung Han 
253*5f39d1b3SJooyung Han template <>
254*5f39d1b3SJooyung Han inline v4i32 RoundingHalfSum(v4i32 a, v4i32 b) {
255*5f39d1b3SJooyung Han   return __builtin_msa_aver_s_w(a, b);
256*5f39d1b3SJooyung Han }
257*5f39d1b3SJooyung Han 
258*5f39d1b3SJooyung Han template <>
259*5f39d1b3SJooyung Han inline v8i16 RoundingHalfSum(v8i16 a, v8i16 b) {
260*5f39d1b3SJooyung Han   return __builtin_msa_aver_s_h(a, b);
261*5f39d1b3SJooyung Han }
262*5f39d1b3SJooyung Han 
263*5f39d1b3SJooyung Han template <>
264*5f39d1b3SJooyung Han inline v4i32 SaturatingRoundingDoublingHighMul(v4i32 a, v4i32 b) {
265*5f39d1b3SJooyung Han   return __builtin_msa_mulr_q_w(a, b);
266*5f39d1b3SJooyung Han }
267*5f39d1b3SJooyung Han 
268*5f39d1b3SJooyung Han template <>
269*5f39d1b3SJooyung Han inline v8i16 SaturatingRoundingDoublingHighMul(v8i16 a, v8i16 b) {
270*5f39d1b3SJooyung Han   return __builtin_msa_mulr_q_h(a, b);
271*5f39d1b3SJooyung Han }
272*5f39d1b3SJooyung Han 
273*5f39d1b3SJooyung Han template <int Exponent>
274*5f39d1b3SJooyung Han struct ImplSaturatingRoundingMultiplyByPOT<Exponent, v4i32, 1> {
275*5f39d1b3SJooyung Han   static v4i32 eval(v4i32 x) {
276*5f39d1b3SJooyung Han     static_assert(Exponent >= 0 && Exponent < 32, "");
277*5f39d1b3SJooyung Han     if (Exponent < 5) {
278*5f39d1b3SJooyung Han       for (int i = 0; i < Exponent; i++) {
279*5f39d1b3SJooyung Han         x = __builtin_msa_adds_s_w(x, x);
280*5f39d1b3SJooyung Han       }
281*5f39d1b3SJooyung Han       return x;
282*5f39d1b3SJooyung Han     } else {
283*5f39d1b3SJooyung Han       // Saturate each signed 32-bit element to (32 - Exponent)
284*5f39d1b3SJooyung Han       // bits (this takes full care of negative elements).
285*5f39d1b3SJooyung Han       v4i32 res = __builtin_msa_sat_s_w(x, 31 - Exponent);
286*5f39d1b3SJooyung Han       // Set tmp to 0x7FFFFFFF for those elements which staturated
287*5f39d1b3SJooyung Han       // to smaller (positive) values and 0 for all others.
288*5f39d1b3SJooyung Han       v4i32 tmp = __builtin_msa_srli_w(__builtin_msa_clt_s_w(res, x), 1);
289*5f39d1b3SJooyung Han       // Shift the saturated elements. The positive saturated elements
290*5f39d1b3SJooyung Han       // will have Exponent trailing zero bits after the shift. Those
291*5f39d1b3SJooyung Han       // need to be ones, not zeroes.
292*5f39d1b3SJooyung Han       res = __builtin_msa_slli_w(res, Exponent);
293*5f39d1b3SJooyung Han       // Finally, set those trailing zero bits to ones.
294*5f39d1b3SJooyung Han       res = reinterpret_cast<v4i32>(__builtin_msa_or_v(reinterpret_cast<v16u8>(res),
295*5f39d1b3SJooyung Han                                                        reinterpret_cast<v16u8>(tmp)));
296*5f39d1b3SJooyung Han       return res;
297*5f39d1b3SJooyung Han     }
298*5f39d1b3SJooyung Han   }
299*5f39d1b3SJooyung Han };
300*5f39d1b3SJooyung Han 
301*5f39d1b3SJooyung Han template <int Exponent>
302*5f39d1b3SJooyung Han struct ImplSaturatingRoundingMultiplyByPOT<Exponent, v8i16, 1> {
303*5f39d1b3SJooyung Han   static v8i16 eval(v8i16 x) {
304*5f39d1b3SJooyung Han     static_assert(Exponent >= 0 && Exponent < 16, "");
305*5f39d1b3SJooyung Han     if (Exponent < 5) {
306*5f39d1b3SJooyung Han       for (int i = 0; i < Exponent; i++) {
307*5f39d1b3SJooyung Han         x = __builtin_msa_adds_s_h(x, x);
308*5f39d1b3SJooyung Han       }
309*5f39d1b3SJooyung Han       return x;
310*5f39d1b3SJooyung Han     } else {
311*5f39d1b3SJooyung Han       // Saturate each signed 16-bit element to (16 - Exponent)
312*5f39d1b3SJooyung Han       // bits (this takes full care of negative elements).
313*5f39d1b3SJooyung Han       v8i16 res = __builtin_msa_sat_s_h(x, 15 - Exponent);
314*5f39d1b3SJooyung Han       // Set tmp to 0x7FFF for those elements which staturated
315*5f39d1b3SJooyung Han       // to smaller (positive) values and 0 for all others.
316*5f39d1b3SJooyung Han       v8i16 tmp = __builtin_msa_srli_h(__builtin_msa_clt_s_h(res, x), 1);
317*5f39d1b3SJooyung Han       // Shift the saturated elements. The positive saturated elements
318*5f39d1b3SJooyung Han       // will have Exponent trailing zero bits after the shift. Those
319*5f39d1b3SJooyung Han       // need to be ones, not zeroes.
320*5f39d1b3SJooyung Han       res = __builtin_msa_slli_h(res, Exponent);
321*5f39d1b3SJooyung Han       // Finally, set those trailing zero bits to ones.
322*5f39d1b3SJooyung Han       res = reinterpret_cast<v8i16>(__builtin_msa_or_v(reinterpret_cast<v16u8>(res),
323*5f39d1b3SJooyung Han                                                        reinterpret_cast<v16u8>(tmp)));
324*5f39d1b3SJooyung Han       return res;
325*5f39d1b3SJooyung Han     }
326*5f39d1b3SJooyung Han   }
327*5f39d1b3SJooyung Han };
328*5f39d1b3SJooyung Han 
329*5f39d1b3SJooyung Han template <int Exponent>
330*5f39d1b3SJooyung Han struct ImplSaturatingRoundingMultiplyByPOT<Exponent, v4i32, -1> {
331*5f39d1b3SJooyung Han   static v4i32 eval(v4i32 x) {
332*5f39d1b3SJooyung Han     static_assert(-31 <= Exponent && Exponent <= -1, "");
333*5f39d1b3SJooyung Han     // Isolate the sign bits.
334*5f39d1b3SJooyung Han     v4i32 sign = __builtin_msa_srli_w(x, 31);
335*5f39d1b3SJooyung Han     // Decrement the negative elements by 1 (with saturation).
336*5f39d1b3SJooyung Han     x = __builtin_msa_subs_s_w(x, sign);
337*5f39d1b3SJooyung Han     // Arithmetic shift right with rounding.
338*5f39d1b3SJooyung Han     // The srari instruction rounds all midpoint values towards +infinity.
339*5f39d1b3SJooyung Han     // It will correctly round negative midpoint values as we just
340*5f39d1b3SJooyung Han     // decremented the negative values by 1.
341*5f39d1b3SJooyung Han     return __builtin_msa_srari_w(x, -Exponent);
342*5f39d1b3SJooyung Han   }
343*5f39d1b3SJooyung Han };
344*5f39d1b3SJooyung Han 
345*5f39d1b3SJooyung Han template <int Exponent>
346*5f39d1b3SJooyung Han struct ImplSaturatingRoundingMultiplyByPOT<Exponent, v8i16, -1> {
347*5f39d1b3SJooyung Han   static v8i16 eval(v8i16 x) {
348*5f39d1b3SJooyung Han     static_assert(-15 <= Exponent && Exponent <= -1, "");
349*5f39d1b3SJooyung Han     // Isolate the sign bits.
350*5f39d1b3SJooyung Han     v8i16 sign = __builtin_msa_srli_h(x, 15);
351*5f39d1b3SJooyung Han     // Decrement the negative elements by 1 (with saturation).
352*5f39d1b3SJooyung Han     x = __builtin_msa_subs_s_h(x, sign);
353*5f39d1b3SJooyung Han     // Arithmetic shift right with rounding.
354*5f39d1b3SJooyung Han     // The srari instruction rounds all midpoint values towards +infinity.
355*5f39d1b3SJooyung Han     // It will correctly round negative midpoint values as we just
356*5f39d1b3SJooyung Han     // decremented the negative values by 1.
357*5f39d1b3SJooyung Han     return __builtin_msa_srari_h(x, -Exponent);
358*5f39d1b3SJooyung Han   }
359*5f39d1b3SJooyung Han };
360*5f39d1b3SJooyung Han 
361*5f39d1b3SJooyung Han template <>
362*5f39d1b3SJooyung Han inline v4i32 RoundingDivideByPOT(v4i32 x, int exponent) {
363*5f39d1b3SJooyung Han   v4i32 e = __builtin_msa_fill_w(exponent);
364*5f39d1b3SJooyung Han   // Isolate the sign bits.
365*5f39d1b3SJooyung Han   v4i32 sign = __builtin_msa_srli_w(x, 31);
366*5f39d1b3SJooyung Han   // Reset them to 0 if exponent is 0.
367*5f39d1b3SJooyung Han   sign = __builtin_msa_min_s_w(sign, e);
368*5f39d1b3SJooyung Han   // Decrement the negative elements by 1 (with saturation)
369*5f39d1b3SJooyung Han   // if exponent is non-zero.
370*5f39d1b3SJooyung Han   x = __builtin_msa_subs_s_w(x, sign);
371*5f39d1b3SJooyung Han   // Arithmetic shift right with rounding.
372*5f39d1b3SJooyung Han   // The srar instruction rounds all midpoint values towards +infinity.
373*5f39d1b3SJooyung Han   // It will correctly round negative midpoint values as we just
374*5f39d1b3SJooyung Han   // decremented the negative values by 1.
375*5f39d1b3SJooyung Han   return __builtin_msa_srar_w(x, e);
376*5f39d1b3SJooyung Han }
377*5f39d1b3SJooyung Han 
378*5f39d1b3SJooyung Han template <>
379*5f39d1b3SJooyung Han inline v8i16 RoundingDivideByPOT(v8i16 x, int exponent) {
380*5f39d1b3SJooyung Han   v8i16 e = __builtin_msa_fill_h(exponent);
381*5f39d1b3SJooyung Han   // Isolate the sign bits.
382*5f39d1b3SJooyung Han   v8i16 sign = __builtin_msa_srli_h(x, 15);
383*5f39d1b3SJooyung Han   // Reset them to 0 if exponent is 0.
384*5f39d1b3SJooyung Han   sign = __builtin_msa_min_s_h(sign, e);
385*5f39d1b3SJooyung Han   // Decrement the negative elements by 1 (with saturation)
386*5f39d1b3SJooyung Han   // if exponent is non-zero.
387*5f39d1b3SJooyung Han   x = __builtin_msa_subs_s_h(x, sign);
388*5f39d1b3SJooyung Han   // Arithmetic shift right with rounding.
389*5f39d1b3SJooyung Han   // The srar instruction rounds all midpoint values towards +infinity.
390*5f39d1b3SJooyung Han   // It will correctly round negative midpoint values as we just
391*5f39d1b3SJooyung Han   // decremented the negative values by 1.
392*5f39d1b3SJooyung Han   return __builtin_msa_srar_h(x, e);
393*5f39d1b3SJooyung Han }
394*5f39d1b3SJooyung Han 
395*5f39d1b3SJooyung Han template <>
396*5f39d1b3SJooyung Han inline v4i32 Dup<v4i32>(std::int32_t x) {
397*5f39d1b3SJooyung Han   return __builtin_msa_fill_w(x);
398*5f39d1b3SJooyung Han }
399*5f39d1b3SJooyung Han 
400*5f39d1b3SJooyung Han template <>
401*5f39d1b3SJooyung Han inline v8i16 Dup<v8i16>(std::int16_t x) {
402*5f39d1b3SJooyung Han   return __builtin_msa_fill_h(x);
403*5f39d1b3SJooyung Han }
404*5f39d1b3SJooyung Han 
405*5f39d1b3SJooyung Han // So far this is only needed for int16.
406*5f39d1b3SJooyung Han template <>
407*5f39d1b3SJooyung Han inline v8i16 SaturatingAdd(v8i16 a, v8i16 b) {
408*5f39d1b3SJooyung Han   return __builtin_msa_adds_s_h(a, b);
409*5f39d1b3SJooyung Han }
410*5f39d1b3SJooyung Han 
411*5f39d1b3SJooyung Han }  // end namespace gemmlowp
412*5f39d1b3SJooyung Han 
413*5f39d1b3SJooyung Han #endif  // GEMMLOWP_INTERNAL_FIXEDPOINT_MSA_H_
414