13

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

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

生成的代码似乎为参数选择了一个内存约束3,如果我们被寄存器饿死,这会很好,以避免溢出。显然,x86-64 上的注册压力比 IA32 上要小。但是,生成的程序集片段(由clang)是:

    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),它应该评估每个替代方案的成本,并选择导致较少复制的那个。这似乎可行,但 clang 只是选择了第一个- 如下所示:"m,r" (y)


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

4

1 回答 1

12

我从其中一位开发人员那里得到了对 cfe-dev(clang 前端开发人员列表)的回复:

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

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


由于这不是错误,我将继续使用"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。

于 2013-06-06T05:17:22.440 回答