Merge pull request #5435 from Sonicadvance1/143

unittests/ASM: Add unittests to ensure correct cmpxchg8b/16b flag setting
This commit is contained in:
LC authored and GitHub committed 2026-04-25 10:34:07 -04:00
commit 7dc1f54fb6
7 files changed
+296 -13

No files matched your search

+1 -1
View File
@@ -274,7 +274,7 @@ DEF_OP(CmpPairZ) {
// Restore NzCV
if (CTX->HostFeatures.SupportsFlagM) {
rmif(TMP1, 0, 0xb /* NzCV */);
rmif(TMP1, 28, 0xb /* NzCV */);
} else {
cset(ARMEmitter::Size::i32Bit, TMP2, ARMEmitter::Condition::CC_EQ);
bfi(ARMEmitter::Size::i32Bit, TMP1, TMP2, 30 /* lsb: Z */, 1);
+147
View File
@@ -0,0 +1,147 @@
%ifdef CONFIG
{
"RegData": {
"R13": "0x20",
"R14": "0x0000000000010dd4",
"R15": "1"
}
}
%endif
; FEX-Emu had a bug where cmpxchg8b/cmpxchg16b wasn't setting z flag correctly on flagm supporting CPUs.
; This runs through all the configurations to both ensure that the z flag is set correctly, and that the other flags aren't affected.
; There is an additional cmpxchg8b test in another file.
global temp_data
%define FULL_FLAGS ((1 << 0) | (1 << 2) | (1 << 4) | (1 << 6) | (1 << 7))
%define EMPTY_FLAGS
%define DATA_LOW 0x4142434445464748
%define DATA_HIGH 0x5152535455565758
%define DATA_INCORRECT_LOW 0x4142433445464748
%define DATA_INCORRECT_HIGH 0x5152533455565758
; Clobbers: RAX
%macro reset_data 0
mov rax, DATA_LOW
mov [rel temp_data], rax
mov rax, DATA_HIGH
mov [rel temp_data + 8], rax
%endmacro
; Clobbers: RAX
; Args: <immediate constant>
%macro reset_flag 1
mov rax, %1
push rax
popfq
%endmacro
; Clobbers: RAX, RBX, RCX, RDX
; Compares incoming values against memory, and replaces
; Args: <64-bit immediate>, <64-bit immediate>
; Return: Compare result in ZF (ZF==1 == compare_success)
%macro cas_u64x2 2
mov rax, %1
mov rdx, %2
mov rbx, 0
mov rcx, 0
cmpxchg16b [rel temp_data]
%endmacro
; Clobbers: RAX, RBX
; Compares flags with correct result
; Args: <jnz if ZF == 0, jz if ZF == 1>, <Expected other flags>
%macro check_flags 2
pushfq
pop rbx
; Remove IF and Reserved
and rbx, ~(0x202)
; just compare ZF
mov rax, rbx
and rax, (1 << 6)
%if %1 == 0
jz %%.no_error
%else
jnz %%.no_error
%endif
hlt
%%.no_error:
; compare full flags
cmp rbx, %2
je %%.second_no_error
hlt
%%.second_no_error:
; Continue forward
%endmacro
; Args: <Compare Result>, <Expected flags>, <Data to compare low>, <Data to compare high>
%macro do_test 4
reset_flag %2
reset_data
cas_u64x2 %3, %4
; Check flag adding reserved for comparison
check_flags %1, %2
%endmacro
mov r15, 0
mov r14, 0
mov r13, 0
mov rsp, 0xe000_1000
; %define FULL_FLAGS ((1 << 0) | (1 << 2) | (1 << 4) | (1 << 6) | (1 << 7))
%assign eq_val 0
; EQ
%rep 2
%assign flag_0 0
%rep 2
%assign flag_2 0
%rep 2
%assign flag_4 0
%rep 2
%assign flag_7 0
%rep 2
; if eq_val == 0 then zf is expected to be zero, aka non-match
%if eq_val == 0
%assign data_low DATA_LOW
%assign data_high DATA_INCORRECT_HIGH
%else
%assign data_low DATA_LOW
%assign data_high DATA_HIGH
%endif
%assign expected_flags ((flag_0 << 0) | (flag_2 << 2) | (flag_4 << 4) | (flag_7 << 7) | (eq_val << 6))
inc r13
do_test eq_val, expected_flags, data_low, data_high
%assign flag_7 flag_7+1
%endrep
%assign flag_4 flag_4+1
%endrep
%assign flag_2 flag_2+1
%endrep
%assign flag_0 flag_0+1
%endrep
%assign eq_val eq_val+1
%endrep
mov r15, 1
lea r14, [rel .end]
.end:
hlt
align 4096
temp_data:
dq 0
dq 0
+144
View File
@@ -0,0 +1,144 @@
%ifdef CONFIG
{
"RegData": {
"R13": "0x20",
"R14": "0x0000000000010c74",
"R15": "1"
}
}
%endif
; FEX-Emu had a bug where cmpxchg8b/cmpxchg16b wasn't setting z flag correctly on flagm supporting CPUs.
; This runs through all the configurations to both ensure that the z flag is set correctly, and that the other flags aren't affected.
; There is an additional cmpxchg16b test in another file.
global temp_data
%define FULL_FLAGS ((1 << 0) | (1 << 2) | (1 << 4) | (1 << 6) | (1 << 7))
%define EMPTY_FLAGS
%define DATA_LOW 0x4142434445464748
%define DATA_HIGH 0x5152535455565758
%define DATA_INCORRECT_LOW 0x4142433445464748
%define DATA_INCORRECT_HIGH 0x5152533455565758
; Clobbers: RAX
%macro reset_data 0
mov rax, DATA_LOW
mov [rel temp_data], rax
mov rax, DATA_HIGH
mov [rel temp_data + 8], rax
%endmacro
; Clobbers: RAX
; Args: <immediate constant>
%macro reset_flag 1
mov rax, %1
push rax
popfq
%endmacro
; Clobbers: RAX, RBX, RCX, RDX
; Compares incoming values against memory, and replaces
; Args: <64-bit immediate>
; Return: Compare result in ZF (ZF==1 == compare_success)
%macro cas_u32x2 1
mov eax, (%1 & 0xFFFF_FFFF)
mov edx, %1 >> 32
mov ebx, 0
mov ecx, 0
cmpxchg8b [rel temp_data]
%endmacro
; Clobbers: RAX, RBX
; Compares flags with correct result
; Args: <jnz if ZF == 0, jz if ZF == 1>, <Expected other flags>
%macro check_flags 2
pushfq
pop rbx
; Remove IF and Reserved
and rbx, ~(0x202)
; just compare ZF
mov rax, rbx
and rax, (1 << 6)
%if %1 == 0
jz %%.no_error
%else
jnz %%.no_error
%endif
hlt
%%.no_error:
; compare full flags
cmp rbx, %2
je %%.second_no_error
hlt
%%.second_no_error:
; Continue forward
%endmacro
; Args: <Compare Result>, <Expected flags>, <Data to compare>
%macro do_test 3
reset_flag %2
reset_data
cas_u32x2 %3
; Check flag adding reserved for comparison
check_flags %1, %2
%endmacro
mov r15, 0
mov r14, 0
mov r13, 0
mov rsp, 0xe000_1000
; %define FULL_FLAGS ((1 << 0) | (1 << 2) | (1 << 4) | (1 << 6) | (1 << 7))
%assign eq_val 0
; EQ
%rep 2
%assign flag_0 0
%rep 2
%assign flag_2 0
%rep 2
%assign flag_4 0
%rep 2
%assign flag_7 0
%rep 2
; if eq_val == 0 then zf is expected to be zero, aka non-match
%if eq_val == 0
%assign data DATA_INCORRECT_LOW
%else
%assign data DATA_LOW
%endif
%assign expected_flags ((flag_0 << 0) | (flag_2 << 2) | (flag_4 << 4) | (flag_7 << 7) | (eq_val << 6))
inc r13
do_test eq_val, expected_flags, data
%assign flag_7 flag_7+1
%endrep
%assign flag_4 flag_4+1
%endrep
%assign flag_2 flag_2+1
%endrep
%assign flag_0 flag_0+1
%endrep
%assign eq_val eq_val+1
%endrep
mov r15, 1
lea r14, [rel .end]
.end:
hlt
align 4096
temp_data:
dq 0
dq 0
@@ -377,7 +377,7 @@
"mrs x0, nzcv",
"cmp w20, w4",
"ccmp w21, w5, #nzcv, eq",
"rmif x0, #0, #NzCV",
"rmif x0, #28, #NzCV",
"csel x4, x20, x4, ne",
"csel x5, x21, x5, ne",
"subs x26, x4, #0x0 (0)"
@@ -126,7 +126,7 @@
"mrs x0, nzcv",
"cmp w22, w4",
"ccmp w23, w5, #nzcv, eq",
"rmif x0, #0, #NzCV",
"rmif x0, #28, #NzCV",
"csel x4, x22, x4, ne",
"csel x5, x23, x5, ne",
"cfinv"
@@ -713,7 +713,7 @@
"mrs x0, nzcv",
"cmp w20, w4",
"ccmp w21, w5, #nzcv, eq",
"rmif x0, #0, #NzCV",
"rmif x0, #28, #NzCV",
"csel x4, x20, x4, ne",
"csel x5, x21, x5, ne"
]
@@ -728,7 +728,7 @@
"mrs x0, nzcv",
"cmp x20, x4",
"ccmp x21, x5, #nzcv, eq",
"rmif x0, #0, #NzCV",
"rmif x0, #28, #NzCV",
"csel x4, x20, x4, ne",
"csel x5, x21, x5, ne"
]
@@ -1826,14 +1826,6 @@
"strh w20, [x8, #-2]!"
]
},
"push dword -1": {
"ExpectedInstructionCount": 2,
"Comment": "0x6a",
"ExpectedArm64ASM": [
"mov x20, #0xffffffffffffffff",
"str x20, [x8, #-8]!"
]
},
"push qword -1": {
"ExpectedInstructionCount": 2,
"Comment": "0x6a",