clang(LLVM)内联汇编 - 无限溢出/重载的多个约束

Bre*_*ale 12 assembly gcc x86-64 clang inline-assembly

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

__asm__ ("mulq %q3" : "=a" (rl), "=d" (rh) : "%0" (x), "rm" (y) : "cc")
Run Code Online (Sandbox Code Playgroud)

生成的代码似乎为参数选择了一个内存约束3,如果我们注册了饥饿就可以了,以避免溢出.显然,x86-64的注册压力要小于IA32.但是,(通过clang)生成的程序集片段是:

    movq    %rcx, -8(%rbp)
    ## InlineAsm Start
    mulq -8(%rbp)
    ## InlineAsm End
Run Code Online (Sandbox Code Playgroud)

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

    ## InlineAsm Start
    mulq %rcx
    ## InlineAsm End
Run Code Online (Sandbox Code Playgroud)

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

其次,有较少广泛使用的,用逗号分隔,多个替代约束语法:
"r,m" (y),这应该评估各方案的成本,并选择导致较少拷贝的一个.这似乎有效,但是clang只选择了第一个 - 如下所示:"m,r" (y)


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

Bre*_*ale 10

我对其中一位开发人员的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)
Run Code Online (Sandbox Code Playgroud)

对于GCC的多个替代约束,这是必需的.但是我们进入的领域过去已经知道海湾合作委员会会出现虫子 - 无论是否真的如4.8.1所述,我不知道.Clang 在其他约束中没有替代方法,这与GCC语法不兼容,因此必须被视为错误.

如果性能至关重要,那么使用"r",否则,坚持"rm"并且可能会在将来解决这个问题,即使它有利于GCC.