gpt4 book ai didi

gcc - 在内联汇编中使用特定的 zmm 寄存器

转载 作者:行者123 更新时间:2023-12-03 08:59:31 36 4
gpt4 key购买 nike

我可以告诉gcc-style inline assembly把我的__m512i变量到特定 zmm注册,如 zmm31

最佳答案

就像在根本没有特定寄存器约束的目标(如 ARM)上一样,使用 local register variables获得广泛的约束来为 asm 语句选择特定的寄存器。编译器仍然可以以其他方式进行优化,因为寄存器本地的唯一有记录的保证效果是针对asm输入/输出。

即使没有 asm,编译器也会优先指定的寄存器。 (因此,您可以使用诸如 register int ebx asm("ebx"); return ebx; 之类的内容编写看似有效但一般不安全的代码。GCC 文档是保证行为的原因/面向 future ,即使当前的 gcc 更喜欢使用指定的寄存器,当约束与指定的寄存器不兼容时,足以浪费指令,请参见下文。)

无论如何,register-asm 本地变量的使用是它们保证起作用的唯一事情:

#include <immintrin.h>
__m512i foo() {
register __m512i z31 asm("zmm31") = _mm512_set1_epi32(123);
register __m512i z30 asm("zmm30");

asm("vmovdqa64 %1, %0 # from inline asm"
: "=v"(z30)
: "v"(z31)
);
return z30;
}

关于the Godbolt compiler explorer ,使用 clang6.0 编译为:

    # clang -O3 -march=skylake-avx512
vbroadcastss .LCPI0_0(%rip), %zmm31 # zmm31 = [1.72359711E-43,1.72359711E-43,1.72359711E-43,1.72359711E-43,1.72359711E-43,1.72359711E-43,1.72359711E-43,1.72359711E-43,1.72359711E-43,1.72359711E-43,1.72359711E-43,1.72359711E-43,1.72359711E-43,1.72359711E-43,1.72359711E-43,1.72359711E-43]
vmovdqa64 %zmm31, %zmm30 # from inline asm
vmovaps %zmm30, %zmm0
retq

和gcc8.2:

# gcc -O3 -march=skylake-avx512
foo():
movl $123, %eax
vpbroadcastd %eax, %zmm31
vmovdqa64 %zmm31, %zmm30 # from inline asm
vmovdqa64 %zmm30, %zmm0
ret

注意"v"约束,它允许任何EVEX向量寄存器(0..31),与"x"不同,它只允许第一个 16. "x" 被记录为“任何 SSE 寄存器”,但也适用于 AVX YMM 寄存器。 https://gcc.gnu.org/onlinedocs/gcc/Machine-Constraints.html .

使用 "x" 不会导致任何警告,但使用 gcc "x" 会胜过寄存器变量声明,因此它选择了 % zmm2 和 %zmm1 (奇怪的是不是 zmm0 所以需要额外的移动)。因此,register-asm 声明确实降低了我们的效率。

使用 clang 时,它仍然使用 zmm31 和 zmm30,显然违反了 "x" 约束,因此如果您在 XMM 或 YMM 上使用没有 EVEX 版本的指令,它将无法汇编寄存器操作数的一部分,如 AVX2 vpcmpeqd ymm,ymm,ymm (与向量比较,而不是与掩码比较)。 (In GNU C inline asm, what're the modifiers for xmm/ymm/zmm for a single operand?)。

//#ifndef __clang__
__m512i broken_with_clang() {
register __m512i z31 asm("zmm31") = _mm512_set1_epi32(123);
register __m512i z30 asm("zmm30") = _mm512_setzero_si512();
// notice that gcc still inits these in zmm31 and 30, *then* copies
// so register asm costs us efficiency.

// AVX512 only has compares into k registers, not into YMM registers.
asm("vpcmpeqd %t1, %t0, %t0 # from inline asm. input was %0"
: "+x"(z30)
: "x"(z31)
);
return z30;
}
//#endif

使用 clang,我们会得到每个操作数的错误;我猜 clang 不支持 t 修饰符来获取寄存器的 YMM 名称(因为即使我删除 register ... asm(),clang6.0 也会失败) > 完全是东西。)

<source>:21:9: error: invalid operand in inline asm: 'vpcmpeqd ${1:t}, ${0:t}, ${0:t}  # from inline asm. input was $0'
asm("vpcmpeqd %t1, %t0, %t0 # from inline asm. input was %0"
^
...
<source>:21:9: error: unknown token in expression
<inline asm>:1:11: note: instantiated into assembly here
vpcmpeqd , , # from inline asm. input was %zmm30

但是 gcc 编译得很好:

broken_with_clang():
movl $123, %eax
vpbroadcastd %eax, %zmm31
vpxord %xmm30, %xmm30, %xmm30

vmovdqa64 %zmm30, %zmm1 # extra overhead because of register asm
vmovdqa64 %zmm31, %zmm2 # which didn't match the constraints

vpcmpeqd %ymm2, %ymm1, %ymm1 # from inline asm. input was %zmm1

vmovdqa64 %zmm1, %zmm0 # extra overhead because gcc didn't pick zmm0
ret

关于gcc - 在内联汇编中使用特定的 zmm 寄存器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52014436/

36 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com