中文
注册
我要评分
文档获取效率
文档正确性
内容完整性
文档易理解
在线提单
论坛求助

选项 -ftree-slp-transpose-vectorize

该选项在循环拆分阶段,增强对存在连续访存读的循环的数据流分析能力,通过插入临时数组拆分循环;SLP矢量化阶段,新增对grouped_stores进行转置的SLP分析。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
int foo (unsigned char *oxa, int ia, unsigned char *oxb, int ib)
{
    unsigned tmp[4][4];
    unsigned a0, a1, a2, a3;
    int sum = 0;
    for (int i = 0; i < 4; i++, oxa += ia, oxb += ib)
    {
        a0 = (oxa[0] - oxb[0]) + ((oxa[4] - oxb[4]) << 16);
        a1 = (oxa[1] - oxb[1]) + ((oxa[5] - oxb[5]) << 16);
        a2 = (oxa[2] - oxb[2]) + ((oxa[6] - oxb[6]) << 16);
        a3 = (oxa[3] - oxb[3]) + ((oxa[7] - oxb[7]) << 16);
        int t0 = a0 + a1;
        int t1 = a0 - a1;
        int t2 = a2 + a3;
        int t3 = a2 - a3;
        tmp[i][0] = t0 + t2;
        tmp[i][2] = t0 - t2;
        tmp[i][1] = t1 + t3;
        tmp[i][3] = t1 - t3;
    }

    for (int i = 0; i < 4; i++)
    {
        int t0 = tmp[0][i] + tmp[1][i];
        int t1 = tmp[0][i] - tmp[1][i];
        int t2 = tmp[2][i] + tmp[3][i];
        int t3 = tmp[2][i] - tmp[3][i];
        a0 = t0 + t2;
        a2 = t0 - t2;
        a1 = t1 + t3;
        a3 = t1 - t3;
        sum += a0 + a1 + a2 + a3;
    }
    return sum;
}

对于如上所示的用例,针对第一个for循环,可以拆分为如下形式

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
for (int i = 0; i < 4; i++, oxa += ia, oxb += ib)
{
    a00[i] = (oxa[0] - oxb[0]) + ((oxa[4] - oxb[4]) << 16);
    a11[i] = (oxa[1] - oxb[1]) + ((oxa[5] - oxb[5]) << 16);
    a22[i] = (oxa[2] - oxb[2]) + ((oxa[6] - oxb[6]) << 16);
    a33[i] = (oxa[3] - oxb[3]) + ((oxa[7] - oxb[7]) << 16);
}

for (int i = 0; i < 4; i++)
{
    int t0 = a00[i] + a11[i];
    int t1 = a00[i] - a11[i];
    int t2 = a22[i] + a33[i];
    int t3 = a22[i] - a33[i];
    tmp[i][0] = t0 + t2;
    tmp[i][2] = t0 - t2;
    tmp[i][1] = t1 + t3;
    tmp[i][3] = t1 - t3;
}

再针对于拆分所得的第一个循环,等号右边的计算同构且为连续load可以矢量化,但是由于左边a00[i]、a11[i]、a22[i]、a33[i]的内存地址不连续,无法作为矢量化SLP树的根节点,因此失去这种场景的矢量化机会。 在a00[i]、a11[i]、a22[i]、a33[i]写入内存时,期望寄存器中的内容为:

register

values

vec0

a00[0] a00[1] a00[2] a00[3]

vec1

a11[0] a11[1] a11[2] a11[3]

vec2

a22[0] a22[1] a22[2] a22[3]

vec3

a33[0] a33[1] a33[2] a33[3]

而每次迭代内可以计算得到寄存器的内容为:

register

values

vec0

a00[0] a11[0] a22[0] a33[0]

vec1

a00[1] a11[1] a22[1] a33[1]

vec2

a00[2] a11[2] a22[2] a33[2]

vec3

a00[3] a11[3] a22[3] a33[3]

将grouped_store进行转置,即可得到预期的SLP树根节点。再利用SLP原有的能力,进行后续的矢量化分析。

此外,针对拆分所得的第二个循环以及示例中的最后一个循环,tmp二维数组存在写入内存后立刻读取的行为,针对这种场景,将访存行为优化为寄存器之间的permutation行为。该访存优化默认开启。

使用方法

在选项中加入:

1
-O3 -ftree-slp-transpose-vectorize

-ftree-slp-transpose-vectorize选项,需要在-O3开启的基础上才使能。