1*5f39d1b3SJooyung Han // Copyright 2017 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 // simd_wrappers_neon.h: NEON specialization of simd_wrappers.h 16*5f39d1b3SJooyung Han 17*5f39d1b3SJooyung Han #ifndef GEMMLOWP_INTERNAL_SIMD_WRAPPERS_NEON_H_ 18*5f39d1b3SJooyung Han #define GEMMLOWP_INTERNAL_SIMD_WRAPPERS_NEON_H_ 19*5f39d1b3SJooyung Han 20*5f39d1b3SJooyung Han #include <arm_neon.h> 21*5f39d1b3SJooyung Han 22*5f39d1b3SJooyung Han namespace gemmlowp { 23*5f39d1b3SJooyung Han 24*5f39d1b3SJooyung Han using Int32x4 = int32x4_t; 25*5f39d1b3SJooyung Han using Int16x4 = int16x4_t; 26*5f39d1b3SJooyung Han using Int16x8 = int16x8_t; 27*5f39d1b3SJooyung Han using Uint8x8 = uint8x8_t; 28*5f39d1b3SJooyung Han using Int8x8 = int8x8_t; 29*5f39d1b3SJooyung Han 30*5f39d1b3SJooyung Han template <int ScalarCount> 31*5f39d1b3SJooyung Han struct RegisterType<std::int32_t, ScalarCount> { 32*5f39d1b3SJooyung Han using Type = 33*5f39d1b3SJooyung Han typename std::conditional<ScalarCount >= 4, Int32x4, std::int32_t>::type; 34*5f39d1b3SJooyung Han }; 35*5f39d1b3SJooyung Han 36*5f39d1b3SJooyung Han template <int ScalarCount> 37*5f39d1b3SJooyung Han struct RegisterType<std::int16_t, ScalarCount> { 38*5f39d1b3SJooyung Han using Type = typename std::conditional< 39*5f39d1b3SJooyung Han ScalarCount >= 8, Int16x8, 40*5f39d1b3SJooyung Han typename std::conditional<ScalarCount >= 4, Int16x4, 41*5f39d1b3SJooyung Han std::int16_t>::type>::type; 42*5f39d1b3SJooyung Han }; 43*5f39d1b3SJooyung Han 44*5f39d1b3SJooyung Han template <int ScalarCount> 45*5f39d1b3SJooyung Han struct RegisterType<std::uint8_t, ScalarCount> { 46*5f39d1b3SJooyung Han using Type = typename std::conditional< 47*5f39d1b3SJooyung Han ScalarCount >= 8, Uint8x8, 48*5f39d1b3SJooyung Han typename std::conditional<ScalarCount >= 4, std::uint32_t, 49*5f39d1b3SJooyung Han std::uint8_t>::type>::type; 50*5f39d1b3SJooyung Han }; 51*5f39d1b3SJooyung Han 52*5f39d1b3SJooyung Han template <int ScalarCount> 53*5f39d1b3SJooyung Han struct RegisterType<std::int8_t, ScalarCount> { 54*5f39d1b3SJooyung Han using Type = typename std::conditional< 55*5f39d1b3SJooyung Han ScalarCount >= 8, Int8x8, 56*5f39d1b3SJooyung Han typename std::conditional<ScalarCount >= 4, std::int32_t, 57*5f39d1b3SJooyung Han std::int8_t>::type>::type; 58*5f39d1b3SJooyung Han }; 59*5f39d1b3SJooyung Han 60*5f39d1b3SJooyung Han inline Int32x4 LoadInt32x4(const std::int32_t* src) { return vld1q_s32(src); } 61*5f39d1b3SJooyung Han inline Int16x4 LoadInt16x4(const std::int16_t* src) { return vld1_s16(src); } 62*5f39d1b3SJooyung Han inline Int16x8 LoadInt16x8(const std::int16_t* src) { return vld1q_s16(src); } 63*5f39d1b3SJooyung Han 64*5f39d1b3SJooyung Han inline void StoreInt32x4(std::int32_t* dst, Int32x4 value) { 65*5f39d1b3SJooyung Han vst1q_s32(dst, value); 66*5f39d1b3SJooyung Han } 67*5f39d1b3SJooyung Han 68*5f39d1b3SJooyung Han inline void StoreInt16x4(std::int16_t* dst, Int16x4 value) { 69*5f39d1b3SJooyung Han vst1_s16(dst, value); 70*5f39d1b3SJooyung Han } 71*5f39d1b3SJooyung Han 72*5f39d1b3SJooyung Han inline void StoreInt16x8(std::int16_t* dst, Int16x8 value) { 73*5f39d1b3SJooyung Han vst1q_s16(dst, value); 74*5f39d1b3SJooyung Han } 75*5f39d1b3SJooyung Han 76*5f39d1b3SJooyung Han template <int Lane> 77*5f39d1b3SJooyung Han std::int32_t GetLane(Int32x4 value) { 78*5f39d1b3SJooyung Han return vgetq_lane_s32(value, Lane); 79*5f39d1b3SJooyung Han } 80*5f39d1b3SJooyung Han 81*5f39d1b3SJooyung Han template <int Lane> 82*5f39d1b3SJooyung Han Int32x4 DupLane(Int32x4 value) { 83*5f39d1b3SJooyung Han switch (Lane) { 84*5f39d1b3SJooyung Han case 0: 85*5f39d1b3SJooyung Han return vdupq_lane_s32(vget_low_s32(value), 0); 86*5f39d1b3SJooyung Han case 1: 87*5f39d1b3SJooyung Han return vdupq_lane_s32(vget_low_s32(value), 1); 88*5f39d1b3SJooyung Han case 2: 89*5f39d1b3SJooyung Han return vdupq_lane_s32(vget_high_s32(value), 0); 90*5f39d1b3SJooyung Han case 3: 91*5f39d1b3SJooyung Han return vdupq_lane_s32(vget_high_s32(value), 1); 92*5f39d1b3SJooyung Han default: 93*5f39d1b3SJooyung Han static_assert(Lane >= 0 && Lane <= 3, ""); 94*5f39d1b3SJooyung Han return vdupq_n_s32(0); 95*5f39d1b3SJooyung Han } 96*5f39d1b3SJooyung Han } 97*5f39d1b3SJooyung Han 98*5f39d1b3SJooyung Han inline Int32x4 Mul(Int32x4 a, std::int32_t b) { return vmulq_n_s32(a, b); } 99*5f39d1b3SJooyung Han 100*5f39d1b3SJooyung Han inline Int32x4 Min(Int32x4 a, Int32x4 b) { return vminq_s32(a, b); } 101*5f39d1b3SJooyung Han 102*5f39d1b3SJooyung Han inline Int32x4 Max(Int32x4 a, Int32x4 b) { return vmaxq_s32(a, b); } 103*5f39d1b3SJooyung Han 104*5f39d1b3SJooyung Han inline Int32x4 Max(Int32x4 a, std::int32_t b) { 105*5f39d1b3SJooyung Han return vmaxq_s32(a, vdupq_n_s32(b)); 106*5f39d1b3SJooyung Han } 107*5f39d1b3SJooyung Han 108*5f39d1b3SJooyung Han inline Int32x4 SaturatingRoundingDoublingHighMul(Int32x4 a, std::int32_t b) { 109*5f39d1b3SJooyung Han return vqrdmulhq_n_s32(a, b); 110*5f39d1b3SJooyung Han } 111*5f39d1b3SJooyung Han 112*5f39d1b3SJooyung Han template <int Lane> 113*5f39d1b3SJooyung Han Int32x4 MulByRhsLane(Int32x4 a, Int32x4 b) { 114*5f39d1b3SJooyung Han switch (Lane) { 115*5f39d1b3SJooyung Han case 0: 116*5f39d1b3SJooyung Han return vmulq_lane_s32(a, vget_low_s32(b), 0); 117*5f39d1b3SJooyung Han case 1: 118*5f39d1b3SJooyung Han return vmulq_lane_s32(a, vget_low_s32(b), 1); 119*5f39d1b3SJooyung Han case 2: 120*5f39d1b3SJooyung Han return vmulq_lane_s32(a, vget_high_s32(b), 0); 121*5f39d1b3SJooyung Han case 3: 122*5f39d1b3SJooyung Han return vmulq_lane_s32(a, vget_high_s32(b), 1); 123*5f39d1b3SJooyung Han default: 124*5f39d1b3SJooyung Han static_assert(Lane >= 0 && Lane <= 3, ""); 125*5f39d1b3SJooyung Han return vdupq_n_s32(0); 126*5f39d1b3SJooyung Han } 127*5f39d1b3SJooyung Han } 128*5f39d1b3SJooyung Han 129*5f39d1b3SJooyung Han inline void MulAdd(Int32x4 lhs, Int32x4 rhs, Int32x4* acc) { 130*5f39d1b3SJooyung Han *acc = vmlaq_s32(*acc, lhs, rhs); 131*5f39d1b3SJooyung Han } 132*5f39d1b3SJooyung Han 133*5f39d1b3SJooyung Han inline void MulAdd(Int32x4 lhs, std::int32_t rhs, Int32x4* acc) { 134*5f39d1b3SJooyung Han *acc = vmlaq_n_s32(*acc, lhs, rhs); 135*5f39d1b3SJooyung Han } 136*5f39d1b3SJooyung Han 137*5f39d1b3SJooyung Han template <int Lane> 138*5f39d1b3SJooyung Han inline void MulAddByRhsLane(Int32x4 lhs, Int32x4 rhs, Int32x4* acc) { 139*5f39d1b3SJooyung Han switch (Lane) { 140*5f39d1b3SJooyung Han case 0: 141*5f39d1b3SJooyung Han *acc = vmlaq_lane_s32(*acc, lhs, vget_low_s32(rhs), 0); 142*5f39d1b3SJooyung Han break; 143*5f39d1b3SJooyung Han case 1: 144*5f39d1b3SJooyung Han *acc = vmlaq_lane_s32(*acc, lhs, vget_low_s32(rhs), 1); 145*5f39d1b3SJooyung Han break; 146*5f39d1b3SJooyung Han case 2: 147*5f39d1b3SJooyung Han *acc = vmlaq_lane_s32(*acc, lhs, vget_high_s32(rhs), 0); 148*5f39d1b3SJooyung Han break; 149*5f39d1b3SJooyung Han case 3: 150*5f39d1b3SJooyung Han *acc = vmlaq_lane_s32(*acc, lhs, vget_high_s32(rhs), 1); 151*5f39d1b3SJooyung Han break; 152*5f39d1b3SJooyung Han default: 153*5f39d1b3SJooyung Han static_assert(Lane >= 0 && Lane <= 3, ""); 154*5f39d1b3SJooyung Han } 155*5f39d1b3SJooyung Han } 156*5f39d1b3SJooyung Han 157*5f39d1b3SJooyung Han template <> 158*5f39d1b3SJooyung Han struct LoadContiguousImpl<RegBlockInt16<8, 8>> { 159*5f39d1b3SJooyung Han static RegBlockInt16<8, 8> Run(const std::int16_t* src) { 160*5f39d1b3SJooyung Han RegBlockInt16<8, 8> result; 161*5f39d1b3SJooyung Han for (int i = 0; i < 8; i++) { 162*5f39d1b3SJooyung Han result.buf.reg[i] = vld1q_s16(src + 8 * i); 163*5f39d1b3SJooyung Han } 164*5f39d1b3SJooyung Han return result; 165*5f39d1b3SJooyung Han } 166*5f39d1b3SJooyung Han }; 167*5f39d1b3SJooyung Han 168*5f39d1b3SJooyung Han template <> 169*5f39d1b3SJooyung Han struct LoadContiguousImpl<RegBlockUint8<8, 8>> { 170*5f39d1b3SJooyung Han static RegBlockUint8<8, 8> Run(const std::uint8_t* src) { 171*5f39d1b3SJooyung Han RegBlockUint8<8, 8> result; 172*5f39d1b3SJooyung Han for (int i = 0; i < 8; i++) { 173*5f39d1b3SJooyung Han result.buf.reg[i] = vld1_u8(src + 8 * i); 174*5f39d1b3SJooyung Han } 175*5f39d1b3SJooyung Han return result; 176*5f39d1b3SJooyung Han } 177*5f39d1b3SJooyung Han }; 178*5f39d1b3SJooyung Han 179*5f39d1b3SJooyung Han template <> 180*5f39d1b3SJooyung Han struct LoadContiguousImpl<RegBlockInt8<8, 8>> { 181*5f39d1b3SJooyung Han static RegBlockInt8<8, 8> Run(const std::int8_t* src) { 182*5f39d1b3SJooyung Han RegBlockInt8<8, 8> result; 183*5f39d1b3SJooyung Han for (int i = 0; i < 8; i++) { 184*5f39d1b3SJooyung Han result.buf.reg[i] = vld1_s8(src + 8 * i); 185*5f39d1b3SJooyung Han } 186*5f39d1b3SJooyung Han return result; 187*5f39d1b3SJooyung Han } 188*5f39d1b3SJooyung Han }; 189*5f39d1b3SJooyung Han 190*5f39d1b3SJooyung Han template <> 191*5f39d1b3SJooyung Han struct LoadContiguousImpl<RegBlockInt32<8, 8>> { 192*5f39d1b3SJooyung Han static RegBlockInt32<8, 8> Run(const std::int32_t* src) { 193*5f39d1b3SJooyung Han RegBlockInt32<8, 8> result; 194*5f39d1b3SJooyung Han for (int i = 0; i < 16; i++) { 195*5f39d1b3SJooyung Han result.buf.reg[i] = vld1q_s32(src + 4 * i); 196*5f39d1b3SJooyung Han } 197*5f39d1b3SJooyung Han return result; 198*5f39d1b3SJooyung Han } 199*5f39d1b3SJooyung Han }; 200*5f39d1b3SJooyung Han 201*5f39d1b3SJooyung Han // 4x1 := 4x1 + 1x1 202*5f39d1b3SJooyung Han template <> 203*5f39d1b3SJooyung Han struct BroadcastShiftLeftImpl<RegBlockInt32<4, 1>, RegBlockInt32<1, 1>> { 204*5f39d1b3SJooyung Han static RegBlockInt32<4, 1> Run(const RegBlockInt32<4, 1>& lhs, 205*5f39d1b3SJooyung Han const RegBlockInt32<1, 1>& rhs) { 206*5f39d1b3SJooyung Han RegBlockInt32<4, 1> result; 207*5f39d1b3SJooyung Han result.buf.reg[0] = ShiftLeft(lhs.buf.reg[0], Dup<Int32x4>(rhs.buf.reg[0])); 208*5f39d1b3SJooyung Han return result; 209*5f39d1b3SJooyung Han } 210*5f39d1b3SJooyung Han }; 211*5f39d1b3SJooyung Han 212*5f39d1b3SJooyung Han // 1x4 := 1x4 + 1x1 213*5f39d1b3SJooyung Han template <> 214*5f39d1b3SJooyung Han struct BroadcastShiftLeftImpl<RegBlockInt32<1, 4>, RegBlockInt32<1, 1>> { 215*5f39d1b3SJooyung Han static RegBlockInt32<1, 4> Run(const RegBlockInt32<1, 4>& lhs, 216*5f39d1b3SJooyung Han const RegBlockInt32<1, 1>& rhs) { 217*5f39d1b3SJooyung Han RegBlockInt32<1, 4> result; 218*5f39d1b3SJooyung Han result.buf.reg[0] = ShiftLeft(lhs.buf.reg[0], Dup<Int32x4>(rhs.buf.reg[0])); 219*5f39d1b3SJooyung Han return result; 220*5f39d1b3SJooyung Han } 221*5f39d1b3SJooyung Han }; 222*5f39d1b3SJooyung Han 223*5f39d1b3SJooyung Han // 4x1 := 4x1 + 4x1 224*5f39d1b3SJooyung Han template <> 225*5f39d1b3SJooyung Han struct BroadcastShiftLeftImpl<RegBlockInt32<4, 1>, RegBlockInt32<4, 1>> { 226*5f39d1b3SJooyung Han static RegBlockInt32<4, 1> Run(const RegBlockInt32<4, 1>& lhs, 227*5f39d1b3SJooyung Han const RegBlockInt32<4, 1>& rhs) { 228*5f39d1b3SJooyung Han RegBlockInt32<4, 1> result; 229*5f39d1b3SJooyung Han result.buf.reg[0] = ShiftLeft(lhs.buf.reg[0], rhs.buf.reg[0]); 230*5f39d1b3SJooyung Han return result; 231*5f39d1b3SJooyung Han } 232*5f39d1b3SJooyung Han }; 233*5f39d1b3SJooyung Han 234*5f39d1b3SJooyung Han // 1x4 := 1x4 + 1x4 235*5f39d1b3SJooyung Han template <> 236*5f39d1b3SJooyung Han struct BroadcastShiftLeftImpl<RegBlockInt32<1, 4>, RegBlockInt32<1, 4>> { 237*5f39d1b3SJooyung Han static RegBlockInt32<1, 4> Run(const RegBlockInt32<1, 4>& lhs, 238*5f39d1b3SJooyung Han const RegBlockInt32<1, 4>& rhs) { 239*5f39d1b3SJooyung Han RegBlockInt32<1, 4> result; 240*5f39d1b3SJooyung Han result.buf.reg[0] = ShiftLeft(lhs.buf.reg[0], rhs.buf.reg[0]); 241*5f39d1b3SJooyung Han return result; 242*5f39d1b3SJooyung Han } 243*5f39d1b3SJooyung Han }; 244*5f39d1b3SJooyung Han 245*5f39d1b3SJooyung Han // 4x4 := 4x4 + 1x4 246*5f39d1b3SJooyung Han template <> 247*5f39d1b3SJooyung Han struct BroadcastShiftLeftImpl<RegBlockInt32<4, 4>, RegBlockInt32<1, 4>> { 248*5f39d1b3SJooyung Han static RegBlockInt32<4, 4> Run(const RegBlockInt32<4, 4>& lhs, 249*5f39d1b3SJooyung Han const RegBlockInt32<1, 4>& rhs) { 250*5f39d1b3SJooyung Han RegBlockInt32<4, 4> result; 251*5f39d1b3SJooyung Han result.buf.reg[0] = ShiftLeft(lhs.buf.reg[0], DupLane<0>(rhs.buf.reg[0])); 252*5f39d1b3SJooyung Han result.buf.reg[1] = ShiftLeft(lhs.buf.reg[1], DupLane<1>(rhs.buf.reg[0])); 253*5f39d1b3SJooyung Han result.buf.reg[2] = ShiftLeft(lhs.buf.reg[2], DupLane<2>(rhs.buf.reg[0])); 254*5f39d1b3SJooyung Han result.buf.reg[3] = ShiftLeft(lhs.buf.reg[3], DupLane<3>(rhs.buf.reg[0])); 255*5f39d1b3SJooyung Han return result; 256*5f39d1b3SJooyung Han } 257*5f39d1b3SJooyung Han }; 258*5f39d1b3SJooyung Han 259*5f39d1b3SJooyung Han // 4x4 := 4x4 + 4x1 260*5f39d1b3SJooyung Han template <> 261*5f39d1b3SJooyung Han struct BroadcastShiftLeftImpl<RegBlockInt32<4, 4>, RegBlockInt32<4, 1>> { 262*5f39d1b3SJooyung Han static RegBlockInt32<4, 4> Run(const RegBlockInt32<4, 4>& lhs, 263*5f39d1b3SJooyung Han const RegBlockInt32<4, 1>& rhs) { 264*5f39d1b3SJooyung Han RegBlockInt32<4, 4> result; 265*5f39d1b3SJooyung Han result.buf.reg[0] = ShiftLeft(lhs.buf.reg[0], rhs.buf.reg[0]); 266*5f39d1b3SJooyung Han result.buf.reg[1] = ShiftLeft(lhs.buf.reg[1], rhs.buf.reg[0]); 267*5f39d1b3SJooyung Han result.buf.reg[2] = ShiftLeft(lhs.buf.reg[2], rhs.buf.reg[0]); 268*5f39d1b3SJooyung Han result.buf.reg[3] = ShiftLeft(lhs.buf.reg[3], rhs.buf.reg[0]); 269*5f39d1b3SJooyung Han return result; 270*5f39d1b3SJooyung Han } 271*5f39d1b3SJooyung Han }; 272*5f39d1b3SJooyung Han 273*5f39d1b3SJooyung Han // 8x1 := 8x1 + 1x1 274*5f39d1b3SJooyung Han template <> 275*5f39d1b3SJooyung Han struct BroadcastShiftLeftImpl<RegBlockInt32<8, 1>, RegBlockInt32<1, 1>> { 276*5f39d1b3SJooyung Han static RegBlockInt32<8, 1> Run(const RegBlockInt32<8, 1>& lhs, 277*5f39d1b3SJooyung Han const RegBlockInt32<1, 1>& rhs) { 278*5f39d1b3SJooyung Han RegBlockInt32<8, 1> result; 279*5f39d1b3SJooyung Han const Int32x4 p = Dup<Int32x4>(rhs.buf.reg[0]); 280*5f39d1b3SJooyung Han for (int i = 0; i < 2; i++) { 281*5f39d1b3SJooyung Han result.buf.reg[i] = ShiftLeft(lhs.buf.reg[i], p); 282*5f39d1b3SJooyung Han } 283*5f39d1b3SJooyung Han return result; 284*5f39d1b3SJooyung Han } 285*5f39d1b3SJooyung Han }; 286*5f39d1b3SJooyung Han 287*5f39d1b3SJooyung Han // 8x1 := 8x1 + 8x1 288*5f39d1b3SJooyung Han template <> 289*5f39d1b3SJooyung Han struct BroadcastShiftLeftImpl<RegBlockInt32<8, 1>, RegBlockInt32<8, 1>> { 290*5f39d1b3SJooyung Han static RegBlockInt32<8, 1> Run(const RegBlockInt32<8, 1>& lhs, 291*5f39d1b3SJooyung Han const RegBlockInt32<8, 1>& rhs) { 292*5f39d1b3SJooyung Han RegBlockInt32<8, 1> result; 293*5f39d1b3SJooyung Han for (int i = 0; i < 2; i++) { 294*5f39d1b3SJooyung Han result.buf.reg[i] = ShiftLeft(lhs.buf.reg[i], rhs.buf.reg[i]); 295*5f39d1b3SJooyung Han } 296*5f39d1b3SJooyung Han return result; 297*5f39d1b3SJooyung Han } 298*5f39d1b3SJooyung Han }; 299*5f39d1b3SJooyung Han 300*5f39d1b3SJooyung Han // 8x4 := 8x4 + 1x4 301*5f39d1b3SJooyung Han template <> 302*5f39d1b3SJooyung Han struct BroadcastShiftLeftImpl<RegBlockInt32<8, 4>, RegBlockInt32<1, 4>> { 303*5f39d1b3SJooyung Han static RegBlockInt32<8, 4> Run(const RegBlockInt32<8, 4>& lhs, 304*5f39d1b3SJooyung Han const RegBlockInt32<1, 4>& rhs) { 305*5f39d1b3SJooyung Han RegBlockInt32<8, 4> result; 306*5f39d1b3SJooyung Han result.buf.reg[0] = ShiftLeft(lhs.buf.reg[0], DupLane<0>(rhs.buf.reg[0])); 307*5f39d1b3SJooyung Han result.buf.reg[1] = ShiftLeft(lhs.buf.reg[1], DupLane<0>(rhs.buf.reg[0])); 308*5f39d1b3SJooyung Han result.buf.reg[2] = ShiftLeft(lhs.buf.reg[2], DupLane<1>(rhs.buf.reg[0])); 309*5f39d1b3SJooyung Han result.buf.reg[3] = ShiftLeft(lhs.buf.reg[3], DupLane<1>(rhs.buf.reg[0])); 310*5f39d1b3SJooyung Han result.buf.reg[4] = ShiftLeft(lhs.buf.reg[4], DupLane<2>(rhs.buf.reg[0])); 311*5f39d1b3SJooyung Han result.buf.reg[5] = ShiftLeft(lhs.buf.reg[5], DupLane<2>(rhs.buf.reg[0])); 312*5f39d1b3SJooyung Han result.buf.reg[6] = ShiftLeft(lhs.buf.reg[6], DupLane<3>(rhs.buf.reg[0])); 313*5f39d1b3SJooyung Han result.buf.reg[7] = ShiftLeft(lhs.buf.reg[7], DupLane<3>(rhs.buf.reg[0])); 314*5f39d1b3SJooyung Han return result; 315*5f39d1b3SJooyung Han } 316*5f39d1b3SJooyung Han }; 317*5f39d1b3SJooyung Han 318*5f39d1b3SJooyung Han // 8x4 := 8x4 + 8x1 319*5f39d1b3SJooyung Han template <> 320*5f39d1b3SJooyung Han struct BroadcastShiftLeftImpl<RegBlockInt32<8, 4>, RegBlockInt32<8, 1>> { 321*5f39d1b3SJooyung Han static RegBlockInt32<8, 4> Run(const RegBlockInt32<8, 4>& lhs, 322*5f39d1b3SJooyung Han const RegBlockInt32<8, 1>& rhs) { 323*5f39d1b3SJooyung Han RegBlockInt32<8, 4> result; 324*5f39d1b3SJooyung Han result.buf.reg[0] = ShiftLeft(lhs.buf.reg[0], rhs.buf.reg[0]); 325*5f39d1b3SJooyung Han result.buf.reg[1] = ShiftLeft(lhs.buf.reg[1], rhs.buf.reg[1]); 326*5f39d1b3SJooyung Han result.buf.reg[2] = ShiftLeft(lhs.buf.reg[2], rhs.buf.reg[0]); 327*5f39d1b3SJooyung Han result.buf.reg[3] = ShiftLeft(lhs.buf.reg[3], rhs.buf.reg[1]); 328*5f39d1b3SJooyung Han result.buf.reg[4] = ShiftLeft(lhs.buf.reg[4], rhs.buf.reg[0]); 329*5f39d1b3SJooyung Han result.buf.reg[5] = ShiftLeft(lhs.buf.reg[5], rhs.buf.reg[1]); 330*5f39d1b3SJooyung Han result.buf.reg[6] = ShiftLeft(lhs.buf.reg[6], rhs.buf.reg[0]); 331*5f39d1b3SJooyung Han result.buf.reg[7] = ShiftLeft(lhs.buf.reg[7], rhs.buf.reg[1]); 332*5f39d1b3SJooyung Han return result; 333*5f39d1b3SJooyung Han } 334*5f39d1b3SJooyung Han }; 335*5f39d1b3SJooyung Han 336*5f39d1b3SJooyung Han // 1x8 := 1x8 + 1x8 337*5f39d1b3SJooyung Han template <> 338*5f39d1b3SJooyung Han struct BroadcastShiftLeftImpl<RegBlockInt32<1, 8>, RegBlockInt32<1, 8>> { 339*5f39d1b3SJooyung Han static RegBlockInt32<1, 8> Run(const RegBlockInt32<1, 8>& lhs, 340*5f39d1b3SJooyung Han const RegBlockInt32<1, 8>& rhs) { 341*5f39d1b3SJooyung Han RegBlockInt32<1, 8> result; 342*5f39d1b3SJooyung Han result.buf.reg[0] = ShiftLeft(lhs.buf.reg[0], rhs.buf.reg[0]); 343*5f39d1b3SJooyung Han result.buf.reg[1] = ShiftLeft(lhs.buf.reg[1], rhs.buf.reg[1]); 344*5f39d1b3SJooyung Han return result; 345*5f39d1b3SJooyung Han } 346*5f39d1b3SJooyung Han }; 347*5f39d1b3SJooyung Han 348*5f39d1b3SJooyung Han // 1x8 := 1x8 + 1x1 349*5f39d1b3SJooyung Han template <> 350*5f39d1b3SJooyung Han struct BroadcastShiftLeftImpl<RegBlockInt32<1, 8>, RegBlockInt32<1, 1>> { 351*5f39d1b3SJooyung Han static RegBlockInt32<1, 8> Run(const RegBlockInt32<1, 8>& lhs, 352*5f39d1b3SJooyung Han const RegBlockInt32<1, 1>& rhs) { 353*5f39d1b3SJooyung Han RegBlockInt32<1, 8> result; 354*5f39d1b3SJooyung Han result.buf.reg[0] = ShiftLeft(lhs.buf.reg[0], Dup<Int32x4>(rhs.buf.reg[0])); 355*5f39d1b3SJooyung Han result.buf.reg[1] = ShiftLeft(lhs.buf.reg[1], Dup<Int32x4>(rhs.buf.reg[0])); 356*5f39d1b3SJooyung Han return result; 357*5f39d1b3SJooyung Han } 358*5f39d1b3SJooyung Han }; 359*5f39d1b3SJooyung Han 360*5f39d1b3SJooyung Han // 4x1 := 4x1 + 1x1 361*5f39d1b3SJooyung Han template <> 362*5f39d1b3SJooyung Han struct BroadcastRoundingDivideByPOTImpl<RegBlockInt32<4, 1>, 363*5f39d1b3SJooyung Han RegBlockInt32<1, 1>> { 364*5f39d1b3SJooyung Han static RegBlockInt32<4, 1> Run(const RegBlockInt32<4, 1>& lhs, 365*5f39d1b3SJooyung Han const RegBlockInt32<1, 1>& rhs) { 366*5f39d1b3SJooyung Han RegBlockInt32<4, 1> result; 367*5f39d1b3SJooyung Han result.buf.reg[0] = 368*5f39d1b3SJooyung Han RoundingDivideByPOT(lhs.buf.reg[0], Dup<Int32x4>(rhs.buf.reg[0])); 369*5f39d1b3SJooyung Han return result; 370*5f39d1b3SJooyung Han } 371*5f39d1b3SJooyung Han }; 372*5f39d1b3SJooyung Han 373*5f39d1b3SJooyung Han // 1x4 := 1x4 + 1x1 374*5f39d1b3SJooyung Han template <> 375*5f39d1b3SJooyung Han struct BroadcastRoundingDivideByPOTImpl<RegBlockInt32<1, 4>, 376*5f39d1b3SJooyung Han RegBlockInt32<1, 1>> { 377*5f39d1b3SJooyung Han static RegBlockInt32<1, 4> Run(const RegBlockInt32<1, 4>& lhs, 378*5f39d1b3SJooyung Han const RegBlockInt32<1, 1>& rhs) { 379*5f39d1b3SJooyung Han RegBlockInt32<1, 4> result; 380*5f39d1b3SJooyung Han result.buf.reg[0] = 381*5f39d1b3SJooyung Han RoundingDivideByPOT(lhs.buf.reg[0], Dup<Int32x4>(rhs.buf.reg[0])); 382*5f39d1b3SJooyung Han return result; 383*5f39d1b3SJooyung Han } 384*5f39d1b3SJooyung Han }; 385*5f39d1b3SJooyung Han 386*5f39d1b3SJooyung Han // 4x1 := 4x1 + 4x1 387*5f39d1b3SJooyung Han template <> 388*5f39d1b3SJooyung Han struct BroadcastRoundingDivideByPOTImpl<RegBlockInt32<4, 1>, 389*5f39d1b3SJooyung Han RegBlockInt32<4, 1>> { 390*5f39d1b3SJooyung Han static RegBlockInt32<4, 1> Run(const RegBlockInt32<4, 1>& lhs, 391*5f39d1b3SJooyung Han const RegBlockInt32<4, 1>& rhs) { 392*5f39d1b3SJooyung Han RegBlockInt32<4, 1> result; 393*5f39d1b3SJooyung Han result.buf.reg[0] = RoundingDivideByPOT(lhs.buf.reg[0], rhs.buf.reg[0]); 394*5f39d1b3SJooyung Han return result; 395*5f39d1b3SJooyung Han } 396*5f39d1b3SJooyung Han }; 397*5f39d1b3SJooyung Han 398*5f39d1b3SJooyung Han // 1x4 := 1x4 + 1x4 399*5f39d1b3SJooyung Han template <> 400*5f39d1b3SJooyung Han struct BroadcastRoundingDivideByPOTImpl<RegBlockInt32<1, 4>, 401*5f39d1b3SJooyung Han RegBlockInt32<1, 4>> { 402*5f39d1b3SJooyung Han static RegBlockInt32<1, 4> Run(const RegBlockInt32<1, 4>& lhs, 403*5f39d1b3SJooyung Han const RegBlockInt32<1, 4>& rhs) { 404*5f39d1b3SJooyung Han RegBlockInt32<1, 4> result; 405*5f39d1b3SJooyung Han result.buf.reg[0] = RoundingDivideByPOT(lhs.buf.reg[0], rhs.buf.reg[0]); 406*5f39d1b3SJooyung Han return result; 407*5f39d1b3SJooyung Han } 408*5f39d1b3SJooyung Han }; 409*5f39d1b3SJooyung Han 410*5f39d1b3SJooyung Han // 4x4 := 4x4 + 1x4 411*5f39d1b3SJooyung Han template <> 412*5f39d1b3SJooyung Han struct BroadcastRoundingDivideByPOTImpl<RegBlockInt32<4, 4>, 413*5f39d1b3SJooyung Han RegBlockInt32<1, 4>> { 414*5f39d1b3SJooyung Han static RegBlockInt32<4, 4> Run(const RegBlockInt32<4, 4>& lhs, 415*5f39d1b3SJooyung Han const RegBlockInt32<1, 4>& rhs) { 416*5f39d1b3SJooyung Han RegBlockInt32<4, 4> result; 417*5f39d1b3SJooyung Han result.buf.reg[0] = 418*5f39d1b3SJooyung Han RoundingDivideByPOT(lhs.buf.reg[0], DupLane<0>(rhs.buf.reg[0])); 419*5f39d1b3SJooyung Han result.buf.reg[1] = 420*5f39d1b3SJooyung Han RoundingDivideByPOT(lhs.buf.reg[1], DupLane<1>(rhs.buf.reg[0])); 421*5f39d1b3SJooyung Han result.buf.reg[2] = 422*5f39d1b3SJooyung Han RoundingDivideByPOT(lhs.buf.reg[2], DupLane<2>(rhs.buf.reg[0])); 423*5f39d1b3SJooyung Han result.buf.reg[3] = 424*5f39d1b3SJooyung Han RoundingDivideByPOT(lhs.buf.reg[3], DupLane<3>(rhs.buf.reg[0])); 425*5f39d1b3SJooyung Han return result; 426*5f39d1b3SJooyung Han } 427*5f39d1b3SJooyung Han }; 428*5f39d1b3SJooyung Han 429*5f39d1b3SJooyung Han // 4x4 := 4x4 + 4x1 430*5f39d1b3SJooyung Han template <> 431*5f39d1b3SJooyung Han struct BroadcastRoundingDivideByPOTImpl<RegBlockInt32<4, 4>, 432*5f39d1b3SJooyung Han RegBlockInt32<4, 1>> { 433*5f39d1b3SJooyung Han static RegBlockInt32<4, 4> Run(const RegBlockInt32<4, 4>& lhs, 434*5f39d1b3SJooyung Han const RegBlockInt32<4, 1>& rhs) { 435*5f39d1b3SJooyung Han RegBlockInt32<4, 4> result; 436*5f39d1b3SJooyung Han result.buf.reg[0] = RoundingDivideByPOT(lhs.buf.reg[0], rhs.buf.reg[0]); 437*5f39d1b3SJooyung Han result.buf.reg[1] = RoundingDivideByPOT(lhs.buf.reg[1], rhs.buf.reg[0]); 438*5f39d1b3SJooyung Han result.buf.reg[2] = RoundingDivideByPOT(lhs.buf.reg[2], rhs.buf.reg[0]); 439*5f39d1b3SJooyung Han result.buf.reg[3] = RoundingDivideByPOT(lhs.buf.reg[3], rhs.buf.reg[0]); 440*5f39d1b3SJooyung Han return result; 441*5f39d1b3SJooyung Han } 442*5f39d1b3SJooyung Han }; 443*5f39d1b3SJooyung Han 444*5f39d1b3SJooyung Han // 8x1 := 8x1 + 1x1 445*5f39d1b3SJooyung Han template <> 446*5f39d1b3SJooyung Han struct BroadcastRoundingDivideByPOTImpl<RegBlockInt32<8, 1>, 447*5f39d1b3SJooyung Han RegBlockInt32<1, 1>> { 448*5f39d1b3SJooyung Han static RegBlockInt32<8, 1> Run(const RegBlockInt32<8, 1>& lhs, 449*5f39d1b3SJooyung Han const RegBlockInt32<1, 1>& rhs) { 450*5f39d1b3SJooyung Han RegBlockInt32<8, 1> result; 451*5f39d1b3SJooyung Han const Int32x4 p = Dup<Int32x4>(rhs.buf.reg[0]); 452*5f39d1b3SJooyung Han for (int i = 0; i < 2; i++) { 453*5f39d1b3SJooyung Han result.buf.reg[i] = RoundingDivideByPOT(lhs.buf.reg[i], p); 454*5f39d1b3SJooyung Han } 455*5f39d1b3SJooyung Han return result; 456*5f39d1b3SJooyung Han } 457*5f39d1b3SJooyung Han }; 458*5f39d1b3SJooyung Han 459*5f39d1b3SJooyung Han // 8x1 := 8x1 + 8x1 460*5f39d1b3SJooyung Han template <> 461*5f39d1b3SJooyung Han struct BroadcastRoundingDivideByPOTImpl<RegBlockInt32<8, 1>, 462*5f39d1b3SJooyung Han RegBlockInt32<8, 1>> { 463*5f39d1b3SJooyung Han static RegBlockInt32<8, 1> Run(const RegBlockInt32<8, 1>& lhs, 464*5f39d1b3SJooyung Han const RegBlockInt32<8, 1>& rhs) { 465*5f39d1b3SJooyung Han RegBlockInt32<8, 1> result; 466*5f39d1b3SJooyung Han for (int i = 0; i < 2; i++) { 467*5f39d1b3SJooyung Han result.buf.reg[i] = RoundingDivideByPOT(lhs.buf.reg[i], rhs.buf.reg[i]); 468*5f39d1b3SJooyung Han } 469*5f39d1b3SJooyung Han return result; 470*5f39d1b3SJooyung Han } 471*5f39d1b3SJooyung Han }; 472*5f39d1b3SJooyung Han 473*5f39d1b3SJooyung Han // 8x4 := 8x4 + 1x4 474*5f39d1b3SJooyung Han template <> 475*5f39d1b3SJooyung Han struct BroadcastRoundingDivideByPOTImpl<RegBlockInt32<8, 4>, 476*5f39d1b3SJooyung Han RegBlockInt32<1, 4>> { 477*5f39d1b3SJooyung Han static RegBlockInt32<8, 4> Run(const RegBlockInt32<8, 4>& lhs, 478*5f39d1b3SJooyung Han const RegBlockInt32<1, 4>& rhs) { 479*5f39d1b3SJooyung Han RegBlockInt32<8, 4> result; 480*5f39d1b3SJooyung Han result.buf.reg[0] = 481*5f39d1b3SJooyung Han RoundingDivideByPOT(lhs.buf.reg[0], DupLane<0>(rhs.buf.reg[0])); 482*5f39d1b3SJooyung Han result.buf.reg[1] = 483*5f39d1b3SJooyung Han RoundingDivideByPOT(lhs.buf.reg[1], DupLane<0>(rhs.buf.reg[0])); 484*5f39d1b3SJooyung Han result.buf.reg[2] = 485*5f39d1b3SJooyung Han RoundingDivideByPOT(lhs.buf.reg[2], DupLane<1>(rhs.buf.reg[0])); 486*5f39d1b3SJooyung Han result.buf.reg[3] = 487*5f39d1b3SJooyung Han RoundingDivideByPOT(lhs.buf.reg[3], DupLane<1>(rhs.buf.reg[0])); 488*5f39d1b3SJooyung Han result.buf.reg[4] = 489*5f39d1b3SJooyung Han RoundingDivideByPOT(lhs.buf.reg[4], DupLane<2>(rhs.buf.reg[0])); 490*5f39d1b3SJooyung Han result.buf.reg[5] = 491*5f39d1b3SJooyung Han RoundingDivideByPOT(lhs.buf.reg[5], DupLane<2>(rhs.buf.reg[0])); 492*5f39d1b3SJooyung Han result.buf.reg[6] = 493*5f39d1b3SJooyung Han RoundingDivideByPOT(lhs.buf.reg[6], DupLane<3>(rhs.buf.reg[0])); 494*5f39d1b3SJooyung Han result.buf.reg[7] = 495*5f39d1b3SJooyung Han RoundingDivideByPOT(lhs.buf.reg[7], DupLane<3>(rhs.buf.reg[0])); 496*5f39d1b3SJooyung Han return result; 497*5f39d1b3SJooyung Han } 498*5f39d1b3SJooyung Han }; 499*5f39d1b3SJooyung Han 500*5f39d1b3SJooyung Han // 8x4 := 8x4 + 8x1 501*5f39d1b3SJooyung Han template <> 502*5f39d1b3SJooyung Han struct BroadcastRoundingDivideByPOTImpl<RegBlockInt32<8, 4>, 503*5f39d1b3SJooyung Han RegBlockInt32<8, 1>> { 504*5f39d1b3SJooyung Han static RegBlockInt32<8, 4> Run(const RegBlockInt32<8, 4>& lhs, 505*5f39d1b3SJooyung Han const RegBlockInt32<8, 1>& rhs) { 506*5f39d1b3SJooyung Han RegBlockInt32<8, 4> result; 507*5f39d1b3SJooyung Han result.buf.reg[0] = RoundingDivideByPOT(lhs.buf.reg[0], rhs.buf.reg[0]); 508*5f39d1b3SJooyung Han result.buf.reg[1] = RoundingDivideByPOT(lhs.buf.reg[1], rhs.buf.reg[1]); 509*5f39d1b3SJooyung Han result.buf.reg[2] = RoundingDivideByPOT(lhs.buf.reg[2], rhs.buf.reg[0]); 510*5f39d1b3SJooyung Han result.buf.reg[3] = RoundingDivideByPOT(lhs.buf.reg[3], rhs.buf.reg[1]); 511*5f39d1b3SJooyung Han result.buf.reg[4] = RoundingDivideByPOT(lhs.buf.reg[4], rhs.buf.reg[0]); 512*5f39d1b3SJooyung Han result.buf.reg[5] = RoundingDivideByPOT(lhs.buf.reg[5], rhs.buf.reg[1]); 513*5f39d1b3SJooyung Han result.buf.reg[6] = RoundingDivideByPOT(lhs.buf.reg[6], rhs.buf.reg[0]); 514*5f39d1b3SJooyung Han result.buf.reg[7] = RoundingDivideByPOT(lhs.buf.reg[7], rhs.buf.reg[1]); 515*5f39d1b3SJooyung Han return result; 516*5f39d1b3SJooyung Han } 517*5f39d1b3SJooyung Han }; 518*5f39d1b3SJooyung Han 519*5f39d1b3SJooyung Han // 1x8 := 1x8 + 1x8 520*5f39d1b3SJooyung Han template <> 521*5f39d1b3SJooyung Han struct BroadcastRoundingDivideByPOTImpl<RegBlockInt32<1, 8>, 522*5f39d1b3SJooyung Han RegBlockInt32<1, 8>> { 523*5f39d1b3SJooyung Han static RegBlockInt32<1, 8> Run(const RegBlockInt32<1, 8>& lhs, 524*5f39d1b3SJooyung Han const RegBlockInt32<1, 8>& rhs) { 525*5f39d1b3SJooyung Han RegBlockInt32<1, 8> result; 526*5f39d1b3SJooyung Han result.buf.reg[0] = RoundingDivideByPOT(lhs.buf.reg[0], rhs.buf.reg[0]); 527*5f39d1b3SJooyung Han result.buf.reg[1] = RoundingDivideByPOT(lhs.buf.reg[1], rhs.buf.reg[1]); 528*5f39d1b3SJooyung Han return result; 529*5f39d1b3SJooyung Han } 530*5f39d1b3SJooyung Han }; 531*5f39d1b3SJooyung Han 532*5f39d1b3SJooyung Han // 1x8 := 1x8 + 1x1 533*5f39d1b3SJooyung Han template <> 534*5f39d1b3SJooyung Han struct BroadcastRoundingDivideByPOTImpl<RegBlockInt32<1, 8>, 535*5f39d1b3SJooyung Han RegBlockInt32<1, 1>> { 536*5f39d1b3SJooyung Han static RegBlockInt32<1, 8> Run(const RegBlockInt32<1, 8>& lhs, 537*5f39d1b3SJooyung Han const RegBlockInt32<1, 1>& rhs) { 538*5f39d1b3SJooyung Han RegBlockInt32<1, 8> result; 539*5f39d1b3SJooyung Han result.buf.reg[0] = 540*5f39d1b3SJooyung Han RoundingDivideByPOT(lhs.buf.reg[0], Dup<Int32x4>(rhs.buf.reg[0])); 541*5f39d1b3SJooyung Han result.buf.reg[1] = 542*5f39d1b3SJooyung Han RoundingDivideByPOT(lhs.buf.reg[1], Dup<Int32x4>(rhs.buf.reg[0])); 543*5f39d1b3SJooyung Han return result; 544*5f39d1b3SJooyung Han } 545*5f39d1b3SJooyung Han }; 546*5f39d1b3SJooyung Han 547*5f39d1b3SJooyung Han } // end namespace gemmlowp 548*5f39d1b3SJooyung Han 549*5f39d1b3SJooyung Han #include "simd_wrappers_common_neon_sse.h" 550*5f39d1b3SJooyung Han 551*5f39d1b3SJooyung Han #endif // GEMMLOWP_INTERNAL_SIMD_WRAPPERS_NEON_H_ 552