常量浮点数与SIMD

7
我一直在尝试使用微软的SSE内置函数来优化我的代码。优化代码时最大的问题之一是每当我想要使用常量时都会发生LHS。有一些关于生成特定常量的信息(这里这里 - 第13.4节),但都是汇编语言(我宁愿避免使用)。问题在于,当我尝试使用内置函数实现相同的功能时,MSVC会抱怨不兼容的类型等。是否有人知道使用内置函数的等效技巧?例如 - 生成{1.0,1.0,1.0,1.0}。
//pcmpeqw xmm0,xmm0 
__m128 t = _mm_cmpeq_epi16( t, t );

//pslld xmm0,25 
_mm_slli_epi32(t, 25);

//psrld xmm0,2
return _mm_srli_epi32(t, 2);

这会生成一堆关于不兼容类型(__m128 vs _m128i)的错误。由于我对此很陌生,所以我相信我肯定漏掉了一些明显的东西。有人能帮忙吗?
简而言之 - 我如何使用ms内部函数生成一个填充有单精度常量浮点数的__m128向量?
谢谢阅读 :)

你为什么认为你需要这样做?通常常量只会在计算循环之前加载一次,因此内存访问的相对成本是可以忽略不计的。 - Paul R
我有几个常量,它们都在一个循环中使用,不幸的是这个循环似乎已经使用了所有8个xmm寄存器。在vtune中,当一些这些常量被使用时,我得到了非常高的CPI。我想如果我能减少我正在访问的常量数量,并生成一些常量,那么可能会减少成本,因为一个常量的成本会隐藏另一个常量的成本。此外,奇怪的是,在其中一个常量上使用register关键字帮助了很多(尽管这只是导致某些其他值被推出xmm regs)。 - JBeFat
4
如果可以的话,请使用x86-64,这样您将获得16个XMM寄存器。还要注意,即使在第一次加载这些常数时出现一个或多个缓存未命中,这也应该在大量后续迭代中摊销,因为常数将随后位于L1缓存中(除非您只有很少的循环迭代次数?)。 - Paul R
请注意,一些编译器会在使用t之前生成一个pxor指令将其清零,即使您正在尝试使用未初始化的变量。根据编译器的不同,您可能更容易从_mm_set1_epi16(-1)开始,因为编译器知道如何使用pcmpge进行操作。还有_mm_undefined_si128(),专门用于此类情况,但并非所有编译器都支持它。例如,clang-3.5不支持,但clang-3.8支持。 - Peter Cordes
2个回答

5

0x1a11 251 movaps xmm6,xmmword ptr [0x414890] 0x1a18 251 xorps xmm5,xmm5 你好,感谢您抽出时间回答 :) 如您所见(格式不佳,抱歉),__mm_set_ps 对我并没有帮助,因为它仍然使用 movaps 从内存中的某个位置加载常量。我想要的是使用现有方法直接在 xmm 寄存器中生成常量。 - JBeFat
@JBeFat:你尝试过直接转换结果吗?那些技巧使用整数指令来创建浮点值,所以编译器报告类型不匹配也就不足为奇了。 - Ben Voigt
1
还要注意,由于FPU没有参与,因此__mm_set_ps没有LHS存储。 - Ben Voigt
@Damon:这里没有转换,只是为了类型检查器(仅在编译时)等效于 reinterpret_cast。 同时,适当命名的内联函数可以解决可读性问题。 - Ben Voigt
2
@Ben Voigt:是的,这就是问题所在。引用《Intel、AMD和VIA CPU的微架构》(http://www.agner.org/optimize/microarchitecture.pdf)中的内容:“XMM寄存器具有一些标记位,用于记住浮点值是正常、非正常还是零。当整数指令的输出被用作单精度或双精度浮点指令的输入时,必须设置这些标记位。这会导致所谓的重新格式化延迟。” - Damon
显示剩余3条评论

3

使用_mm_castsi128_ps将__m128i转换为__m128。同时,第二行应该是

t = _mm_slli_epi32(t, 25)

谢谢!我就觉得这应该是一些简单的东西。 - JBeFat

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接