【问题标题】:gcc memory alignment pragmagcc 内存对齐编译指示
【发布时间】:2011-02-10 20:19:39
【问题描述】:

gcc 是否有内存对齐编译指示,类似于英特尔编译器中的#pragma vector aligned? 我想告诉编译器使用对齐的加载/存储指令优化特定循环。为避免可能的混淆,这与结构打包无关。

例如:

#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);
        }

谢谢

【问题讨论】:

    标签: optimization memory gcc alignment pragma


    【解决方案1】:

    你可以告诉 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

    【讨论】:

    • 两者都不是。我有编译器无法确定对齐的数组。我必须明确告诉使用对齐的加载和存储。它不会是编译器选项,它必须是 pragma,才能对每个单独的循环进行矢量化。
    • 为什么不能在数组上使用变量属性?
    • 数组被分配,加上数组的结构相当复杂。具体来说,它是一个四维张量
    • 你可以把对齐放在类型上,而不是变量上。
    • 类型为双精度*。如果我对此进行对齐,我将得到的只是指针变量对齐。数组是手动对齐的,没有办法解决。 Intel pragma 专门告诉编译器使用 loadpd 指令。我需要 gcc 等价物
    【解决方案2】:

    我使用 g++ 4.5.2 版(Ubuntu 和 Windows)尝试了您的解决方案,它确实没有对循环进行矢量化。

    如果对齐属性被移除,那么它将使用未对齐的负载对循环进行矢量化。

    如果函数是内联的,以便可以在消除指针的情况下直接访问数组,那么它会使用对齐的负载进行矢量化。

    在这两种情况下,对齐属性都会阻止矢量化。这很讽刺:“aligned_double *x”本应启用矢量化,但结果恰恰相反。

    哪个编译器为您报告了矢量化循环?我怀疑它不是 gcc 编译器?

    【讨论】:

      【解决方案3】:

      gcc 是否有内存对齐 pragma,类似于 #pragma 向量对齐

      看起来较新版本的 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 字节对齐的。

      根据大约 2010 年 Stack Overflow 上的一些其他问题和答案,GCC 3 和早期的 GCC 4 中似乎没有内置。但我不知道截止点在哪里。

      【讨论】:

        猜你喜欢
        • 2015-04-12
        • 1970-01-01
        • 1970-01-01
        • 2014-12-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-11-27
        • 1970-01-01
        相关资源
        最近更新 更多