为啥 gcc 将 _mm256_permute2f128_ps 编译为 Vinsertf128 指令?

Posted

技术标签:

【中文标题】为啥 gcc 将 _mm256_permute2f128_ps 编译为 Vinsertf128 指令?【英文标题】:Why gcc compile _mm256_permute2f128_ps to Vinsertf128 instruction?为什么 gcc 将 _mm256_permute2f128_ps 编译为 Vinsertf128 指令? 【发布时间】:2016-03-31 01:19:49 【问题描述】:

该指令是 C 程序 (gcc -O2) 的汇编输出的一部分。根据结果​​,我知道ymm6source operand 1,所有这些都被克隆到ymm9,然后xmm1 被克隆到ymm6[127-256] 我读到Intel manual,但它使用英特尔汇编语法而不是At&t而且我不想使用英特尔语法。所以ymm8ymm2ymm6 这里是SRC1。这是真的?

vshufps     $68,  %ymm0, %ymm8, %ymm6
vshufps     $68,  %ymm4, %ymm2, %ymm1
Vinsertf128 $1,  %xmm1, %ymm6, %ymm9

主要问题是为什么gcc 改变了指令

row0 = _mm256_permute2f128_ps(__tt0, __tt4, 0x20);

Vinsertf128 $1,  %xmm1, %ymm6, %ymm9

row4 = _mm256_permute2f128_ps(__tt0, __tt4, 0x31);

Vperm2f128  $49, %ymm1, %ymm6, %ymm1

我怎么能忽略这个优化?我试过-O0,但没有用。

【问题讨论】:

【参考方案1】:

所以这里的 ymm8、ymm2 和 ymm6 是 SRC1。这是真的吗?

是的,在这两种语法中,中间操作数始终是 3 操作数指令中的 src1。

美国电话电报公司:op %src2, %src1, %dest 英特尔:op dest, src1, src2

我不想使用 Intel 语法

艰难。我所知道的关于每条指令的确切作用的唯一真正好的文档是英特尔 insn 参考手册。我曾经认为 AT&T 语法更好,因为 $ 和 % 装饰器消除了歧义。我确实喜欢这样,但现在更喜欢英特尔语法。每个规则都非常简单,您可以轻松地在思想上转换或“思考”您正在阅读 ATM 的任何一个。

除非您实际上是在编写 GNU C 内联 asm,否则您可以使用 gcc -masm=intelobjdump -Mintel 使用英特尔助记符、操作数顺序等来获得 GNU 风格的 asm。汇编器指令仍然是 gas 风格,而不是 NASM。使用 http://gcc.godbolt.org/ 获得格式良好的 asm 输出代码,只保留基本标签。


gcc 和 clang 都对内在函数的实际作用有所了解,因此它们在内部将内在函数转换为某些数据移动。当需要发布代码时,他们发现可以使用vinsertf128 完成所述数据移动,因此他们发布了该代码。

在某些 CPU(Intel SnB 系列)上,两条指令具有相同的性能,但在 AMD Bulldozer 系列(只有 128b ALU)上,vinsertf128vperm2f128 快得多。 (来源:参见 Agner Fog 的指南,以及 x86 标签 wiki 上的其他链接)。它们都需要 6 个字节进行编码,包括立即数,因此没有代码大小差异。 vinsertf128 总是比进行相同数据移动的 vperm2f128 更好的选择。

gcc 和 clang 没有“内在函数到指令的字面翻译”模式,因为它需要额外的工作来实现。如果您确切关心编译器使用哪些指令,那就是内联 asm 的用途。

Keep in mind that -O0 doesn't mean "no optimization"。在发出 asm 之前,它仍然需要通过几个内部表示进行转换。

【讨论】:

【参考方案2】:

检查指令分析报告中绑定到端口 5 的指令显示指令为broadcastsvpermilpsbroadcasts 只能在端口 5 上执行,但是将它们替换为 128-bit 加载后跟 vinsertf128 指令可以减少端口 5 的压力,因为 vinsertf128 可以在端口 0 上执行。来自IACA user guid

【讨论】:

以上是关于为啥 gcc 将 _mm256_permute2f128_ps 编译为 Vinsertf128 指令?的主要内容,如果未能解决你的问题,请参考以下文章

在 GCC 10.3.0 中找不到 _mm256_rem_epu64 内在函数

gcc 标头错误:“_mm256_set_m128d”未在此范围内声明

如何通过英特尔 OpenCL SVML 使用 _mm256_log_ps?

AVX2 的汇编错误

正确使用 _mm256_maskload_ps 将少于 8 个浮点数加载到 __m256

将 __m256i 存储为整数