Gcc clang(LLVM)内联程序集-具有无用溢出/重新加载的多个约束
clang/gcc:当操作数可以满足寄存器或内存位置时,一些内联程序集操作数可以满足多个约束,例如Gcc clang(LLVM)内联程序集-具有无用溢出/重新加载的多个约束,gcc,assembly,clang,x86-64,inline-assembly,Gcc,Assembly,Clang,X86 64,Inline Assembly,clang/gcc:当操作数可以满足寄存器或内存位置时,一些内联程序集操作数可以满足多个约束,例如“rm”。例如,64 x 64=128位乘法: __asm__ ("mulq %q3" : "=a" (rl), "=d" (rh) : "%0" (x), "rm" (y) : "cc") 生成的代码似乎为参数3选择了一个内存约束,如果寄存器不足,这将很好,以避免溢出。显然,x86-64上的寄存器压力比IA32上的更小。但是,(通过clang生成的程序集代码段是: 选择内存约束显然毫无意义!将约
“rm”
。例如,64 x 64=128位乘法:
__asm__ ("mulq %q3" : "=a" (rl), "=d" (rh) : "%0" (x), "rm" (y) : "cc")
生成的代码似乎为参数3
选择了一个内存约束,如果寄存器不足,这将很好,以避免溢出。显然,x86-64上的寄存器压力比IA32上的更小。但是,(通过clang生成的程序集代码段是:
选择内存约束显然毫无意义!将约束更改为:“r”(y)
,但是(强制寄存器)我们得到:
正如所料。这些结果适用于clang/LLVM 3.2(当前的Xcode版本)。第一个问题:在这种情况下,为什么clang会选择效率较低的约束?
其次,还有使用较少的逗号分隔语法:“r,m”(y)
,它应该评估每个备选方案的成本,并选择一个能够减少复制的方案。这似乎是可行的,但clang只是选择了第一个——正如:“m,r”(y)
我可以简单地删除
“m”
替代约束,但这并不表示可能的合法操作数的范围。这就引出了第二个问题:这些问题是否在3.3中得到了解决或至少得到了承认?我已经尝试过查看LLVM开发文档,但我宁愿在不必要地进一步限制限制约束或加入项目讨论之前征求一些答案,等等。我已经得到了(叮当的前端开发人员列表)其中一位开发商:
LLVM当前总是溢出“rm”约束,以简化
在后端处理内联asm(如果需要,可以在llvmdev上询问
详情)。我不知道在不久的将来有什么计划来解决这个问题
因此,这显然是一个“已知”的问题。clang的目标之一是正确处理gcc的内联汇编语法,以及其他扩展,在本例中它就是这样做的——只是效率不高。简而言之,这本身不是一个bug
由于这不是一个bug,我将继续使用
“r,m”
约束语法。我认为这是目前最好的妥协gcc
将选择最好的-可能的话可能是一个寄存器-并且clang
将通过忽略逗号后的其他选项来强制使用寄存器。如果没有其他内容,它仍然保留汇编语句的语义意图,即描述可能的约束,即使它们被忽略
最后一个注释(20130715):此特定示例不会在单个位置使用
“r,m”
约束进行编译-我们必须为每个位置提供替代约束匹配,例如
: "=a,a" (rl), "=d,d" (rh) : "%0,0" (x), "r,m" (y)
这对于GCC的多个备选约束是必需的。但我们正在进入GCC过去被认为存在漏洞的领域——我不知道在4.8.1中这是否属实。Clang在没有其他约束的情况下工作,这与GCC语法不兼容,因此必须将其视为bug
如果性能至关重要,请使用
“r”
,否则,请坚持使用“rm”
,也许clang将来会解决这个问题,即使它有利于GCC。启用优化是否有效果?@bames53-根本没有<代码>-O0-O3
都会产生相同的扩展。您最好的答案可能是在llvm错误跟踪器中报告该错误。似乎确实存在一个公开的错误:
## InlineAsm Start
mulq %rcx
## InlineAsm End
: "=a,a" (rl), "=d,d" (rh) : "%0,0" (x), "r,m" (y)