I'm working on some code where it would be highly desirable to take condition-flags output from an inline asm block and use that as a condition to branch on in the calling C code. I don't want to store the flags (that would be useless and inefficient; there are already more efficient ways to achieve the result) but use the flags directly. Is there any way to achieve this with GNU C inline asm constraints? I'm interested in approaches that would work for multiple instruction set architectures, with the intent of using it with the condition flags produced by the architecture's LL/SC style atomics. Of course another obvious usage case (separate from what I'm doing) would be to allow the outer C code to branch on the result of the carry flag from an operation in inline asm.
Starting with GCC6 on x86 you can actually use "=@ccCOND"
as output (where COND
is any valid x86 condition code).
Example originally from here, cleaned up by David's suggestions:
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;
}
Before using this, you should test if __GCC_ASM_FLAG_OUTPUTS__
is defined.
I have a partial solution, but I don't really like it because it requires putting the branch instruction inside the asm, and because it requires a very ugly GCC feature that other "GNU C compatible" compilers might not support: asm goto
. It does however allow the branch outside the asm to be eliminated. The idea is:
static inline int foo(...)
{
__asm__ goto ( " .... ; cond_jmp %l[ret0]" : : "r"(...) ...
: "clobbers" : ret0 );
return 1;
ret0:
return 0;
}
When inlined into the caller that does if (foo(...)) ... else ...
, the conditional jump in the asm block ends up pointing directly to the else
branch, even though at the abstract-machine level there are return values involved.
Unfortunately GCC doesn't support accessing condition flags outside of asm statements. If you don't want to set a value then you'll have to move the conditional branch into the asm statement. That means either using asm goto labels that you've already discovered, or also bringing branch target into your asm statement.
You might also want to check to see if either GCC's old style __sync atomic builtins or the newer memory model based atomics provide the functionality you want out of the atomic instructions you're using.
来源:https://stackoverflow.com/questions/30314907/using-condition-flags-as-gnu-c-inline-asm-outputs