Fix the 64-bit i386 atomic according to assembly output

The assembly output showed that GCC was generating some wrong code in
some conditions, so update the constraints so it will do the right
thing: the expectedValue constraint needs to be in/out with early
clobber. In/out because cmpxchg8b really does produce output and, even
if we don't care about it, GCC needs to be told that the registers
used (EAX:EDX) were modified. The early clobber is necessary so it
won't schedule EAX or EDX to be the same as the EBX_reg (the register
we'll xchg EBX with).

Since EAX and EDX are in/out and EBX can't be used, the only remaining
low register for the "sete" instruction is CL. So use it directly and
set ECX to be in/out too.

For whatever reason, it can't find enough registers in debug mode and
this expansion doesn't work. It looks like a bug though, since this
requires 4 registers and one memory operand and in debug mode it must
have EAX, ECX, EDX, ESI and EDI free for use. One of ESI or EDI is
used to xchg EBX with, which means there must be at least one more
free general register.

Change-Id: I1f11e68d776bf9ad216b34ca316a53129122fabe
Reviewed-by: Bradley T. Hughes <bradley.hughes@nokia.com>
This commit is contained in:
Thiago Macieira 2012-01-08 20:45:11 -02:00 committed by Qt by Nokia
parent fe778b94bd
commit 99802f0c14

View File

@ -322,17 +322,17 @@ template <> struct QBasicAtomicOps<8>: QGenericAtomicOps<QBasicAtomicOps<8> >
# define EBX_reg "b"
# define EBX_load(reg)
#endif
unsigned char ret;
quint32 highExpectedValue = quint32(newValue >> 32); // ECX
asm volatile(EBX_load("%3")
"lock\n"
"cmpxchg8b %0\n"
EBX_load("%3")
"sete %1\n"
: "+m" (_q_value), "=qm" (ret),
"+A" (expectedValue)
: EBX_reg (quint32(newValue & 0xffffffff)), "c" (quint32(newValue >> 32))
"sete %%cl\n"
: "+m" (_q_value), "+c" (highExpectedValue), "+&A" (expectedValue)
: EBX_reg (quint32(newValue & 0xffffffff))
: "memory");
return ret != 0;
// if the comparison failed, expectedValue here contains the current value
return quint8(highExpectedValue) != 0;
#undef EBX_reg
#undef EBX_load
}