d1bb978ba1
Unlike the memory case, where "the destination operand receives a write cycle without regard to the result of the comparison", rm must not be touched altogether if the write fails, including not zero-extending it on 64-bit processors. This is not how the movcond currently works, because it is always followed by a gen_op_mov_reg_v to rm. To fix it, introduce a new function that is similar to gen_op_mov_reg_v but writes to a TCG temporary. Considering that gen_extu(ot, oldv) is not needed in the memory case either, the two cases for register and memory destinations are different enough that one might as well fuse the two "if (mod == 3)" into one. So do that too. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/508 Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> [rth: Add a test case ] Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
43 lines
911 B
C
43 lines
911 B
C
#include <assert.h>
|
|
|
|
static int mem;
|
|
|
|
static unsigned long test_cmpxchgb(unsigned long orig)
|
|
{
|
|
unsigned long ret;
|
|
mem = orig;
|
|
asm("cmpxchgb %b[cmp],%[mem]"
|
|
: [ mem ] "+m"(mem), [ rax ] "=a"(ret)
|
|
: [ cmp ] "r"(0x77), "a"(orig));
|
|
return ret;
|
|
}
|
|
|
|
static unsigned long test_cmpxchgw(unsigned long orig)
|
|
{
|
|
unsigned long ret;
|
|
mem = orig;
|
|
asm("cmpxchgw %w[cmp],%[mem]"
|
|
: [ mem ] "+m"(mem), [ rax ] "=a"(ret)
|
|
: [ cmp ] "r"(0x7777), "a"(orig));
|
|
return ret;
|
|
}
|
|
|
|
static unsigned long test_cmpxchgl(unsigned long orig)
|
|
{
|
|
unsigned long ret;
|
|
mem = orig;
|
|
asm("cmpxchgl %[cmp],%[mem]"
|
|
: [ mem ] "+m"(mem), [ rax ] "=a"(ret)
|
|
: [ cmp ] "r"(0x77777777u), "a"(orig));
|
|
return ret;
|
|
}
|
|
|
|
int main()
|
|
{
|
|
unsigned long test = 0xdeadbeef12345678ull;
|
|
assert(test == test_cmpxchgb(test));
|
|
assert(test == test_cmpxchgw(test));
|
|
assert(test == test_cmpxchgl(test));
|
|
return 0;
|
|
}
|