问题 clang(LLVM)内联汇编 - 多个约束,无用的溢出/重新加载


clang / gcc :一些内联汇编操作数可以满足多个约束,例如, "rm",当操作数可以满足寄存器或存储器位置时。例如,64 x 64 = 128位乘法:

__asm__ ("mulq %q3" : "=a" (rl), "=d" (rh) : "%0" (x), "rm" (y) : "cc")

生成的代码似乎为参数选择内存约束 3如果我们注册饥饿,这将是好的,以避免泄漏。显然,x86-64的注册压力要小于IA32。但是,生成的程序集片段(由 )是:

    movq    %rcx, -8(%rbp)
    ## InlineAsm Start
    mulq -8(%rbp)
    ## InlineAsm End

选择内存约束显然毫无意义!将约束更改为: "r" (y)但是(强制注册)我们得到:

    ## InlineAsm Start
    mulq %rcx
    ## InlineAsm End

正如所料。这些结果适用于clang / LLVM 3.2(当前Xcode版本)。第一个问题: 为什么clang会在这种情况下选择效率较低的约束?

其次,使用较少,逗号分隔, 多种替代约束 句法:
"r,m" (y), 哪一个 应该 评估每种替代方案的成本,并选择导致复制较少的方法。这似乎工作, 但是铿锵只选择了第一个  - 如下所示: "m,r" (y)


我可以简单地放弃 "m" 替代约束,但这并不表示可能的合法操作数的范围。这让我想到第二个问题: 这些问题是否已在3.3中得到解决或至少得到承认? 我试过查看LLVM开发档案,但我宁愿在不必要地进一步限制约束或加入项目讨论等之前征求一些答案。


11911
2018-05-31 05:25


起源

启用优化会产生影响吗? - bames53
@ bames53 - 一点也不。 -O0 .. -O3 都产生相同的扩张。 - Brett Hale
答案的最佳选择可能是报告llvm bug跟踪器中的错误。 - Stephen Canon


答案:


我对此有回应 CFE-dev的 (clang前端开发人员名单)来自其中一位开发人员:

LLVM目前总是溢出“rm”约束以简化   在后端处理内联asm(如果需要,可以在llvmdev上询问   细节)。我不知道有什么计划在不久的将来解决这个问题。

所以这显然是一个“已知”的问题。 clang的目标之一是正确处理gcc的内联汇编语法,以及其他扩展,在这种情况下它也是如此 - 只是效率不高。简而言之,这本身并不是一个错误。


由于这不是一个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语法不兼容,因此必须被视为错误。

如果性能至关重要,请使用 "r",否则,坚持 "rm" 也许clang将在未来解决这个问题,即使它有利于GCC。


9
2018-06-06 05:17