Assembly G++;Asm内联:寄存器关闭

Assembly G++;Asm内联:寄存器关闭,assembly,g++,sse,inline-assembly,avx,Assembly,G++,Sse,Inline Assembly,Avx,如果我不在clobber列表中写入任何内容,gcc编译器是否使用push/pop进行寄存器备份?输入和输出列表寄存器会发生什么情况 我将制作一个简短的asm内联,将一些通用寄存器保存到XMM/YMM寄存器,然后在通用寄存器上播放。最后,原始值从XMM/YMM寄存器返回到通用寄存器。编译器是否会使用push/pops来保存它们 我如何告诉GCC编译器:“不要为我推/弹出任何东西,我使用XMM/YMM就是为了这个目的。也许我会自己推/弹出” 比如: __asm__ __volatile__ (

如果我不在clobber列表中写入任何内容,gcc编译器是否使用push/pop进行寄存器备份?输入和输出列表寄存器会发生什么情况

我将制作一个简短的asm内联,将一些通用寄存器保存到XMM/YMM寄存器,然后在通用寄存器上播放。最后,原始值从XMM/YMM寄存器返回到通用寄存器。编译器是否会使用push/pops来保存它们

我如何告诉GCC编译器:“不要为我推/弹出任何东西,我使用XMM/YMM就是为了这个目的。也许我会自己推/弹出”

比如:

__asm__ __volatile__ (
        ".intel_syntax noprefix \n\t"
        "movd xmm0,eax \n\t"//storing in xmm registers instead of   pushing
        "movd xmm1,ebx \n\t"
        "movd xmm2,ecx \n\t"
        "movd xmm3,edx \n\t"
        "movd xmm4,edi \n\t" // end of  backups
        //.
        //... doing work
        //.
        "movd edi,xmm4 \n\t"
        "movd edx,xmm3 \n\t"
        "movd ecx,xmm2 \n\t"
        "movd ebx,xmm1 \n\t"
        "movd eax,xmm0 \n\t" // end of pops

        ://outputs
        "=g"(x[0]),  //%0
        "=g"(x[1])   //%1
        ://inputs
        "g"(x[0]),  //%2
        "g"(x[1])   //%3
        ://no clobber list
    );
或者类似的东西(我知道这种交换非常慢,只是想让push-pops工作):


这个问题有点棘手。据我所知,编译的方式将对结果产生影响。我不确定这是否是您需要的,但如果您不使用内联汇编,您可以控制它

您在一个单独的.s文件中编写代码,并使用-O3之类的优化进行编译,gcc不会推送和保护非易失性寄存器。我自己不使用内联装配,所以我不清楚该零件。你可以自己测试:D

顺便说一句:我认为如果您编写.asm文件并使用nasm编译它并将对象与gcc链接,同样的事情也会发生。通过优化,我认为gcc不会自动执行推送/弹出操作。如果我的答复中有错误,请告诉我。谢谢

祝你好运


香槟> < /p>链接C++到java(通过JNI和G+编译器)是我的头顶(我几乎没办法),现在你告诉我链接C++和汇编就像D:好的,我会试试-O3。它起作用了!OMG-o3是一种优化,它允许我在asm内联中做任何我想做的事情。分离的

.s
文件与在内联汇编程序中嵌入相同的代码非常不同;首先,执行函数调用告诉编译器,当函数调用返回时,无法保证某些寄存器保留其值。代码可能不会假定在调用指令后保留任何XMM REG、任何参数REG(RDIRSIRDXRCXR8R9)或RAX。因此,如果你的汇编函数只使用这些函数中的任何一个,只要你有一个单独的函数,就不需要推送任何东西。你说的是我拥有的64位窗口。对于64位窗口,同样的规则适用,只有整数参数寄存器是
RDX
RCX
R8
R9
,返回值仍然是
RAX
,您仍然没有义务保留任何
XMM
regs(或者,如果您有支持AVX的CPU,
YMM
regs)。简而言之,如果你可以为你的asm代码提供一个单独的函数,你就不需要“clobber”规范/不必担心保存/恢复注册表,只要你可以限制自己只使用上述五个(Windows)响应。七个(UN*X)通用正则表达式,加上任何向量正则表达式。编译器希望像普通通用正则表达式一样“拥有”XMM正则表达式。除非您告诉编译器:您的内联程序集期望XMM REG中的值作为输入/输出操作数,或者:通过在clobber列表中显式列出您希望修改的REG,否则您不能简单地从内联程序集中使用它们。如果你这样做,那么你就没有必要自己推/
pop
。如果(且仅当)编译器选择将任何变量放入您声明要修改的某个寄存器中,编译器将在内联asm语句之前/之后自动插入此类代码。好的,我是否将它们显示为“YMM0”、“YMM16”?保存/恢复寄存器的开销是否可能小于JNI调用的开销?是的,理论上可以在clobber列表中列出所有向量寄存器。但这是浪费而且可能是不必要的。。。这取决于您的具体用例,是内联汇编程序还是完全独立的函数都是用汇编程序编写的更好。构造的人工测试用例可以为以下两种情况找到。。。我需要更多地了解你试图解决的真正问题。我感觉到一种误解。。。GCC内联程序集与MSVC非常不同。在后一种情况下(没有64位),编译器在内联汇编块之前/之后对“C程序状态”的保存/恢复“不做任何事情”。有了MSVC
\u asm:
您必须使用
推送
/
弹出
进行您计划使用的regs。gcc内联asm的情况并非如此;如果您的asm使用的REG数不超过您的输入/输出数,那么您根本不需要任何缓冲列表。您可以使用“temp”变量作为“获取注册表”的输入。只有当您必须通过名称显式使用寄存器时,才必须将其列为clobbered。还请注意,至少在UNX上,如果您从内联程序块中推送,您将破坏ABI。这是因为64位x86 UNX上的叶函数允许使用
-128(%rsp)。。。(%rsp)
无需显式调整堆栈指针(所谓的红色区域),并且如果从叶函数中
推送
,则可以删除
asm()
所在函数的局部变量。同样,也不能从内联程序集块中调用
__asm__ __volatile__ (
        ".intel_syntax noprefix \n\t"
        "push rax \n\t"
        "push rbx \n\t"
        "push rcx \n\t"
        "push rdx \n\t"

        "mov eax,%2 \n\t"
        "mov ecx,%3 \n\t"
        "mov edx,eax \n\t"
        "mov eax,ecx \n\t"
        "mov ecx,edx \n\t"
        "mov %0,eax \n\t"
        "mov %1,ecx \n\t"

        "pop rdx \n\t"
        "pop rcx \n\t"
        "pop rbx \n\t"
        "pop rax \n\t"

        ://outputs
        "=g"(x[0]),  //%0
        "=g"(x[1])   //%1
        ://inputs
        "g"(x[0]),  //%2
        "g"(x[1])   //%3
        ://no clobber list
    );