gcc在英特尔编译器中是否有内存对齐编译指示,类似#pragma vector aligned
?
我想告诉编译器使用对齐的加载/存储指令优化特定的循环。为了避免可能的混淆,这不是关于结构包装。
e.g:
#if defined (__INTEL_COMPILER)
#pragma vector aligned
#endif
for (int a = 0; a < int(N); ++a) {
q10 += Ix(a,0,0)*Iy(a,1,1)*Iz(a,0,0);
q11 += Ix(a,0,0)*Iy(a,0,1)*Iz(a,1,0);
q12 += Ix(a,0,0)*Iy(a,0,0)*Iz(a,0,1);
q13 += Ix(a,1,0)*Iy(a,0,0)*Iz(a,0,1);
q14 += Ix(a,0,0)*Iy(a,1,0)*Iz(a,0,1);
q15 += Ix(a,0,0)*Iy(a,0,0)*Iz(a,1,1);
}
由于
答案 0 :(得分:10)
你可以告诉GCC指针指向对齐的内存,方法是使用typedef来创建一个可以声明指针的过度对齐类型。
这有助于gcc而不是clang7.0或ICC19,请参阅x86-64非AVX asm,它们会发出on Godbolt 。 (只有GCC会将负载折叠到mulps
的内存操作数中,而不是使用单独的movups
)。如果你想向GCC本身以外的GNU C编译器移植一个对齐承诺,你必须使用__builtin_assume_aligned
。
来自http://gcc.gnu.org/onlinedocs/gcc/Type-Attributes.html
typedef double aligned_double __attribute__((aligned (16)));
// Note: sizeof(aligned_double) is 8, not 16
void some_function(aligned_double *x, aligned_double *y, int n)
{
for (int i = 0; i < n; ++i) {
// math!
}
}
这不会使aligned_double
16字节宽。这将使它与16字节边界对齐,或者更确切地说是数组中的第一个边界。看看我的计算机上的反汇编,一旦我使用了对齐指令,我就开始看到很多矢量操作。我目前正在使用Power架构计算机,因此它是altivec代码,但我认为这可以满足您的需求。
(注意:我测试时没有使用double
,因为altivec不支持双浮点数。)
您可以在此处使用类型属性查看自动向量化的其他一些示例:http://gcc.gnu.org/projects/tree-ssa/vectorization.html
答案 1 :(得分:5)
我尝试使用g ++版本4.5.2(Ubuntu和Windows)的解决方案,并且不对循环进行矢量化。
如果删除了alignment属性,则使用未对齐的加载来对循环进行矢量化。
如果函数是内联的,那么可以在删除指针的情况下直接访问数组,然后使用对齐的加载进行矢量化。
在这两种情况下,alignment属性都会阻止矢量化。具有讽刺意味的是:“aligned_double * x”应该能够实现矢量化,但却恰恰相反。
为您报告矢量化循环的是哪个编译器?我怀疑它不是gcc编译器?
答案 2 :(得分:3)
gcc是否具有内存对齐编译指示,类似于#pragma vector aligned
看起来新版本的GCC有__builtin_assume_aligned
:
内置函数:
void * __builtin_assume_aligned (const void *exp, size_t align, ...)
此函数返回其第一个参数,并允许编译器假定返回的指针至少对齐字节对齐。 这个内置可以有两个或三个参数,如果它有三个, 第三个参数应该是整数类型,如果它是非零的 意味着错位偏移。例如:
void *x = __builtin_assume_aligned (arg, 16);
表示编译器可以假设x(设置为arg)至少为16字节对齐,而:
void *x = __builtin_assume_aligned (arg, 32, 8);
表示编译器可以假设为x,设置为arg,(char *)x - 8是32字节对齐的。
基于Stack Overflow大约2010年的一些其他问题和答案,看起来内置在GCC 3和早期GCC 4中不可用。但我不知道截止点在哪里。