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