【发布时间】:2023-12-21 16:18:01
【问题描述】:
使用 SSE 内在函数时,通常需要零向量。避免在函数被调用时(每次有效地调用一些异或向量指令)在函数内部创建零变量的一种方法是使用静态局部变量,如
static inline __m128i negate(__m128i a)
{
static __m128i zero = __mm_setzero_si128();
return _mm_sub_epi16(zero, a);
}
似乎该变量仅在第一次调用该函数时才被初始化。 (我通过调用一个真正的函数而不是 _mm_setzero_si128() 内在函数来检查这一点。顺便说一句,这似乎只能在 C++ 中实现,而不是在 C 语言中。)
(1) 然而,一旦这个初始化发生:这是否会为程序的其余部分阻塞一个 xmm 寄存器?
(2) 更糟糕的是:如果在多个函数中使用这样的静态局部变量,会不会阻塞多个xmm寄存器?
(3) 反过来:如果它不阻塞了一个xmm寄存器,当函数被调用时,零变量是否总是从内存中重新加载?那么静态局部变量将毫无意义,因为使用 _mm_setzero_si128() 会更快。
作为替代方案,我正在考虑将零放入将在程序启动时初始化的全局静态变量:
static __m128i zero = _mm_setzero_si128();
(4) 程序运行时全局变量是否会保留在 xmm 寄存器中?
非常感谢您的帮助!
(因为这也适用于 AVX 内在函数,所以我还添加了 AVX 标签。)
【问题讨论】:
-
1 和 2,用 16 个静态变量创建 16 个函数,看看是否编译和运行。 4、创建16个全局变量,看是否编译运行。 3 受编译器优化的影响。 (顺便说一句,您正在进行微优化,因为在当前处理器上将寄存器归零基本上是免费的)
-
如果你广播一个非零值,你的问题会更有趣,例如
_mm_set1_epi32(-1). -
原来
-1也很特别。所以广播除了0和-1之外的任何东西都会很有趣。例如_mm_set1_epi32(1). -
感谢@Zboson,提供两个有用的链接。关于您的最后一条评论:为什么 -1 也很特别?另外,我查看了广播操作(至少对于 -mssse3 而言),它们似乎非常昂贵(编译成两条指令,其中一条是向量随机播放)。