1ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang/*
2ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang *  Copyright (c) 2012 The WebM project authors. All Rights Reserved.
3ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang *
4ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang *  Use of this source code is governed by a BSD-style license
5ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang *  that can be found in the LICENSE file in the root of the source
6ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang *  tree. An additional intellectual property rights grant can be found
7ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang *  in the file PATENTS.  All contributing project authors may
8ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang *  be found in the AUTHORS file in the root of the source tree.
9ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang */
10ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang
11ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang#include <emmintrin.h>  // SSE2
12ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang#include "vp9/common/vp9_idct.h"  // for cospi constants
1391037db265ecdd914a26e056cf69207b4f50924ehkuang#include "vpx_ports/mem.h"
14ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang
155ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuangvoid vp9_fdct4x4_sse2(const int16_t *input, int16_t *output, int stride) {
16b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  // This 2D transform implements 4 vertical 1D transforms followed
17b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  // by 4 horizontal 1D transforms.  The multiplies and adds are as given
18b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  // by Chen, Smith and Fralick ('77).  The commands for moving the data
19b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  // around have been minimized by hand.
20b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  // For the purposes of the comments, the 16 inputs are referred to at i0
21b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  // through iF (in raster order), intermediate variables are a0, b0, c0
22b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  // through f, and correspond to the in-place computations mapped to input
23b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  // locations.  The outputs, o0 through oF are labeled according to the
24b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  // output locations.
25b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian
26ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  // Constants
27b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  // These are the coefficients used for the multiplies.
28b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  // In the comments, pN means cos(N pi /64) and mN is -cos(N pi /64),
29b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  // where cospi_N_64 = cos(N pi /64)
30b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  const __m128i k__cospi_A = _mm_setr_epi16(cospi_16_64, cospi_16_64,
31b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian                                            cospi_16_64, cospi_16_64,
32b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian                                            cospi_16_64, -cospi_16_64,
33b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian                                            cospi_16_64, -cospi_16_64);
34b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  const __m128i k__cospi_B = _mm_setr_epi16(cospi_16_64, -cospi_16_64,
35b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian                                            cospi_16_64, -cospi_16_64,
36b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian                                            cospi_16_64, cospi_16_64,
37b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian                                            cospi_16_64, cospi_16_64);
38b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  const __m128i k__cospi_C = _mm_setr_epi16(cospi_8_64, cospi_24_64,
39b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian                                            cospi_8_64, cospi_24_64,
40b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian                                            cospi_24_64, -cospi_8_64,
41b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian                                            cospi_24_64, -cospi_8_64);
42b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  const __m128i k__cospi_D = _mm_setr_epi16(cospi_24_64, -cospi_8_64,
43b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian                                            cospi_24_64, -cospi_8_64,
44b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian                                            cospi_8_64, cospi_24_64,
45b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian                                            cospi_8_64, cospi_24_64);
46b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  const __m128i k__cospi_E = _mm_setr_epi16(cospi_16_64, cospi_16_64,
47b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian                                            cospi_16_64, cospi_16_64,
48b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian                                            cospi_16_64, cospi_16_64,
49b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian                                            cospi_16_64, cospi_16_64);
50b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  const __m128i k__cospi_F = _mm_setr_epi16(cospi_16_64, -cospi_16_64,
51b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian                                            cospi_16_64, -cospi_16_64,
52b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian                                            cospi_16_64, -cospi_16_64,
53b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian                                            cospi_16_64, -cospi_16_64);
54b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  const __m128i k__cospi_G = _mm_setr_epi16(cospi_8_64, cospi_24_64,
55b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian                                            cospi_8_64, cospi_24_64,
56b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian                                            -cospi_8_64, -cospi_24_64,
57b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian                                            -cospi_8_64, -cospi_24_64);
58b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  const __m128i k__cospi_H = _mm_setr_epi16(cospi_24_64, -cospi_8_64,
59b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian                                            cospi_24_64, -cospi_8_64,
60b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian                                            -cospi_24_64, cospi_8_64,
61b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian                                            -cospi_24_64, cospi_8_64);
62b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian
63ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  const __m128i k__DCT_CONST_ROUNDING = _mm_set1_epi32(DCT_CONST_ROUNDING);
64b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  // This second rounding constant saves doing some extra adds at the end
65b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  const __m128i k__DCT_CONST_ROUNDING2 = _mm_set1_epi32(DCT_CONST_ROUNDING
66b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian                                               +(DCT_CONST_ROUNDING << 1));
67b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  const int DCT_CONST_BITS2 =  DCT_CONST_BITS+2;
68ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  const __m128i k__nonzero_bias_a = _mm_setr_epi16(0, 1, 1, 1, 1, 1, 1, 1);
69ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  const __m128i k__nonzero_bias_b = _mm_setr_epi16(1, 0, 0, 0, 0, 0, 0, 0);
70b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  __m128i in0, in1;
71b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian
72ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  // Load inputs.
73ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  {
74ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    in0  = _mm_loadl_epi64((const __m128i *)(input +  0 * stride));
75ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    in1  = _mm_loadl_epi64((const __m128i *)(input +  1 * stride));
76b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    in1  = _mm_unpacklo_epi64(in1, _mm_loadl_epi64((const __m128i *)
77b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian           (input +  2 * stride)));
78b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    in0  = _mm_unpacklo_epi64(in0, _mm_loadl_epi64((const __m128i *)
79b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian           (input +  3 * stride)));
80b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    // in0 = [i0 i1 i2 i3 iC iD iE iF]
81b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    // in1 = [i4 i5 i6 i7 i8 i9 iA iB]
82b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian
83b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian
84b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    // multiply by 16 to give some extra precision
85ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    in0 = _mm_slli_epi16(in0, 4);
86ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    in1 = _mm_slli_epi16(in1, 4);
87ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    // if (i == 0 && input[0]) input[0] += 1;
88b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    // add 1 to the upper left pixel if it is non-zero, which helps reduce
89b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    // the round-trip error
90ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    {
91b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian      // The mask will only contain whether the first value is zero, all
92ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      // other comparison will fail as something shifted by 4 (above << 4)
93ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      // can never be equal to one. To increment in the non-zero case, we
94ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      // add the mask and one for the first element:
95ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      //   - if zero, mask = -1, v = v - 1 + 1 = v
96ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      //   - if non-zero, mask = 0, v = v + 0 + 1 = v + 1
97ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      __m128i mask = _mm_cmpeq_epi16(in0, k__nonzero_bias_a);
98ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      in0 = _mm_add_epi16(in0, mask);
99ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      in0 = _mm_add_epi16(in0, k__nonzero_bias_b);
100ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    }
101ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  }
102b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  // There are 4 total stages, alternating between an add/subtract stage
103b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  // followed by an multiply-and-add stage.
104b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  {
105b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    // Stage 1: Add/subtract
106b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian
107b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    // in0 = [i0 i1 i2 i3 iC iD iE iF]
108b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    // in1 = [i4 i5 i6 i7 i8 i9 iA iB]
109b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    const __m128i r0 = _mm_unpacklo_epi16(in0, in1);
110b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    const __m128i r1 = _mm_unpackhi_epi16(in0, in1);
111b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    // r0 = [i0 i4 i1 i5 i2 i6 i3 i7]
112b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    // r1 = [iC i8 iD i9 iE iA iF iB]
113b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    const __m128i r2 = _mm_shuffle_epi32(r0, 0xB4);
114b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    const __m128i r3 = _mm_shuffle_epi32(r1, 0xB4);
115b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    // r2 = [i0 i4 i1 i5 i3 i7 i2 i6]
116b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    // r3 = [iC i8 iD i9 iF iB iE iA]
117b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian
118b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    const __m128i t0 = _mm_add_epi16(r2, r3);
119b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    const __m128i t1 = _mm_sub_epi16(r2, r3);
120b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    // t0 = [a0 a4 a1 a5 a3 a7 a2 a6]
121b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    // t1 = [aC a8 aD a9 aF aB aE aA]
122b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian
123b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    // Stage 2: multiply by constants (which gets us into 32 bits).
124b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    // The constants needed here are:
125b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    // k__cospi_A = [p16 p16 p16 p16 p16 m16 p16 m16]
126b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    // k__cospi_B = [p16 m16 p16 m16 p16 p16 p16 p16]
127b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    // k__cospi_C = [p08 p24 p08 p24 p24 m08 p24 m08]
128b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    // k__cospi_D = [p24 m08 p24 m08 p08 p24 p08 p24]
129b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    const __m128i u0 = _mm_madd_epi16(t0, k__cospi_A);
130b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    const __m128i u2 = _mm_madd_epi16(t0, k__cospi_B);
131b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    const __m128i u1 = _mm_madd_epi16(t1, k__cospi_C);
132b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    const __m128i u3 = _mm_madd_epi16(t1, k__cospi_D);
133b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    // Then add and right-shift to get back to 16-bit range
134ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    const __m128i v0 = _mm_add_epi32(u0, k__DCT_CONST_ROUNDING);
135b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    const __m128i v1 = _mm_add_epi32(u1, k__DCT_CONST_ROUNDING);
136ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    const __m128i v2 = _mm_add_epi32(u2, k__DCT_CONST_ROUNDING);
137b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    const __m128i v3 = _mm_add_epi32(u3, k__DCT_CONST_ROUNDING);
138ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    const __m128i w0 = _mm_srai_epi32(v0, DCT_CONST_BITS);
139b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    const __m128i w1 = _mm_srai_epi32(v1, DCT_CONST_BITS);
140ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    const __m128i w2 = _mm_srai_epi32(v2, DCT_CONST_BITS);
141b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    const __m128i w3 = _mm_srai_epi32(v3, DCT_CONST_BITS);
142b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    // w0 = [b0 b1 b7 b6]
143b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    // w1 = [b8 b9 bF bE]
144b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    // w2 = [b4 b5 b3 b2]
145b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    // w3 = [bC bD bB bA]
146b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    const __m128i x0 = _mm_packs_epi32(w0, w1);
147b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    const __m128i x1 = _mm_packs_epi32(w2, w3);
148b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    // x0 = [b0 b1 b7 b6 b8 b9 bF bE]
149b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    // x1 = [b4 b5 b3 b2 bC bD bB bA]
150b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    in0 = _mm_shuffle_epi32(x0, 0xD8);
151b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    in1 = _mm_shuffle_epi32(x1, 0x8D);
152b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    // in0 = [b0 b1 b8 b9 b7 b6 bF bE]
153b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    // in1 = [b3 b2 bB bA b4 b5 bC bD]
154b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  }
155b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  {
156b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    // vertical DCTs finished. Now we do the horizontal DCTs.
157b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    // Stage 3: Add/subtract
158b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian
159b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    const __m128i t0 = _mm_add_epi16(in0, in1);
160b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    const __m128i t1 = _mm_sub_epi16(in0, in1);
161b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    // t0 = [c0 c1 c8 c9  c4  c5  cC  cD]
162b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    // t1 = [c3 c2 cB cA -c7 -c6 -cF -cE]
163b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian
164b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    // Stage 4: multiply by constants (which gets us into 32 bits).
165b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    // The constants needed here are:
166b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    // k__cospi_E = [p16 p16 p16 p16 p16 p16 p16 p16]
167b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    // k__cospi_F = [p16 m16 p16 m16 p16 m16 p16 m16]
168b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    // k__cospi_G = [p08 p24 p08 p24 m08 m24 m08 m24]
169b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    // k__cospi_H = [p24 m08 p24 m08 m24 p08 m24 p08]
170b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    const __m128i u0 = _mm_madd_epi16(t0, k__cospi_E);
171b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    const __m128i u1 = _mm_madd_epi16(t0, k__cospi_F);
172b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    const __m128i u2 = _mm_madd_epi16(t1, k__cospi_G);
173b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    const __m128i u3 = _mm_madd_epi16(t1, k__cospi_H);
174b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    // Then add and right-shift to get back to 16-bit range
175b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    // but this combines the final right-shift as well to save operations
176b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    // This unusual rounding operations is to maintain bit-accurate
177b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    // compatibility with the c version of this function which has two
178b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    // rounding steps in a row.
179b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    const __m128i v0 = _mm_add_epi32(u0, k__DCT_CONST_ROUNDING2);
180b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    const __m128i v1 = _mm_add_epi32(u1, k__DCT_CONST_ROUNDING2);
181b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    const __m128i v2 = _mm_add_epi32(u2, k__DCT_CONST_ROUNDING2);
182b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    const __m128i v3 = _mm_add_epi32(u3, k__DCT_CONST_ROUNDING2);
183b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    const __m128i w0 = _mm_srai_epi32(v0, DCT_CONST_BITS2);
184b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    const __m128i w1 = _mm_srai_epi32(v1, DCT_CONST_BITS2);
185b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    const __m128i w2 = _mm_srai_epi32(v2, DCT_CONST_BITS2);
186b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    const __m128i w3 = _mm_srai_epi32(v3, DCT_CONST_BITS2);
187b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    // w0 = [o0 o4 o8 oC]
188b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    // w1 = [o2 o6 oA oE]
189b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    // w2 = [o1 o5 o9 oD]
190b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    // w3 = [o3 o7 oB oF]
191b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    // remember the o's are numbered according to the correct output location
192b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    const __m128i x0 = _mm_packs_epi32(w0, w1);
193b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    const __m128i x1 = _mm_packs_epi32(w2, w3);
194b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    // x0 = [o0 o4 o8 oC o2 o6 oA oE]
195b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    // x1 = [o1 o5 o9 oD o3 o7 oB oF]
196b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    const __m128i y0 = _mm_unpacklo_epi16(x0, x1);
197b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    const __m128i y1 = _mm_unpackhi_epi16(x0, x1);
198b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    // y0 = [o0 o1 o4 o5 o8 o9 oC oD]
199b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    // y1 = [o2 o3 o6 o7 oA oB oE oF]
200b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    in0 = _mm_unpacklo_epi32(y0, y1);
201b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    // in0 = [o0 o1 o2 o3 o4 o5 o6 o7]
202b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    in1 = _mm_unpackhi_epi32(y0, y1);
203b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    // in1 = [o8 o9 oA oB oC oD oE oF]
204b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  }
205b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  // Post-condition (v + 1) >> 2 is now incorporated into previous
206b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  // add and right-shift commands.  Only 2 store instructions needed
207b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  // because we are using the fact that 1/3 are stored just after 0/2.
208b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian  {
209b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian     _mm_storeu_si128((__m128i *)(output + 0 * 4), in0);
210b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian     _mm_storeu_si128((__m128i *)(output + 2 * 4), in1);
211ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  }
212ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang}
213ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang
214b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian
2155ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuangstatic INLINE void load_buffer_4x4(const int16_t *input, __m128i *in,
2165ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang                                   int stride) {
21791037db265ecdd914a26e056cf69207b4f50924ehkuang  const __m128i k__nonzero_bias_a = _mm_setr_epi16(0, 1, 1, 1, 1, 1, 1, 1);
21891037db265ecdd914a26e056cf69207b4f50924ehkuang  const __m128i k__nonzero_bias_b = _mm_setr_epi16(1, 0, 0, 0, 0, 0, 0, 0);
21991037db265ecdd914a26e056cf69207b4f50924ehkuang  __m128i mask;
22091037db265ecdd914a26e056cf69207b4f50924ehkuang
22191037db265ecdd914a26e056cf69207b4f50924ehkuang  in[0] = _mm_loadl_epi64((const __m128i *)(input + 0 * stride));
22291037db265ecdd914a26e056cf69207b4f50924ehkuang  in[1] = _mm_loadl_epi64((const __m128i *)(input + 1 * stride));
22391037db265ecdd914a26e056cf69207b4f50924ehkuang  in[2] = _mm_loadl_epi64((const __m128i *)(input + 2 * stride));
22491037db265ecdd914a26e056cf69207b4f50924ehkuang  in[3] = _mm_loadl_epi64((const __m128i *)(input + 3 * stride));
22591037db265ecdd914a26e056cf69207b4f50924ehkuang
22691037db265ecdd914a26e056cf69207b4f50924ehkuang  in[0] = _mm_slli_epi16(in[0], 4);
22791037db265ecdd914a26e056cf69207b4f50924ehkuang  in[1] = _mm_slli_epi16(in[1], 4);
22891037db265ecdd914a26e056cf69207b4f50924ehkuang  in[2] = _mm_slli_epi16(in[2], 4);
22991037db265ecdd914a26e056cf69207b4f50924ehkuang  in[3] = _mm_slli_epi16(in[3], 4);
23091037db265ecdd914a26e056cf69207b4f50924ehkuang
23191037db265ecdd914a26e056cf69207b4f50924ehkuang  mask = _mm_cmpeq_epi16(in[0], k__nonzero_bias_a);
23291037db265ecdd914a26e056cf69207b4f50924ehkuang  in[0] = _mm_add_epi16(in[0], mask);
23391037db265ecdd914a26e056cf69207b4f50924ehkuang  in[0] = _mm_add_epi16(in[0], k__nonzero_bias_b);
23491037db265ecdd914a26e056cf69207b4f50924ehkuang}
23591037db265ecdd914a26e056cf69207b4f50924ehkuang
23691037db265ecdd914a26e056cf69207b4f50924ehkuangstatic INLINE void write_buffer_4x4(int16_t *output, __m128i *res) {
23791037db265ecdd914a26e056cf69207b4f50924ehkuang  const __m128i kOne = _mm_set1_epi16(1);
23891037db265ecdd914a26e056cf69207b4f50924ehkuang  __m128i in01 = _mm_unpacklo_epi64(res[0], res[1]);
23991037db265ecdd914a26e056cf69207b4f50924ehkuang  __m128i in23 = _mm_unpacklo_epi64(res[2], res[3]);
24091037db265ecdd914a26e056cf69207b4f50924ehkuang  __m128i out01 = _mm_add_epi16(in01, kOne);
24191037db265ecdd914a26e056cf69207b4f50924ehkuang  __m128i out23 = _mm_add_epi16(in23, kOne);
24291037db265ecdd914a26e056cf69207b4f50924ehkuang  out01 = _mm_srai_epi16(out01, 2);
24391037db265ecdd914a26e056cf69207b4f50924ehkuang  out23 = _mm_srai_epi16(out23, 2);
24491037db265ecdd914a26e056cf69207b4f50924ehkuang  _mm_store_si128((__m128i *)(output + 0 * 8), out01);
24591037db265ecdd914a26e056cf69207b4f50924ehkuang  _mm_store_si128((__m128i *)(output + 1 * 8), out23);
24691037db265ecdd914a26e056cf69207b4f50924ehkuang}
24791037db265ecdd914a26e056cf69207b4f50924ehkuang
24891037db265ecdd914a26e056cf69207b4f50924ehkuangstatic INLINE void transpose_4x4(__m128i *res) {
24991037db265ecdd914a26e056cf69207b4f50924ehkuang  // Combine and transpose
25091037db265ecdd914a26e056cf69207b4f50924ehkuang  // 00 01 02 03 20 21 22 23
25191037db265ecdd914a26e056cf69207b4f50924ehkuang  // 10 11 12 13 30 31 32 33
25291037db265ecdd914a26e056cf69207b4f50924ehkuang  const __m128i tr0_0 = _mm_unpacklo_epi16(res[0], res[1]);
25391037db265ecdd914a26e056cf69207b4f50924ehkuang  const __m128i tr0_1 = _mm_unpackhi_epi16(res[0], res[1]);
25491037db265ecdd914a26e056cf69207b4f50924ehkuang
25591037db265ecdd914a26e056cf69207b4f50924ehkuang  // 00 10 01 11 02 12 03 13
25691037db265ecdd914a26e056cf69207b4f50924ehkuang  // 20 30 21 31 22 32 23 33
25791037db265ecdd914a26e056cf69207b4f50924ehkuang  res[0] = _mm_unpacklo_epi32(tr0_0, tr0_1);
25891037db265ecdd914a26e056cf69207b4f50924ehkuang  res[2] = _mm_unpackhi_epi32(tr0_0, tr0_1);
25991037db265ecdd914a26e056cf69207b4f50924ehkuang
26091037db265ecdd914a26e056cf69207b4f50924ehkuang  // 00 10 20 30 01 11 21 31
26191037db265ecdd914a26e056cf69207b4f50924ehkuang  // 02 12 22 32 03 13 23 33
26291037db265ecdd914a26e056cf69207b4f50924ehkuang  // only use the first 4 16-bit integers
26391037db265ecdd914a26e056cf69207b4f50924ehkuang  res[1] = _mm_unpackhi_epi64(res[0], res[0]);
26491037db265ecdd914a26e056cf69207b4f50924ehkuang  res[3] = _mm_unpackhi_epi64(res[2], res[2]);
26591037db265ecdd914a26e056cf69207b4f50924ehkuang}
26691037db265ecdd914a26e056cf69207b4f50924ehkuang
267b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanianvoid fdct4_sse2(__m128i *in) {
26891037db265ecdd914a26e056cf69207b4f50924ehkuang  const __m128i k__cospi_p16_p16 = _mm_set1_epi16(cospi_16_64);
26991037db265ecdd914a26e056cf69207b4f50924ehkuang  const __m128i k__cospi_p16_m16 = pair_set_epi16(cospi_16_64, -cospi_16_64);
2705ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang  const __m128i k__cospi_p08_p24 = pair_set_epi16(cospi_8_64, cospi_24_64);
2715ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang  const __m128i k__cospi_p24_m08 = pair_set_epi16(cospi_24_64, -cospi_8_64);
27291037db265ecdd914a26e056cf69207b4f50924ehkuang  const __m128i k__DCT_CONST_ROUNDING = _mm_set1_epi32(DCT_CONST_ROUNDING);
27391037db265ecdd914a26e056cf69207b4f50924ehkuang
27491037db265ecdd914a26e056cf69207b4f50924ehkuang  __m128i u[4], v[4];
2755ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang  u[0]=_mm_unpacklo_epi16(in[0], in[1]);
2765ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang  u[1]=_mm_unpacklo_epi16(in[3], in[2]);
2775ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang
2785ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang  v[0] = _mm_add_epi16(u[0], u[1]);
2795ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang  v[1] = _mm_sub_epi16(u[0], u[1]);
28091037db265ecdd914a26e056cf69207b4f50924ehkuang
28191037db265ecdd914a26e056cf69207b4f50924ehkuang  u[0] = _mm_madd_epi16(v[0], k__cospi_p16_p16);  // 0
28291037db265ecdd914a26e056cf69207b4f50924ehkuang  u[1] = _mm_madd_epi16(v[0], k__cospi_p16_m16);  // 2
2835ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang  u[2] = _mm_madd_epi16(v[1], k__cospi_p08_p24);  // 1
2845ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang  u[3] = _mm_madd_epi16(v[1], k__cospi_p24_m08);  // 3
28591037db265ecdd914a26e056cf69207b4f50924ehkuang
28691037db265ecdd914a26e056cf69207b4f50924ehkuang  v[0] = _mm_add_epi32(u[0], k__DCT_CONST_ROUNDING);
28791037db265ecdd914a26e056cf69207b4f50924ehkuang  v[1] = _mm_add_epi32(u[1], k__DCT_CONST_ROUNDING);
28891037db265ecdd914a26e056cf69207b4f50924ehkuang  v[2] = _mm_add_epi32(u[2], k__DCT_CONST_ROUNDING);
28991037db265ecdd914a26e056cf69207b4f50924ehkuang  v[3] = _mm_add_epi32(u[3], k__DCT_CONST_ROUNDING);
29091037db265ecdd914a26e056cf69207b4f50924ehkuang  u[0] = _mm_srai_epi32(v[0], DCT_CONST_BITS);
29191037db265ecdd914a26e056cf69207b4f50924ehkuang  u[1] = _mm_srai_epi32(v[1], DCT_CONST_BITS);
29291037db265ecdd914a26e056cf69207b4f50924ehkuang  u[2] = _mm_srai_epi32(v[2], DCT_CONST_BITS);
29391037db265ecdd914a26e056cf69207b4f50924ehkuang  u[3] = _mm_srai_epi32(v[3], DCT_CONST_BITS);
29491037db265ecdd914a26e056cf69207b4f50924ehkuang
29591037db265ecdd914a26e056cf69207b4f50924ehkuang  in[0] = _mm_packs_epi32(u[0], u[1]);
29691037db265ecdd914a26e056cf69207b4f50924ehkuang  in[1] = _mm_packs_epi32(u[2], u[3]);
29791037db265ecdd914a26e056cf69207b4f50924ehkuang  transpose_4x4(in);
29891037db265ecdd914a26e056cf69207b4f50924ehkuang}
29991037db265ecdd914a26e056cf69207b4f50924ehkuang
300b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanianvoid fadst4_sse2(__m128i *in) {
30191037db265ecdd914a26e056cf69207b4f50924ehkuang  const __m128i k__sinpi_p01_p02 = pair_set_epi16(sinpi_1_9, sinpi_2_9);
30291037db265ecdd914a26e056cf69207b4f50924ehkuang  const __m128i k__sinpi_p04_m01 = pair_set_epi16(sinpi_4_9, -sinpi_1_9);
30391037db265ecdd914a26e056cf69207b4f50924ehkuang  const __m128i k__sinpi_p03_p04 = pair_set_epi16(sinpi_3_9, sinpi_4_9);
30491037db265ecdd914a26e056cf69207b4f50924ehkuang  const __m128i k__sinpi_m03_p02 = pair_set_epi16(-sinpi_3_9, sinpi_2_9);
30591037db265ecdd914a26e056cf69207b4f50924ehkuang  const __m128i k__sinpi_p03_p03 = _mm_set1_epi16(sinpi_3_9);
30691037db265ecdd914a26e056cf69207b4f50924ehkuang  const __m128i kZero = _mm_set1_epi16(0);
30791037db265ecdd914a26e056cf69207b4f50924ehkuang  const __m128i k__DCT_CONST_ROUNDING = _mm_set1_epi32(DCT_CONST_ROUNDING);
30891037db265ecdd914a26e056cf69207b4f50924ehkuang  __m128i u[8], v[8];
30991037db265ecdd914a26e056cf69207b4f50924ehkuang  __m128i in7 = _mm_add_epi16(in[0], in[1]);
31091037db265ecdd914a26e056cf69207b4f50924ehkuang
31191037db265ecdd914a26e056cf69207b4f50924ehkuang  u[0] = _mm_unpacklo_epi16(in[0], in[1]);
31291037db265ecdd914a26e056cf69207b4f50924ehkuang  u[1] = _mm_unpacklo_epi16(in[2], in[3]);
31391037db265ecdd914a26e056cf69207b4f50924ehkuang  u[2] = _mm_unpacklo_epi16(in7, kZero);
31491037db265ecdd914a26e056cf69207b4f50924ehkuang  u[3] = _mm_unpacklo_epi16(in[2], kZero);
3159b35249446b07f40ac5fcc3205f2c048616efacchkuang  u[4] = _mm_unpacklo_epi16(in[3], kZero);
31691037db265ecdd914a26e056cf69207b4f50924ehkuang
31791037db265ecdd914a26e056cf69207b4f50924ehkuang  v[0] = _mm_madd_epi16(u[0], k__sinpi_p01_p02);  // s0 + s2
31891037db265ecdd914a26e056cf69207b4f50924ehkuang  v[1] = _mm_madd_epi16(u[1], k__sinpi_p03_p04);  // s4 + s5
31991037db265ecdd914a26e056cf69207b4f50924ehkuang  v[2] = _mm_madd_epi16(u[2], k__sinpi_p03_p03);  // x1
32091037db265ecdd914a26e056cf69207b4f50924ehkuang  v[3] = _mm_madd_epi16(u[0], k__sinpi_p04_m01);  // s1 - s3
32191037db265ecdd914a26e056cf69207b4f50924ehkuang  v[4] = _mm_madd_epi16(u[1], k__sinpi_m03_p02);  // -s4 + s6
32291037db265ecdd914a26e056cf69207b4f50924ehkuang  v[5] = _mm_madd_epi16(u[3], k__sinpi_p03_p03);  // s4
3239b35249446b07f40ac5fcc3205f2c048616efacchkuang  v[6] = _mm_madd_epi16(u[4], k__sinpi_p03_p03);
32491037db265ecdd914a26e056cf69207b4f50924ehkuang
32591037db265ecdd914a26e056cf69207b4f50924ehkuang  u[0] = _mm_add_epi32(v[0], v[1]);
3269b35249446b07f40ac5fcc3205f2c048616efacchkuang  u[1] = _mm_sub_epi32(v[2], v[6]);
32791037db265ecdd914a26e056cf69207b4f50924ehkuang  u[2] = _mm_add_epi32(v[3], v[4]);
32891037db265ecdd914a26e056cf69207b4f50924ehkuang  u[3] = _mm_sub_epi32(u[2], u[0]);
32991037db265ecdd914a26e056cf69207b4f50924ehkuang  u[4] = _mm_slli_epi32(v[5], 2);
33091037db265ecdd914a26e056cf69207b4f50924ehkuang  u[5] = _mm_sub_epi32(u[4], v[5]);
33191037db265ecdd914a26e056cf69207b4f50924ehkuang  u[6] = _mm_add_epi32(u[3], u[5]);
33291037db265ecdd914a26e056cf69207b4f50924ehkuang
33391037db265ecdd914a26e056cf69207b4f50924ehkuang  v[0] = _mm_add_epi32(u[0], k__DCT_CONST_ROUNDING);
33491037db265ecdd914a26e056cf69207b4f50924ehkuang  v[1] = _mm_add_epi32(u[1], k__DCT_CONST_ROUNDING);
33591037db265ecdd914a26e056cf69207b4f50924ehkuang  v[2] = _mm_add_epi32(u[2], k__DCT_CONST_ROUNDING);
33691037db265ecdd914a26e056cf69207b4f50924ehkuang  v[3] = _mm_add_epi32(u[6], k__DCT_CONST_ROUNDING);
33791037db265ecdd914a26e056cf69207b4f50924ehkuang
33891037db265ecdd914a26e056cf69207b4f50924ehkuang  u[0] = _mm_srai_epi32(v[0], DCT_CONST_BITS);
33991037db265ecdd914a26e056cf69207b4f50924ehkuang  u[1] = _mm_srai_epi32(v[1], DCT_CONST_BITS);
34091037db265ecdd914a26e056cf69207b4f50924ehkuang  u[2] = _mm_srai_epi32(v[2], DCT_CONST_BITS);
34191037db265ecdd914a26e056cf69207b4f50924ehkuang  u[3] = _mm_srai_epi32(v[3], DCT_CONST_BITS);
34291037db265ecdd914a26e056cf69207b4f50924ehkuang
34391037db265ecdd914a26e056cf69207b4f50924ehkuang  in[0] = _mm_packs_epi32(u[0], u[2]);
34491037db265ecdd914a26e056cf69207b4f50924ehkuang  in[1] = _mm_packs_epi32(u[1], u[3]);
34591037db265ecdd914a26e056cf69207b4f50924ehkuang  transpose_4x4(in);
34691037db265ecdd914a26e056cf69207b4f50924ehkuang}
34791037db265ecdd914a26e056cf69207b4f50924ehkuang
348b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanianvoid vp9_fht4x4_sse2(const int16_t *input, int16_t *output,
349b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian                     int stride, int tx_type) {
35091037db265ecdd914a26e056cf69207b4f50924ehkuang  __m128i in[4];
351b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian
35291037db265ecdd914a26e056cf69207b4f50924ehkuang  switch (tx_type) {
353b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    case DCT_DCT:
354b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian      vp9_fdct4x4_sse2(input, output, stride);
35591037db265ecdd914a26e056cf69207b4f50924ehkuang      break;
356b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    case ADST_DCT:
357b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian      load_buffer_4x4(input, in, stride);
358b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian      fadst4_sse2(in);
359b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian      fdct4_sse2(in);
360b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian      write_buffer_4x4(output, in);
36191037db265ecdd914a26e056cf69207b4f50924ehkuang      break;
362b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    case DCT_ADST:
363b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian      load_buffer_4x4(input, in, stride);
364b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian      fdct4_sse2(in);
365b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian      fadst4_sse2(in);
366b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian      write_buffer_4x4(output, in);
36791037db265ecdd914a26e056cf69207b4f50924ehkuang      break;
368b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    case ADST_ADST:
369b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian      load_buffer_4x4(input, in, stride);
370b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian      fadst4_sse2(in);
371b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian      fadst4_sse2(in);
372b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian      write_buffer_4x4(output, in);
37391037db265ecdd914a26e056cf69207b4f50924ehkuang      break;
374b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian   default:
375b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian     assert(0);
376b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian     break;
37791037db265ecdd914a26e056cf69207b4f50924ehkuang  }
37891037db265ecdd914a26e056cf69207b4f50924ehkuang}
37991037db265ecdd914a26e056cf69207b4f50924ehkuang
3805ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuangvoid vp9_fdct8x8_sse2(const int16_t *input, int16_t *output, int stride) {
381ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  int pass;
382ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  // Constants
383ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  //    When we use them, in one case, they are all the same. In all others
384ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  //    it's a pair of them that we need to repeat four times. This is done
385ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  //    by constructing the 32 bit constant corresponding to that pair.
386ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  const __m128i k__cospi_p16_p16 = _mm_set1_epi16(cospi_16_64);
387ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  const __m128i k__cospi_p16_m16 = pair_set_epi16(cospi_16_64, -cospi_16_64);
388ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  const __m128i k__cospi_p24_p08 = pair_set_epi16(cospi_24_64, cospi_8_64);
389ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  const __m128i k__cospi_m08_p24 = pair_set_epi16(-cospi_8_64, cospi_24_64);
390ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  const __m128i k__cospi_p28_p04 = pair_set_epi16(cospi_28_64, cospi_4_64);
391ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  const __m128i k__cospi_m04_p28 = pair_set_epi16(-cospi_4_64, cospi_28_64);
392ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  const __m128i k__cospi_p12_p20 = pair_set_epi16(cospi_12_64, cospi_20_64);
393ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  const __m128i k__cospi_m20_p12 = pair_set_epi16(-cospi_20_64, cospi_12_64);
394ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  const __m128i k__DCT_CONST_ROUNDING = _mm_set1_epi32(DCT_CONST_ROUNDING);
395ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  // Load input
39691037db265ecdd914a26e056cf69207b4f50924ehkuang  __m128i in0  = _mm_load_si128((const __m128i *)(input + 0 * stride));
39791037db265ecdd914a26e056cf69207b4f50924ehkuang  __m128i in1  = _mm_load_si128((const __m128i *)(input + 1 * stride));
39891037db265ecdd914a26e056cf69207b4f50924ehkuang  __m128i in2  = _mm_load_si128((const __m128i *)(input + 2 * stride));
39991037db265ecdd914a26e056cf69207b4f50924ehkuang  __m128i in3  = _mm_load_si128((const __m128i *)(input + 3 * stride));
40091037db265ecdd914a26e056cf69207b4f50924ehkuang  __m128i in4  = _mm_load_si128((const __m128i *)(input + 4 * stride));
40191037db265ecdd914a26e056cf69207b4f50924ehkuang  __m128i in5  = _mm_load_si128((const __m128i *)(input + 5 * stride));
40291037db265ecdd914a26e056cf69207b4f50924ehkuang  __m128i in6  = _mm_load_si128((const __m128i *)(input + 6 * stride));
40391037db265ecdd914a26e056cf69207b4f50924ehkuang  __m128i in7  = _mm_load_si128((const __m128i *)(input + 7 * stride));
404ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  // Pre-condition input (shift by two)
405ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  in0 = _mm_slli_epi16(in0, 2);
406ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  in1 = _mm_slli_epi16(in1, 2);
407ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  in2 = _mm_slli_epi16(in2, 2);
408ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  in3 = _mm_slli_epi16(in3, 2);
409ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  in4 = _mm_slli_epi16(in4, 2);
410ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  in5 = _mm_slli_epi16(in5, 2);
411ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  in6 = _mm_slli_epi16(in6, 2);
412ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  in7 = _mm_slli_epi16(in7, 2);
413ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang
414ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  // We do two passes, first the columns, then the rows. The results of the
415ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  // first pass are transposed so that the same column code can be reused. The
416ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  // results of the second pass are also transposed so that the rows (processed
417ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  // as columns) are put back in row positions.
418ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  for (pass = 0; pass < 2; pass++) {
419ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    // To store results of each pass before the transpose.
420ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    __m128i res0, res1, res2, res3, res4, res5, res6, res7;
421b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian    // Add/subtract
422ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    const __m128i q0 = _mm_add_epi16(in0, in7);
423ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    const __m128i q1 = _mm_add_epi16(in1, in6);
424ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    const __m128i q2 = _mm_add_epi16(in2, in5);
425ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    const __m128i q3 = _mm_add_epi16(in3, in4);
426ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    const __m128i q4 = _mm_sub_epi16(in3, in4);
427ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    const __m128i q5 = _mm_sub_epi16(in2, in5);
428ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    const __m128i q6 = _mm_sub_epi16(in1, in6);
429ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    const __m128i q7 = _mm_sub_epi16(in0, in7);
430ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    // Work on first four results
431ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    {
432b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian      // Add/subtract
433ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i r0 = _mm_add_epi16(q0, q3);
434ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i r1 = _mm_add_epi16(q1, q2);
435ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i r2 = _mm_sub_epi16(q1, q2);
436ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i r3 = _mm_sub_epi16(q0, q3);
437ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      // Interleave to do the multiply by constants which gets us into 32bits
438ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i t0 = _mm_unpacklo_epi16(r0, r1);
439ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i t1 = _mm_unpackhi_epi16(r0, r1);
440ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i t2 = _mm_unpacklo_epi16(r2, r3);
441ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i t3 = _mm_unpackhi_epi16(r2, r3);
442ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i u0 = _mm_madd_epi16(t0, k__cospi_p16_p16);
443ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i u1 = _mm_madd_epi16(t1, k__cospi_p16_p16);
444ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i u2 = _mm_madd_epi16(t0, k__cospi_p16_m16);
445ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i u3 = _mm_madd_epi16(t1, k__cospi_p16_m16);
446ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i u4 = _mm_madd_epi16(t2, k__cospi_p24_p08);
447ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i u5 = _mm_madd_epi16(t3, k__cospi_p24_p08);
448ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i u6 = _mm_madd_epi16(t2, k__cospi_m08_p24);
449ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i u7 = _mm_madd_epi16(t3, k__cospi_m08_p24);
450ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      // dct_const_round_shift
451ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i v0 = _mm_add_epi32(u0, k__DCT_CONST_ROUNDING);
452ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i v1 = _mm_add_epi32(u1, k__DCT_CONST_ROUNDING);
453ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i v2 = _mm_add_epi32(u2, k__DCT_CONST_ROUNDING);
454ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i v3 = _mm_add_epi32(u3, k__DCT_CONST_ROUNDING);
455ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i v4 = _mm_add_epi32(u4, k__DCT_CONST_ROUNDING);
456ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i v5 = _mm_add_epi32(u5, k__DCT_CONST_ROUNDING);
457ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i v6 = _mm_add_epi32(u6, k__DCT_CONST_ROUNDING);
458ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i v7 = _mm_add_epi32(u7, k__DCT_CONST_ROUNDING);
459ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i w0 = _mm_srai_epi32(v0, DCT_CONST_BITS);
460ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i w1 = _mm_srai_epi32(v1, DCT_CONST_BITS);
461ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i w2 = _mm_srai_epi32(v2, DCT_CONST_BITS);
462ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i w3 = _mm_srai_epi32(v3, DCT_CONST_BITS);
463ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i w4 = _mm_srai_epi32(v4, DCT_CONST_BITS);
464ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i w5 = _mm_srai_epi32(v5, DCT_CONST_BITS);
465ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i w6 = _mm_srai_epi32(v6, DCT_CONST_BITS);
466ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i w7 = _mm_srai_epi32(v7, DCT_CONST_BITS);
467ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      // Combine
468ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      res0 = _mm_packs_epi32(w0, w1);
469ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      res4 = _mm_packs_epi32(w2, w3);
470ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      res2 = _mm_packs_epi32(w4, w5);
471ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      res6 = _mm_packs_epi32(w6, w7);
472ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    }
473ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    // Work on next four results
474ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    {
475ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      // Interleave to do the multiply by constants which gets us into 32bits
476ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i d0 = _mm_unpacklo_epi16(q6, q5);
477ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i d1 = _mm_unpackhi_epi16(q6, q5);
478ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i e0 = _mm_madd_epi16(d0, k__cospi_p16_m16);
479ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i e1 = _mm_madd_epi16(d1, k__cospi_p16_m16);
480ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i e2 = _mm_madd_epi16(d0, k__cospi_p16_p16);
481ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i e3 = _mm_madd_epi16(d1, k__cospi_p16_p16);
482ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      // dct_const_round_shift
483ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i f0 = _mm_add_epi32(e0, k__DCT_CONST_ROUNDING);
484ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i f1 = _mm_add_epi32(e1, k__DCT_CONST_ROUNDING);
485ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i f2 = _mm_add_epi32(e2, k__DCT_CONST_ROUNDING);
486ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i f3 = _mm_add_epi32(e3, k__DCT_CONST_ROUNDING);
487ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i s0 = _mm_srai_epi32(f0, DCT_CONST_BITS);
488ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i s1 = _mm_srai_epi32(f1, DCT_CONST_BITS);
489ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i s2 = _mm_srai_epi32(f2, DCT_CONST_BITS);
490ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i s3 = _mm_srai_epi32(f3, DCT_CONST_BITS);
491ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      // Combine
492ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i r0 = _mm_packs_epi32(s0, s1);
493ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i r1 = _mm_packs_epi32(s2, s3);
494b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian      // Add/subtract
495ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i x0 = _mm_add_epi16(q4, r0);
496ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i x1 = _mm_sub_epi16(q4, r0);
497ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i x2 = _mm_sub_epi16(q7, r1);
498ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i x3 = _mm_add_epi16(q7, r1);
499ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      // Interleave to do the multiply by constants which gets us into 32bits
500ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i t0 = _mm_unpacklo_epi16(x0, x3);
501ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i t1 = _mm_unpackhi_epi16(x0, x3);
502ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i t2 = _mm_unpacklo_epi16(x1, x2);
503ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i t3 = _mm_unpackhi_epi16(x1, x2);
504ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i u0 = _mm_madd_epi16(t0, k__cospi_p28_p04);
505ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i u1 = _mm_madd_epi16(t1, k__cospi_p28_p04);
506ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i u2 = _mm_madd_epi16(t0, k__cospi_m04_p28);
507ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i u3 = _mm_madd_epi16(t1, k__cospi_m04_p28);
508ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i u4 = _mm_madd_epi16(t2, k__cospi_p12_p20);
509ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i u5 = _mm_madd_epi16(t3, k__cospi_p12_p20);
510ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i u6 = _mm_madd_epi16(t2, k__cospi_m20_p12);
511ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i u7 = _mm_madd_epi16(t3, k__cospi_m20_p12);
512ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      // dct_const_round_shift
513ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i v0 = _mm_add_epi32(u0, k__DCT_CONST_ROUNDING);
514ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i v1 = _mm_add_epi32(u1, k__DCT_CONST_ROUNDING);
515ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i v2 = _mm_add_epi32(u2, k__DCT_CONST_ROUNDING);
516ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i v3 = _mm_add_epi32(u3, k__DCT_CONST_ROUNDING);
517ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i v4 = _mm_add_epi32(u4, k__DCT_CONST_ROUNDING);
518ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i v5 = _mm_add_epi32(u5, k__DCT_CONST_ROUNDING);
519ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i v6 = _mm_add_epi32(u6, k__DCT_CONST_ROUNDING);
520ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i v7 = _mm_add_epi32(u7, k__DCT_CONST_ROUNDING);
521ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i w0 = _mm_srai_epi32(v0, DCT_CONST_BITS);
522ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i w1 = _mm_srai_epi32(v1, DCT_CONST_BITS);
523ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i w2 = _mm_srai_epi32(v2, DCT_CONST_BITS);
524ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i w3 = _mm_srai_epi32(v3, DCT_CONST_BITS);
525ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i w4 = _mm_srai_epi32(v4, DCT_CONST_BITS);
526ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i w5 = _mm_srai_epi32(v5, DCT_CONST_BITS);
527ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i w6 = _mm_srai_epi32(v6, DCT_CONST_BITS);
528ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i w7 = _mm_srai_epi32(v7, DCT_CONST_BITS);
529ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      // Combine
530ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      res1 = _mm_packs_epi32(w0, w1);
531ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      res7 = _mm_packs_epi32(w2, w3);
532ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      res5 = _mm_packs_epi32(w4, w5);
533ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      res3 = _mm_packs_epi32(w6, w7);
534ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    }
535ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    // Transpose the 8x8.
536ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    {
537ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      // 00 01 02 03 04 05 06 07
538ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      // 10 11 12 13 14 15 16 17
539ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      // 20 21 22 23 24 25 26 27
540ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      // 30 31 32 33 34 35 36 37
541ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      // 40 41 42 43 44 45 46 47
542ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      // 50 51 52 53 54 55 56 57
543ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      // 60 61 62 63 64 65 66 67
544ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      // 70 71 72 73 74 75 76 77
545ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i tr0_0 = _mm_unpacklo_epi16(res0, res1);
546ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i tr0_1 = _mm_unpacklo_epi16(res2, res3);
547ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i tr0_2 = _mm_unpackhi_epi16(res0, res1);
548ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i tr0_3 = _mm_unpackhi_epi16(res2, res3);
549ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i tr0_4 = _mm_unpacklo_epi16(res4, res5);
550ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i tr0_5 = _mm_unpacklo_epi16(res6, res7);
551ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i tr0_6 = _mm_unpackhi_epi16(res4, res5);
552ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i tr0_7 = _mm_unpackhi_epi16(res6, res7);
553ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      // 00 10 01 11 02 12 03 13
554ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      // 20 30 21 31 22 32 23 33
555ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      // 04 14 05 15 06 16 07 17
556ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      // 24 34 25 35 26 36 27 37
557ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      // 40 50 41 51 42 52 43 53
558ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      // 60 70 61 71 62 72 63 73
559ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      // 54 54 55 55 56 56 57 57
560ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      // 64 74 65 75 66 76 67 77
561ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i tr1_0 = _mm_unpacklo_epi32(tr0_0, tr0_1);
562ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i tr1_1 = _mm_unpacklo_epi32(tr0_2, tr0_3);
563ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i tr1_2 = _mm_unpackhi_epi32(tr0_0, tr0_1);
564ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i tr1_3 = _mm_unpackhi_epi32(tr0_2, tr0_3);
565ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i tr1_4 = _mm_unpacklo_epi32(tr0_4, tr0_5);
566ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i tr1_5 = _mm_unpacklo_epi32(tr0_6, tr0_7);
567ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i tr1_6 = _mm_unpackhi_epi32(tr0_4, tr0_5);
568ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      const __m128i tr1_7 = _mm_unpackhi_epi32(tr0_6, tr0_7);
569ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      // 00 10 20 30 01 11 21 31
570ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      // 40 50 60 70 41 51 61 71
571ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      // 02 12 22 32 03 13 23 33
572ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      // 42 52 62 72 43 53 63 73
573ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      // 04 14 24 34 05 15 21 36
574ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      // 44 54 64 74 45 55 61 76
575ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      // 06 16 26 36 07 17 27 37
576ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      // 46 56 66 76 47 57 67 77
577ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      in0 = _mm_unpacklo_epi64(tr1_0, tr1_4);
578ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      in1 = _mm_unpackhi_epi64(tr1_0, tr1_4);
579ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      in2 = _mm_unpacklo_epi64(tr1_2, tr1_6);
580ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      in3 = _mm_unpackhi_epi64(tr1_2, tr1_6);
581ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      in4 = _mm_unpacklo_epi64(tr1_1, tr1_5);
582ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      in5 = _mm_unpackhi_epi64(tr1_1, tr1_5);
583ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      in6 = _mm_unpacklo_epi64(tr1_3, tr1_7);
584ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      in7 = _mm_unpackhi_epi64(tr1_3, tr1_7);
585ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      // 00 10 20 30 40 50 60 70
586ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      // 01 11 21 31 41 51 61 71
587ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      // 02 12 22 32 42 52 62 72
588ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      // 03 13 23 33 43 53 63 73
589ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      // 04 14 24 34 44 54 64 74
590ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      // 05 15 25 35 45 55 65 75
591ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      // 06 16 26 36 46 56 66 76
592ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      // 07 17 27 37 47 57 67 77
593ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    }
594ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  }
595ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  // Post-condition output and store it
596ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  {
597ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    // Post-condition (division by two)
598ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    //    division of two 16 bits signed numbers using shifts
599ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    //    n / 2 = (n - (n >> 15)) >> 1
600ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    const __m128i sign_in0 = _mm_srai_epi16(in0, 15);
601ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    const __m128i sign_in1 = _mm_srai_epi16(in1, 15);
602ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    const __m128i sign_in2 = _mm_srai_epi16(in2, 15);
603ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    const __m128i sign_in3 = _mm_srai_epi16(in3, 15);
604ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    const __m128i sign_in4 = _mm_srai_epi16(in4, 15);
605ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    const __m128i sign_in5 = _mm_srai_epi16(in5, 15);
606ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    const __m128i sign_in6 = _mm_srai_epi16(in6, 15);
607ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    const __m128i sign_in7 = _mm_srai_epi16(in7, 15);
608ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    in0 = _mm_sub_epi16(in0, sign_in0);
609ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    in1 = _mm_sub_epi16(in1, sign_in1);
610ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    in2 = _mm_sub_epi16(in2, sign_in2);
611ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    in3 = _mm_sub_epi16(in3, sign_in3);
612ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    in4 = _mm_sub_epi16(in4, sign_in4);
613ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    in5 = _mm_sub_epi16(in5, sign_in5);
614ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    in6 = _mm_sub_epi16(in6, sign_in6);
615ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    in7 = _mm_sub_epi16(in7, sign_in7);
616ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    in0 = _mm_srai_epi16(in0, 1);
617ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    in1 = _mm_srai_epi16(in1, 1);
618ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    in2 = _mm_srai_epi16(in2, 1);
619ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    in3 = _mm_srai_epi16(in3, 1);
620ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    in4 = _mm_srai_epi16(in4, 1);
621ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    in5 = _mm_srai_epi16(in5, 1);
622ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    in6 = _mm_srai_epi16(in6, 1);
623ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    in7 = _mm_srai_epi16(in7, 1);
624ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    // store results
62591037db265ecdd914a26e056cf69207b4f50924ehkuang    _mm_store_si128((__m128i *)(output + 0 * 8), in0);
62691037db265ecdd914a26e056cf69207b4f50924ehkuang    _mm_store_si128((__m128i *)(output + 1 * 8), in1);
62791037db265ecdd914a26e056cf69207b4f50924ehkuang    _mm_store_si128((__m128i *)(output + 2 * 8), in2);
62891037db265ecdd914a26e056cf69207b4f50924ehkuang    _mm_store_si128((__m128i *)(output + 3 * 8), in3);
62991037db265ecdd914a26e056cf69207b4f50924ehkuang    _mm_store_si128((__m128i *)(output + 4 * 8), in4);
63091037db265ecdd914a26e056cf69207b4f50924ehkuang    _mm_store_si128((__m128i *)(output + 5 * 8), in5);
63191037db265ecdd914a26e056cf69207b4f50924ehkuang    _mm_store_si128((__m128i *)(output + 6 * 8), in6);
63291037db265ecdd914a26e056cf69207b4f50924ehkuang    _mm_store_si128((__m128i *)(output + 7 * 8), in7);
63391037db265ecdd914a26e056cf69207b4f50924ehkuang  }
63491037db265ecdd914a26e056cf69207b4f50924ehkuang}
63591037db265ecdd914a26e056cf69207b4f50924ehkuang
63691037db265ecdd914a26e056cf69207b4f50924ehkuang// load 8x8 array
6375ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuangstatic INLINE void load_buffer_8x8(const int16_t *input, __m128i *in,
6385ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang                                   int stride) {
6395ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang  in[0]  = _mm_load_si128((const __m128i *)(input + 0 * stride));
6405ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang  in[1]  = _mm_load_si128((const __m128i *)(input + 1 * stride));
6415ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang  in[2]  = _mm_load_si128((const __m128i *)(input + 2 * stride));
6425ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang  in[3]  = _mm_load_si128((const __m128i *)(input + 3 * stride));
6435ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang  in[4]  = _mm_load_si128((const __m128i *)(input + 4 * stride));
6445ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang  in[5]  = _mm_load_si128((const __m128i *)(input + 5 * stride));
6455ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang  in[6]  = _mm_load_si128((const __m128i *)(input + 6 * stride));
6465ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang  in[7]  = _mm_load_si128((const __m128i *)(input + 7 * stride));
64791037db265ecdd914a26e056cf69207b4f50924ehkuang
64891037db265ecdd914a26e056cf69207b4f50924ehkuang  in[0] = _mm_slli_epi16(in[0], 2);
64991037db265ecdd914a26e056cf69207b4f50924ehkuang  in[1] = _mm_slli_epi16(in[1], 2);
65091037db265ecdd914a26e056cf69207b4f50924ehkuang  in[2] = _mm_slli_epi16(in[2], 2);
65191037db265ecdd914a26e056cf69207b4f50924ehkuang  in[3] = _mm_slli_epi16(in[3], 2);
65291037db265ecdd914a26e056cf69207b4f50924ehkuang  in[4] = _mm_slli_epi16(in[4], 2);
65391037db265ecdd914a26e056cf69207b4f50924ehkuang  in[5] = _mm_slli_epi16(in[5], 2);
65491037db265ecdd914a26e056cf69207b4f50924ehkuang  in[6] = _mm_slli_epi16(in[6], 2);
65591037db265ecdd914a26e056cf69207b4f50924ehkuang  in[7] = _mm_slli_epi16(in[7], 2);
65691037db265ecdd914a26e056cf69207b4f50924ehkuang}
65791037db265ecdd914a26e056cf69207b4f50924ehkuang
65891037db265ecdd914a26e056cf69207b4f50924ehkuang// right shift and rounding
65991037db265ecdd914a26e056cf69207b4f50924ehkuangstatic INLINE void right_shift_8x8(__m128i *res, int const bit) {
66091037db265ecdd914a26e056cf69207b4f50924ehkuang  const __m128i kOne = _mm_set1_epi16(1);
66191037db265ecdd914a26e056cf69207b4f50924ehkuang  const int bit_m02 = bit - 2;
66291037db265ecdd914a26e056cf69207b4f50924ehkuang  __m128i sign0 = _mm_srai_epi16(res[0], 15);
66391037db265ecdd914a26e056cf69207b4f50924ehkuang  __m128i sign1 = _mm_srai_epi16(res[1], 15);
66491037db265ecdd914a26e056cf69207b4f50924ehkuang  __m128i sign2 = _mm_srai_epi16(res[2], 15);
66591037db265ecdd914a26e056cf69207b4f50924ehkuang  __m128i sign3 = _mm_srai_epi16(res[3], 15);
66691037db265ecdd914a26e056cf69207b4f50924ehkuang  __m128i sign4 = _mm_srai_epi16(res[4], 15);
66791037db265ecdd914a26e056cf69207b4f50924ehkuang  __m128i sign5 = _mm_srai_epi16(res[5], 15);
66891037db265ecdd914a26e056cf69207b4f50924ehkuang  __m128i sign6 = _mm_srai_epi16(res[6], 15);
66991037db265ecdd914a26e056cf69207b4f50924ehkuang  __m128i sign7 = _mm_srai_epi16(res[7], 15);
67091037db265ecdd914a26e056cf69207b4f50924ehkuang
67191037db265ecdd914a26e056cf69207b4f50924ehkuang  if (bit_m02 >= 0) {
67291037db265ecdd914a26e056cf69207b4f50924ehkuang    __m128i k_const_rounding = _mm_slli_epi16(kOne, bit_m02);
67391037db265ecdd914a26e056cf69207b4f50924ehkuang    res[0] = _mm_add_epi16(res[0], k_const_rounding);
67491037db265ecdd914a26e056cf69207b4f50924ehkuang    res[1] = _mm_add_epi16(res[1], k_const_rounding);
67591037db265ecdd914a26e056cf69207b4f50924ehkuang    res[2] = _mm_add_epi16(res[2], k_const_rounding);
67691037db265ecdd914a26e056cf69207b4f50924ehkuang    res[3] = _mm_add_epi16(res[3], k_const_rounding);
67791037db265ecdd914a26e056cf69207b4f50924ehkuang    res[4] = _mm_add_epi16(res[4], k_const_rounding);
67891037db265ecdd914a26e056cf69207b4f50924ehkuang    res[5] = _mm_add_epi16(res[5], k_const_rounding);
67991037db265ecdd914a26e056cf69207b4f50924ehkuang    res[6] = _mm_add_epi16(res[6], k_const_rounding);
68091037db265ecdd914a26e056cf69207b4f50924ehkuang    res[7] = _mm_add_epi16(res[7], k_const_rounding);
68191037db265ecdd914a26e056cf69207b4f50924ehkuang  }
68291037db265ecdd914a26e056cf69207b4f50924ehkuang
68391037db265ecdd914a26e056cf69207b4f50924ehkuang  res[0] = _mm_sub_epi16(res[0], sign0);
68491037db265ecdd914a26e056cf69207b4f50924ehkuang  res[1] = _mm_sub_epi16(res[1], sign1);
68591037db265ecdd914a26e056cf69207b4f50924ehkuang  res[2] = _mm_sub_epi16(res[2], sign2);
68691037db265ecdd914a26e056cf69207b4f50924ehkuang  res[3] = _mm_sub_epi16(res[3], sign3);
68791037db265ecdd914a26e056cf69207b4f50924ehkuang  res[4] = _mm_sub_epi16(res[4], sign4);
68891037db265ecdd914a26e056cf69207b4f50924ehkuang  res[5] = _mm_sub_epi16(res[5], sign5);
68991037db265ecdd914a26e056cf69207b4f50924ehkuang  res[6] = _mm_sub_epi16(res[6], sign6);
69091037db265ecdd914a26e056cf69207b4f50924ehkuang  res[7] = _mm_sub_epi16(res[7], sign7);
69191037db265ecdd914a26e056cf69207b4f50924ehkuang
69291037db265ecdd914a26e056cf69207b4f50924ehkuang  res[0] = _mm_srai_epi16(res[0], bit);
69391037db265ecdd914a26e056cf69207b4f50924ehkuang  res[1] = _mm_srai_epi16(res[1], bit);
69491037db265ecdd914a26e056cf69207b4f50924ehkuang  res[2] = _mm_srai_epi16(res[2], bit);
69591037db265ecdd914a26e056cf69207b4f50924ehkuang  res[3] = _mm_srai_epi16(res[3], bit);
69691037db265ecdd914a26e056cf69207b4f50924ehkuang  res[4] = _mm_srai_epi16(res[4], bit);
69791037db265ecdd914a26e056cf69207b4f50924ehkuang  res[5] = _mm_srai_epi16(res[5], bit);
69891037db265ecdd914a26e056cf69207b4f50924ehkuang  res[6] = _mm_srai_epi16(res[6], bit);
69991037db265ecdd914a26e056cf69207b4f50924ehkuang  res[7] = _mm_srai_epi16(res[7], bit);
70091037db265ecdd914a26e056cf69207b4f50924ehkuang}
70191037db265ecdd914a26e056cf69207b4f50924ehkuang
70291037db265ecdd914a26e056cf69207b4f50924ehkuang// write 8x8 array
70391037db265ecdd914a26e056cf69207b4f50924ehkuangstatic INLINE void write_buffer_8x8(int16_t *output, __m128i *res, int stride) {
70491037db265ecdd914a26e056cf69207b4f50924ehkuang  _mm_store_si128((__m128i *)(output + 0 * stride), res[0]);
70591037db265ecdd914a26e056cf69207b4f50924ehkuang  _mm_store_si128((__m128i *)(output + 1 * stride), res[1]);
70691037db265ecdd914a26e056cf69207b4f50924ehkuang  _mm_store_si128((__m128i *)(output + 2 * stride), res[2]);
70791037db265ecdd914a26e056cf69207b4f50924ehkuang  _mm_store_si128((__m128i *)(output + 3 * stride), res[3]);
70891037db265ecdd914a26e056cf69207b4f50924ehkuang  _mm_store_si128((__m128i *)(output + 4 * stride), res[4]);
70991037db265ecdd914a26e056cf69207b4f50924ehkuang  _mm_store_si128((__m128i *)(output + 5 * stride), res[5]);
71091037db265ecdd914a26e056cf69207b4f50924ehkuang  _mm_store_si128((__m128i *)(output + 6 * stride), res[6]);
71191037db265ecdd914a26e056cf69207b4f50924ehkuang  _mm_store_si128((__m128i *)(output + 7 * stride), res[7]);
71291037db265ecdd914a26e056cf69207b4f50924ehkuang}
71391037db265ecdd914a26e056cf69207b4f50924ehkuang
71491037db265ecdd914a26e056cf69207b4f50924ehkuang// perform in-place transpose
71591037db265ecdd914a26e056cf69207b4f50924ehkuangstatic INLINE void array_transpose_8x8(__m128i *in, __m128i *res) {
71691037db265ecdd914a26e056cf69207b4f50924ehkuang  const __m128i tr0_0 = _mm_unpacklo_epi16(in[0], in[1]);
71791037db265ecdd914a26e056cf69207b4f50924ehkuang  const __m128i tr0_1 = _mm_unpacklo_epi16(in[2], in[3]);
71891037db265ecdd914a26e056cf69207b4f50924ehkuang  const __m128i tr0_2 = _mm_unpackhi_epi16(in[0], in[1]);
71991037db265ecdd914a26e056cf69207b4f50924ehkuang  const __m128i tr0_3 = _mm_unpackhi_epi16(in[2], in[3]);
72091037db265ecdd914a26e056cf69207b4f50924ehkuang  const __m128i tr0_4 = _mm_unpacklo_epi16(in[4], in[5]);
72191037db265ecdd914a26e056cf69207b4f50924ehkuang  const __m128i tr0_5 = _mm_unpacklo_epi16(in[6], in[7]);
72291037db265ecdd914a26e056cf69207b4f50924ehkuang  const __m128i tr0_6 = _mm_unpackhi_epi16(in[4], in[5]);
72391037db265ecdd914a26e056cf69207b4f50924ehkuang  const __m128i tr0_7 = _mm_unpackhi_epi16(in[6], in[7]);
72491037db265ecdd914a26e056cf69207b4f50924ehkuang  // 00 10 01 11 02 12 03 13
72591037db265ecdd914a26e056cf69207b4f50924ehkuang  // 20 30 21 31 22 32 23 33
72691037db265ecdd914a26e056cf69207b4f50924ehkuang  // 04 14 05 15 06 16 07 17
72791037db265ecdd914a26e056cf69207b4f50924ehkuang  // 24 34 25 35 26 36 27 37
72891037db265ecdd914a26e056cf69207b4f50924ehkuang  // 40 50 41 51 42 52 43 53
72991037db265ecdd914a26e056cf69207b4f50924ehkuang  // 60 70 61 71 62 72 63 73
73091037db265ecdd914a26e056cf69207b4f50924ehkuang  // 44 54 45 55 46 56 47 57
73191037db265ecdd914a26e056cf69207b4f50924ehkuang  // 64 74 65 75 66 76 67 77
73291037db265ecdd914a26e056cf69207b4f50924ehkuang  const __m128i tr1_0 = _mm_unpacklo_epi32(tr0_0, tr0_1);
73391037db265ecdd914a26e056cf69207b4f50924ehkuang  const __m128i tr1_1 = _mm_unpacklo_epi32(tr0_4, tr0_5);
73491037db265ecdd914a26e056cf69207b4f50924ehkuang  const __m128i tr1_2 = _mm_unpackhi_epi32(tr0_0, tr0_1);
73591037db265ecdd914a26e056cf69207b4f50924ehkuang  const __m128i tr1_3 = _mm_unpackhi_epi32(tr0_4, tr0_5);
73691037db265ecdd914a26e056cf69207b4f50924ehkuang  const __m128i tr1_4 = _mm_unpacklo_epi32(tr0_2, tr0_3);
73791037db265ecdd914a26e056cf69207b4f50924ehkuang  const __m128i tr1_5 = _mm_unpacklo_epi32(tr0_6, tr0_7);
73891037db265ecdd914a26e056cf69207b4f50924ehkuang  const __m128i tr1_6 = _mm_unpackhi_epi32(tr0_2, tr0_3);
73991037db265ecdd914a26e056cf69207b4f50924ehkuang  const __m128i tr1_7 = _mm_unpackhi_epi32(tr0_6, tr0_7);
74091037db265ecdd914a26e056cf69207b4f50924ehkuang  // 00 10 20 30 01 11 21 31
74191037db265ecdd914a26e056cf69207b4f50924ehkuang  // 40 50 60 70 41 51 61 71
74291037db265ecdd914a26e056cf69207b4f50924ehkuang  // 02 12 22 32 03 13 23 33
74391037db265ecdd914a26e056cf69207b4f50924ehkuang  // 42 52 62 72 43 53 63 73
74491037db265ecdd914a26e056cf69207b4f50924ehkuang  // 04 14 24 34 05 15 25 35
74591037db265ecdd914a26e056cf69207b4f50924ehkuang  // 44 54 64 74 45 55 65 75
74691037db265ecdd914a26e056cf69207b4f50924ehkuang  // 06 16 26 36 07 17 27 37
74791037db265ecdd914a26e056cf69207b4f50924ehkuang  // 46 56 66 76 47 57 67 77
74891037db265ecdd914a26e056cf69207b4f50924ehkuang  res[0] = _mm_unpacklo_epi64(tr1_0, tr1_1);
74991037db265ecdd914a26e056cf69207b4f50924ehkuang  res[1] = _mm_unpackhi_epi64(tr1_0, tr1_1);
75091037db265ecdd914a26e056cf69207b4f50924ehkuang  res[2] = _mm_unpacklo_epi64(tr1_2, tr1_3);
75191037db265ecdd914a26e056cf69207b4f50924ehkuang  res[3] = _mm_unpackhi_epi64(tr1_2, tr1_3);
75291037db265ecdd914a26e056cf69207b4f50924ehkuang  res[4] = _mm_unpacklo_epi64(tr1_4, tr1_5);
75391037db265ecdd914a26e056cf69207b4f50924ehkuang  res[5] = _mm_unpackhi_epi64(tr1_4, tr1_5);
75491037db265ecdd914a26e056cf69207b4f50924ehkuang  res[6] = _mm_unpacklo_epi64(tr1_6, tr1_7);
75591037db265ecdd914a26e056cf69207b4f50924ehkuang  res[7] = _mm_unpackhi_epi64(tr1_6, tr1_7);
75691037db265ecdd914a26e056cf69207b4f50924ehkuang  // 00 10 20 30 40 50 60 70
75791037db265ecdd914a26e056cf69207b4f50924ehkuang  // 01 11 21 31 41 51 61 71
75891037db265ecdd914a26e056cf69207b4f50924ehkuang  // 02 12 22 32 42 52 62 72
75991037db265ecdd914a26e056cf69207b4f50924ehkuang  // 03 13 23 33 43 53 63 73
76091037db265ecdd914a26e056cf69207b4f50924ehkuang  // 04 14 24 34 44 54 64 74
76191037db265ecdd914a26e056cf69207b4f50924ehkuang  // 05 15 25 35 45 55 65 75
76291037db265ecdd914a26e056cf69207b4f50924ehkuang  // 06 16 26 36 46 56 66 76
76391037db265ecdd914a26e056cf69207b4f50924ehkuang  // 07 17 27 37 47 57 67 77
76491037db265ecdd914a26e056cf69207b4f50924ehkuang}
76591037db265ecdd914a26e056cf69207b4f50924ehkuang
766b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanianvoid fdct8_sse2(__m128i *in) {
76791037db265ecdd914a26e056cf69207b4f50924ehkuang  // constants
76891037db265ecdd914a26e056cf69207b4f50924ehkuang  const __m128i k__cospi_p16_p16 = _mm_set1_epi16(cospi_16_64);
76991037db265ecdd914a26e056cf69207b4f50924ehkuang  const __m128i k__cospi_p16_m16 = pair_set_epi16(cospi_16_64, -cospi_16_64);
77091037db265ecdd914a26e056cf69207b4f50924ehkuang  const __m128i k__cospi_p24_p08 = pair_set_epi16(cospi_24_64, cospi_8_64);
77191037db265ecdd914a26e056cf69207b4f50924ehkuang  const __m128i k__cospi_m08_p24 = pair_set_epi16(-cospi_8_64, cospi_24_64);
77291037db265ecdd914a26e056cf69207b4f50924ehkuang  const __m128i k__cospi_p28_p04 = pair_set_epi16(cospi_28_64, cospi_4_64);
77391037db265ecdd914a26e056cf69207b4f50924ehkuang  const __m128i k__cospi_m04_p28 = pair_set_epi16(-cospi_4_64, cospi_28_64);
77491037db265ecdd914a26e056cf69207b4f50924ehkuang  const __m128i k__cospi_p12_p20 = pair_set_epi16(cospi_12_64, cospi_20_64);
77591037db265ecdd914a26e056cf69207b4f50924ehkuang  const __m128i k__cospi_m20_p12 = pair_set_epi16(-cospi_20_64, cospi_12_64);
77691037db265ecdd914a26e056cf69207b4f50924ehkuang  const __m128i k__DCT_CONST_ROUNDING = _mm_set1_epi32(DCT_CONST_ROUNDING);
77791037db265ecdd914a26e056cf69207b4f50924ehkuang  __m128i u0, u1, u2, u3, u4, u5, u6, u7;
77891037db265ecdd914a26e056cf69207b4f50924ehkuang  __m128i v0, v1, v2, v3, v4, v5, v6, v7;
77991037db265ecdd914a26e056cf69207b4f50924ehkuang  __m128i s0, s1, s2, s3, s4, s5, s6, s7;
78091037db265ecdd914a26e056cf69207b4f50924ehkuang
78191037db265ecdd914a26e056cf69207b4f50924ehkuang  // stage 1
78291037db265ecdd914a26e056cf69207b4f50924ehkuang  s0 = _mm_add_epi16(in[0], in[7]);
78391037db265ecdd914a26e056cf69207b4f50924ehkuang  s1 = _mm_add_epi16(in[1], in[6]);
78491037db265ecdd914a26e056cf69207b4f50924ehkuang  s2 = _mm_add_epi16(in[2], in[5]);
78591037db265ecdd914a26e056cf69207b4f50924ehkuang  s3 = _mm_add_epi16(in[3], in[4]);
78691037db265ecdd914a26e056cf69207b4f50924ehkuang  s4 = _mm_sub_epi16(in[3], in[4]);
78791037db265ecdd914a26e056cf69207b4f50924ehkuang  s5 = _mm_sub_epi16(in[2], in[5]);
78891037db265ecdd914a26e056cf69207b4f50924ehkuang  s6 = _mm_sub_epi16(in[1], in[6]);
78991037db265ecdd914a26e056cf69207b4f50924ehkuang  s7 = _mm_sub_epi16(in[0], in[7]);
79091037db265ecdd914a26e056cf69207b4f50924ehkuang
79191037db265ecdd914a26e056cf69207b4f50924ehkuang  u0 = _mm_add_epi16(s0, s3);
79291037db265ecdd914a26e056cf69207b4f50924ehkuang  u1 = _mm_add_epi16(s1, s2);
79391037db265ecdd914a26e056cf69207b4f50924ehkuang  u2 = _mm_sub_epi16(s1, s2);
79491037db265ecdd914a26e056cf69207b4f50924ehkuang  u3 = _mm_sub_epi16(s0, s3);
79591037db265ecdd914a26e056cf69207b4f50924ehkuang  // interleave and perform butterfly multiplication/addition
796