使用条件标志作为 GNU C 内联 asm 输出

Using condition flags as GNU C inline asm outputs

我正在编写一些代码,非常希望从内联 asm 块中获取条件标志输出并将其用作在调用 C 代码中分支的条件。我不想 store 标志(那将是无用且低效的;已经有更有效的方法来实现结果)而是直接使用标志。有没有办法用 GNU C 内联汇编约束来实现这一点?我对适用于多指令集架构的方法很感兴趣,目的是将其与架构的 LL/SC 样式原子生成的条件标志一起使用。当然,另一个明显的用例(与我正在做的不同)是允许外部 C 代码根据内联 asm 中操作的进位标志的结果进行分支。

我有一个部分解决方案,但我不太喜欢它,因为它需要将分支指令放在 asm 中,并且因为它需要其他 "GNU C compatible" 编译器可能不支持的非常丑陋的 GCC 功能:asm goto。但是,它确实允许消除 asm 之外的分支。思路是:

static inline int foo(...)
{
    __asm__ goto ( " .... ; cond_jmp %l[ret0]" : : "r"(...) ... 
                   : "clobbers" : ret0 );
    return 1;
ret0:
    return 0;
}

当内联到执行 if (foo(...)) ... else ... 的调用程序中时,asm 块中的条件跳转最终直接指向 else 分支,即使在抽象机级别存在 return 涉及值。

不幸的是,GCC 不支持在 asm 语句之外访问条件标志。如果您不想设置值,则必须将条件分支移动到 asm 语句中。这意味着要么使用您已经发现的 asm goto labels,要么将分支目标带入您的 asm 语句。

您可能还想检查 GCC 的旧式 __sync atomic builtins or the newer memory model based atomics 是否提供了您使用的原子指令所需的功能。

从 x86 上的 GCC6 开始,您实际上可以使用 "=@ccCOND" 作为输出(其中 COND 是任何有效的 x86 条件代码)。

示例 originally from here,根据 David 的建议进行了清理:

int variable_test_bit(long n, volatile const unsigned long *addr)
{
    int oldbit;
    asm volatile("bt %[value],%[bit]"
                 : "=@ccc" (oldbit)
                 : [value] "m" (*addr), [bit] "Jr" (n));
    return oldbit;
}

在使用这个之前,你应该测试是否定义了__GCC_ASM_FLAG_OUTPUTS__

Documentation at https://gcc.gnu.org.