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