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