| // Copyright 2019 Google LLC |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // ----------------------------------------------------------------------------- |
| // |
| // SSE implementation of Transforms |
| // |
| // Author: Skal (pascal.massimino@gmail.com) |
| // |
| |
| #include <algorithm> |
| #include <cassert> |
| #include <cmath> |
| #include <cstdint> |
| #include <cstdio> |
| #include <cstring> |
| |
| #include "src/dsp/dsp.h" |
| #include "src/dsp/math.h" |
| |
| #if defined(WP2_USE_SSE) |
| |
| #include "src/dsp/dsp_x86.h" |
| |
| namespace { |
| |
| //------------------------------------------------------------------------------ |
| // Constants for 10 bit precision |
| |
| // kCosPi[j] = (int)round(cos(M_PI*j/128) * (1<<kPrecision)); |
| constexpr uint32_t kPrecision = 10u; |
| constexpr int32_t kCosPi[64] = { |
| 1024, 1024, 1023, 1021, 1019, 1016, 1013, 1009, 1004, 999, 993, 987, 980, |
| 972, 964, 955, 946, 936, 926, 915, 903, 891, 878, 865, 851, 837, |
| 822, 807, 792, 775, 759, 742, 724, 706, 688, 669, 650, 630, 610, |
| 590, 569, 548, 526, 505, 483, 460, 438, 415, 392, 369, 345, 321, |
| 297, 273, 249, 224, 200, 175, 150, 125, 100, 75, 50, 25}; |
| // Pre-calculated constants kCosPi[32] * kCosPi[16/48] |
| constexpr int32_t kCos32Cos48 = 277; // cos(pi/4) * cos(3 * pi / 8) |
| constexpr int32_t kCos32Cos16 = 669; // cos(pi/4) * cos(pi / 8) |
| // These are the same constants but with one extra precision bit (p=pre-scaled). |
| constexpr int32_t kCos32Cos48p = 554; // 2 * cos(pi/4) * cos(3 * pi / 8) |
| constexpr int32_t kCos32Cos16p = 1337; // 2 * cos(pi/4) * cos(pi / 8) |
| |
| //------------------------------------------------------------------------------ |
| |
| template <class V> |
| class ColTransformGen { |
| public: |
| static void idct2(int16_t* coeffs, uint32_t w); |
| static void idct4(int16_t* coeffs, uint32_t w); |
| static void idct8(int16_t* coeffs, uint32_t w); |
| |
| static void fdct2(int32_t* coeffs, uint32_t w); |
| static void fdct4(int32_t* coeffs, uint32_t w); |
| static void fdct8(int32_t* coeffs, uint32_t w); |
| static void fdct16(int32_t* coeffs, uint32_t w); |
| |
| private: |
| static constexpr uint32_t kStep = V::Step(); |
| static V Load(const int32_t in[]) { return V(in); } |
| static constexpr V Rounding(uint32_t n) { return V::Rounding(n); } |
| }; |
| |
| //------------------------------------------------------------------------------ |
| // column-wise idct |
| |
| template <class V> |
| void ColTransformGen<V>::idct2(int16_t* coeffs, uint32_t w) { |
| const V c_32 = kCosPi[32]; |
| const V kRnd0 = Rounding(kPrecision); |
| for (uint32_t n = V::Size(w); n--; coeffs += kStep) { |
| const V a0 = Load_s16_s32(coeffs + w * 0); |
| const V a1 = Load_s16_s32(coeffs + w * 1); |
| const V b0 = ((a0 + a1) * c_32 + kRnd0) >> kPrecision; |
| const V b1 = ((a0 - a1) * c_32 + kRnd0) >> kPrecision; |
| b0.Store16(coeffs + w * 0); |
| b1.Store16(coeffs + w * 1); |
| } |
| } |
| |
| template <class V> |
| void ColTransformGen<V>::idct4(int16_t* coeffs, uint32_t w) { |
| const V kRnd0 = Rounding(kPrecision); |
| const V c_32_48 = kCos32Cos48p; |
| const V c_32_16 = kCos32Cos16p; |
| for (uint32_t n = V::Size(w); n--; coeffs += kStep) { |
| V a0 = Load_s16_s32(coeffs + w * 0); |
| V a1 = Load_s16_s32(coeffs + w * 2); |
| V a2 = Load_s16_s32(coeffs + w * 1); |
| V a3 = Load_s16_s32(coeffs + w * 3); |
| |
| const V b0 = a0 + a1; |
| const V b1 = a0 - a1; |
| const V b2 = (c_32_48 * a2 - c_32_16 * a3 + kRnd0) >> kPrecision; |
| const V b3 = (c_32_16 * a2 + c_32_48 * a3 + kRnd0) >> kPrecision; |
| |
| a0 = (b0 + b3) >> 1; |
| a1 = (b1 + b2) >> 1; |
| a2 = (b1 - b2) >> 1; |
| a3 = (b0 - b3) >> 1; |
| |
| a0.Store16(coeffs + w * 0); |
| a1.Store16(coeffs + w * 1); |
| a2.Store16(coeffs + w * 2); |
| a3.Store16(coeffs + w * 3); |
| } |
| } |
| |
| template <class V> |
| void ColTransformGen<V>::idct8(int16_t* coeffs, uint32_t w) { |
| const V c_08 = kCosPi[8]; |
| const V c_16 = kCosPi[16]; |
| const V c_24 = kCosPi[24]; |
| const V c_32 = kCosPi[32]; |
| const V c_40 = kCosPi[40]; |
| const V c_48 = kCosPi[48]; |
| const V c_56 = kCosPi[56]; |
| constexpr uint32_t shift = 1; |
| const V kRnd0 = Rounding(kPrecision); |
| const V kRnd1 = 1; // rounder |
| for (uint32_t n = V::Size(w); n--; coeffs += kStep) { |
| V b0 = Load_s16_s32(coeffs + w * 0); |
| V b1 = Load_s16_s32(coeffs + w * 4); |
| V b2 = Load_s16_s32(coeffs + w * 2); |
| V b3 = Load_s16_s32(coeffs + w * 6); |
| |
| V a0 = (((b0 + b1) * c_32 + kRnd0) >> kPrecision) + kRnd1; |
| V a1 = (((b0 - b1) * c_32 + kRnd0) >> kPrecision) + kRnd1; |
| V a2 = (c_48 * b2 - c_16 * b3 + kRnd0) >> kPrecision; |
| V a3 = (c_16 * b2 + c_48 * b3 + kRnd0) >> kPrecision; |
| |
| b0 = a0 + a3; |
| b1 = a1 + a2; |
| b2 = a1 - a2; |
| b3 = a0 - a3; |
| |
| V a4 = Load_s16_s32(coeffs + w * 1); |
| V a5 = Load_s16_s32(coeffs + w * 5); |
| V a6 = Load_s16_s32(coeffs + w * 3); |
| V a7 = Load_s16_s32(coeffs + w * 7); |
| |
| V b4 = (c_56 * a4 - c_08 * a7 + kRnd0) >> kPrecision; |
| V b7 = (c_08 * a4 + c_56 * a7 + kRnd0) >> kPrecision; |
| V b5 = (c_24 * a5 - c_40 * a6 + kRnd0) >> kPrecision; |
| V b6 = (c_40 * a5 + c_24 * a6 + kRnd0) >> kPrecision; |
| |
| a4 = b5 + b4; |
| a5 = b4 - b5; |
| a6 = b7 - b6; |
| a7 = b6 + b7; |
| |
| b4 = a4; |
| b5 = ((a6 - a5) * c_32 + kRnd0) >> kPrecision; |
| b6 = ((a6 + a5) * c_32 + kRnd0) >> kPrecision; |
| b7 = a7; |
| |
| a0 = (b0 + b7) >> shift; |
| a1 = (b1 + b6) >> shift; |
| a6 = (b1 - b6) >> shift; |
| a7 = (b0 - b7) >> shift; |
| |
| a0.Store16(coeffs + w * 0); |
| a1.Store16(coeffs + w * 1); |
| a6.Store16(coeffs + w * 6); |
| a7.Store16(coeffs + w * 7); |
| |
| a2 = (b2 + b5) >> shift; |
| a3 = (b3 + b4) >> shift; |
| a4 = (b3 - b4) >> shift; |
| a5 = (b2 - b5) >> shift; |
| |
| a2.Store16(coeffs + w * 2); |
| a3.Store16(coeffs + w * 3); |
| a4.Store16(coeffs + w * 4); |
| a5.Store16(coeffs + w * 5); |
| } |
| } |
| |
| //------------------------------------------------------------------------------ |
| // column-wise fdct |
| |
| template <class V> |
| void ColTransformGen<V>::fdct2(int32_t* coeffs, uint32_t w) { |
| const V c_32 = kCosPi[32]; |
| const V kRnd0 = Rounding(kPrecision); |
| for (uint32_t n = V::Size(w); n--; coeffs += kStep) { |
| const V a0(coeffs + w * 0); |
| const V a1(coeffs + w * 1); |
| const V b0 = ((a0 + a1) * c_32 + kRnd0) >> kPrecision; |
| const V b1 = ((a0 - a1) * c_32 + kRnd0) >> kPrecision; |
| b0.Store(coeffs + w * 0); |
| b1.Store(coeffs + w * 1); |
| } |
| } |
| |
| template <class V> |
| void ColTransformGen<V>::fdct4(int32_t* coeffs, uint32_t w) { |
| const V kRnd1 = 1; // rounder for shift=1 |
| const V kRnd0 = Rounding(kPrecision); |
| const V c_32_48 = kCos32Cos48; |
| const V c_32_16 = kCos32Cos16; |
| for (uint32_t n = V::Size(w); n--; coeffs += kStep) { |
| V b0(coeffs + w * 0); |
| V b1(coeffs + w * 1); |
| V b2(coeffs + w * 2); |
| V b3(coeffs + w * 3); |
| |
| const V a0 = b3 + b0; |
| const V a1 = b2 + b1; |
| const V a2 = b1 - b2; |
| const V a3 = b0 - b3; |
| |
| b0 = (a0 + a1 + kRnd1) >> 1; |
| b1 = (a0 - a1 + kRnd1) >> 1; |
| b2 = (c_32_48 * a2 + c_32_16 * a3 + kRnd0) >> kPrecision; |
| b3 = (c_32_48 * a3 - c_32_16 * a2 + kRnd0) >> kPrecision; |
| |
| b0.Store(coeffs + w * 0); |
| b2.Store(coeffs + w * 1); |
| b1.Store(coeffs + w * 2); |
| b3.Store(coeffs + w * 3); |
| } |
| } |
| |
| template <class V> |
| void ColTransformGen<V>::fdct8(int32_t* coeffs, uint32_t w) { |
| constexpr uint32_t shift = kPrecision + 1; |
| const V kRnd0 = Rounding(kPrecision); |
| const V kRnd1 = Rounding(shift); |
| const V c_08 = kCosPi[8]; |
| const V c_16 = kCosPi[16]; |
| const V c_24 = kCosPi[24]; |
| const V c_32 = kCosPi[32]; |
| const V c_40 = kCosPi[40]; |
| const V c_48 = kCosPi[48]; |
| const V c_56 = kCosPi[56]; |
| for (uint32_t n = V::Size(w); n--; coeffs += kStep) { |
| V a0(coeffs + w * 0); |
| V a1(coeffs + w * 1); |
| V a2(coeffs + w * 2); |
| V a3(coeffs + w * 3); |
| |
| V b3(coeffs + w * 4); |
| V b2(coeffs + w * 5); |
| V b1(coeffs + w * 6); |
| V b0(coeffs + w * 7); |
| |
| // Save for later |
| V a7 = a0; |
| V a6 = a1; |
| V a5 = a2; |
| V a4 = a3; |
| V b4 = b3; |
| V b5 = b2; |
| V b6 = b1; |
| V b7 = b0; |
| |
| a2 = a2 + b2; |
| a3 = a3 + b3; |
| a0 = a0 + b0; |
| a1 = a1 + b1; |
| |
| b0 = a3 + a0; |
| b1 = a2 + a1; |
| b2 = a1 - a2; |
| b3 = a0 - a3; |
| |
| a0 = ((b0 + b1) * c_32 + kRnd1) >> shift; |
| a1 = ((b0 - b1) * c_32 + kRnd1) >> shift; |
| a2 = (c_48 * b2 + c_16 * b3 + kRnd1) >> shift; |
| a3 = (c_48 * b3 - c_16 * b2 + kRnd1) >> shift; |
| |
| a0.Store(coeffs + w * 0); |
| a2.Store(coeffs + w * 2); |
| a1.Store(coeffs + w * 4); |
| a3.Store(coeffs + w * 6); |
| |
| a4 = a4 - b4; |
| a5 = a5 - b5; |
| a6 = a6 - b6; |
| a7 = a7 - b7; |
| |
| b5 = ((a6 - a5) * c_32 + kRnd0) >> kPrecision; |
| b6 = ((a6 + a5) * c_32 + kRnd0) >> kPrecision; |
| |
| a5 = a4 - b5; |
| a6 = a7 - b6; |
| a4 = a4 + b5; |
| a7 = a7 + b6; |
| |
| b4 = (c_56 * a4 + c_08 * a7 + kRnd1) >> shift; |
| b7 = (c_56 * a7 - c_08 * a4 + kRnd1) >> shift; |
| b5 = (c_24 * a5 + c_40 * a6 + kRnd1) >> shift; |
| b6 = (c_24 * a6 - c_40 * a5 + kRnd1) >> shift; |
| |
| b4.Store(coeffs + w * 1); |
| b6.Store(coeffs + w * 3); |
| b5.Store(coeffs + w * 5); |
| b7.Store(coeffs + w * 7); |
| } |
| } |
| |
| template <class V> |
| void ColTransformGen<V>::fdct16(int32_t* coeffs, uint32_t w) { |
| constexpr uint32_t shift = kPrecision + 1; |
| const V kRnd0 = Rounding(kPrecision); |
| const V kRnd1 = Rounding(shift); |
| for (uint32_t n = V::Size(w); n--; coeffs += kStep) { |
| int32_t temp[8 * kStep]; |
| V c0, c1; |
| |
| // low |
| V a0 = Load(coeffs + w * 0) + Load(coeffs + w * 15); |
| V a1 = Load(coeffs + w * 1) + Load(coeffs + w * 14); |
| V a2 = Load(coeffs + w * 2) + Load(coeffs + w * 13); |
| V a3 = Load(coeffs + w * 3) + Load(coeffs + w * 12); |
| V a4 = Load(coeffs + w * 4) + Load(coeffs + w * 11); |
| V a5 = Load(coeffs + w * 5) + Load(coeffs + w * 10); |
| V a6 = Load(coeffs + w * 6) + Load(coeffs + w * 9); |
| V a7 = Load(coeffs + w * 7) + Load(coeffs + w * 8); |
| |
| V b0 = a7 + a0; |
| V b1 = a6 + a1; |
| V b2 = a5 + a2; |
| V b3 = a4 + a3; |
| V b4 = a3 - a4; |
| V b5 = a2 - a5; |
| V b6 = a1 - a6; |
| V b7 = a0 - a7; |
| |
| // part 1 |
| a0 = b3 + b0; |
| a1 = b2 + b1; |
| a2 = b1 - b2; |
| a3 = b0 - b3; |
| c0 = kCosPi[32]; |
| b0 = ((a0 + a1) * c0 + kRnd0) >> kPrecision; |
| b1 = ((a0 - a1) * c0 + kRnd0) >> kPrecision; |
| c0 = kCosPi[48]; |
| c1 = kCosPi[16]; |
| b2 = (c0 * a2 + c1 * a3 + kRnd0) >> kPrecision; |
| b3 = (c0 * a3 - c1 * a2 + kRnd0) >> kPrecision; |
| c0 = kCosPi[32]; |
| b0 = (b0 * c0 + kRnd1) >> shift; |
| b1 = (b1 * c0 + kRnd1) >> shift; |
| b2 = (b2 * c0 + kRnd1) >> shift; |
| b3 = (b3 * c0 + kRnd1) >> shift; |
| |
| b0.Store(temp + 0); // 0 |
| b2.Store(temp + 4); // 4 |
| b1.Store(temp + 8); // 8 |
| b3.Store(temp + 12); // 12 |
| |
| // part 2 |
| c0 = kCosPi[32]; |
| a5 = ((b6 - b5) * c0 + kRnd0) >> kPrecision; |
| a6 = ((b6 + b5) * c0 + kRnd0) >> kPrecision; |
| b5 = b4 - a5; |
| b6 = b7 - a6; |
| b4 = b4 + a5; |
| b7 = b7 + a6; |
| c0 = kCosPi[24]; |
| c1 = kCosPi[40]; |
| a5 = (c0 * b5 + c1 * b6 + kRnd0) >> kPrecision; |
| a6 = (c0 * b6 - c1 * b5 + kRnd0) >> kPrecision; |
| c0 = kCosPi[56]; |
| c1 = kCosPi[8]; |
| a4 = (c0 * b4 + c1 * b7 + kRnd0) >> kPrecision; |
| a7 = (c0 * b7 - c1 * b4 + kRnd0) >> kPrecision; |
| c0 = kCosPi[32]; |
| a4 = (a4 * c0 + kRnd1) >> shift; |
| a5 = (a5 * c0 + kRnd1) >> shift; |
| a6 = (a6 * c0 + kRnd1) >> shift; |
| a7 = (a7 * c0 + kRnd1) >> shift; |
| |
| a4.Store(temp + 16); // 2 |
| a6.Store(temp + 20); // 6 |
| a5.Store(temp + 24); // 10 |
| a7.Store(temp + 28); // 14 |
| |
| // high |
| a3 = Load(coeffs + w * 4) - Load(coeffs + w * 11); |
| a4 = Load(coeffs + w * 3) - Load(coeffs + w * 12); |
| c0 = kCosPi[32]; |
| b3 = ((a4 - a3) * c0 + kRnd0) >> kPrecision; |
| b4 = ((a4 + a3) * c0 + kRnd0) >> kPrecision; |
| a0 = Load(coeffs + w * 7) - Load(coeffs + w * 8); |
| a7 = Load(coeffs + w * 0) - Load(coeffs + w * 15); |
| b0 = a0 + b3; |
| b7 = a7 + b4; |
| b3 = a0 - b3; |
| b4 = a7 - b4; |
| |
| a2 = Load(coeffs + w * 5) - Load(coeffs + w * 10); |
| a5 = Load(coeffs + w * 2) - Load(coeffs + w * 13); |
| b2 = ((a5 - a2) * c0 + kRnd0) >> kPrecision; |
| b5 = ((a5 + a2) * c0 + kRnd0) >> kPrecision; |
| b1 = Load(coeffs + w * 6) - Load(coeffs + w * 9); |
| b6 = Load(coeffs + w * 1) - Load(coeffs + w * 14); |
| a1 = b2 + b1; |
| a2 = b2 - b1; |
| a5 = b6 - b5; |
| a6 = b6 + b5; |
| c0 = kCosPi[48]; |
| c1 = kCosPi[16]; |
| b1 = (c0 * a6 - c1 * a1 + kRnd0) >> kPrecision; |
| b2 = (c0 * a2 - c1 * a5 + kRnd0) >> kPrecision; |
| b5 = (c0 * a5 + c1 * a2 + kRnd0) >> kPrecision; |
| b6 = (c0 * a1 + c1 * a6 + kRnd0) >> kPrecision; |
| |
| a0 = b0 + b1; |
| a1 = b0 - b1; |
| a6 = b7 - b6; |
| a7 = b7 + b6; |
| c0 = kCosPi[60]; |
| c1 = kCosPi[4]; |
| b0 = (c0 * a0 + c1 * a7 + kRnd0) >> kPrecision; |
| b7 = (c0 * a7 - c1 * a0 + kRnd0) >> kPrecision; |
| c0 = kCosPi[28]; |
| c1 = kCosPi[36]; |
| b1 = (c0 * a1 + c1 * a6 + kRnd0) >> kPrecision; |
| b6 = (c0 * a6 - c1 * a1 + kRnd0) >> kPrecision; |
| c0 = kCosPi[32]; |
| b0 = (b0 * c0 + kRnd1) >> shift; |
| b1 = (b1 * c0 + kRnd1) >> shift; |
| b6 = (b6 * c0 + kRnd1) >> shift; |
| b7 = (b7 * c0 + kRnd1) >> shift; |
| |
| b0.Store(coeffs + w * 1); |
| b6.Store(coeffs + w * 7); |
| b1.Store(coeffs + w * 9); |
| b7.Store(coeffs + w * 15); |
| |
| a2 = b3 - b2; |
| a3 = b3 + b2; |
| a4 = b4 + b5; |
| a5 = b4 - b5; |
| c0 = kCosPi[12]; |
| c1 = kCosPi[52]; |
| b3 = (c0 * a3 + c1 * a4 + kRnd0) >> kPrecision; |
| b4 = (c0 * a4 - c1 * a3 + kRnd0) >> kPrecision; |
| c0 = kCosPi[44]; |
| c1 = kCosPi[20]; |
| b2 = (c0 * a2 + c1 * a5 + kRnd0) >> kPrecision; |
| b5 = (c0 * a5 - c1 * a2 + kRnd0) >> kPrecision; |
| c0 = kCosPi[32]; |
| b2 = (b2 * c0 + kRnd1) >> shift; |
| b3 = (b3 * c0 + kRnd1) >> shift; |
| b4 = (b4 * c0 + kRnd1) >> shift; |
| b5 = (b5 * c0 + kRnd1) >> shift; |
| |
| b4.Store(coeffs + w * 3); |
| b2.Store(coeffs + w * 5); |
| b5.Store(coeffs + w * 11); |
| b3.Store(coeffs + w * 13); |
| |
| a0 = Load(temp + 0); |
| a1 = Load(temp + 4); |
| a2 = Load(temp + 8); |
| a3 = Load(temp + 12); |
| a4 = Load(temp + 16); |
| a5 = Load(temp + 20); |
| a6 = Load(temp + 24); |
| a7 = Load(temp + 28); |
| |
| a0.Store(coeffs + w * 0); |
| a1.Store(coeffs + w * 4); |
| a2.Store(coeffs + w * 8); |
| a3.Store(coeffs + w * 12); |
| a4.Store(coeffs + w * 2); |
| a5.Store(coeffs + w * 6); |
| a6.Store(coeffs + w * 10); |
| a7.Store(coeffs + w * 14); |
| } |
| } |
| |
| //------------------------------------------------------------------------------ |
| // row-wise idct |
| |
| static void idct4_SSE(int16_t* coeffs) { |
| constexpr uint32_t one = 1 << kPrecision; |
| const __m128i kRnd0 = _mm_set1_epi32((1 << kPrecision) >> 1); |
| __m128i v0, v1, c0, c1; |
| |
| // stage 1 |
| v0 = Load_s16_s32(coeffs); |
| v0 = _mm_shuffle_epi32(v0, 0xd8); |
| |
| // stage 2 |
| c0 = _mm_setr_epi32(one, -one, kCos32Cos48p, kCos32Cos48p); |
| c1 = _mm_setr_epi32(one, one, -kCos32Cos16p, kCos32Cos16p); |
| v1 = _mm_shuffle_epi32(v0, 0xb1); |
| v0 = _mm_mullo_epi32(v0, c0); |
| v1 = _mm_mullo_epi32(v1, c1); |
| v0 = _mm_add_epi32(v0, v1); |
| v0 = _mm_add_epi32(v0, kRnd0); |
| v0 = _mm_srai_epi32(v0, kPrecision); |
| |
| // stage 3 |
| c0 = _mm_setr_epi32(-1, -1, 1, 1); |
| v1 = _mm_sign_epi32(v0, c0); |
| v0 = _mm_shuffle_epi32(v0, 0x1b); |
| v0 = _mm_sub_epi32(v0, v1); |
| v0 = _mm_srai_epi32(v0, 1); |
| |
| Store_s32_s16(v0, coeffs); |
| } |
| |
| static void idct8_SSE(int16_t* coeffs) { |
| constexpr uint32_t shift = 1; |
| const __m128i kRnd0 = _mm_set1_epi32((1 << kPrecision) >> 1); |
| __m128i v4, v5, c0, c1; |
| |
| // stage 1 |
| __m128i v0 = Load_s16_s32(coeffs + 0); |
| __m128i v1 = Load_s16_s32(coeffs + 4); |
| __m128i v3 = _mm_shuffle_epi32(v0, 0xb1); |
| __m128i v2 = _mm_shuffle_epi32(v1, 0xb1); |
| v0 = _mm_blend_epi16(v0, v2, 0xcc); |
| v1 = _mm_blend_epi16(v1, v3, 0x33); |
| |
| // stage 2 |
| c0 = _mm_setr_epi32(kCosPi[56], kCosPi[24], kCosPi[24], kCosPi[56]); |
| c1 = _mm_setr_epi32(-kCosPi[8], -kCosPi[40], kCosPi[40], kCosPi[8]); |
| v3 = _mm_shuffle_epi32(v1, 0x1b); |
| v1 = _mm_mullo_epi32(v1, c0); |
| v3 = _mm_mullo_epi32(v3, c1); |
| v1 = _mm_add_epi32(v1, v3); |
| v1 = _mm_add_epi32(v1, kRnd0); |
| v1 = _mm_srai_epi32(v1, kPrecision); |
| |
| // stage 3 |
| c0 = _mm_setr_epi32(kCosPi[32], -kCosPi[32], kCosPi[48], kCosPi[48]); |
| c1 = _mm_setr_epi32(kCosPi[32], kCosPi[32], -kCosPi[16], kCosPi[16]); |
| v2 = _mm_shuffle_epi32(v0, 0xb1); |
| v0 = _mm_mullo_epi32(v0, c0); |
| v2 = _mm_mullo_epi32(v2, c1); |
| // +1=rounder |
| c0 = _mm_setr_epi32((3 << kPrecision) >> 1, (3 << kPrecision) >> 1, |
| (1 << kPrecision) >> 1, (1 << kPrecision) >> 1); |
| v0 = _mm_add_epi32(v0, v2); |
| v0 = _mm_add_epi32(v0, c0); |
| v0 = _mm_srai_epi32(v0, kPrecision); |
| |
| c0 = _mm_setr_epi32(1, -1, -1, 1); |
| v3 = _mm_shuffle_epi32(v1, 0xb1); |
| v1 = _mm_sign_epi32(v1, c0); |
| v1 = _mm_add_epi32(v1, v3); |
| |
| // stage 4 |
| c0 = _mm_setr_epi32(-1, -1, 1, 1); |
| c1 = _mm_set1_epi32(kCosPi[32]); |
| v2 = _mm_sign_epi32(v0, c0); |
| v0 = _mm_shuffle_epi32(v0, 0x1b); |
| v0 = _mm_sub_epi32(v0, v2); |
| |
| v5 = _mm_shuffle_epi32(v1, 0x1b); |
| v4 = _mm_sign_epi32(v1, c0); |
| v5 = _mm_add_epi32(v5, v4); |
| v5 = _mm_mullo_epi32(v5, c1); |
| v5 = _mm_add_epi32(v5, kRnd0); |
| v5 = _mm_srai_epi32(v5, kPrecision); |
| v1 = _mm_blend_epi16(v1, v5, 0x3c); |
| |
| // stage 5 |
| v3 = _mm_shuffle_epi32(v1, 0x1b); |
| v2 = _mm_shuffle_epi32(v0, 0x1b); |
| v3 = _mm_add_epi32(v3, v0); |
| v2 = _mm_sub_epi32(v2, v1); |
| v3 = _mm_srai_epi32(v3, shift); |
| v2 = _mm_srai_epi32(v2, shift); |
| |
| Store_s32_s16(v3, coeffs + 0); |
| Store_s32_s16(v2, coeffs + 4); |
| } |
| |
| static void idct16_SSE(int16_t* coeffs) { |
| constexpr uint32_t shift = kPrecision + 1; |
| const __m128i kRnd0 = _mm_set1_epi32((1 << kPrecision) >> 1); |
| const __m128i kRnd1 = _mm_set1_epi32((1 << shift) >> 1); |
| __m128i v0, v1, v2, v3, v4, v5, v6, v7, c0, c1; |
| |
| // stage 1 |
| v0 = Load_s16_s32(coeffs + 0); |
| v1 = Load_s16_s32(coeffs + 4); |
| v2 = Load_s16_s32(coeffs + 8); |
| v3 = Load_s16_s32(coeffs + 12); |
| v4 = _mm_unpacklo_epi64(v0, v2); // 0189 |
| v5 = _mm_unpackhi_epi64(v0, v2); // 23ab |
| v6 = _mm_unpacklo_epi64(v1, v3); // 45cd |
| v7 = _mm_unpackhi_epi64(v1, v3); // 67ef |
| v0 = _mm_unpacklo_epi32(v4, v6); // 0415 |
| v1 = _mm_unpackhi_epi32(v4, v6); // 8c9d |
| v2 = _mm_unpacklo_epi32(v5, v7); // 2637 |
| v3 = _mm_unpackhi_epi32(v5, v7); // aebf |
| v4 = _mm_unpacklo_epi32(v0, v1); // 084c |
| v6 = _mm_unpackhi_epi32(v0, v1); // 195d |
| v5 = _mm_unpacklo_epi32(v2, v3); // 2a6e |
| v7 = _mm_unpackhi_epi32(v2, v3); // 3b7f |
| |
| // stage 2 |
| c0 = _mm_setr_epi32(kCosPi[60], kCosPi[28], kCosPi[44], kCosPi[12]); |
| c1 = _mm_setr_epi32(kCosPi[4], kCosPi[36], kCosPi[20], kCosPi[52]); |
| v7 = _mm_shuffle_epi32(v7, 0x1b); // fedc |
| v0 = _mm_mullo_epi32(v6, c1); |
| v6 = _mm_mullo_epi32(v6, c0); |
| v1 = _mm_mullo_epi32(v7, c1); |
| v7 = _mm_mullo_epi32(v7, c0); |
| v6 = _mm_sub_epi32(v6, v1); |
| v7 = _mm_add_epi32(v7, v0); |
| v6 = _mm_add_epi32(v6, kRnd0); |
| v7 = _mm_add_epi32(v7, kRnd0); |
| v6 = _mm_srai_epi32(v6, kPrecision); |
| v7 = _mm_srai_epi32(v7, kPrecision); |
| |
| // stage 3 |
| c0 = _mm_setr_epi32(kCosPi[56], kCosPi[24], kCosPi[24], kCosPi[56]); |
| c1 = _mm_setr_epi32(kCosPi[8], kCosPi[40], -kCosPi[40], -kCosPi[8]); |
| v0 = _mm_shuffle_epi32(v5, 0x1b); |
| v5 = _mm_mullo_epi32(v5, c0); |
| v0 = _mm_mullo_epi32(v0, c1); |
| v5 = _mm_sub_epi32(v5, v0); |
| v5 = _mm_add_epi32(v5, kRnd0); |
| v5 = _mm_srai_epi32(v5, kPrecision); |
| |
| v7 = _mm_shuffle_epi32(v7, 0x4e); |
| v0 = _mm_blend_epi16(v6, v7, 0x3c); // 8cfb |
| v1 = _mm_blend_epi16(v6, v7, 0xc3); |
| v1 = _mm_shuffle_epi32(v1, 0xb1); // 9dea |
| v6 = _mm_add_epi32(v0, v1); |
| v7 = _mm_sub_epi32(v0, v1); |
| |
| // stage 4 |
| c0 = _mm_setr_epi32(kCosPi[32], -kCosPi[32], kCosPi[48], kCosPi[48]); |
| c1 = _mm_setr_epi32(kCosPi[32], kCosPi[32], -kCosPi[16], kCosPi[16]); |
| v0 = _mm_shuffle_epi32(v4, 0xb1); |
| v4 = _mm_mullo_epi32(v4, c0); |
| v0 = _mm_mullo_epi32(v0, c1); |
| v4 = _mm_add_epi32(v4, v0); |
| v4 = _mm_add_epi32(v4, kRnd0); |
| v4 = _mm_srai_epi32(v4, kPrecision); |
| |
| c0 = _mm_setr_epi32(1, -1, -1, 1); |
| v0 = _mm_shuffle_epi32(v5, 0xb1); |
| v5 = _mm_sign_epi32(v5, c0); |
| v5 = _mm_add_epi32(v5, v0); |
| |
| c0 = _mm_setr_epi32(-kCosPi[16], kCosPi[48], kCosPi[16], -kCosPi[48]); |
| c1 = _mm_setr_epi32(kCosPi[48], -kCosPi[16], kCosPi[48], -kCosPi[16]); |
| v0 = _mm_shuffle_epi32(v7, 0x4e); |
| v7 = _mm_mullo_epi32(v7, c0); |
| v0 = _mm_mullo_epi32(v0, c1); |
| v7 = _mm_add_epi32(v7, v0); |
| v7 = _mm_add_epi32(v7, kRnd0); |
| v7 = _mm_srai_epi32(v7, kPrecision); |
| |
| // stage 5 |
| v0 = _mm_unpacklo_epi32(v6, v7); // 89cd |
| v1 = _mm_unpackhi_epi32(v7, v6); // efab |
| v6 = _mm_unpacklo_epi64(v1, v0); // ef89 |
| v7 = _mm_unpackhi_epi64(v1, v0); // abcd |
| |
| v0 = _mm_shuffle_epi32(v6, 0x1b); |
| v1 = _mm_shuffle_epi32(v7, 0x1b); |
| v6 = _mm_add_epi32(v6, v1); |
| v7 = _mm_sub_epi32(v0, v7); |
| |
| c0 = _mm_setr_epi32(-1, -1, 1, 1); |
| c1 = _mm_set1_epi32(kCosPi[32]); |
| v0 = _mm_sign_epi32(v4, c0); |
| v4 = _mm_shuffle_epi32(v4, 0x1b); |
| v4 = _mm_sub_epi32(v4, v0); |
| |
| v3 = _mm_shuffle_epi32(v5, 0x1b); |
| v1 = _mm_sign_epi32(v5, c0); |
| v3 = _mm_add_epi32(v3, v1); |
| v3 = _mm_mullo_epi32(v3, c1); |
| v3 = _mm_add_epi32(v3, kRnd0); |
| v3 = _mm_srai_epi32(v3, kPrecision); |
| v5 = _mm_blend_epi16(v5, v3, 0x3c); |
| |
| // stage 6 |
| v0 = _mm_shuffle_epi32(v5, 0x1b); |
| v1 = _mm_shuffle_epi32(v4, 0x1b); |
| v0 = _mm_add_epi32(v0, v4); |
| v1 = _mm_sub_epi32(v1, v5); |
| |
| v3 = _mm_sign_epi32(v7, c0); |
| v7 = _mm_shuffle_epi32(v7, 0x1b); |
| v7 = _mm_add_epi32(v7, v3); |
| v7 = _mm_mullo_epi32(v7, c1); |
| v7 = _mm_add_epi32(v7, kRnd0); |
| v7 = _mm_srai_epi32(v7, kPrecision); |
| v2 = _mm_alignr_epi8(v7, v6, 8); |
| v3 = _mm_alignr_epi8(v6, v7, 8); |
| |
| // stage 7 |
| v4 = _mm_shuffle_epi32(v3, 0x1b); |
| v5 = _mm_shuffle_epi32(v2, 0x1b); |
| v6 = _mm_shuffle_epi32(v1, 0x1b); |
| v7 = _mm_shuffle_epi32(v0, 0x1b); |
| v4 = _mm_add_epi32(v4, v0); |
| v5 = _mm_add_epi32(v5, v1); |
| v6 = _mm_sub_epi32(v6, v2); |
| v7 = _mm_sub_epi32(v7, v3); |
| |
| v4 = _mm_mullo_epi32(v4, c1); |
| v5 = _mm_mullo_epi32(v5, c1); |
| v6 = _mm_mullo_epi32(v6, c1); |
| v7 = _mm_mullo_epi32(v7, c1); |
| v4 = _mm_add_epi32(v4, kRnd1); |
| v5 = _mm_add_epi32(v5, kRnd1); |
| v6 = _mm_add_epi32(v6, kRnd1); |
| v7 = _mm_add_epi32(v7, kRnd1); |
| v4 = _mm_srai_epi32(v4, shift); |
| v5 = _mm_srai_epi32(v5, shift); |
| v6 = _mm_srai_epi32(v6, shift); |
| v7 = _mm_srai_epi32(v7, shift); |
| |
| Store_s32_s16(v4, coeffs + 0); |
| Store_s32_s16(v5, coeffs + 4); |
| Store_s32_s16(v6, coeffs + 8); |
| Store_s32_s16(v7, coeffs + 12); |
| } |
| |
| //------------------------------------------------------------------------------ |
| // row-wise fdct |
| |
| static void fdct4_SSE(int32_t* coeffs) { |
| constexpr uint32_t rounding = (1 << kPrecision) >> 1; |
| const __m128i kRnd0 = _mm_set1_epi32(rounding); |
| __m128i v0, v1, c0, c1; |
| |
| // stage 1 |
| v0 = Load128b(coeffs); |
| c0 = _mm_setr_epi32(-1, -1, 1, 1); |
| v1 = _mm_sign_epi32(v0, c0); |
| v0 = _mm_shuffle_epi32(v0, 0x1b); |
| v0 = _mm_sub_epi32(v0, v1); |
| |
| // stage 2 |
| c0 = _mm_setr_epi32(rounding, -rounding, kCos32Cos48, kCos32Cos48); |
| c1 = _mm_setr_epi32(rounding, rounding, kCos32Cos16, -kCos32Cos16); |
| v1 = _mm_shuffle_epi32(v0, 0xb1); |
| v0 = _mm_mullo_epi32(v0, c0); |
| v1 = _mm_mullo_epi32(v1, c1); |
| v0 = _mm_add_epi32(v0, v1); |
| v0 = _mm_add_epi32(v0, kRnd0); |
| v0 = _mm_srai_epi32(v0, kPrecision); |
| |
| // stage 3 |
| v0 = _mm_shuffle_epi32(v0, 0xd8); |
| Store128b(v0, coeffs); |
| } |
| |
| static void fdct8_SSE(int32_t* coeffs) { |
| constexpr uint32_t shift = kPrecision + 1; |
| const __m128i kRnd0 = _mm_set1_epi32((1 << kPrecision) >> 1); |
| const __m128i kRnd1 = _mm_set1_epi32((1 << shift) >> 1); |
| __m128i v0, v1, v2, v3, v4, v5, c0, c1; |
| |
| // stage 1 |
| v0 = Load128b(coeffs + 0); |
| v1 = Load128b(coeffs + 4); |
| v3 = _mm_shuffle_epi32(v0, 0x1b); |
| v2 = _mm_shuffle_epi32(v1, 0x1b); |
| v3 = _mm_sub_epi32(v3, v1); |
| v2 = _mm_add_epi32(v2, v0); |
| |
| // stage 2 |
| c0 = _mm_setr_epi32(-1, -1, 1, 1); |
| c1 = _mm_set1_epi32(kCosPi[32]); |
| v0 = _mm_sign_epi32(v2, c0); |
| v2 = _mm_shuffle_epi32(v2, 0x1b); |
| v2 = _mm_sub_epi32(v2, v0); |
| |
| v5 = _mm_shuffle_epi32(v3, 0x1b); |
| v4 = _mm_sign_epi32(v3, c0); |
| v5 = _mm_add_epi32(v5, v4); |
| v5 = _mm_mullo_epi32(v5, c1); |
| v5 = _mm_add_epi32(v5, kRnd0); |
| v5 = _mm_srai_epi32(v5, kPrecision); |
| v5 = _mm_shuffle_epi32(v5, 0xa5); |
| |
| // stage 3 |
| c0 = _mm_setr_epi32(1, -1, -1, 1); |
| v3 = _mm_shuffle_epi32(v3, 0xf0); |
| v5 = _mm_sign_epi32(v5, c0); |
| v3 = _mm_add_epi32(v3, v5); |
| |
| c0 = _mm_setr_epi32(kCosPi[32], -kCosPi[32], kCosPi[48], kCosPi[48]); |
| c1 = _mm_setr_epi32(kCosPi[32], kCosPi[32], kCosPi[16], -kCosPi[16]); |
| v4 = _mm_shuffle_epi32(v2, 0xb1); |
| v2 = _mm_mullo_epi32(v2, c0); |
| v4 = _mm_mullo_epi32(v4, c1); |
| v2 = _mm_add_epi32(v2, v4); |
| v2 = _mm_add_epi32(v2, kRnd1); |
| v2 = _mm_srai_epi32(v2, shift); |
| |
| // stage 4 |
| c0 = _mm_setr_epi32(kCosPi[56], kCosPi[24], kCosPi[24], kCosPi[56]); |
| c1 = _mm_setr_epi32(kCosPi[8], kCosPi[40], -kCosPi[40], -kCosPi[8]); |
| v0 = _mm_shuffle_epi32(v3, 0x1b); |
| v3 = _mm_mullo_epi32(v3, c0); |
| v0 = _mm_mullo_epi32(v0, c1); |
| v3 = _mm_add_epi32(v3, v0); |
| v3 = _mm_add_epi32(v3, kRnd1); |
| v3 = _mm_srai_epi32(v3, shift); |
| |
| // stage 5 |
| v1 = _mm_shuffle_epi32(v2, 0xb1); |
| v0 = _mm_shuffle_epi32(v3, 0xb1); |
| v1 = _mm_blend_epi16(v1, v3, 0xcc); |
| v0 = _mm_blend_epi16(v0, v2, 0x33); |
| |
| Store128b(v0, coeffs + 0); |
| Store128b(v1, coeffs + 4); |
| } |
| |
| static void fdct16_SSE(int32_t* coeffs) { |
| constexpr uint32_t shift = kPrecision + 1; |
| const __m128i kRnd0 = _mm_set1_epi32((1 << kPrecision) >> 1); |
| const __m128i kRnd1 = _mm_set1_epi32((1 << shift) >> 1); |
| __m128i v0, v1, v2, v3, v4, v5, v6, v7, c0, c1; |
| |
| // stage 1 |
| v0 = Load128b(coeffs + 0); |
| v1 = Load128b(coeffs + 4); |
| v2 = Load128b(coeffs + 8); |
| v3 = Load128b(coeffs + 12); |
| v4 = _mm_shuffle_epi32(v0, 0x1b); |
| v5 = _mm_shuffle_epi32(v1, 0x1b); |
| v6 = _mm_shuffle_epi32(v2, 0x1b); |
| v7 = _mm_shuffle_epi32(v3, 0x1b); |
| v1 = _mm_add_epi32(v1, v6); |
| v2 = _mm_sub_epi32(v5, v2); |
| v0 = _mm_add_epi32(v0, v7); |
| v3 = _mm_sub_epi32(v4, v3); |
| |
| // stage 2 |
| v7 = _mm_shuffle_epi32(v1, 0x1b); |
| v6 = _mm_shuffle_epi32(v0, 0x1b); |
| v4 = _mm_add_epi32(v0, v7); |
| v5 = _mm_sub_epi32(v6, v1); |
| v6 = _mm_alignr_epi8(v3, v2, 8); // abcd |
| v3 = _mm_alignr_epi8(v2, v3, 8); // ef89 |
| c0 = _mm_setr_epi32(-1, -1, 1, 1); |
| v7 = _mm_shuffle_epi32(v6, 0x1b); |
| v6 = _mm_sign_epi32(v6, c0); |
| c1 = _mm_set1_epi32(kCosPi[32]); |
| v6 = _mm_add_epi32(v6, v7); |
| v6 = _mm_mullo_epi32(v6, c1); |
| v6 = _mm_add_epi32(v6, kRnd0); |
| v6 = _mm_srai_epi32(v6, kPrecision); |
| |
| // stage 3 |
| v0 = _mm_shuffle_epi32(v6, 0x1b); |
| v1 = _mm_shuffle_epi32(v3, 0x1b); |
| v0 = _mm_add_epi32(v0, v3); |
| v1 = _mm_sub_epi32(v1, v6); |
| v2 = _mm_shuffle_epi32(v4, 0x1b); |
| v3 = _mm_sign_epi32(v4, c0); |
| v2 = _mm_sub_epi32(v2, v3); |
| |
| v3 = _mm_shuffle_epi32(v5, 0x1b); |
| v4 = _mm_sign_epi32(v5, c0); |
| v3 = _mm_add_epi32(v3, v4); |
| v3 = _mm_mullo_epi32(v3, c1); |
| v3 = _mm_add_epi32(v3, kRnd0); |
| v3 = _mm_srai_epi32(v3, kPrecision); |
| v3 = _mm_shuffle_epi32(v3, 0xa5); |
| |
| // stage 4 |
| c0 = _mm_setr_epi32(1, -1, -1, 1); |
| v5 = _mm_shuffle_epi32(v5, 0xf0); |
| v3 = _mm_sign_epi32(v3, c0); |
| v3 = _mm_add_epi32(v3, v5); |
| |
| c0 = _mm_setr_epi32(kCosPi[32], -kCosPi[32], kCosPi[48], kCosPi[48]); |
| c1 = _mm_setr_epi32(kCosPi[32], kCosPi[32], kCosPi[16], -kCosPi[16]); |
| v4 = _mm_shuffle_epi32(v2, 0xb1); |
| v2 = _mm_mullo_epi32(v2, c0); |
| v4 = _mm_mullo_epi32(v4, c1); |
| v2 = _mm_add_epi32(v2, v4); |
| v2 = _mm_add_epi32(v2, kRnd0); |
| v2 = _mm_srai_epi32(v2, kPrecision); |
| |
| v0 = _mm_shuffle_epi32(v0, 0xb1); |
| v4 = _mm_blend_epi16(v0, v1, 0x3c); // fbc8 |
| v5 = _mm_blend_epi16(v0, v1, 0xc3); // ae9d |
| |
| c0 = _mm_setr_epi32(-kCosPi[48], kCosPi[16], -kCosPi[16], kCosPi[48]); |
| c1 = _mm_setr_epi32(-kCosPi[16], kCosPi[48], kCosPi[48], -kCosPi[16]); |
| v0 = _mm_shuffle_epi32(v5, 0x1b); |
| v5 = _mm_mullo_epi32(v5, c0); |
| v0 = _mm_mullo_epi32(v0, c1); |
| v5 = _mm_add_epi32(v5, v0); |
| v5 = _mm_add_epi32(v5, kRnd0); |
| v5 = _mm_srai_epi32(v5, kPrecision); |
| |
| // stage 5 |
| c0 = _mm_setr_epi32(kCosPi[56], kCosPi[24], kCosPi[24], kCosPi[56]); |
| c1 = _mm_setr_epi32(kCosPi[8], kCosPi[40], -kCosPi[40], -kCosPi[8]); |
| v0 = _mm_shuffle_epi32(v3, 0x1b); |
| v3 = _mm_mullo_epi32(v3, c0); |
| v0 = _mm_mullo_epi32(v0, c1); |
| v3 = _mm_add_epi32(v3, v0); |
| v3 = _mm_add_epi32(v3, kRnd0); |
| v3 = _mm_srai_epi32(v3, kPrecision); |
| |
| v0 = _mm_shuffle_epi32(v5, 0xb1); |
| v5 = _mm_sub_epi32(v4, v0); // ead9 |
| v4 = _mm_add_epi32(v4, v0); // fbc8 |
| |
| // stage 6 |
| v0 = _mm_shuffle_epi32(v5, 0x4e); // d9ea |
| v5 = _mm_unpacklo_epi64(v4, v0); // fbd9 |
| v4 = _mm_unpackhi_epi64(v0, v4); // eac8 |
| v4 = _mm_shuffle_epi32(v4, 0x1b); // 8cae |
| |
| c0 = _mm_setr_epi32(kCosPi[4], -kCosPi[52], kCosPi[20], -kCosPi[36]); |
| c1 = _mm_setr_epi32(kCosPi[60], kCosPi[12], kCosPi[44], kCosPi[28]); |
| v0 = _mm_mullo_epi32(v4, c0); |
| v1 = _mm_mullo_epi32(v5, c0); |
| v4 = _mm_mullo_epi32(v4, c1); |
| v5 = _mm_mullo_epi32(v5, c1); |
| v4 = _mm_add_epi32(v4, v1); |
| v5 = _mm_sub_epi32(v5, v0); |
| v4 = _mm_add_epi32(v4, kRnd0); |
| v5 = _mm_add_epi32(v5, kRnd0); |
| v0 = _mm_srai_epi32(v4, kPrecision); |
| v1 = _mm_srai_epi32(v5, kPrecision); |
| v1 = _mm_shuffle_epi32(v1, 0x1b); |
| |
| // stage 7 |
| c0 = _mm_set1_epi32(kCosPi[32]); |
| v2 = _mm_mullo_epi32(v2, c0); |
| v3 = _mm_mullo_epi32(v3, c0); |
| v0 = _mm_mullo_epi32(v0, c0); |
| v1 = _mm_mullo_epi32(v1, c0); |
| v2 = _mm_add_epi32(v2, kRnd1); |
| v3 = _mm_add_epi32(v3, kRnd1); |
| v0 = _mm_add_epi32(v0, kRnd1); |
| v1 = _mm_add_epi32(v1, kRnd1); |
| v2 = _mm_srai_epi32(v2, shift); |
| v3 = _mm_srai_epi32(v3, shift); |
| v0 = _mm_srai_epi32(v0, shift); |
| v1 = _mm_srai_epi32(v1, shift); |
| |
| v4 = _mm_unpacklo_epi32(v2, v3); // 0415 |
| v5 = _mm_unpackhi_epi32(v2, v3); // 2637 |
| v6 = _mm_unpacklo_epi32(v4, v0); // 084c |
| v7 = _mm_unpackhi_epi32(v5, v1); // 3b7f |
| v0 = _mm_shuffle_epi32(v0, 0x4e); |
| v1 = _mm_shuffle_epi32(v1, 0x4e); |
| v5 = _mm_unpacklo_epi32(v5, v0); // 2a6e |
| v4 = _mm_unpackhi_epi32(v4, v1); // 195d |
| |
| Store128b(v6, coeffs + 0); |
| Store128b(v5, coeffs + 4); |
| Store128b(v4, coeffs + 8); |
| Store128b(v7, coeffs + 12); |
| } |
| |
| void fdct32_SSE(int32_t* coeffs) { |
| constexpr uint32_t shift = kPrecision + 2; |
| const __m128i kRnd0 = _mm_set1_epi32((1 << kPrecision) >> 1); |
| const __m128i kRnd1 = _mm_set1_epi32((1 << shift) >> 1); |
| __m128i v0, v1, v2, v3, v4, v5, v6, v7, c0, c1; |
| int32_t temp[16]; |
| |
| // stage 1 |
| v0 = Load128b(coeffs + 0); |
| v1 = Load128b(coeffs + 4); |
| v2 = Load128b(coeffs + 8); |
| v3 = Load128b(coeffs + 12); |
| v4 = Load128b(coeffs + 16); |
| v5 = Load128b(coeffs + 20); |
| v6 = Load128b(coeffs + 24); |
| v7 = Load128b(coeffs + 28); |
| v6 = _mm_shuffle_epi32(v6, 0x1b); |
| v7 = _mm_shuffle_epi32(v7, 0x1b); |
| v4 = _mm_shuffle_epi32(v4, 0x1b); |
| v5 = _mm_shuffle_epi32(v5, 0x1b); |
| v0 = _mm_add_epi32(v0, v7); |
| v1 = _mm_add_epi32(v1, v6); |
| v2 = _mm_add_epi32(v2, v5); |
| v3 = _mm_add_epi32(v3, v4); |
| |
| // stage 2 |
| v4 = _mm_shuffle_epi32(v3, 0x1b); |
| v5 = _mm_shuffle_epi32(v2, 0x1b); |
| v6 = _mm_shuffle_epi32(v1, 0x1b); |
| v7 = _mm_shuffle_epi32(v0, 0x1b); |
| v4 = _mm_add_epi32(v4, v0); |
| v5 = _mm_add_epi32(v5, v1); |
| v6 = _mm_sub_epi32(v6, v2); |
| v7 = _mm_sub_epi32(v7, v3); |
| |
| // stage 3 |
| v0 = _mm_shuffle_epi32(v5, 0x1b); |
| v1 = _mm_shuffle_epi32(v4, 0x1b); |
| v0 = _mm_add_epi32(v0, v4); |
| v1 = _mm_sub_epi32(v1, v5); |
| |
| v2 = _mm_alignr_epi8(v6, v7, 8); // ef89 |
| v3 = _mm_alignr_epi8(v7, v6, 8); // abcd |
| c0 = _mm_setr_epi32(-1, -1, 1, 1); |
| c1 = _mm_set1_epi32(kCosPi[32]); |
| v4 = _mm_sign_epi32(v3, c0); |
| v3 = _mm_shuffle_epi32(v3, 0x1b); |
| v3 = _mm_add_epi32(v3, v4); |
| v3 = _mm_mullo_epi32(v3, c1); |
| v3 = _mm_add_epi32(v3, kRnd0); |
| v3 = _mm_srai_epi32(v3, kPrecision); |
| |
| // stage 4 |
| v4 = _mm_shuffle_epi32(v0, 0x1b); |
| v0 = _mm_sign_epi32(v0, c0); |
| v4 = _mm_sub_epi32(v4, v0); |
| |
| v6 = _mm_shuffle_epi32(v3, 0x1b); |
| v7 = _mm_shuffle_epi32(v2, 0x1b); |
| v6 = _mm_add_epi32(v6, v2); |
| v7 = _mm_sub_epi32(v7, v3); |
| |
| v5 = _mm_shuffle_epi32(v1, 0x1b); |
| v2 = _mm_sign_epi32(v1, c0); |
| v5 = _mm_add_epi32(v5, v2); |
| v5 = _mm_mullo_epi32(v5, c1); |
| v5 = _mm_add_epi32(v5, kRnd0); |
| v5 = _mm_srai_epi32(v5, kPrecision); |
| v5 = _mm_shuffle_epi32(v5, 0xa5); |
| |
| // stage 5 |
| c0 = _mm_setr_epi32(1, -1, -1, 1); |
| v1 = _mm_shuffle_epi32(v1, 0xf0); |
| v5 = _mm_sign_epi32(v5, c0); |
| v1 = _mm_add_epi32(v1, v5); |
| |
| v6 = _mm_shuffle_epi32(v6, 0xb1); // fe98 |
| v2 = _mm_blend_epi16(v6, v7, 0x3c); // fbc8 |
| v3 = _mm_blend_epi16(v6, v7, 0xc3); // ae9d |
| |
| c0 = _mm_setr_epi32(-kCosPi[48], kCosPi[16], -kCosPi[16], kCosPi[48]); |
| c1 = _mm_setr_epi32(-kCosPi[16], kCosPi[48], kCosPi[48], -kCosPi[16]); |
| v0 = _mm_shuffle_epi32(v3, 0x1b); |
| v3 = _mm_mullo_epi32(v3, c0); |
| v0 = _mm_mullo_epi32(v0, c1); |
| v3 = _mm_add_epi32(v3, v0); |
| v3 = _mm_add_epi32(v3, kRnd0); |
| v3 = _mm_srai_epi32(v3, kPrecision); |
| |
| c0 = _mm_setr_epi32(kCosPi[32], -kCosPi[32], kCosPi[48], kCosPi[48]); |
| c1 = _mm_setr_epi32(kCosPi[32], kCosPi[32], kCosPi[16], -kCosPi[16]); |
| v0 = _mm_shuffle_epi32(v4, 0xb1); |
| v4 = _mm_mullo_epi32(v4, c0); |
| v0 = _mm_mullo_epi32(v0, c1); |
| v0 = _mm_add_epi32(v0, v4); |
| v0 = _mm_add_epi32(v0, kRnd1); |
| v0 = _mm_srai_epi32(v0, shift); |
| |
| // stage 6 |
| c0 = _mm_setr_epi32(kCosPi[56], kCosPi[24], kCosPi[24], kCosPi[56]); |
| c1 = _mm_setr_epi32(kCosPi[8], kCosPi[40], -kCosPi[40], -kCosPi[8]); |
| v4 = _mm_shuffle_epi32(v1, 0x1b); |
| v1 = _mm_mullo_epi32(v1, c0); |
| v4 = _mm_mullo_epi32(v4, c1); |
| v1 = _mm_add_epi32(v1, v4); |
| v1 = _mm_add_epi32(v1, kRnd1); |
| v1 = _mm_srai_epi32(v1, shift); |
| |
| v7 = _mm_shuffle_epi32(v2, 0xb1); |
| v6 = _mm_add_epi32(v3, v7); // bf8c |
| v7 = _mm_sub_epi32(v7, v3); // ae9d |
| |
| // stage 7 |
| v6 = _mm_shuffle_epi32(v6, 0x4e); // 8cbf |
| v3 = _mm_unpackhi_epi64(v7, v6); // 9dbf |
| v2 = _mm_unpacklo_epi64(v6, v7); // 8cae |
| v3 = _mm_shuffle_epi32(v3, 0x1b); // fbd9 |
| |
| c0 = _mm_setr_epi32(kCosPi[4], -kCosPi[52], kCosPi[20], -kCosPi[36]); |
| c1 = _mm_setr_epi32(kCosPi[60], kCosPi[12], kCosPi[44], kCosPi[28]); |
| v4 = _mm_mullo_epi32(v2, c0); |
| v5 = _mm_mullo_epi32(v3, c0); |
| v2 = _mm_mullo_epi32(v2, c1); |
| v3 = _mm_mullo_epi32(v3, c1); |
| v2 = _mm_add_epi32(v2, v5); |
| v3 = _mm_sub_epi32(v3, v4); |
| v2 = _mm_add_epi32(v2, kRnd1); |
| v3 = _mm_add_epi32(v3, kRnd1); |
| v2 = _mm_srai_epi32(v2, shift); |
| v3 = _mm_srai_epi32(v3, shift); |
| v3 = _mm_shuffle_epi32(v3, 0x1b); |
| |
| // stage 8 |
| |
| // stage 9 |
| v4 = _mm_unpacklo_epi32(v0, v1); // 0415 |
| v5 = _mm_unpackhi_epi32(v0, v1); // 2637 |
| v6 = _mm_unpacklo_epi32(v4, v2); // 084c |
| v7 = _mm_unpackhi_epi32(v5, v3); // 3b7f |
| v2 = _mm_shuffle_epi32(v2, 0x4e); |
| v3 = _mm_shuffle_epi32(v3, 0x4e); |
| v5 = _mm_unpacklo_epi32(v5, v2); // 2a6e |
| v4 = _mm_unpackhi_epi32(v4, v3); // 195d |
| |
| Store128b(v6, temp + 0); |
| Store128b(v5, temp + 4); |
| Store128b(v4, temp + 8); |
| Store128b(v7, temp + 12); |
| |
| // stage 1 |
| v3 = Load128b(coeffs + 0); |
| v2 = Load128b(coeffs + 4); |
| v1 = Load128b(coeffs + 8); |
| v0 = Load128b(coeffs + 12); |
| v4 = Load128b(coeffs + 16); |
| v5 = Load128b(coeffs + 20); |
| v6 = Load128b(coeffs + 24); |
| v7 = Load128b(coeffs + 28); |
| v0 = _mm_shuffle_epi32(v0, 0x1b); |
| v1 = _mm_shuffle_epi32(v1, 0x1b); |
| v2 = _mm_shuffle_epi32(v2, 0x1b); |
| v3 = _mm_shuffle_epi32(v3, 0x1b); |
| v0 = _mm_sub_epi32(v0, v4); |
| v1 = _mm_sub_epi32(v1, v5); |
| v2 = _mm_sub_epi32(v2, v6); |
| v3 = _mm_sub_epi32(v3, v7); |
| |
| // stage 2 |
| c1 = _mm_set1_epi32(kCosPi[32]); |
| v5 = _mm_shuffle_epi32(v2, 0x1b); |
| v6 = _mm_shuffle_epi32(v1, 0x1b); |
| v5 = _mm_sub_epi32(v5, v1); |
| v6 = _mm_add_epi32(v6, v2); |
| v5 = _mm_mullo_epi32(v5, c1); |
| v6 = _mm_mullo_epi32(v6, c1); |
| v5 = _mm_add_epi32(v5, kRnd0); |
| v6 = _mm_add_epi32(v6, kRnd0); |
| v5 = _mm_srai_epi32(v5, kPrecision); |
| v6 = _mm_srai_epi32(v6, kPrecision); |
| |
| // stage 3 |
| v4 = _mm_shuffle_epi32(v5, 0x1b); |
| v1 = _mm_shuffle_epi32(v0, 0x1b); |
| v2 = _mm_shuffle_epi32(v3, 0x1b); |
| v7 = _mm_shuffle_epi32(v6, 0x1b); |
| v0 = _mm_add_epi32(v0, v4); |
| v1 = _mm_sub_epi32(v1, v5); |
| v2 = _mm_sub_epi32(v2, v6); |
| v3 = _mm_add_epi32(v3, v7); |
| |
| // stage 4 |
| v4 = _mm_unpacklo_epi32(v0, v2); // 0819 |
| v5 = _mm_unpackhi_epi32(v0, v2); // 2a3b |
| v6 = _mm_unpacklo_epi32(v1, v3); // 4c5d |
| v7 = _mm_unpackhi_epi32(v1, v3); // 6e7f |
| c0 = _mm_setr_epi32(-kCosPi[16], kCosPi[48], -kCosPi[16], kCosPi[48]); |
| c1 = _mm_setr_epi32(-kCosPi[48], kCosPi[16], -kCosPi[48], kCosPi[16]); |
| v1 = _mm_shuffle_epi32(v6, 0x1b); |
| v2 = _mm_shuffle_epi32(v5, 0x1b); |
| v5 = _mm_mullo_epi32(v5, c0); |
| v6 = _mm_mullo_epi32(v6, c1); |
| v1 = _mm_mullo_epi32(v1, c1); |
| v2 = _mm_mullo_epi32(v2, c0); |
| v5 = _mm_sub_epi32(v5, v1); |
| v6 = _mm_add_epi32(v6, v2); |
| v5 = _mm_add_epi32(v5, kRnd0); |
| v6 = _mm_add_epi32(v6, kRnd0); |
| v5 = _mm_srai_epi32(v5, kPrecision); |
| v6 = _mm_srai_epi32(v6, kPrecision); |
| |
| // stage 5 |
| v0 = _mm_shuffle_epi32(v5, 0x4e); |
| v1 = _mm_shuffle_epi32(v4, 0x4e); |
| v2 = _mm_shuffle_epi32(v7, 0x4e); |
| v3 = _mm_shuffle_epi32(v6, 0x4e); |
| v0 = _mm_add_epi32(v0, v4); |
| v1 = _mm_sub_epi32(v1, v5); |
| v2 = _mm_sub_epi32(v2, v6); |
| v3 = _mm_add_epi32(v3, v7); |
| |
| // stage 6 |
| v4 = _mm_unpacklo_epi64(v0, v2); // 084c |
| v5 = _mm_unpackhi_epi64(v0, v2); // 195d |
| v6 = _mm_unpacklo_epi64(v1, v3); // 2a6e |
| v7 = _mm_unpackhi_epi64(v1, v3); // 3b7f |
| c0 = _mm_setr_epi32(-kCosPi[8], kCosPi[24], -kCosPi[40], kCosPi[56]); |
| c1 = _mm_setr_epi32(-kCosPi[56], kCosPi[40], -kCosPi[24], kCosPi[8]); |
| v1 = _mm_shuffle_epi32(v6, 0x1b); |
| v2 = _mm_shuffle_epi32(v5, 0x1b); |
| v5 = _mm_mullo_epi32(v5, c0); |
| v6 = _mm_mullo_epi32(v6, c1); |
| v1 = _mm_mullo_epi32(v1, c1); |
| v2 = _mm_mullo_epi32(v2, c0); |
| v5 = _mm_sub_epi32(v5, v1); |
| v6 = _mm_add_epi32(v6, v2); |
| v5 = _mm_add_epi32(v5, kRnd0); |
| v6 = _mm_add_epi32(v6, kRnd0); |
| v5 = _mm_srai_epi32(v5, kPrecision); |
| v6 = _mm_srai_epi32(v6, kPrecision); |
| |
| // stage 7 |
| v0 = _mm_add_epi32(v4, v5); |
| v1 = _mm_sub_epi32(v4, v5); |
| v2 = _mm_sub_epi32(v7, v6); |
| v3 = _mm_add_epi32(v7, v6); |
| |
| // stage 8 |
| c0 = _mm_setr_epi32(kCosPi[62], kCosPi[6], kCosPi[54], kCosPi[14]); |
| c1 = _mm_setr_epi32(kCosPi[2], -kCosPi[58], kCosPi[10], -kCosPi[50]); |
| v3 = _mm_shuffle_epi32(v3, 0x1b); |
| v4 = _mm_mullo_epi32(v0, c1); |
| v7 = _mm_mullo_epi32(v3, c1); |
| v0 = _mm_mullo_epi32(v0, c0); |
| v3 = _mm_mullo_epi32(v3, c0); |
| v0 = _mm_add_epi32(v0, v7); |
| v3 = _mm_sub_epi32(v3, v4); |
| v0 = _mm_add_epi32(v0, kRnd1); |
| v3 = _mm_add_epi32(v3, kRnd1); |
| v0 = _mm_srai_epi32(v0, shift); |
| v3 = _mm_srai_epi32(v3, shift); |
| v3 = _mm_shuffle_epi32(v3, 0x1b); |
| |
| c0 = _mm_setr_epi32(kCosPi[30], kCosPi[38], kCosPi[22], kCosPi[46]); |
| c1 = _mm_setr_epi32(kCosPi[34], -kCosPi[26], kCosPi[42], -kCosPi[18]); |
| v2 = _mm_shuffle_epi32(v2, 0x1b); |
| v5 = _mm_mullo_epi32(v1, c1); |
| v6 = _mm_mullo_epi32(v2, c1); |
| v1 = _mm_mullo_epi32(v1, c0); |
| v2 = _mm_mullo_epi32(v2, c0); |
| v1 = _mm_add_epi32(v1, v6); |
| v2 = _mm_sub_epi32(v2, v5); |
| v1 = _mm_add_epi32(v1, kRnd1); |
| v2 = _mm_add_epi32(v2, kRnd1); |
| v1 = _mm_srai_epi32(v1, shift); |
| v2 = _mm_srai_epi32(v2, shift); |
| v2 = _mm_shuffle_epi32(v2, 0x1b); |
| |
| // stage 9 |
| v6 = Load128b(temp + 0); |
| v7 = Load128b(temp + 4); |
| v4 = _mm_unpacklo_epi32(v6, v0); |
| v5 = _mm_unpackhi_epi32(v6, v0); |
| v6 = _mm_unpacklo_epi32(v7, v2); |
| v7 = _mm_unpackhi_epi32(v7, v2); |
| v0 = Load128b(temp + 8); |
| v2 = Load128b(temp + 12); |
| |
| Store128b(v4, coeffs + 0); |
| Store128b(v5, coeffs + 4); |
| Store128b(v6, coeffs + 8); |
| Store128b(v7, coeffs + 12); |
| |
| v4 = _mm_unpacklo_epi32(v0, v1); |
| v5 = _mm_unpackhi_epi32(v0, v1); |
| v6 = _mm_unpacklo_epi32(v2, v3); |
| v7 = _mm_unpackhi_epi32(v2, v3); |
| |
| Store128b(v4, coeffs + 16); |
| Store128b(v5, coeffs + 20); |
| Store128b(v6, coeffs + 24); |
| Store128b(v7, coeffs + 28); |
| } |
| |
| static void fadst8_SSE(int32_t* coeffs) { |
| constexpr uint32_t shift = kPrecision + 1; |
| const __m128i kRnd0 = _mm_set1_epi32((1 << kPrecision) >> 1); |
| const __m128i kRnd1 = _mm_set1_epi32((1 << shift) >> 1); |
| __m128i v0, v1, v2, v3, v4, v5, c0, c1; |
| |
| // stage 1 |
| c0 = _mm_setr_epi32(1, -1, 1, -1); |
| v0 = Load128b(coeffs + 0); |
| v1 = Load128b(coeffs + 4); |
| v0 = _mm_sign_epi32(v0, c0); |
| v1 = _mm_sign_epi32(v1, c0); |
| v0 = _mm_shuffle_epi32(v0, 0xb4); |
| v1 = _mm_shuffle_epi32(v1, 0x4b); |
| |
| // stage 2 |
| v3 = _mm_unpackhi_epi64(v0, v1); |
| v2 = _mm_unpacklo_epi32(v0, v1); |
| v5 = _mm_unpackhi_epi32(v3, v3); |
| v4 = _mm_unpacklo_epi32(v3, v3); |
| v5 = _mm_sign_epi32(v5, c0); |
| c0 = _mm_set1_epi32(kCosPi[32]); |
| |
| v4 = _mm_add_epi32(v4, v5); |
| v4 = _mm_mullo_epi32(v4, c0); |
| v4 = _mm_add_epi32(v4, kRnd0); |
| v4 = _mm_srai_epi32(v4, kPrecision); |
| |
| // stage 3 |
| v3 = _mm_add_epi32(v2, v4); |
| v5 = _mm_sub_epi32(v2, v4); |
| v0 = _mm_unpacklo_epi64(v3, v5); |
| v1 = _mm_unpackhi_epi64(v3, v5); |
| |
| // stage 4 |
| v2 = _mm_shuffle_epi32(v1, 0xa0); |
| v3 = _mm_shuffle_epi32(v1, 0xf5); |
| c0 = _mm_setr_epi32(kCosPi[16], kCosPi[48], -kCosPi[48], kCosPi[16]); |
| c1 = _mm_setr_epi32(kCosPi[48], -kCosPi[16], kCosPi[16], kCosPi[48]); |
| v2 = _mm_mullo_epi32(v2, c0); |
| v3 = _mm_mullo_epi32(v3, c1); |
| v1 = _mm_add_epi32(v2, v3); |
| v1 = _mm_add_epi32(v1, kRnd0); |
| v1 = _mm_srai_epi32(v1, kPrecision); |
| |
| // stage 5 |
| v2 = _mm_add_epi32(v0, v1); |
| v3 = _mm_sub_epi32(v0, v1); |
| |
| // stage 6 |
| v0 = _mm_unpacklo_epi32(v2, v3); |
| v1 = _mm_unpackhi_epi32(v2, v3); |
| v2 = _mm_unpacklo_epi32(v0, v1); |
| v3 = _mm_unpackhi_epi32(v0, v1); |
| |
| c0 = _mm_setr_epi32(kCosPi[4], kCosPi[20], kCosPi[36], kCosPi[52]); |
| c1 = _mm_setr_epi32(kCosPi[60], kCosPi[44], kCosPi[28], kCosPi[12]); |
| v0 = _mm_mullo_epi32(v2, c0); |
| v1 = _mm_mullo_epi32(v2, c1); |
| v4 = _mm_mullo_epi32(v3, c1); |
| v5 = _mm_mullo_epi32(v3, c0); |
| |
| v2 = _mm_add_epi32(v0, v4); |
| v3 = _mm_sub_epi32(v1, v5); |
| v2 = _mm_add_epi32(v2, kRnd1); |
| v3 = _mm_add_epi32(v3, kRnd1); |
| v2 = _mm_srai_epi32(v2, shift); |
| v3 = _mm_srai_epi32(v3, shift); |
| |
| // stage 7 |
| v2 = _mm_shuffle_epi32(v2, 0x1b); |
| v0 = _mm_unpacklo_epi32(v3, v2); |
| v1 = _mm_unpackhi_epi32(v3, v2); |
| |
| Store128b(v0, coeffs + 0); |
| Store128b(v1, coeffs + 4); |
| } |
| |
| //------------------------------------------------------------------------------ |
| // row-wise fadst |
| |
| #define HALF_BTF_VEC(v0, v1, t0, t1, t2, t3) \ |
| t0 = _mm_mullo_epi32(v0, c0); \ |
| t1 = _mm_mullo_epi32(v0, c1); \ |
| t2 = _mm_mullo_epi32(v1, c1); \ |
| t3 = _mm_mullo_epi32(v1, c0); \ |
| v0 = _mm_add_epi32(t0, t2); \ |
| v1 = _mm_sub_epi32(t1, t3); \ |
| v0 = _mm_add_epi32(v0, kRnd0); \ |
| v1 = _mm_add_epi32(v1, kRnd0); \ |
| v0 = _mm_srai_epi32(v0, kPrecision); \ |
| v1 = _mm_srai_epi32(v1, kPrecision) |
| |
| static void fadst16_SSE(int32_t* coeffs) { |
| constexpr uint32_t shift = kPrecision + 1; |
| const __m128i kRnd0 = _mm_set1_epi32((1 << kPrecision) >> 1); |
| const __m128i kRnd1 = _mm_set1_epi32((1 << shift) >> 1); |
| __m128i v0, v1, v2, v3, v4, v5, v6, v7, c0, c1; |
| |
| // stage 1 |
| c0 = _mm_setr_epi32(1, -1, 1, -1); |
| v0 = Load128b(coeffs + 0); |
| v2 = Load128b(coeffs + 4); |
| v3 = Load128b(coeffs + 8); |
| v1 = Load128b(coeffs + 12); |
| v0 = _mm_sign_epi32(v0, c0); |
| v1 = _mm_sign_epi32(v1, c0); |
| v2 = _mm_sign_epi32(v2, c0); |
| v3 = _mm_sign_epi32(v3, c0); |
| v0 = _mm_shuffle_epi32(v0, 0x9c); // 048c |
| v1 = _mm_shuffle_epi32(v1, 0x63); // 159d |
| v2 = _mm_shuffle_epi32(v2, 0x63); // 26ae |
| v3 = _mm_shuffle_epi32(v3, 0x9c); // 37bf |
| |
| // stage 2 |
| c0 = _mm_set1_epi32(kCosPi[32]); |
| v4 = _mm_add_epi32(v2, v3); |
| v5 = _mm_sub_epi32(v2, v3); |
| v4 = _mm_mullo_epi32(v4, c0); |
| v5 = _mm_mullo_epi32(v5, c0); |
| v4 = _mm_add_epi32(v4, kRnd0); |
| v5 = _mm_add_epi32(v5, kRnd0); |
| v4 = _mm_srai_epi32(v4, kPrecision); |
| v5 = _mm_srai_epi32(v5, kPrecision); |
| |
| // stage 3 |
| v2 = _mm_add_epi32(v0, v4); |
| v3 = _mm_add_epi32(v1, v5); |
| v4 = _mm_sub_epi32(v0, v4); |
| v5 = _mm_sub_epi32(v1, v5); |
| |
| // stage 4 |
| v6 = _mm_unpacklo_epi32(v2, v4); |
| v7 = _mm_unpacklo_epi32(v3, v5); |
| v4 = _mm_unpackhi_epi32(v2, v4); |
| v5 = _mm_unpackhi_epi32(v3, v5); |
| |
| v0 = _mm_unpacklo_epi64(v6, v4); // 028a |
| v1 = _mm_unpackhi_epi64(v6, v4); // 46ce |
| v2 = _mm_unpacklo_epi64(v7, v5); // 139b |
| v3 = _mm_unpackhi_epi64(v7, v5); // 57df |
| |
| c0 = _mm_setr_epi32(kCosPi[16], -kCosPi[48], kCosPi[16], -kCosPi[48]); |
| c1 = _mm_setr_epi32(kCosPi[48], kCosPi[16], kCosPi[48], kCosPi[16]); |
| HALF_BTF_VEC(v1, v3, v4, v5, v6, v7); |
| |
| // stage 5 |
| v4 = _mm_add_epi32(v0, v1); |
| v5 = _mm_sub_epi32(v0, v1); |
| v6 = _mm_add_epi32(v2, v3); |
| v7 = _mm_sub_epi32(v2, v3); |
| |
| // stage 6 |
| v0 = _mm_unpacklo_epi64(v4, v5); // 0246 |
| v1 = _mm_unpackhi_epi64(v4, v5); // 8ace |
| v2 = _mm_unpacklo_epi64(v6, v7); // 1357 |
| v3 = _mm_unpackhi_epi64(v6, v7); // 9bdf |
| |
| c0 = _mm_setr_epi32(kCosPi[8], kCosPi[40], -kCosPi[56], -kCosPi[24]); |
| c1 = _mm_setr_epi32(kCosPi[56], kCosPi[24], kCosPi[8], kCosPi[40]); |
| HALF_BTF_VEC(v1, v3, v4, v5, v6, v7); |
| |
| // stage 7 |
| v4 = _mm_add_epi32(v0, v1); |
| v5 = _mm_sub_epi32(v0, v1); |
| v6 = _mm_add_epi32(v2, v3); |
| v7 = _mm_sub_epi32(v2, v3); |
| |
| // stage 8 |
| c0 = _mm_setr_epi32(kCosPi[2], kCosPi[10], kCosPi[18], kCosPi[26]); |
| c1 = _mm_setr_epi32(kCosPi[62], kCosPi[54], kCosPi[46], kCosPi[38]); |
| HALF_BTF_VEC(v4, v6, v0, v1, v2, v3); |
| c0 = _mm_setr_epi32(kCosPi[34], kCosPi[42], kCosPi[50], kCosPi[58]); |
| c1 = _mm_setr_epi32(kCosPi[30], kCosPi[22], kCosPi[14], kCosPi[6]); |
| HALF_BTF_VEC(v5, v7, v0, v1, v2, v3); |
| |
| // stage 9 |
| c0 = _mm_set1_epi32(kCosPi[32]); |
| v4 = _mm_mullo_epi32(v4, c0); |
| v5 = _mm_mullo_epi32(v5, c0); |
| v6 = _mm_mullo_epi32(v6, c0); |
| v7 = _mm_mullo_epi32(v7, c0); |
| v4 = _mm_add_epi32(v4, kRnd1); |
| v5 = _mm_add_epi32(v5, kRnd1); |
| v6 = _mm_add_epi32(v6, kRnd1); |
| v7 = _mm_add_epi32(v7, kRnd1); |
| v4 = _mm_srai_epi32(v4, shift); |
| v5 = _mm_srai_epi32(v5, shift); |
| v6 = _mm_srai_epi32(v6, shift); |
| v7 = _mm_srai_epi32(v7, shift); |
| |
| v4 = _mm_shuffle_epi32(v4, 0x1b); // 6420 |
| v5 = _mm_shuffle_epi32(v5, 0x1b); // eca8 |
| v0 = _mm_unpacklo_epi32(v6, v5); |
| v1 = _mm_unpackhi_epi32(v6, v5); |
| v2 = _mm_unpacklo_epi32(v7, v4); |
| v3 = _mm_unpackhi_epi32(v7, v4); |
| |
| Store128b(v0, coeffs + 0); |
| Store128b(v1, coeffs + 4); |
| Store128b(v2, coeffs + 8); |
| Store128b(v3, coeffs + 12); |
| } |
| #undef HALF_BTF_VEC |
| |
| //------------------------------------------------------------------------------ |
| |
| inline void Transpose_4x4_32(const __m128i* const in0, const __m128i* const in1, |
| const __m128i* const in2, const __m128i* const in3, |
| __m128i* const out0, __m128i* const out1, |
| __m128i* const out2, __m128i* const out3) { |
| const __m128i t_0 = _mm_unpacklo_epi32(*in0, *in1); |
| const __m128i t_1 = _mm_unpacklo_epi32(*in2, *in3); |
| const __m128i t_2 = _mm_unpackhi_epi32(*in0, *in1); |
| const __m128i t_3 = _mm_unpackhi_epi32(*in2, *in3); |
| *out0 = _mm_unpacklo_epi64(t_0, t_1); |
| *out1 = _mm_unpackhi_epi64(t_0, t_1); |
| *out2 = _mm_unpacklo_epi64(t_2, t_3); |
| *out3 = _mm_unpackhi_epi64(t_2, t_3); |
| } |
| |
| void Transpose32_SSE(const int32_t* in, uint32_t w, uint32_t h, int32_t* out) { |
| assert(in != out); |
| if (w == 2 || h == 2) { |
| // fallback to C-impl for these cases |
| // TODO(skal): remove need for 2x2 transforms |
| for (size_t j = 0; j < h; ++j) { |
| for (size_t i = 0; i < w; ++i) { |
| out[j + h * i] = in[i + w * j]; |
| } |
| } |
| return; |
| } |
| for (size_t j = 0; j < h; j += 4) { |
| const int32_t* const ptr0 = &in[w * (j + 0)]; |
| const int32_t* const ptr1 = &in[w * (j + 1)]; |
| const int32_t* const ptr2 = &in[w * (j + 2)]; |
| const int32_t* const ptr3 = &in[w * (j + 3)]; |
| for (size_t i = 0; i < w; i += 4) { |
| __m128i out0, out1, out2, out3; |
| const __m128i in0 = Load128b(ptr0 + i); |
| const __m128i in1 = Load128b(ptr1 + i); |
| const __m128i in2 = Load128b(ptr2 + i); |
| const __m128i in3 = Load128b(ptr3 + i); |
| Transpose_4x4_32(&in0, &in1, &in2, &in3, &out0, &out1, &out2, &out3); |
| Store128b(out0, &out[j + h * (i + 0)]); |
| Store128b(out1, &out[j + h * (i + 1)]); |
| Store128b(out2, &out[j + h * (i + 2)]); |
| Store128b(out3, &out[j + h * (i + 3)]); |
| } |
| } |
| } |
| |
| inline void Transpose_4x4_16(const __m128i* const in0, const __m128i* const in1, |
| const __m128i* const in2, const __m128i* const in3, |
| __m128i* const out0, __m128i* const out1) { |
| const __m128i t_0 = _mm_unpacklo_epi16(*in0, *in1); |
| const __m128i t_1 = _mm_unpacklo_epi16(*in2, *in3); |
| *out0 = _mm_unpacklo_epi32(t_0, t_1); |
| *out1 = _mm_unpackhi_epi32(t_0, t_1); |
| } |
| |
| void Transpose16_SSE(const int16_t* in, uint32_t w, uint32_t h, int16_t* out) { |
| assert(in != out); |
| if (w == 2 || h == 2) { |
| // fallback to C-impl for these cases |
| // TODO(skal): remove need for 2x2 transforms |
| for (size_t j = 0; j < h; ++j) { |
| for (size_t i = 0; i < w; ++i) { |
| out[j + h * i] = in[i + w * j]; |
| } |
| } |
| return; |
| } |
| for (size_t j = 0; j < h; j += 4) { |
| const int16_t* const ptr0 = &in[w * (j + 0)]; |
| const int16_t* const ptr1 = &in[w * (j + 1)]; |
| const int16_t* const ptr2 = &in[w * (j + 2)]; |
| const int16_t* const ptr3 = &in[w * (j + 3)]; |
| for (size_t i = 0; i < w; i += 4) { |
| __m128i out0, out1; |
| const __m128i in0 = Load64b(ptr0 + i); |
| const __m128i in1 = Load64b(ptr1 + i); |
| const __m128i in2 = Load64b(ptr2 + i); |
| const __m128i in3 = Load64b(ptr3 + i); |
| Transpose_4x4_16(&in0, &in1, &in2, &in3, &out0, &out1); |
| Store64b(out0, &out[j + h * (i + 0)]); |
| Store64b(_mm_srli_si128(out0, 8), &out[j + h * (i + 1)]); |
| Store64b(out1, &out[j + h * (i + 2)]); |
| Store64b(_mm_srli_si128(out1, 8), &out[j + h * (i + 3)]); |
| } |
| } |
| } |
| |
| //------------------------------------------------------------------------------ |
| |
| // double horizontal-add |
| int32_t hadd(const __m128 v0, const __m128 v1) { |
| float tmp[4]; |
| _mm_storeu_ps(tmp, _mm_add_ps(v0, v1)); |
| return (int32_t)lrintf((tmp[0] + tmp[1] + tmp[2] + tmp[3]) * 256.f); |
| } |
| |
| int32_t SlowDct8x8_SSE(const int32_t in[64], const float cos_x[8], |
| const float cos_y[8]) { |
| __m128 sum0 = _mm_set1_ps(0.f); |
| __m128 sum4 = _mm_set1_ps(0.f); |
| const __m128 cos_x0 = _mm_loadu_ps(cos_x + 0); |
| const __m128 cos_x4 = _mm_loadu_ps(cos_x + 4); |
| const __m128i* src = (const __m128i*)in; |
| for (uint32_t j = 0; j < 8; ++j, src += 2) { |
| const __m128 C = _mm_set1_ps(cos_y[j]); |
| const __m128 in0 = _mm_cvtepi32_ps(_mm_loadu_si128(src + 0)); |
| const __m128 in4 = _mm_cvtepi32_ps(_mm_loadu_si128(src + 1)); |
| const __m128 a0 = _mm_mul_ps(in0, cos_x0); |
| const __m128 a4 = _mm_mul_ps(in4, cos_x4); |
| sum0 = _mm_add_ps(sum0, _mm_mul_ps(a0, C)); |
| sum4 = _mm_add_ps(sum4, _mm_mul_ps(a4, C)); |
| } |
| return hadd(sum0, sum4); |
| } |
| |
| //------------------------------------------------------------------------------ |
| } // namespace |
| |
| extern void WP2TransformInitSSE(); |
| |
| WP2_TSAN_IGNORE_FUNCTION void WP2TransformInitSSE() { |
| WP2Transpose16b = Transpose16_SSE; |
| WP2Transpose32b = Transpose32_SSE; |
| |
| WP2InvDct[1] = idct4_SSE; |
| WP2InvDct[2] = idct8_SSE; |
| WP2InvDct[3] = idct16_SSE; |
| WP2FwdDct[1] = fdct4_SSE; |
| WP2FwdDct[2] = fdct8_SSE; |
| WP2FwdDct[3] = fdct16_SSE; |
| WP2FwdDct[4] = fdct32_SSE; |
| WP2FwdAdst[2] = fadst8_SSE; |
| WP2FwdAdst[3] = fadst16_SSE; |
| |
| for (int i = 1; i < 5; i++) { |
| WP2InvDctCol[0][i] = ColTransformGen<VecI32_SSE>::idct2; |
| WP2InvDctCol[1][i] = ColTransformGen<VecI32_SSE>::idct4; |
| WP2InvDctCol[2][i] = ColTransformGen<VecI32_SSE>::idct8; |
| |
| WP2FwdDctCol[0][i] = ColTransformGen<VecI32_SSE>::fdct2; |
| WP2FwdDctCol[1][i] = ColTransformGen<VecI32_SSE>::fdct4; |
| WP2FwdDctCol[2][i] = ColTransformGen<VecI32_SSE>::fdct8; |
| WP2FwdDctCol[3][i] = ColTransformGen<VecI32_SSE>::fdct16; |
| } |
| |
| WP2SlowDct8x8 = SlowDct8x8_SSE; |
| } |
| |
| #else // !WP2_USE_SSE |
| |
| WP2_DSP_INIT_STUB(WP2TransformInitSSE); |
| |
| #endif // WP2_USE_SSE |