GCC带限制指针的别名检查

GCC带限制指针的别名检查,c,optimization,gcc,strict-aliasing,C,Optimization,Gcc,Strict Aliasing,考虑以下两个片段: #define ALIGN_BYTES 32 #define ASSUME_ALIGNED(x) x = __builtin_assume_aligned(x, ALIGN_BYTES) void fn0(const float *restrict a0, const float *restrict a1, float *restrict b, int n) { ASSUME_ALIGNED(a0); ASSUME_ALIGNED(a1); ASS

考虑以下两个片段:

#define ALIGN_BYTES 32
#define ASSUME_ALIGNED(x) x = __builtin_assume_aligned(x, ALIGN_BYTES)

void fn0(const float *restrict a0, const float *restrict a1,
         float *restrict b, int n)
{
    ASSUME_ALIGNED(a0); ASSUME_ALIGNED(a1); ASSUME_ALIGNED(b);

    for (int i = 0; i < n; ++i)
        b[i] = a0[i] + a1[i];
}

void fn1(const float *restrict *restrict a, float *restrict b, int n)
{
    ASSUME_ALIGNED(a[0]); ASSUME_ALIGNED(a[1]); ASSUME_ALIGNED(b);

    for (int i = 0; i < n; ++i)
        b[i] = a[0][i] + a[1][i];
}
这有帮助吗

