【发布时间】:2019-01-23 14:13:31
【问题描述】:
大多数 C++ 编译器都支持 SIMD(SSE/AVX) 指令,如
_mm_cmpeq_epi32
我的问题是这个函数没有被标记为constexpr,尽管“语义上”没有理由让这个函数不是constexpr,因为它是一个纯函数。
有什么方法可以编写我自己的(例如)_mm_cmpeq_epi32 版本,即constexpr?
显然,我希望该函数在运行时使用正确的 asm,我知道我可以使用 constexpr 的慢速函数重新实现任何 SIMD 函数。
如果您想知道我为什么关心 constexpr 的 SIMD 函数。非 constexprness 具有传染性,这意味着我的任何使用这些 SIMD 函数的函数都不能是constexpr。
【问题讨论】:
-
对不起,你运气不好。内联汇编不能用在 constexpr 函数中,所以不能自己写。
-
在标准 C++ 中不可能,但是例如,GCC 定义了
__builtin_constant_p扩展,它允许使用像#define FOO(x) (__builtin_constant_p(x) ? foo_constexpr(x) : foo_asm(x))这样的技巧 - 如果x可以被编译器评估为常量,那么纯将使用 C++ 实现,允许进一步的内联和编译时优化。 -
编译器必须能够在编译时评估
constexpr函数。如果您的编译器不知道如何评估一些/任何/所有 SIMD 内置函数,则使用这些函数的函数不能是constexpr。请注意,在编译时评估一个函数与编译一个函数是完全不同的。您可能正在为另一个平台进行交叉编译,因此编译器甚至可能无法在编译后运行该函数以获取其值。因此,编译器需要特殊的模拟代码来模拟“普通 C++”中的函数,而这显然不存在。 -
@JimmyB:gcc 确实知道如何在编译时评估所有
__builtin_ia32函数;它可以通过它们进行持续传播,就像标量int的+运算符一样。这纯粹是 C++ 语法和事物声明方式的不幸问题。 (唯一奇怪的是static const __m128 foo = _mm_set1_ps(2.0f);没有 变成一个常量初始化器;它在运行时从.rodata复制,因此很糟糕。) -
@PeterCordes 你确定 _mm_shuffle_epi8 吗?我只是尝试给它 2 个空向量,但它没有优化任何东西。只读常量这个东西是众所周知的限制,目前它必须在前端完成,万一编译器后来意识到它实际上是一个常量。我真的希望有一天这会改变,但我不会屏住呼吸。相关:gcc.gnu.org/bugzilla/show_bug.cgi?id=65197(和 55894、80517)。
标签: c++ sse simd constexpr intrinsics