https://gcc.gnu.org/bugzilla/show_bug.cgi?id=49611

--- Comment #6 from Ryan Johnson <scovich at gmail dot com> ---
(In reply to Jeremy from comment #5)
> It may not be possible, but perhaps a simpler thing might be for
> the asm() to notionally "return" a single boolean value which
> reflects ONE flag only.

Interesting!

Ironically, limiting it to one flag opens the way to cleanly specify branching
based on multiple flags. The optimizer just needs to recognize that when it
sees two otherwise-equivalent (non-volatile) asm statements with different
asm_return attribute, it's really just one asm statement that sets multiple
flags. Thus: 

#ifdef USE_ASM
#define CMP(a,b) asm("cmp %0 %1" : : "r"(a), "r"(b))
#define BELOW(a,b) (__attribute__((asm_return(cc_carry))) CMP(a,b))
#define EQUAL(a,b) (__attribute__((asm_return(cc_zero))) CMP(a,b))
#else
#define BELOW(a,b) ((a) < (b))
#define EQUAL(a,b) ((a) == (b))
#endif
int do_it(unsigned int a, unsigned int b, int c, int d, int e, int f) {
    int x;
    if (BELOW(a,b))
        x = c+d;
    else if (EQUAL(a,b))
        x = d+e;
    else
        x = c+e;
    return x+f;
}

Would produce the same assembly code output---with only one
comparison---whether USE_ASM was defined or not.

Even more fun would be if the optimizer could recognize conditionals that
depend on multiple flags (like x86 "less or equal") and turn this:

if ((__attribute__((asm_return(cc_zero))) CMP(a,b) 
        || __attribute__((asm_return(cc_overflow))) CMP(a,b) 
            != __attribute__((asm_return(cc_sign))) CMP(a,b))
    do_less_or_equal();
do_something_else();

into:

    cmp %[a] %[b]
    jg 1f
    call do_less_or_equal
1:
    call do_something_else

Much of the flag-wrangling machinery seems to already exist, because the
compiler emits the above asm if you replace the inline asm with either "a <= b"
or "a < b || a == b" (assuming now that a and b are signed ints).

Reply via email to