【问题标题】:Where to initialize SSE constants在哪里初始化 SSE 常量
【发布时间】:2013-10-10 16:30:31
【问题描述】:

我的问题是关于在基于内部函数的代码中定义 __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 上进行最大优化的编译。

【问题讨论】:

    标签: c++ constants sse simd


    【解决方案1】:

    选项 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);
            // ...
        }
    }
    

    【讨论】:

    • 谢谢,我希望你能回答这个问题 :) 在这种情况下可移植性不是问题。如果我理解正确,将常量传递给函数比在标头或类中初始化它更有效(或 as 有效)?
    • 好吧,这种事情并不能保证,同一编译器的不同版本或不同的编译器选项可能会导致不同的行为。我认为选项 A 或 B 应该没问题,尽管我更喜欢 A,但我的选择可能是更安全的选择,因为常量通常会在循环之前生成一次,并保存在寄存器中。与往常一样,分析您的代码!
    • 如何处理C 中的SIMD 常量?虽然在C++ 中可以使用static __m128 const a = _mm_set1_ps(12102203.2f); 并在代码中使用a,但在C 中应该怎么做?
    • @PaulR,我尝试在stackoverflow.com/questions/52139380 上更好地解释自己。
    猜你喜欢
    • 2011-02-06
    • 2023-01-20
    • 2014-04-27
    • 2015-06-27
    • 1970-01-01
    • 1970-01-01
    • 2023-02-04
    • 2011-05-29
    • 1970-01-01
    相关资源
    最近更新 更多