Clang 的 __restrict 不一致?

问题描述 投票:0回答:1

我正在研究高度“可向量化”的代码,并注意到关于 C++ __restrict 关键字/扩展 ~,即使在简单的情况下,与 GCC 相比,Clang 的行为也是不同且不切实际的。

对于编译器生成的代码,速度减慢约 15 倍(在我的具体情况下,不是下面的示例)。

这是代码(也可在https://godbolt.org/z/sdGd43x75获取):

struct Param {
    int *x;
};

int foo(int *a, int *b) {
    *a = 5;
    *b = 6;
    // No significant optimization here, as expected (for clang/gcc)
    return *a + *b;
}

int foo(Param a, Param b) {
    *a.x = 5;
    *b.x = 6;
    // No significant optimization here, as expected (for clang/gcc)
    return *a.x + *b.x;
}

/////////////////////

struct ParamR {
    // "Restricted pointers assert that members point to disjoint storage"
    // https://en.cppreference.com/w/c/language/restrict, is restrict's 
    // interpretation for C can be used in C++ (for __restrict too ?) ?
    int *__restrict x;
};

int rfoo(int *__restrict a, int *__restrict b) {
    *a = 5;
    *b = 6;
    // Significant optimization here, as expected (for clang/gcc)
    return *a + *b;
}

int rfoo(ParamR a, ParamR b) {
    *a.x = 5;
    *b.x = 6;
    // No significant optimization here, NOT expected (clang fails?, gcc optimizes)
    return *a.x + *b.x;
}

int rfoo(ParamR *__restrict a, ParamR *__restrict b) {
    *a->x = 5;
    *b->x = 6;
    // No significant optimization here, NOT expected (clang fails?, gcc optimizes)
    return *a->x + *b->x;
}

C++ (__restrict) 和 C 代码(使用 std 限制)都会发生这种情况。

如何让 Clang 理解指针将始终指向不相交的存储?

c++ clang vectorization restrict-qualifier pointer-aliasing
1个回答
1
投票

这似乎是一个错误。好吧,我不知道是否应该将其称为错误,因为它确实为程序创建了正确的行为,假设这是优化器中错失的机会。

我尝试了一些解决方法,唯一有效的方法是始终将指针作为限制参数传递。像这样:

int rfoo(int *__restrict a, int *__restrict b) {
    *a = 5;
    *b = 6;
    // Significant optimization here, as expected (for clang/gcc)
    return *a + *b;
}

// change this:
int rfoo(ParamR a, ParamR b) {
    *a.x = 5;
    *b.x = 6;
    // No significant optimization here, NOT expected (clang fails?, gcc optimizes)
    return *a.x + *b.x;
}

// to this:
int rfoo2(ParamR a, ParamR b) {
    return rfoo(a.x, b.x);
}

clang 12.0.0 的输出:

rfoo(ParamR, ParamR):                       # @rfoo(ParamR, ParamR)
        mov     dword ptr [rdi], 5
        mov     dword ptr [rsi], 6
        mov     eax, dword ptr [rdi]
        add     eax, 6
        ret
rfoo2(ParamR, ParamR):                      # @rfoo2(ParamR, ParamR)
        mov     dword ptr [rdi], 5
        mov     dword ptr [rsi], 6
        mov     eax, 11
        ret

现在这非常不方便,尤其是对于更复杂的代码,但如果性能差异如此巨大且重要,并且您无法更改为 gcc,那么可能需要考虑这样做。

最新问题
© www.soinside.com 2019 - 2024. All rights reserved.