Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Gcc 在内联asm中使用特定的zmm寄存器_Gcc_Assembly_X86_Inline Assembly - Fatal编程技术网

Gcc 在内联asm中使用特定的zmm寄存器

Gcc 在内联asm中使用特定的zmm寄存器,gcc,assembly,x86,inline-assembly,Gcc,Assembly,X86,Inline Assembly,我能告诉你如何将我的\uuuum512i变量放入一个特定的zmm寄存器中,比如zmm31?像在根本没有特定寄存器约束的目标(比如ARM)上一样,使用广泛的约束为asm语句选择一个特定的寄存器。编译器仍然可以以其他方式进行优化,因为本地寄存器的唯一有文件保证的效果是用于asm输入/输出 即使没有asm,编译器也会选择指定的寄存器。(因此,您可以编写看似有效但通常不安全的代码,比如register int ebx asm(“ebx”);return ebx;。GCC文档是行为保证/未来证明的基础,即

我能告诉你如何将我的
\uuuum512i
变量放入一个特定的
zmm
寄存器中,比如
zmm31

像在根本没有特定寄存器约束的目标(比如ARM)上一样,使用广泛的约束为
asm
语句选择一个特定的寄存器。编译器仍然可以以其他方式进行优化,因为本地寄存器的唯一有文件保证的效果是用于
asm
输入/输出

即使没有
asm
,编译器也会选择指定的寄存器。(因此,您可以编写看似有效但通常不安全的代码,比如
register int ebx asm(“ebx”);return ebx;
。GCC文档是行为保证/未来证明的基础,即使当前GCC更喜欢使用指定的寄存器,以至于在约束与指定寄存器不兼容时浪费指令,请参见下文。)

无论如何,寄存器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;
}
和gcc8.2:

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

注意允许任何EVEX向量寄存器(0..31)的
“v”
约束,与只允许前16个的
“x”
不同<代码>“x”被记录为“任何SSE寄存器”,但也适用于AVX YMM寄存器

为此使用
“x”
不会导致任何警告,但使用gcc
“x”
会与寄存器变量声明相对,因此它选择了%zmm2和%zmm1(奇怪的是,这不是
zmm0
,因此需要额外移动)。因此,注册asm声明确实降低了我们的效率

对于clang,它仍然使用zmm31和zmm30,显然违反了
“x”
约束,因此如果在寄存器操作数的XMM或YMM部分使用没有EVEX版本的指令,例如AVX2(比较到向量,而不是比较到掩码),它将无法汇编。()

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


你支持他们吗?你确定你需要吗?显然,您希望确保它不会将值放在asm中要使用的其他zmm寄存器中,但这些寄存器可能会被破坏,gcc已经不会将值放在那里了。如果局部变量寄存器不起作用,我想您可以删除除zmm31之外的所有zmm寄存器。虽然输入+输出参数的数量是有限制的,但我不知道碰撞的数量有任何限制(这并不意味着没有一个…。@MichaelPetch:我只是尝试了一下:<代码>寄存器uum512i z31 asm(“zmm31”)与clang一起工作,但gcc似乎有一个缺陷,使其暂时使用zmm31,但随后将输入放在实际
asm
语句的不同寄存器中。@PeterCordes您需要使用“v”约束。“x”约束只允许前16个SIMD寄存器。@RossRidge:谢谢,这就是我所缺少的。在“新”asm文档中添加“此功能唯一支持的用途是在调用扩展asm时为输入和输出操作数指定寄存器”时,有些犹豫。我在这里的措辞是故意挑衅性的(只有?!?),目的是抽掉任何其他受支持的用法,以便我可以记录它们或提供它们作为示例。最终,人们承认根本没有任何潜在的bug,而且有一整类潜在的bug被明确无误地描述为不受支持。不会阻止人们尝试,但当它不起作用时,有一个(可链接的)线索来解释原因。
# gcc -O3 -march=skylake-avx512
foo():
    movl    $123, %eax
    vpbroadcastd    %eax, %zmm31
    vmovdqa64 %zmm31, %zmm30  # from inline asm
    vmovdqa64       %zmm30, %zmm0
    ret
//#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
<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
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