c++ - 如何结合 constexpr 和矢量化代码?
问题描述
我正在为 x64 和 neon 开发 C++ 内在包装器。我希望我的函数是 constexpr。我的动机类似于Consexpr 和 SSE intrinsics,但编译器 (GCC) 在 constexpr 函数中可能不支持 #pragma omp simd 和 intrinsics 。以下代码只是一个演示(自动矢量化足以进行添加)。
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_evaluate,你可以得到你想要的:
#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
推荐阅读
- mongodb - 如何在 mongoDb 查询中使用多个条件?
- php - 多语言 Laravel 应用刀片导航
- android - Google Play 结算 - 检查订阅状态
- rspec - 使用 RSpec 进行测试时,如何在 Sidekiq 工作人员中正确捕获错误?
- javascript - Javascript 用其他东西替换一个值,有什么建议吗?
- elasticsearch - 字符串数组的 ElasticSearch multi_match 查询
- python - 为什么我的验证数据不能做出准确的猜测
- c - 由于此错误,无法使用 HAL 库
- r - 使用 stlplus::stlplus() 函数会出现奇怪的错误
- bash - 如何让awk打印第n列的所有内容