void fn1(const float **restrict a, float *restrict b, int n)
{
    const float * restrict a0 = a[0];
    const float * restrict a1 = a[1];

    ASSUME_ALIGNED(a0); ASSUME_ALIGNED(a1); ASSUME_ALIGNED(b);

    for (int i = 0; i < n; ++i)
        b[i] = a0[i] + a1[i];
}
void fn1(常量浮点**限制a,浮点*限制b,整数n)
{
常量浮点*限制a0=a[0];
常量浮点*限制a1=a[1];
假设对齐(a0);假设对齐(a1);假设对齐(b);
对于(int i=0;i
编辑:第二次尝试:)。从


gcc——快速数学…

那么,标志呢

-fno-strict-aliasing
?

据我所知,你只是想知道如何关闭这个检查?如果仅此而已,gcc命令行的这个参数应该会对您有所帮助

编辑:

除了您的评论之外:是否禁止使用const类型的restrict指针

这来自ISO/IEC 9899(6.7.3.1限制的正式定义):

一,

设D为普通标识符的声明,该标识符提供了指定 对象P作为类型T的限制限定指针

四,

在B的每次执行过程中,设L是基于p的&L的任何左值 访问它指定的对象X的值,并且X也会被修改(通过任何方式), 然后适用以下要求:T不应为合格的。其他左值 用于访问X值的地址也应基于P。每次访问 就本款而言,修改X也应视为修改P。如果P 为基于另一个受限指针的指针表达式E赋值 对象P2,与块B2关联,则B2的执行应在 B或B2的执行应在转让前结束。如果这些 如果未满足要求,则行为未定义

还有一个更有趣的点,和register一样,是:

六,

译者可以自由地忽略使用restrict的任何或所有别名含义


因此,如果您找不到强制gcc执行此操作的命令参数,这可能是不可能的,因为根据标准,它不必给出执行此操作的选项。

有一种方法可以告诉编译器停止检查别名:

请添加行:

#pragma GCC ivdep
在要矢量化的循环前面,如果需要更多信息,请阅读:


我提前表示歉意,因为我无法在我的机器上使用GCC4.7复制结果,但有两种可能的解决方案

  • 使用typedef正确编写
    *restrict*restrict
    。这是, 据一位开发LLVM编译器的前同事说,
    typedef
    的单一异常行为与中的预处理器类似 它的存在是为了允许您希望的抗锯齿行为

    我在下面尝试过,但我不确定是否成功。请仔细检查我的尝试

  • 使用的答案中描述的语法

    我在下面尝试过,但我不确定是否成功。请仔细检查我的尝试

  • 这是我用来执行实验的代码,但我无法确定我的建议是否符合预期

    #define ALIGN_BYTES 32
    #define ASSUME_ALIGNED(x) x = __builtin_assume_aligned(x, ALIGN_BYTES)
    
    void fn0(const float *restrict a0, const float *restrict a1,
             float *restrict b, int n)
    {
        ASSUME_ALIGNED(a0); ASSUME_ALIGNED(a1); ASSUME_ALIGNED(b);
    
        for (int i = 0; i < n; ++i)
            b[i] = a0[i] + a1[i];
    }
    
    #if defined(ARRAY_RESTRICT)
    void fn1(const float *restrict a[restrict], float * restrict b, int n)
    #elif defined(TYPEDEF_SOLUTION)
    typedef float * restrict frp;
    void fn1(const frp *restrict a, float *restrict b, int n)
    #else
    void fn1(const float *restrict *restrict a, float *restrict b, int n)
    #endif
    {
        //ASSUME_ALIGNED(a[0]); ASSUME_ALIGNED(a[1]); ASSUME_ALIGNED(b);
    
        for (int i = 0; i < n; ++i)
            b[i] = a[0][i] + a[1][i];
    }
    
    #定义对齐字节32
    #定义假定对齐(x)x=\uuuuuu内置\u假定对齐(x,对齐\u字节)
    无效fn0(常数浮点*限制a0,常数浮点*限制a1,
    浮动*限制b,整数n)
    {
    假设对齐(a0);假设对齐(a1);假设对齐(b);
    对于(int i=0;i

    我再次为这个回答的不成熟性道歉。请不要因为我尝试但没有成功而否决我。

    选项
    --param vect max version for alias checks=n
    是否有帮助?当有很多指针在使用时,它会有帮助(通常GCC会放弃尝试对函数进行向量化,除非n~100)。然而,我想知道如何才能让GCC相信这些检查是毫无意义的。你能展示一下编译器生成的程序集吗?这篇文章可能会有所帮助:@Freddie Witherden那么-fno严格别名现在怎么样了?这对你有帮助吗?遗憾的是没有;GCC仍然会发出别名检查。@Freddie Witherden我在汇编程序方面不是很好,但我知道您提到的行通过这个标志(到目前为止,我在我的案例中测试过)将超出.o。我还知道这一行建议编译器不要根据别名规则进行任何优化,所以我建议他不要用这个标志检查任何别名,如果他不允许根据这些检查进行操作的话。所以这应该可以解决你的问题,是的。@Freddie Witherden只是为了让你正确:你想做的是,阻止编译器进行任何基于严格别名的优化,不是吗?因为这就是我们的目的。所以它应该做你想做的,因为我做对了。不完全是这样。我希望编译器尊重传递的变量上的限制限定符。虽然与别名相关,但它不同于GCCs严格别名。@Freddie Witherden,但在6.7.3.1 restrict?s/restrict/___;的正式定义之后,是否禁止使用const type restrict指针;s/std=c99/std=gnu99/;我在这里的兴趣纯粹是让GCC生成尽可能最好的程序集。在GCC-4.7.4上,
    ARRAY\u RESTRICT
    TYPEDEF\u RESTRICT
    都为
    fn1
    生成相同的程序集作为默认情况(别名检查)。是的,这也是我看到的,但我不认为GCC4.7是自动矢量化方面最激进的编译器。我们现在是4.7.2,不是吗
    #define ALIGN_BYTES 32
    #define ASSUME_ALIGNED(x) x = __builtin_assume_aligned(x, ALIGN_BYTES)
    
    void fn0(const float *restrict a0, const float *restrict a1,
             float *restrict b, int n)
    {
        ASSUME_ALIGNED(a0); ASSUME_ALIGNED(a1); ASSUME_ALIGNED(b);
    
        for (int i = 0; i < n; ++i)
            b[i] = a0[i] + a1[i];
    }
    
    #if defined(ARRAY_RESTRICT)
    void fn1(const float *restrict a[restrict], float * restrict b, int n)
    #elif defined(TYPEDEF_SOLUTION)
    typedef float * restrict frp;
    void fn1(const frp *restrict a, float *restrict b, int n)
    #else
    void fn1(const float *restrict *restrict a, float *restrict b, int n)
    #endif
    {
        //ASSUME_ALIGNED(a[0]); ASSUME_ALIGNED(a[1]); ASSUME_ALIGNED(b);
    
        for (int i = 0; i < n; ++i)
            b[i] = a[0][i] + a[1][i];
    }