- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
大多数 C++ 编译器支持 SIMD(SSE/AVX) 指令,其内部结构如
_mm_cmpeq_epi32
我的问题是这个函数没有被标记为constexpr
,虽然“语义上”没有理由让这个函数不是constexpr
,因为它是一个纯函数。
有什么方法可以编写我自己的(例如)_mm_cmpeq_epi32
版本,即 constexpr
?
显然我希望该函数在运行时使用适当的 asm,我知道我可以使用 constexpr
的慢函数重新实现任何 SIMD 函数。
如果您想知道我为什么关心 SIMD 函数的 constexpr
。非 constexprness 具有传染性,这意味着我的任何使用这些 SIMD 函数的函数都不能是 constexpr
。
最佳答案
很遗憾,Intel 的内在函数未定义为 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
}
See it on the Godbolt compiler explorer ,有两个测试调用者(一个有变量,一个有constexpr __m128i v1 {0x100000000, 0x300000002};
输入)。有趣的是,ICC 不通过pcmpeqd
或_mm_cmpeq_epi32
进行持续传播;它加载两个常量并使用和实际 pcmpeqd
,即使启用了优化。使用/不使用 constexpr 都会发生同样的事情。我认为它通常会优化
gcc 接受constexpr __m128i vector_const { pcmpeqd(__m128i{0,0}, __m128i{-1,-1}) };
GCC(但不是 clang)将 __builtin_ia32
函数视为 constexpr
兼容。 documentation for GNU C x86 built-in functions没有提到这一点,但可能只是因为它是 C 文档,而不是 C++。
GNU C native vector 语法也是 constexpr
兼容的;这是第二个选项,只有在您不关心 MSVC 时才可行。
GNU C 将 __m128i
定义为两个 long long
元素的 vector 。所以对于整型SIMD,需要定义其他类型(或者使用gcc/clang/ICC的immintrin.h
(唯一奇怪的是 static const __m128i foo = _mm_set1_epi32(2);
不会变成常量初始值设定项;它在运行时从 .rodata
复制,因此很糟糕,使用在每次函数调用时检查变量以查看变量是否需要静态初始化的保护变量。)
GCC 的 xmmintrin.h
和 emmintrin.h
根据 native vector 运算符(如 *
)或 __builtin_ia32 定义英特尔内部函数
功能。看起来他们更喜欢尽可能使用运算符,而不是 (__m128i)__builtin_ia32_pcmpeqd128((v4si)a, (v4si)b);
gcc 确实需要在不同 vector 类型之间进行显式转换。
来自 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
有趣的是:如果在禁用优化的情况下编译,gcc 的头文件在某些情况下会避免使用内联函数。我想这会导致更好的调试符号,所以你不会单步进入内联函数的定义(当在 GDB 中使用 stepi
优化代码并显示 TUI 源窗口时确实会发生这种情况。 )
关于c++ - Constexpr 和 SSE 内在函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51880079/
C语言sscanf()函数:从字符串中读取指定格式的数据 头文件: ?
最近,我有一个关于工作预评估的问题,即使查询了每个功能的工作原理,我也不知道如何解决。这是一个伪代码。 下面是一个名为foo()的函数,该函数将被传递一个值并返回一个值。如果将以下值传递给foo函数,
CStr 函数 返回表达式,该表达式已被转换为 String 子类型的 Variant。 CStr(expression) expression 参数是任意有效的表达式。 说明 通常,可以
CSng 函数 返回表达式,该表达式已被转换为 Single 子类型的 Variant。 CSng(expression) expression 参数是任意有效的表达式。 说明 通常,可
CreateObject 函数 创建并返回对 Automation 对象的引用。 CreateObject(servername.typename [, location]) 参数 serv
Cos 函数 返回某个角的余弦值。 Cos(number) number 参数可以是任何将某个角表示为弧度的有效数值表达式。 说明 Cos 函数取某个角并返回直角三角形两边的比值。此比值是
CLng 函数 返回表达式,此表达式已被转换为 Long 子类型的 Variant。 CLng(expression) expression 参数是任意有效的表达式。 说明 通常,您可以使
CInt 函数 返回表达式,此表达式已被转换为 Integer 子类型的 Variant。 CInt(expression) expression 参数是任意有效的表达式。 说明 通常,可
Chr 函数 返回与指定的 ANSI 字符代码相对应的字符。 Chr(charcode) charcode 参数是可以标识字符的数字。 说明 从 0 到 31 的数字表示标准的不可打印的
CDbl 函数 返回表达式,此表达式已被转换为 Double 子类型的 Variant。 CDbl(expression) expression 参数是任意有效的表达式。 说明 通常,您可
CDate 函数 返回表达式,此表达式已被转换为 Date 子类型的 Variant。 CDate(date) date 参数是任意有效的日期表达式。 说明 IsDate 函数用于判断 d
CCur 函数 返回表达式,此表达式已被转换为 Currency 子类型的 Variant。 CCur(expression) expression 参数是任意有效的表达式。 说明 通常,
CByte 函数 返回表达式,此表达式已被转换为 Byte 子类型的 Variant。 CByte(expression) expression 参数是任意有效的表达式。 说明 通常,可以
CBool 函数 返回表达式,此表达式已转换为 Boolean 子类型的 Variant。 CBool(expression) expression 是任意有效的表达式。 说明 如果 ex
Atn 函数 返回数值的反正切值。 Atn(number) number 参数可以是任意有效的数值表达式。 说明 Atn 函数计算直角三角形两个边的比值 (number) 并返回对应角的弧
Asc 函数 返回与字符串的第一个字母对应的 ANSI 字符代码。 Asc(string) string 参数是任意有效的字符串表达式。如果 string 参数未包含字符,则将发生运行时错误。
Array 函数 返回包含数组的 Variant。 Array(arglist) arglist 参数是赋给包含在 Variant 中的数组元素的值的列表(用逗号分隔)。如果没有指定此参数,则
Abs 函数 返回数字的绝对值。 Abs(number) number 参数可以是任意有效的数值表达式。如果 number 包含 Null,则返回 Null;如果是未初始化变量,则返回 0。
FormatPercent 函数 返回表达式,此表达式已被格式化为尾随有 % 符号的百分比(乘以 100 )。 FormatPercent(expression[,NumDigitsAfterD
FormatNumber 函数 返回表达式,此表达式已被格式化为数值。 FormatNumber( expression [,NumDigitsAfterDecimal [,Inc
我是一名优秀的程序员,十分优秀!