使用条件标志作为 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__
。
我正在编写一些代码,非常希望从内联 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__
。