From d1bb978ba1654ddc6e927621b554eebb216fb9dd Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Sun, 11 Sep 2022 14:04:36 +0200 Subject: target/i386: fix cmpxchg with 32-bit register destination 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 [rth: Add a test case ] Signed-off-by: Richard Henderson --- tests/tcg/x86_64/Makefile.target | 1 + tests/tcg/x86_64/cmpxchg.c | 42 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 tests/tcg/x86_64/cmpxchg.c (limited to 'tests') diff --git a/tests/tcg/x86_64/Makefile.target b/tests/tcg/x86_64/Makefile.target index 6895db1c43..4eac78293f 100644 --- a/tests/tcg/x86_64/Makefile.target +++ b/tests/tcg/x86_64/Makefile.target @@ -11,6 +11,7 @@ include $(SRC_PATH)/tests/tcg/i386/Makefile.target ifeq ($(filter %-linux-user, $(TARGET)),$(TARGET)) X86_64_TESTS += vsyscall X86_64_TESTS += noexec +X86_64_TESTS += cmpxchg TESTS=$(MULTIARCH_TESTS) $(X86_64_TESTS) test-x86_64 else TESTS=$(MULTIARCH_TESTS) diff --git a/tests/tcg/x86_64/cmpxchg.c b/tests/tcg/x86_64/cmpxchg.c new file mode 100644 index 0000000000..5891735161 --- /dev/null +++ b/tests/tcg/x86_64/cmpxchg.c @@ -0,0 +1,42 @@ +#include + +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; +} -- cgit v1.2.3-55-g7522