https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113280
--- Comment #12 from David Brown <david at westcontrol dot com> ---
(In reply to Segher Boessenkool from comment #11)
> (In reply to David Brown from comment #8)
> > As for using "=X" in the "opt == 3" case, I worry that that could lead to
> > errors as the two assembly lines are independent. The first says "put X
> > anywhere", and the second - if it had "=X" - says "take X from anywhere".
> > These don't have to be the same "anywhere" unless the input and output are
> > in the same statement - and if the compiler picked different anywheres, the
> > code would not work.
>
> This cannot lead to errors. The compiler knows where "x" is (it put it there
> itself!)
If I write :
int regtest(int a, int x) {
(void) a; // Ignore first parameter
return x;
}
I get the assembly (x86-64) :
movl %esi, %eax
ret
or (arm 32-bit)
mov r0, r1
bx lr
That's all fine, and as expected. But with this :
int regtest(int a, int x) {
(void) a; // Ignore first parameter
asm("" :: "X" (x);
asm("" : "=X" (x);
return x;
}
the result is just a "ret" or a "bx lr" instruction. The register move is
missing, because for the first assembly the "anywhere" is picked as esi/r1, and
for the second assembly the "anywhere" is picked as eax/r0. This is a
perfectly valid choice of registers for the compiler, but it is not what we
want in this use-case.
It is only if I use "+X" (or add a "0" (x) input), rather than "=X", that the
compiler picks the same register for input and output, because it is within the
one assembly instruction.
(The same applies to "=g" / "+g".)
I don't understand why having a "asm("" :: "X" (x))" seems to be necessary
sometimes for "asm("" : "+X" (x))" to work the way I expect, without a compiler
error, but I /do/ understand why "asm("" :: "X" (x))" followed by "asm("" :
"=X" (x))" will sometimes not give the results I am looking for.