c++ - 如何结合 constexpr 和矢量化代码?

标签 c++ openmp constexpr intrinsics

我正在为 x64 和 neon 开发 C++ 内在包装器。我希望我的函数是 constexpr。我的动机类似于Constexpr and SSE intrinsics ,但编译器 (GCC) 在 constexpr 函数中可能不支持 #pragma omp simd 和内在函数。下面的代码只是一个演示(自动矢量化对于加法来说已经足够了)。

struct FA{
    float c[4];
};

inline constexpr FA add(FA a, FA b){
    FA result{};
    #pragma omp simd            // clang error: statement not allowed in constexpr function
    for(int i = 0; i < 4; i++){ // GCC error: uninitialized variable 'i' in 'constexpr' function
        result.c[i] = b.c[i] + a.c[i];
    }
    return result;
}
struct FA2{
    __m128 c;
};


inline constexpr FA2 add2(FA2 a, FA2 b){
        FA2 result{};
        result.c = _mm_add_ps(a.c,b.c); // GCC error: call to non-'constexpr' function '__m128 _mm_add_ps(__m128, __m128)'
        return result;                  // fine with clang
}


无论如何,我必须提供引用 C++ 代码以实现可移植性。有没有一种代码有效的方法让编译器在编译时使用引用代码?
f(){
    if(){
        // constexpr version
    }else{
        // intrinsic version
    }
}
它应该适用于所有支持 omp、内部函数和 C++20 的编译器。

最佳答案

使用 std::is_constant_evaluated ,你可以得到你想要的:

#include <type_traits>

struct FA{
    float c[4];
};

// Just for the sake of the example. Makes for nice-looking assembly.
extern FA add_parallel(FA a, FA b);

constexpr FA add(FA a, FA b) {
    if (std::is_constant_evaluated()) {
        // do it in a constexpr-friendly manner
        FA result{};
        for(int i = 0; i < 4; i++) {
            result.c[i] = b.c[i] + a.c[i];
        }
        return result;
    } else {
        // can be anything that's not constexpr-friendly.
        return add_parallel(a, b);
    }
}

constexpr FA at_compile_time = add(FA{1,2,3,4}, FA{5,6,7,8});

FA at_runtime(FA a) {
    return add(a, at_compile_time);
}
见godbolt:https://gcc.godbolt.org/z/szhWKs3ec

关于c++ - 如何结合 constexpr 和矢量化代码?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67726812/

相关文章:

c - 使程序在按下某个键时发出状态报告

cygwin - 如何在 Cygwin 下使 OpenMP 与 MinGW-64 一起工作?

c++ - 具有模板模板参数的模板定义中的函数特化

c++: '{' 标记之前的预期类名

c++ - 实时操作系统 : windows ce : Real mode and protected mode memory accessibility overhead

c++ - 我怎样才能 std::sqrt(boost::lambda::placeholder1_type)?

c++ - OpenMP 中的预分配私有(private) std::vector 在 C++ 中并行化 for 循环

c++ - 为什么我不能在函数中使用 constexpr 值,但我可以在这个值的范围内做同样的事情?

c++ - 编译时将树转换为元组

c++ - 在 constexpr-if 条件下比较 constexpr 函数参数导致错误