gpt4 book ai didi

c - 我怎样才能让 GCC 用 SSE 指令向量化这个简单的复制循环?

转载 作者:太空狗 更新时间:2023-10-29 15:33:09 24 4
gpt4 key购买 nike

这是 this question 关于让 GCC 在循环中优化 memcpy() 的跟进;我已经放弃并决定直接手动优化循环。

不过,我正在努力尽可能地保持可移植性和可维护性,因此我想让 GCC 对一个简单的优化的重复循环内复制本身进行矢量化,而不求助于 SSE 内在函数。然而,无论我给它多少手持,它似乎都拒绝这样做,尽管手动矢量化版本(使用 SSE2 MOVDQA 指令)在经验上对于小型阵列快了 58%( <32 个元素),较大的元素(>=512)至少快 17%。

这是未手动矢量化的版本(有尽可能多的提示告诉 GCC 对其进行矢量化):

__attribute__ ((noinline))
void take(double * out, double * in,
int stride_out_0, int stride_out_1,
int stride_in_0, int stride_in_1,
int * indexer, int n, int k)
{
int i, idx, j, l;
double * __restrict__ subout __attribute__ ((aligned (16)));
double * __restrict__ subin __attribute__ ((aligned (16)));
assert(stride_out_1 == 1);
assert(stride_out_1 == stride_in_1);
l = k - (k % 8);
for(i = 0; i < n; ++i) {
idx = indexer[i];
subout = &out[i * stride_out_0];
subin = &in[idx * stride_in_0];
for(j = 0; j < l; j += 8) {
subout[j+0] = subin[j+0];
subout[j+1] = subin[j+1];
subout[j+2] = subin[j+2];
subout[j+3] = subin[j+3];
subout[j+4] = subin[j+4];
subout[j+5] = subin[j+5];
subout[j+6] = subin[j+6];
subout[j+7] = subin[j+7];
}
for( ; j < k; ++j)
subout[j] = subin[j];
}
}

这是我第一次尝试手动矢量化,我用它来比较性能(它肯定可以进一步改进,但我只是想测试可能的最简单的转换):

__attribute__ ((noinline))
void take(double * out, double * in,
int stride_out_0, int stride_out_1,
int stride_in_0, int stride_in_1,
int * indexer, int n, int k)
{
int i, idx, j, l;
__m128i * __restrict__ subout1 __attribute__ ((aligned (16)));
__m128i * __restrict__ subin1 __attribute__ ((aligned (16)));
double * __restrict__ subout2 __attribute__ ((aligned (16)));
double * __restrict__ subin2 __attribute__ ((aligned (16)));
assert(stride_out_1 == 1);
assert(stride_out_1 == stride_in_1);
l = (k - (k % 8)) / 2;
for(i = 0; i < n; ++i) {
idx = indexer[i];
subout1 = (__m128i*)&out[i * stride_out_0];
subin1 = (__m128i*)&in[idx * stride_in_0];
for(j = 0; j < l; j += 4) {
subout1[j+0] = subin1[j+0];
subout1[j+1] = subin1[j+1];
subout1[j+2] = subin1[j+2];
subout1[j+3] = subin1[j+3];
}
j *= 2;
subout2 = &out[i * stride_out_0];
subin2 = &in[idx * stride_in_0];
for( ; j < k; ++j)
subout2[j] = subin2[j];
}
}

(处理一些特殊情况的实际代码只是稍微复杂一点,但不会影响 GCC 向量化,因为即使上面给出的版本也不会向量化:我的测试工具可以在 LiveWorkspace 上找到)

我正在使用以下命令行编译第一个版本:

gcc-4.7 -O3 -ftree-vectorizer-verbose=3 -march=pentium4m -fverbose-asm \
-msse -msse2 -msse3 take.c -DTAKE5 -S -o take5.s

并且用于主复制循环的结果指令始终是 FLDL/FSTPL 对(即以 8 字节为单位复制)而不是 MOVDQA 说明,这是我手动使用 SSE 内在函数时产生的结果。

tree-vectorize-verbose 的相关输出似乎是:

Analyzing loop at take.c:168

168: vect_model_store_cost: unaligned supported by hardware.
168: vect_model_store_cost: inside_cost = 8, outside_cost = 0 .
168: vect_model_load_cost: unaligned supported by hardware.
168: vect_model_load_cost: inside_cost = 8, outside_cost = 0 .
168: cost model: Adding cost of checks for loop versioning aliasing.

168: cost model: epilogue peel iters set to vf/2 because loop iterations are unknown .
168: cost model: the vector iteration cost = 16 divided by the scalar iteration cost = 16 is greater or equal to the vectorization factor = 1.
168: not vectorized: vectorization not profitable.

我不确定为什么它指的是“未对齐”的存储和加载,而且无论如何,问题似乎是矢量化无法证明是有利可图的(尽管根据经验,它适用于所有情况很重要,我不确定在什么情况下不会)。

是否有任何简单的标志或提示表明我在这里遗漏了,或者 GCC 无论如何都不想这样做?

如果这是显而易见的事情,我会感到尴尬,但希望这也能帮助其他人。

最佳答案

所有的 __attribute__ ((aligned (16))) 指令都实现的很少,因为它们只是定义指针​​变量本身的对齐方式,而不是指针指向的数据。

您可能需要查看 __builtiin_assume_aligned .

关于c - 我怎样才能让 GCC 用 SSE 指令向量化这个简单的复制循环?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15621891/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com