NoS*_*tAl 9 c++ sse simd intrinsics constexpr
大多数C++编译器都支持SIMD(SSE/AVX)指令
_mm_cmpeq_epi32
Run Code Online (Sandbox Code Playgroud)
我的问题是这个函数没有标记为constexpr,虽然"语义上"没有理由不使用这个函数,constexpr因为它是一个纯函数.
有什么办法,我可以写我自己的版本(例如)_mm_cmpeq_epi32是constexpr?
显然我希望运行时的函数使用正确的asm,我知道我可以重新实现具有慢速函数的任何SIMD函数constexpr.
如果你想知道为什么我关心constexprSIMD功能.非constexprness具有传染性,这意味着我的任何使用SIMD功能的功能都不可能constexpr.
不幸的是,英特尔的内在函数没有定义为constexpr.
他们没有理由不能;编译器可以并且确实在编译时评估它们以进行常量传播和其他优化。(这是为什么内置函数/内在函数比单指令的内联 asm 包装器更好的主要原因之一。)
ICC 会编译它,但当您尝试将它用作constexpr __m128i.
constexpr
__m128i pcmpeqd(__m128i a, __m128i b) {
return (v4si)a == (v4si)b; // fine with gcc and ICC
//return (__m128i)__builtin_ia32_pcmpeqd128((v4si)a, (v4si)b); // bad with ICC
//return _mm_cmpeq_epi32(a,b); // not constexpr-compatible
}
Run Code Online (Sandbox Code Playgroud)
在 Godbolt 编译器资源管理器上查看它,有两个测试调用程序(一个带有变量,一个带有
constexpr __m128i v1 {0x100000000, 0x300000002};输入)。有趣的是,ICC不pcmpeqd通过or进行持续传播_mm_cmpeq_epi32;它加载两个常量并使用 和actualpcmpeqd,即使启用了优化。使用/不使用 constexpr 都会发生同样的事情。我认为它通常会优化
gcc 确实接受
constexpr __m128i vector_const { pcmpeqd(__m128i{0,0}, __m128i{-1,-1}) };
GCC(但不是 clang)将__builtin_ia32函数视为constexpr兼容的。GNU C x86 内置函数的文档 没有提到这一点,但可能只是因为它是 C 文档,而不是 C++。
GNU C 原生向量语法也是constexpr兼容的;这是第二种选择,只有当您不关心 MSVC 时才可行。
GNU C 定义__m128i为两个元素的向量long long。所以对于整数SIMD,你需要定义其他类型(或者使用gcc/clang/ICC的定义的类型)immintrin.h
(唯一奇怪的是,它static const __m128i foo = _mm_set1_epi32(2);不会变成常量初始值设定项;它.rodata在运行时复制,因此很糟糕,使用在每个函数调用时检查该变量是否需要静态初始化的保护变量。)
GCCxmmintrin.h并emmintrin.h根据本机向量运算符(如*)或__builtin_ia32函数定义 Intel 内在函数。看起来他们更喜欢在可能的情况下使用运算符,而不是(__m128i)__builtin_ia32_pcmpeqd128((v4si)a, (v4si)b);
gcc 确实需要不同向量类型之间的显式转换。
来自 gcc7.3 emmintrin.h(SSE2):
extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm_cmpeq_epi32 (__m128i __A, __m128i __B)
{
return (__m128i) ((__v4si)__A == (__v4si)__B);
}
#ifdef __OPTIMIZE__
extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_mm_shuffle_epi32 (__m128i __A, const int __mask)
{
return (__m128i)__builtin_ia32_pshufd ((__v4si)__A, __mask);
}
#else
#define _mm_shuffle_epi32(A, N) \
((__m128i)__builtin_ia32_pshufd ((__v4si)(__m128i)(A), (int)(N)))
#endif
Run Code Online (Sandbox Code Playgroud)
有趣的是:如果在禁用优化的情况下进行编译,gcc 的标头在某些情况下会避免使用内联函数。我想这会带来更好的调试符号,因此您不必单步执行内联函数的定义(在stepi显示 TUI 源窗口的优化代码中在 GDB 中使用时确实会发生这种情况。)
| 归档时间: |
|
| 查看次数: |
721 次 |
| 最近记录: |