_mm_movelh_ps 的 AVX 等价物
AVX equivalent for _mm_movelh_ps
因为 _mm_movelh_ps
没有 AVX 版本,所以我通常使用 _mm256_shuffle_ps(a, b, 0x44)
作为 AVX 寄存器的替代品。但是,我记得在其他问题中读过,如果可能的话,应该首选没有控制整数的调配指令(如 _mm256_unpacklo_ps
或 _mm_movelh_ps
)(出于某种我不知道的原因)。昨天,我想到另一种选择可能是使用以下内容:
_mm256_castpd_ps(_mm256_unpacklo_pd(_mm256_castps_pd(a), _mm256_castps_pd(b)));
由于强制转换应该是无操作的,这 better\equal\worse 比使用 _mm256_shuffle_ps
性能更好吗?
此外,如果确实如此,如果有人能用简单的语言解释(我对汇编和微体系结构的理解非常有限)为什么人们应该更喜欢没有控制整数的指令,那就太好了。
提前致谢
补充说明:
Clang 实际上将 shuffle 优化为 vunpcklpd
: https://godbolt.org/z/9XFP8D
所以看来我的想法还不错。但是,GCC 和 ICC 创建了随机播放指令。
避免立即数节省 1 个字节的机器代码大小;就这样。出于性能方面的考虑,它位于列表的底部,但由于这个原因,所有其他类似 _mm256_unpacklo_pd
和隐式 "control" 的随机播放都比直接控制字节好一点。
(但是将控制操作数放在另一个向量中,如 vpermilps
can 或 vpermd
requires 通常更糟,除非你在 long-运行 中有一些奇怪的前端瓶颈ning 循环,并可以在循环外加载 shuffle 控件。不太合理,此时你必须在 asm 中手工编写才能关心代码 size/alignment;在 C++ 中,这仍然不是什么真的可以直接控制。)
Since the casts are supposed to be no-ops, is this better\equal\worse than using _mm256_shuffle_ps
regarding performance?
Ice Lake 有 2/clock vshufps
vs. 1/clock vunpcklpd
,根据 uops.info 在真实硬件上的测试, 运行在端口 1 或端口 5 上连接。绝对使用 _mm256_shuffle_ps
。微不足道的额外代码大小成本实际上可能根本不会对早期的 CPU 造成任何伤害,并且对于 ICL 的未来利益来说可能是值得的,除非您确定端口 5 不会成为瓶颈。
Ice Lake 在端口 1 上有一个第二个洗牌单元,可以处理一些常见的 XMM 和通道内 YMM 洗牌,包括 vpshufb
和显然一些像 vshufps
这样的 2 输入洗牌。我不知道为什么它不只是使用该控制向量将 vunpcklpd
解码为 vshufps
,或者设法 运行 在端口 1 上随机播放。我们知道随机播放硬件本身可以进行随机播放,所以我想这只是控制硬件的问题来设置隐式随机播放,以某种方式将操作码映射到随机播放控件。
除此之外,它在较旧的 AVX CPU 上相同或更好;没有 CPU 会因在其他 PS 指令之间使用 PD 随机播放而受到惩罚。任何现有 CPU 的唯一不同是代码大小。 K8 和 Core 2 等旧 CPU 的 pd
洗牌速度比 ps
快,但没有带有 AVX 的 CPU 具有具有该弱点的洗牌单元。此外,AVX 非破坏性指令级别差异,其中操作数必须是目标。
正如您从 Godbolt link 中看到的那样,随机播放的额外指令为零 before/after。 "cast" 内在函数不进行转换,只是重新解释以使 C++ 类型系统满意,因为英特尔决定为 __m256
与 __m256d
(与 __m256i
提供单独的类型),而不是拥有一种通用的 YMM 类型。不过,他们选择不像 ARM 那样使用单独的 uint8x16
与 uint32x4
向量;对于整数 SIMD 只是 __m256i
.
所以编译器不需要为强制转换发出额外的指令,在实践中确实如此;他们不会引入额外的 vmovaps
/apd
注册副本或类似的东西。
如果您使用的是 clang,您可以方便地编写它,让 clang 的 shuffle 优化器为您发出 vunpcklpd
。或者在其他情况下,无论如何都要做任何事情;有时它做出的选择比来源更糟糕,但通常它做得很好。
Clang 用 -march=icelake-client
搞错了,即使你写 _mm256_shuffle_ps
仍然使用 vunpcklpd
。 (或者根据周围的代码,可能会将洗牌优化为其他内容的一部分。)
因为 _mm_movelh_ps
没有 AVX 版本,所以我通常使用 _mm256_shuffle_ps(a, b, 0x44)
作为 AVX 寄存器的替代品。但是,我记得在其他问题中读过,如果可能的话,应该首选没有控制整数的调配指令(如 _mm256_unpacklo_ps
或 _mm_movelh_ps
)(出于某种我不知道的原因)。昨天,我想到另一种选择可能是使用以下内容:
_mm256_castpd_ps(_mm256_unpacklo_pd(_mm256_castps_pd(a), _mm256_castps_pd(b)));
由于强制转换应该是无操作的,这 better\equal\worse 比使用 _mm256_shuffle_ps
性能更好吗?
此外,如果确实如此,如果有人能用简单的语言解释(我对汇编和微体系结构的理解非常有限)为什么人们应该更喜欢没有控制整数的指令,那就太好了。
提前致谢
补充说明:
Clang 实际上将 shuffle 优化为 vunpcklpd
: https://godbolt.org/z/9XFP8D
所以看来我的想法还不错。但是,GCC 和 ICC 创建了随机播放指令。
避免立即数节省 1 个字节的机器代码大小;就这样。出于性能方面的考虑,它位于列表的底部,但由于这个原因,所有其他类似 _mm256_unpacklo_pd
和隐式 "control" 的随机播放都比直接控制字节好一点。
(但是将控制操作数放在另一个向量中,如 vpermilps
can 或 vpermd
requires 通常更糟,除非你在 long-运行 中有一些奇怪的前端瓶颈ning 循环,并可以在循环外加载 shuffle 控件。不太合理,此时你必须在 asm 中手工编写才能关心代码 size/alignment;在 C++ 中,这仍然不是什么真的可以直接控制。)
Since the casts are supposed to be no-ops, is this better\equal\worse than using
_mm256_shuffle_ps
regarding performance?
Ice Lake 有 2/clock vshufps
vs. 1/clock vunpcklpd
,根据 uops.info 在真实硬件上的测试, 运行在端口 1 或端口 5 上连接。绝对使用 _mm256_shuffle_ps
。微不足道的额外代码大小成本实际上可能根本不会对早期的 CPU 造成任何伤害,并且对于 ICL 的未来利益来说可能是值得的,除非您确定端口 5 不会成为瓶颈。
Ice Lake 在端口 1 上有一个第二个洗牌单元,可以处理一些常见的 XMM 和通道内 YMM 洗牌,包括 vpshufb
和显然一些像 vshufps
这样的 2 输入洗牌。我不知道为什么它不只是使用该控制向量将 vunpcklpd
解码为 vshufps
,或者设法 运行 在端口 1 上随机播放。我们知道随机播放硬件本身可以进行随机播放,所以我想这只是控制硬件的问题来设置隐式随机播放,以某种方式将操作码映射到随机播放控件。
除此之外,它在较旧的 AVX CPU 上相同或更好;没有 CPU 会因在其他 PS 指令之间使用 PD 随机播放而受到惩罚。任何现有 CPU 的唯一不同是代码大小。 K8 和 Core 2 等旧 CPU 的 pd
洗牌速度比 ps
快,但没有带有 AVX 的 CPU 具有具有该弱点的洗牌单元。此外,AVX 非破坏性指令级别差异,其中操作数必须是目标。
正如您从 Godbolt link 中看到的那样,随机播放的额外指令为零 before/after。 "cast" 内在函数不进行转换,只是重新解释以使 C++ 类型系统满意,因为英特尔决定为 __m256
与 __m256d
(与 __m256i
提供单独的类型),而不是拥有一种通用的 YMM 类型。不过,他们选择不像 ARM 那样使用单独的 uint8x16
与 uint32x4
向量;对于整数 SIMD 只是 __m256i
.
所以编译器不需要为强制转换发出额外的指令,在实践中确实如此;他们不会引入额外的 vmovaps
/apd
注册副本或类似的东西。
如果您使用的是 clang,您可以方便地编写它,让 clang 的 shuffle 优化器为您发出 vunpcklpd
。或者在其他情况下,无论如何都要做任何事情;有时它做出的选择比来源更糟糕,但通常它做得很好。
Clang 用 -march=icelake-client
搞错了,即使你写 _mm256_shuffle_ps
仍然使用 vunpcklpd
。 (或者根据周围的代码,可能会将洗牌优化为其他内容的一部分。)