摘要
上一篇文章已经基本讲明DCT系列函数的实现原理,同尺寸的IDCT(DCT反变换)、DST(离散正弦变换)、IDST的实现方法基本相同。本篇文章将要讲述8x8矩阵DCT变换的向量实现。原理类似,但仅仅因为尺寸扩展为8x8,导致数据的构造方式完全不同,而且变换系数的规律的不同也对其造成一定的影响。本文将详细描述其数据构造方式。
正文
原理
8x8的变换系数矩阵为 。
[ 64 64 64 64 64 64 64 64 89 75 50 18 − 18 − 50 − 75 − 89 83 36 − 36 − 83 − 83 − 36 36 83 75 − 18 − 89 − 50 50 89 18 − 75 64 − 64 − 64 64 64 − 64 − 64 64 50 − 89 18 75 − 75 − 18 89 − 50 36 − 83 83 − 36 − 36 83 − 83 36 18 − 50 75 − 89 89 − 75 50 − 18 ] \begin{bmatrix} 64&64&64&64&64&64&64&64\\ 89&75&50&18&-18&-50&-75&-89\\ 83&36&-36&-83&-83&-36&36&83\\ 75&-18&-89&-50&50&89&18&-75\\ 64&-64&-64&64&64&-64&-64&64\\ 50&-89&18&75&-75&-18&89&-50\\ 36&-83&83&-36&-36&83&-83&36\\ 18&-50&75&-89&89&-75&50&-18\\ \end{bmatrix} ⎣⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎡6489837564503618647536−18−64−89−83−506450−36−89−641883756418−83−506475−36−8964−18−835064−75−368964−50−3689−64−1883−7564−753618−6489−835064−8983−7564−5036−18⎦⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎤
变换公式就不列出来了,仍以行变换为例。观察该变换系数的规律,它的奇数行和偶数行的规律还存在差异。首先来看偶数行(第一行为 r o w 0 row0 row0),其计算公式可以简化为下式。
64
∗
(
r
o
w
0
+
r
o
w
7
+
r
o
w
3
+
r
o
w
4
)
+
64
∗
(
r
o
w
1
+
r
o
w
6
+
r
o
w
2
+
r
o
w
5
)
64*(row0+row7+row3+row4)+64*(row1+row6+row2+row5)
64∗(row0+row7+row3+row4)+64∗(row1+row6+row2+row5)
83
∗
(
r
o
w
0
+
r
o
w
7
−
r
o
w
3
−
r
o
w
4
)
+
36
∗
(
r
o
w
1
+
r
o
w
6
−
r
o
w
2
−
r
o
w
5
)
83*(row0+row7-row3-row4)+36*(row1+row6-row2-row5)
83∗(row0+row7−row3−row4)+36∗(row1+row6−row2−row5)
64
∗
(
r
o
w
0
+
r
o
w
7
+
r
o
w
3
+
r
o
w
4
)
−
64
∗
(
r
o
w
1
+
r
o
w
6
+
r
o
w
2
+
r
o
w
5
)
64*(row0+row7+row3+row4)-64*(row1+row6+row2+row5)
64∗(row0+row7+row3+row4)−64∗(row1+row6+row2+row5)
36
∗
(
r
o
w
0
+
r
o
w
7
−
r
o
w
3
−
r
o
w
4
)
−
83
∗
(
r
o
w
1
+
r
o
w
6
−
r
o
w
2
−
r
o
w
5
)
36*(row0+row7-row3-row4)-83*(row1+row6-row2-row5)
36∗(row0+row7−row3−row4)−83∗(row1+row6−row2−row5)
分两个步骤就是首先得到括号内的四种数据加减组合。其次完成括号外的乘法加减操作。
然后是奇数行,计算公式如下。
89
∗
(
r
o
w
0
−
7
)
+
75
∗
(
r
o
w
1
−
6
)
+
50
∗
(
r
o
w
2
−
5
)
+
18
∗
(
r
o
w
3
−
4
)
89*(row0-7)+75*(row1-6)+50*(row2-5)+18*(row3-4)
89∗(row0−7)+75∗(row1−6)+50∗(row2−5)+18∗(row3−4)
75
∗
(
r
o
w
0
−
7
)
−
18
∗
(
r
o
w
1
−
6
)
−
89
∗
(
r
o
w
2
−
5
)
−
50
∗
(
r
o
w
3
−
4
)
75*(row0-7)-18*(row1-6)-89*(row2-5)-50*(row3-4)
75∗(row0−7)−18∗(row1−6)−89∗(row2−5)−50∗(row3−4)
50
∗
(
r
o
w
0
−
7
)
−
89
∗
(
r
o
w
1
−
6
)
+
18
∗
(
r
o
w
2
−
5
)
+
75
∗
(
r
o
w
3
−
4
)
50*(row0-7)-89*(row1-6)+18*(row2-5)+75*(row3-4)
50∗(row0−7)−89∗(row1−6)+18∗(row2−5)+75∗(row3−4)
18
∗
(
r
o
w
0
−
7
)
−
50
∗
(
r
o
w
1
−
6
)
+
75
∗
(
r
o
w
2
−
5
)
−
89
∗
(
r
o
w
3
−
4
)
18*(row0-7)-50*(row1-6)+75*(row2-5)-89*(row3-4)
18∗(row0−7)−50∗(row1−6)+75∗(row2−5)−89∗(row3−4)
同样分两个步骤,首先得到括号内的,其次是括号外的操作。下文的实现就是以上述公式为基础,构造数据格式。
实现
行变换
在具体的实现中,对于奇数行和偶数行的变换系数,采用不同的处理过程,两者是分开处理的。下文也将分开讲述,但首先先讲明起始共用的处理过程。
首先使用ld指令获取所有原始数据。数据表示方法与上文相同。得到数据
{ r o w n [ c o l 7 , c o l 6 , c o l 5 , c o l 4 , c o l 3 , c o l 2 , c o l 1 , c o l 0 ] } \{row_n[col7, col6, col5, col4, col3, col2, col1,col0]\} {rown[col7,col6,col5,col4,col3,col2,col1,col0]}
然后使用ilvr和ilvl交错指令,以16位为交错单位,将相邻两行交错,拿第一行和第二行举例,得到
{
c
o
l
3
[
r
o
w
1
,
r
o
w
0
]
,
c
o
l
2
[
r
o
w
1
,
r
o
w
0
]
,
c
o
l
1
[
r
o
w
1
,
r
o
w
0
]
,
c
o
l
0
[
r
o
w
1
,
r
o
w
0
]
}
\{col3[row1, row0], col2[row1, row0], col1[row1, row0], col0[row1, row0]\}
{col3[row1,row0],col2[row1,row0],col1[row1,row0],col0[row1,row0]}
{
c
o
l
7
[
r
o
w
1
,
r
o
w
0
]
,
c
o
l
6
[
r
o
w
1
,
r
o
w
0
]
,
c
o
l
5
[
r
o
w
1
,
r
o
w
0
]
,
c
o
l
4
[
r
o
w
1
,
r
o
w
0
]
}
\{col7[row1, row0], col6[row1, row0], col5[row1, row0], col4[row1, row0]\}
{col7[row1,row0],col6[row1,row0],col5[row1,row0],col4[row1,row0]}
然后再将两行的交错结果与相邻两行的交错结果继续交错,指令相同,但以32位为交错单位。拿第一二行和三四行作为例子,得到
{
c
o
l
1
[
r
o
w
3
,
r
o
w
2
,
r
o
w
1
,
r
o
w
0
]
,
c
o
l
0
[
r
o
w
3
,
r
o
w
2
,
r
o
w
1
,
r
o
w
0
]
}
\{col1[row3, row2, row1, row0], col0[row3, row2, row1, row0]\}
{col1[row3,row2,row1,row0],col0[row3,row2,row1,row0]}
{
c
o
l
3
[
r
o
w
3
,
r
o
w
2
,
r
o
w
1
,
r
o
w
0
]
,
c
o
l
2
[
r
o
w
3
,
r
o
w
2
,
r
o
w
1
,
r
o
w
0
]
}
\{col3[row3, row2, row1, row0], col2[row3, row2, row1, row0]\}
{col3[row3,row2,row1,row0],col2[row3,row2,row1,row0]}
{
c
o
l
5
[
r
o
w
3
,
r
o
w
2
,
r
o
w
1
,
r
o
w
0
]
,
c
o
l
4
[
r
o
w
3
,
r
o
w
2
,
r
o
w
1
,
r
o
w
0
]
}
\{col5[row3, row2, row1, row0], col4[row3, row2, row1, row0]\}
{col5[row3,row2,row1,row0],col4[row3,row2,row1,row0]}
{
c
o
l
7
[
r
o
w
3
,
r
o
w
2
,
r
o
w
1
,
r
o
w
0
]
,
c
o
l
6
[
r
o
w
3
,
r
o
w
2
,
r
o
w
1
,
r
o
w
0
]
}
\{col7[row3, row2, row1, row0], col6[row3, row2, row1, row0]\}
{col7[row3,row2,row1,row0],col6[row3,row2,row1,row0]}
然后使用shf混洗指令,将第二个和第三个寄存器中,高低64位置换。目的是为了将col0和col7对齐、col1和col6对齐、2和5、还有3和4。得到
{
c
o
l
4
[
r
o
w
3
,
r
o
w
2
,
r
o
w
1
,
r
o
w
0
]
,
c
o
l
5
[
r
o
w
3
,
r
o
w
2
,
r
o
w
1
,
r
o
w
0
]
}
\{col4[row3, row2, row1, row0], col5[row3, row2, row1, row0]\}
{col4[row3,row2,row1,row0],col5[row3,row2,row1,row0]}
{
c
o
l
6
[
r
o
w
3
,
r
o
w
2
,
r
o
w
1
,
r
o
w
0
]
,
c
o
l
7
[
r
o
w
3
,
r
o
w
2
,
r
o
w
1
,
r
o
w
0
]
}
\{col6[row3, row2, row1, row0], col7[row3, row2, row1, row0]\}
{col6[row3,row2,row1,row0],col7[row3,row2,row1,row0]}
到此,第一步的数据格式构造完毕,后续将开始进行加减操作。而为什么需要构造出这样的一种格式,有几点需要说明。首先是我们要进行行变换,需要一行中不同元素的加减操作,这在单个寄存器中是无法完成的。因此我们需要将一行中需要加减的元素置于两个寄存器的对应位置。也就得到上述的以col打头的数据格式。其次是为什么以四行为一个单位进行操作。因为对于奇数行的操作,单行中有四个不同的乘系数。因此在做乘法之前,只需要给每一行提供四个单位的存储空间,并行度和寄存器使用率的平衡点就在于此。以四行为单位进行交错,就可以得到该平衡点。
开始加减操作,使用subv和addv指令,完成向量加减操作,得到。
{
(
c
o
l
1
+
c
o
l
6
)
[
r
o
w
3
,
r
o
w
2
,
r
o
w
1
,
r
o
w
0
]
,
(
c
o
l
0
+
c
o
l
7
)
[
.
.
.
]
}
\{(col1+col6)[row3, row2, row1,row0], (col0+col7)[...]\}
{(col1+col6)[row3,row2,row1,row0],(col0+col7)[...]}
{
(
c
o
l
3
+
c
o
l
4
)
[
.
.
.
]
,
(
c
o
l
2
+
c
o
l
5
)
[
.
.
.
]
}
\{(col3+col4)[...], (col2+col5)[...]\}
{(col3+col4)[...],(col2+col5)[...]}
{
(
c
o
l
1
−
c
o
l
6
)
[
.
.
.
]
,
(
c
o
l
0
−
c
o
l
7
)
[
.
.
.
]
}
\{(col1-col6)[...], (col0-col7)[...]\}
{(col1−col6)[...],(col0−col7)[...]}
{
(
c
o
l
3
−
c
o
l
4
)
[
.
.
.
]
,
(
c
o
l
2
−
c
o
l
5
)
[
.
.
.
]
}
\{(col3-col4)[...], (col2-col5)[...]\}
{(col3−col4)[...],(col2−col5)[...]}
此处就是分歧点,对于奇数行和偶数行变换系数,分别开始进行不同的操作。
奇数行
对于奇数行的变换系数,目前已经得到了第一步的计算结果,之后将进行第二步的乘法加减操作。为方便使用dotp点乘指令,需要变更一下数据格式。使用ilvl和ilvr交错指令,仍以前四行的处理作为例子,得到。
{
r
o
w
3
[
c
o
l
2
−
c
o
l
5
,
c
o
l
0
−
c
o
l
7
]
,
r
o
w
2
[
.
.
.
]
,
r
o
w
1
[
.
.
.
]
,
r
o
w
0
[
.
.
.
]
}
\{row3[col2-col5, col0-col7], row2[...], row1[...], row0[...] \}
{row3[col2−col5,col0−col7],row2[...],row1[...],row0[...]}
{
r
o
w
3
[
c
o
l
3
−
c
o
l
4
,
c
o
l
1
−
c
o
l
6
]
,
r
o
w
2
[
.
.
.
]
,
r
o
w
1
[
.
.
.
]
,
r
o
w
0
[
.
.
.
]
}
\{row3[col3-col4, col1-col6], row2[...], row1[...], row0[...] \}
{row3[col3−col4,col1−col6],row2[...],row1[...],row0[...]}
然后使用dotp指令与常数向量点乘,对应位置相乘,相邻位置求和。常数向量以第一行为例,表明其构造方式。构造出两个寄存器,分别是。
{
50
,
89
,
50
,
89
,
50
,
89
,
50
,
89
}
\{50,89,50,89,50,89,50,89\}
{50,89,50,89,50,89,50,89}
{
18
,
75
,
18
,
75
,
18
,
75
,
18
,
75
}
\{18,75,18,75,18,75,18,75\}
{18,75,18,75,18,75,18,75}
点乘得到
{
r
o
w
3
[
50
∗
(
c
o
l
2
−
c
o
l
5
)
+
89
∗
(
c
o
l
0
−
c
o
l
7
)
]
,
r
o
w
2
[
.
.
.
]
,
r
o
w
1
[
.
.
.
]
,
r
o
w
0
[
.
.
.
]
}
\{row3[50*(col2-col5)+89*(col0-col7)],row2[...], row1[...], row0[...] \}
{row3[50∗(col2−col5)+89∗(col0−col7)],row2[...],row1[...],row0[...]}
{
r
o
w
3
[
18
∗
(
c
o
l
3
−
c
o
l
4
)
+
75
∗
(
c
o
l
1
−
c
o
l
6
)
]
,
r
o
w
2
[
.
.
.
]
,
r
o
w
1
[
.
.
.
]
,
r
o
w
0
[
.
.
.
]
}
\{row3[18*(col3-col4)+75*(col1-col6)],row2[...], row1[...], row0[...] \}
{row3[18∗(col3−col4)+75∗(col1−col6)],row2[...],row1[...],row0[...]}
使用addv向量求和指令得到。
{ r o w 3 [ 50 ∗ ( c o l 2 − c o l 5 ) + 89 ∗ ( c o l 0 − c o l 7 ) + 18 ∗ ( c o l 3 − c o l 4 ) + 75 ∗ ( c o l 1 − c o l 6 ) ] , r o w 2 [ . . . ] , r o w 1 [ . . . ] , r o w 0 [ . . . ] } \{row3[50*(col2-col5)+89*(col0-col7)+18*(col3-col4)+75*(col1-col6)],row2[...], row1[...], row0[...] \} {row3[50∗(col2−col5)+89∗(col0−col7)+18∗(col3−col4)+75∗(col1−col6)],row2[...],row1[...],row0[...]}
当前得到的就是经过行变换后,得到的第一列(奇数)的前四个元素。对于其他的元素只是所使用的变换系数和原始数据不同, 处理过程完全相同。对应关系是,后四行的原始数据对应行变换后列的后四个元素,使用不同行的变换系数对应变换后不同的列。
偶数行
起始数据是
{
(
c
o
l
1
+
c
o
l
6
)
[
r
o
w
3
,
r
o
w
2
,
r
o
w
1
,
r
o
w
0
]
,
(
c
o
l
0
+
c
o
l
7
)
[
.
.
.
]
}
\{(col1+col6)[row3, row2, row1,row0], (col0+col7)[...]\}
{(col1+col6)[row3,row2,row1,row0],(col0+col7)[...]}
{
(
c
o
l
3
+
c
o
l
4
)
[
.
.
.
]
,
(
c
o
l
2
+
c
o
l
5
)
[
.
.
.
]
}
\{(col3+col4)[...], (col2+col5)[...]\}
{(col3+col4)[...],(col2+col5)[...]}
为完成第一步骤的操作,还需要继续加减操作,首先将 ( c o l 0 + c o l 7 ) (col0+col7) (col0+col7)和 ( c o l 3 + c o l 4 ) (col3+col4) (col3+col4)、 ( c o l 1 + c o l 6 ) (col1+col6) (col1+col6)和 ( c o l 2 + c o l 5 ) (col2+col5) (col2+col5)对齐。使用shf混洗指令,置换第二个寄存器的高低64位。得到
{ ( c o l 2 + c o l 5 ) [ r o w 3 , r o w 2 , r o w 1 , r o w 0 ] , ( c o l 3 + c o l 4 ) [ . . . ] } \{(col2+col5)[row3, row2, row1,row0], (col3+col4)[...]\} {(col2+col5)[row3,row2,row1,row0],(col3+col4)[...]}
然后使用addv和subv指令进行加减操作。得到
{
(
c
o
l
1
+
c
o
l
6
+
c
o
l
2
+
c
o
l
5
)
[
.
.
.
]
,
(
c
o
l
0
+
c
o
l
7
+
c
o
l
3
+
c
o
l
4
)
[
.
.
.
]
}
\{(col1+col6+col2+col5)[...], (col0+col7+col3+col4)[...]\}
{(col1+col6+col2+col5)[...],(col0+col7+col3+col4)[...]}
{
(
c
o
l
1
+
c
o
l
6
−
c
o
l
2
−
c
o
l
5
)
[
.
.
.
]
,
(
c
o
l
0
+
c
o
l
7
−
c
o
l
3
−
c
o
l
4
)
[
.
.
.
]
}
\{(col1+col6-col2-col5)[...], (col0+col7-col3-col4)[...]\}
{(col1+col6−col2−col5)[...],(col0+col7−col3−col4)[...]}
至此已经完成了第一步骤的操作,后续进行乘法加减操作。但要使用dotp点乘指令,需要将同行的数据放置于寄存器的相邻位置。使用混洗指令,shf 32位基本单位混洗,然后16位基本单位混洗得到。
t m p 1 = { r o w 3 [ c o l 1 + c o l 6 + c o l 2 + c o l 5 , c o l 0 + c o l 7 + c o l 3 + c o l 4 ] , r o w 2 [ . . . ] , r o w 1 [ . . . ] , r o w 0 [ . . . ] } tmp1 = \{row3[col1+col6+col2+col5, col0+col7+col3+col4], row2[...], row1[...], row0[...]\} tmp1={row3[col1+col6+col2+col5,col0+col7+col3+col4],row2[...],row1[...],row0[...]}
t m p 2 = { r o w 3 [ c o l 1 + c o l 6 − c o l 2 − c o l 5 , c o l 0 + c o l 7 − c o l 3 − c o l 4 ] , r o w 2 [ . . . ] , r o w 1 [ . . . ] , r o w 0 [ . . . ] } tmp2 = \{row3[col1+col6-col2-col5, col0+col7-col3-col4], row2[...], row1[...], row0[...]\} tmp2={row3[col1+col6−col2−col5,col0+col7−col3−col4],row2[...],row1[...],row0[...]}
这里要用到四个常量,分别表示变换系数偶数行的4行系数,分别是
c
o
n
1
=
{
64
,
64
,
64
,
64
,
64
,
64
,
64
,
64
}
con1 = \{64,64,64,64,64,64,64,64\}
con1={64,64,64,64,64,64,64,64}
c
o
n
2
=
{
36
,
83
,
36
,
83
,
36
,
83
,
36
,
83
}
con2 = \{36, 83, 36, 83, 36, 83, 36, 83\}
con2={36,83,36,83,36,83,36,83}
c
o
n
3
=
{
64
,
−
64
,
64
,
−
64
,
64
,
−
64
,
64
,
−
64
}
con3 = \{64, -64, 64, -64, 64, -64, 64, -64\}
con3={64,−64,64,−64,64,−64,64,−64}
c
o
n
4
=
{
−
83
,
36
,
−
83
,
36
,
−
83
,
36
,
−
83
,
36
}
con4 = \{-83, 36, -83, 36, -83, 36, -83, 36\}
con4={−83,36,−83,36,−83,36,−83,36}
t m p 1 tmp1 tmp1和 c o n 1 con1 con1点乘,得到第零列(偶数顺序)、 t m p 2 tmp2 tmp2和 c o n 2 con2 con2点乘,得到第二列、 t m p 1 tmp1 tmp1和 c o n 3 con3 con3点乘,得到第四列、 t m p 2 tmp2 tmp2和 c o n 4 con4 con4点乘,得到第六列。且都是前四个元素。至此完成了行变换。
列变换
dct8函数的列变换不同于dct4函数的实现,dct4是直接进行和行变换相同的过程。但这对于dct8函数是无法实现的。因为经过行变换后,得到的临时数据占用了16个寄存器。后续如果采用同等并行度进行计算,必定导致寄存器过载,出现大量的堆栈操作,这显然是不被允许的。但这种实现方法也会导致最后得到的数据是以列的形式呈现的,也就是说最后的访存是以步长为间隔进行访问,访存空间局部性差,该问题仍需要进行权衡。
因此当前过程需要降低并行度。但一旦降低,整个过程就完全不同于行变换。大致思想是,先完成部分原始数据的变换。当前权衡得到的是以两列元素为单位进行列变换,过程中得到结果直接保存。以第一列和第二列为例,进行详细说明。
首先来看列变换的初始数据格式。有四个寄存器,其中数据都为32位。
{
c
o
l
0
[
r
o
w
3
,
r
o
w
2
,
r
o
w
1
,
r
o
w
0
]
}
\{col0[row3, row2, row1, row0]\}
{col0[row3,row2,row1,row0]}
{
c
o
l
0
[
r
o
w
4
,
r
o
w
5
,
r
o
w
6
,
r
o
w
7
]
}
\{col0[row4, row5, row6, row7]\}
{col0[row4,row5,row6,row7]}
{
c
o
l
1
[
r
o
w
3
,
r
o
w
2
,
r
o
w
1
,
r
o
w
0
]
}
\{col1[row3, row2, row1, row0]\}
{col1[row3,row2,row1,row0]}
{
c
o
l
1
[
r
o
w
4
,
r
o
w
5
,
r
o
w
6
,
r
o
w
7
]
}
\{col1[row4, row5, row6, row7]\}
{col1[row4,row5,row6,row7]}
然后使用addv和subv指令,完成变换第一步骤的操作。得到
{
c
o
l
0
[
r
o
w
3
+
r
o
w
4
,
r
o
w
2
+
r
o
w
5
,
r
o
w
1
+
r
o
w
6
,
r
o
w
0
+
r
o
w
7
]
}
\{col0[row3+row4, row2+row5, row1+row6, row0+row7]\}
{col0[row3+row4,row2+row5,row1+row6,row0+row7]}
{
c
o
l
0
[
r
o
w
3
−
r
o
w
4
,
r
o
w
2
−
r
o
w
5
,
r
o
w
1
−
r
o
w
6
,
r
o
w
0
−
r
o
w
7
]
}
\{col0[row3-row4, row2-row5, row1-row6, row0-row7]\}
{col0[row3−row4,row2−row5,row1−row6,row0−row7]}
{
c
o
l
1
[
r
o
w
3
+
r
o
w
4
,
r
o
w
2
+
r
o
w
5
,
r
o
w
1
+
r
o
w
6
,
r
o
w
0
+
r
o
w
7
]
}
\{col1[row3+row4, row2+row5, row1+row6, row0+row7]\}
{col1[row3+row4,row2+row5,row1+row6,row0+row7]}
{
c
o
l
1
[
r
o
w
3
−
r
o
w
4
,
r
o
w
2
−
r
o
w
5
,
r
o
w
1
−
r
o
w
6
,
r
o
w
0
−
r
o
w
7
]
}
\{col1[row3-row4, row2-row5, row1-row6, row0-row7]\}
{col1[row3−row4,row2−row5,row1−row6,row0−row7]}
列变换中,仍然需要将奇偶行的变换系数分开处理,并且此处就是分歧点。
奇数行
对于奇数行的变换系数,当前已经完成了第一步骤的操作。后续使用dotp点乘指令,完成第二步操作。这里需要四个常量寄存器,表示奇数行的变换系数。以第一行作为例子。
{ 18 , 50 , 75 , 89 } \{18,50,75,89\} {18,50,75,89}
数据宽度为32位,其实就是奇数行变换系数的前四个元素。然后使用dotp和pckev的指令组合,完成点乘以及组合的操作。得到
{ c o l 1 [ 18 ∗ ( r o w 3 − r o w 4 ) + 50 ∗ ( r o w 2 − r o w 5 ) , 75 ∗ ( r o w 1 − r o w 6 ) + 89 ∗ ( r o w 0 − r o w 7 ) ] , c o l 0 [ . . . ] } \{col1[18*(row3-row4)+50*(row2-row5), 75*(row1-row6)+89*(row0-row7)], col0[...]\} {col1[18∗(row3−row4)+50∗(row2−row5),75∗(row1−row6)+89∗(row0−row7)],col0[...]}
然后使用hadd横向加指令,得到
{ c o l 1 [ 18 ∗ ( r o w 3 − r o w 4 ) + 50 ∗ ( r o w 2 − r o w 5 ) + 75 ∗ ( r o w 1 − r o w 6 ) + 89 ∗ ( r o w 0 − r o w 7 ) ] , c o l 0 [ . . . ] } \{col1[18*(row3-row4)+50*(row2-row5)+75*(row1-row6)+89*(row0-row7)], col0[...]\} {col1[18∗(row3−row4)+50∗(row2−row5)+75∗(row1−row6)+89∗(row0−row7)],col0[...]}
当前得到了变换部分最终数据,为第一行的第零和第一个元素,然后在特定位置存入数据即可。
偶数行
需要继续完成第一步骤的操作,首先需要混洗,将使用相同变换系数的数据置于寄存器的相邻位置, 且需要构造适合横向减法操作的数据结构。得到
{
c
o
l
0
[
r
o
w
0
+
r
o
w
7
,
r
o
w
3
+
r
o
w
4
,
r
o
w
1
+
r
o
w
6
,
r
o
w
2
+
r
o
w
5
]
}
\{col0[row0+row7,row3+row4, row1+row6,row2+row5]\}
{col0[row0+row7,row3+row4,row1+row6,row2+row5]}
{
c
o
l
1
[
r
o
w
0
+
r
o
w
7
,
r
o
w
3
+
r
o
w
4
,
r
o
w
1
+
r
o
w
6
,
r
o
w
2
+
r
o
w
5
]
}
\{col1[row0+row7,row3+row4, row1+row6,row2+row5]\}
{col1[row0+row7,row3+row4,row1+row6,row2+row5]}
然后使用hadd、hsub和pckev指令,横向加减,然后寄存器组合。得到
{
c
o
l
1
[
r
o
w
0
+
r
o
w
7
+
r
o
w
3
+
r
o
w
4
,
r
o
w
1
+
r
o
w
6
+
r
o
w
2
+
r
o
w
5
]
,
c
o
l
0
[
.
.
]
}
\{col1[row0+row7+row3+row4, row1+row6+row2+row5],col0[..]\}
{col1[row0+row7+row3+row4,row1+row6+row2+row5],col0[..]}
{
c
o
l
1
[
r
o
w
0
+
r
o
w
7
−
r
o
w
3
−
r
o
w
4
,
r
o
w
1
+
r
o
w
6
−
r
o
w
2
−
r
o
w
5
]
,
c
o
l
0
[
.
.
]
}
\{col1[row0+row7-row3-row4, row1+row6-row2-row5],col0[..]\}
{col1[row0+row7−row3−row4,row1+row6−row2−row5],col0[..]}
然后使用dotp指令,所使用的常量那第二、六行变换系数为例, 表示其结构。
{
83
,
36
,
83
,
36
}
\{83,36,83,36\}
{83,36,83,36}
{
36
,
−
83
,
36
,
−
83
}
\{36,-83,36,-83\}
{36,−83,36,−83}
每个数据宽度是32位,其实就是每行的前两个变换系数的组合。点乘得到结果。
{
c
o
l
1
[
83
∗
(
r
o
w
0
+
r
o
w
7
−
r
o
w
3
−
r
o
w
4
)
+
36
∗
(
r
o
w
1
+
r
o
w
6
−
r
o
w
2
−
r
o
w
5
)
]
,
c
o
l
0
[
.
.
]
}
\{col1[83*(row0+row7-row3-row4)+36*(row1+row6-row2-row5)],col0[..]\}
{col1[83∗(row0+row7−row3−row4)+36∗(row1+row6−row2−row5)],col0[..]}
{
c
o
l
1
[
36
∗
(
r
o
w
0
+
r
o
w
7
−
r
o
w
3
−
r
o
w
4
)
−
83
∗
(
r
o
w
1
+
r
o
w
6
−
r
o
w
2
−
r
o
w
5
)
]
,
c
o
l
0
[
.
.
]
}
\{col1[36*(row0+row7-row3-row4)-83*(row1+row6-row2-row5)],col0[..]\}
{col1[36∗(row0+row7−row3−row4)−83∗(row1+row6−row2−row5)],col0[..]}
分别是变换后最终数据中的第二行前两个元素和第六行前两个元素,特定位置保存。以上内容就是整个dct8函数的实现过程。