summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorPaolo Bonzini2022-09-11 14:04:36 +0200
committerRichard Henderson2022-11-15 00:34:42 +0100
commitd1bb978ba1654ddc6e927621b554eebb216fb9dd (patch)
tree90ee84e4dde9310b4175200161b9db54a8bacdde /tests
parentMerge tag 'pull-target-arm-20221114' of https://git.linaro.org/people/pmaydel... (diff)
downloadqemu-d1bb978ba1654ddc6e927621b554eebb216fb9dd.tar.gz
qemu-d1bb978ba1654ddc6e927621b554eebb216fb9dd.tar.xz
qemu-d1bb978ba1654ddc6e927621b554eebb216fb9dd.zip
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 <pbonzini@redhat.com> [rth: Add a test case ] Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Diffstat (limited to 'tests')
-rw-r--r--tests/tcg/x86_64/Makefile.target1
-rw-r--r--tests/tcg/x86_64/cmpxchg.c42
2 files changed, 43 insertions, 0 deletions
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 <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;
+}