初始化 SSE 常量的位置

Where to initialize SSE constants

本文关键字:位置 常量 SSE 初始化      更新时间:2023-10-16

我的问题是关于在基于内部函数的代码中定义__m128/__m128i编译时间常量的最有效位置。

考虑两个选项:

选项 A

__m128i Foo::DoMasking(const __m128i value) const
{
    //defined in method
    const __m128i mask = _mm_set1_epi32(0x00FF0000);
    return _mm_and_si128(value, mask);
}

选项 B

//Foo.h
const __m128i mask = _mm_set1_epi32(0x00FF0000);
//Foo.cpp
__m128i Foo::DoMasking(const __m128i value) const
{
    return _mm_and_si128(value, mask);
}
    选项
  • A 是否会导致性能损失,或者是否会将其优化为与选项 B 等效?
  • 有没有更好的选项C
  • 答案是否会根据方法是否内联而更改?
  • _mm_set1_epi32/__mm_set_epi32是加载常量的最佳方式吗?我见过一些生成int[4]并将其投射到__m128i的问题。

我知道所有这些问题的适当答案是"检查拆卸!">,但我在生成和解释它方面缺乏经验。

我正在以最大的优化在 MSVC 上进行编译。

选项 A 可能没问题 - 编译器在内联此函数时应该做正确的事情,并且应该将掩码常量从任何循环中提升出来,但根据我的经验,最安全的选择,特别是如果您希望它跨多个平台/编译器可靠地工作,是将其重构为稍微不那么优雅但可能更有效的形式:

__m128i Foo::DoMasking(const __m128i value, const __m128i mask) const
{
    return _mm_and_si128(value, mask);
}
void Foo::DoLotsOfMasking(...)
{
    const __m128i mask = _mm_set1_epi32(0x00FF0000);
    for (int i = 0; ...; ...)
    {
        // ...
        v[i] = DoMasking(x[i], mask);
        // ...
    }
}