mirror of https://github.com/xemu-project/xemu.git
target/arm: Convert to HAVE_CMPXCHG128
Reviewed-by: Emilio G. Cota <cota@braap.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
parent
e1ed709fbe
commit
1ec182c333
|
@ -30,6 +30,7 @@
|
||||||
#include "exec/exec-all.h"
|
#include "exec/exec-all.h"
|
||||||
#include "exec/cpu_ldst.h"
|
#include "exec/cpu_ldst.h"
|
||||||
#include "qemu/int128.h"
|
#include "qemu/int128.h"
|
||||||
|
#include "qemu/atomic128.h"
|
||||||
#include "tcg.h"
|
#include "tcg.h"
|
||||||
#include "fpu/softfloat.h"
|
#include "fpu/softfloat.h"
|
||||||
#include <zlib.h> /* For crc32 */
|
#include <zlib.h> /* For crc32 */
|
||||||
|
@ -509,189 +510,195 @@ uint64_t HELPER(crc32c_64)(uint64_t acc, uint64_t val, uint32_t bytes)
|
||||||
return crc32c(acc, buf, bytes) ^ 0xffffffff;
|
return crc32c(acc, buf, bytes) ^ 0xffffffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Returns 0 on success; 1 otherwise. */
|
uint64_t HELPER(paired_cmpxchg64_le)(CPUARMState *env, uint64_t addr,
|
||||||
static uint64_t do_paired_cmpxchg64_le(CPUARMState *env, uint64_t addr,
|
uint64_t new_lo, uint64_t new_hi)
|
||||||
uint64_t new_lo, uint64_t new_hi,
|
|
||||||
bool parallel, uintptr_t ra)
|
|
||||||
{
|
{
|
||||||
Int128 oldv, cmpv, newv;
|
Int128 cmpv = int128_make128(env->exclusive_val, env->exclusive_high);
|
||||||
|
Int128 newv = int128_make128(new_lo, new_hi);
|
||||||
|
Int128 oldv;
|
||||||
|
uintptr_t ra = GETPC();
|
||||||
|
uint64_t o0, o1;
|
||||||
bool success;
|
bool success;
|
||||||
|
|
||||||
cmpv = int128_make128(env->exclusive_val, env->exclusive_high);
|
|
||||||
newv = int128_make128(new_lo, new_hi);
|
|
||||||
|
|
||||||
if (parallel) {
|
|
||||||
#ifndef CONFIG_ATOMIC128
|
|
||||||
cpu_loop_exit_atomic(ENV_GET_CPU(env), ra);
|
|
||||||
#else
|
|
||||||
int mem_idx = cpu_mmu_index(env, false);
|
|
||||||
TCGMemOpIdx oi = make_memop_idx(MO_LEQ | MO_ALIGN_16, mem_idx);
|
|
||||||
oldv = helper_atomic_cmpxchgo_le_mmu(env, addr, cmpv, newv, oi, ra);
|
|
||||||
success = int128_eq(oldv, cmpv);
|
|
||||||
#endif
|
|
||||||
} else {
|
|
||||||
uint64_t o0, o1;
|
|
||||||
|
|
||||||
#ifdef CONFIG_USER_ONLY
|
#ifdef CONFIG_USER_ONLY
|
||||||
/* ??? Enforce alignment. */
|
/* ??? Enforce alignment. */
|
||||||
uint64_t *haddr = g2h(addr);
|
uint64_t *haddr = g2h(addr);
|
||||||
|
|
||||||
helper_retaddr = ra;
|
helper_retaddr = ra;
|
||||||
o0 = ldq_le_p(haddr + 0);
|
o0 = ldq_le_p(haddr + 0);
|
||||||
o1 = ldq_le_p(haddr + 1);
|
o1 = ldq_le_p(haddr + 1);
|
||||||
oldv = int128_make128(o0, o1);
|
oldv = int128_make128(o0, o1);
|
||||||
|
|
||||||
success = int128_eq(oldv, cmpv);
|
success = int128_eq(oldv, cmpv);
|
||||||
if (success) {
|
if (success) {
|
||||||
stq_le_p(haddr + 0, int128_getlo(newv));
|
stq_le_p(haddr + 0, int128_getlo(newv));
|
||||||
stq_le_p(haddr + 1, int128_gethi(newv));
|
stq_le_p(haddr + 1, int128_gethi(newv));
|
||||||
}
|
|
||||||
helper_retaddr = 0;
|
|
||||||
#else
|
|
||||||
int mem_idx = cpu_mmu_index(env, false);
|
|
||||||
TCGMemOpIdx oi0 = make_memop_idx(MO_LEQ | MO_ALIGN_16, mem_idx);
|
|
||||||
TCGMemOpIdx oi1 = make_memop_idx(MO_LEQ, mem_idx);
|
|
||||||
|
|
||||||
o0 = helper_le_ldq_mmu(env, addr + 0, oi0, ra);
|
|
||||||
o1 = helper_le_ldq_mmu(env, addr + 8, oi1, ra);
|
|
||||||
oldv = int128_make128(o0, o1);
|
|
||||||
|
|
||||||
success = int128_eq(oldv, cmpv);
|
|
||||||
if (success) {
|
|
||||||
helper_le_stq_mmu(env, addr + 0, int128_getlo(newv), oi1, ra);
|
|
||||||
helper_le_stq_mmu(env, addr + 8, int128_gethi(newv), oi1, ra);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
helper_retaddr = 0;
|
||||||
|
#else
|
||||||
|
int mem_idx = cpu_mmu_index(env, false);
|
||||||
|
TCGMemOpIdx oi0 = make_memop_idx(MO_LEQ | MO_ALIGN_16, mem_idx);
|
||||||
|
TCGMemOpIdx oi1 = make_memop_idx(MO_LEQ, mem_idx);
|
||||||
|
|
||||||
|
o0 = helper_le_ldq_mmu(env, addr + 0, oi0, ra);
|
||||||
|
o1 = helper_le_ldq_mmu(env, addr + 8, oi1, ra);
|
||||||
|
oldv = int128_make128(o0, o1);
|
||||||
|
|
||||||
|
success = int128_eq(oldv, cmpv);
|
||||||
|
if (success) {
|
||||||
|
helper_le_stq_mmu(env, addr + 0, int128_getlo(newv), oi1, ra);
|
||||||
|
helper_le_stq_mmu(env, addr + 8, int128_gethi(newv), oi1, ra);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return !success;
|
return !success;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t HELPER(paired_cmpxchg64_le)(CPUARMState *env, uint64_t addr,
|
|
||||||
uint64_t new_lo, uint64_t new_hi)
|
|
||||||
{
|
|
||||||
return do_paired_cmpxchg64_le(env, addr, new_lo, new_hi, false, GETPC());
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t HELPER(paired_cmpxchg64_le_parallel)(CPUARMState *env, uint64_t addr,
|
uint64_t HELPER(paired_cmpxchg64_le_parallel)(CPUARMState *env, uint64_t addr,
|
||||||
uint64_t new_lo, uint64_t new_hi)
|
uint64_t new_lo, uint64_t new_hi)
|
||||||
{
|
|
||||||
return do_paired_cmpxchg64_le(env, addr, new_lo, new_hi, true, GETPC());
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint64_t do_paired_cmpxchg64_be(CPUARMState *env, uint64_t addr,
|
|
||||||
uint64_t new_lo, uint64_t new_hi,
|
|
||||||
bool parallel, uintptr_t ra)
|
|
||||||
{
|
{
|
||||||
Int128 oldv, cmpv, newv;
|
Int128 oldv, cmpv, newv;
|
||||||
|
uintptr_t ra = GETPC();
|
||||||
bool success;
|
bool success;
|
||||||
|
int mem_idx;
|
||||||
|
TCGMemOpIdx oi;
|
||||||
|
|
||||||
/* high and low need to be switched here because this is not actually a
|
if (!HAVE_CMPXCHG128) {
|
||||||
* 128bit store but two doublewords stored consecutively
|
|
||||||
*/
|
|
||||||
cmpv = int128_make128(env->exclusive_high, env->exclusive_val);
|
|
||||||
newv = int128_make128(new_hi, new_lo);
|
|
||||||
|
|
||||||
if (parallel) {
|
|
||||||
#ifndef CONFIG_ATOMIC128
|
|
||||||
cpu_loop_exit_atomic(ENV_GET_CPU(env), ra);
|
cpu_loop_exit_atomic(ENV_GET_CPU(env), ra);
|
||||||
#else
|
|
||||||
int mem_idx = cpu_mmu_index(env, false);
|
|
||||||
TCGMemOpIdx oi = make_memop_idx(MO_BEQ | MO_ALIGN_16, mem_idx);
|
|
||||||
oldv = helper_atomic_cmpxchgo_be_mmu(env, addr, cmpv, newv, oi, ra);
|
|
||||||
success = int128_eq(oldv, cmpv);
|
|
||||||
#endif
|
|
||||||
} else {
|
|
||||||
uint64_t o0, o1;
|
|
||||||
|
|
||||||
#ifdef CONFIG_USER_ONLY
|
|
||||||
/* ??? Enforce alignment. */
|
|
||||||
uint64_t *haddr = g2h(addr);
|
|
||||||
|
|
||||||
helper_retaddr = ra;
|
|
||||||
o1 = ldq_be_p(haddr + 0);
|
|
||||||
o0 = ldq_be_p(haddr + 1);
|
|
||||||
oldv = int128_make128(o0, o1);
|
|
||||||
|
|
||||||
success = int128_eq(oldv, cmpv);
|
|
||||||
if (success) {
|
|
||||||
stq_be_p(haddr + 0, int128_gethi(newv));
|
|
||||||
stq_be_p(haddr + 1, int128_getlo(newv));
|
|
||||||
}
|
|
||||||
helper_retaddr = 0;
|
|
||||||
#else
|
|
||||||
int mem_idx = cpu_mmu_index(env, false);
|
|
||||||
TCGMemOpIdx oi0 = make_memop_idx(MO_BEQ | MO_ALIGN_16, mem_idx);
|
|
||||||
TCGMemOpIdx oi1 = make_memop_idx(MO_BEQ, mem_idx);
|
|
||||||
|
|
||||||
o1 = helper_be_ldq_mmu(env, addr + 0, oi0, ra);
|
|
||||||
o0 = helper_be_ldq_mmu(env, addr + 8, oi1, ra);
|
|
||||||
oldv = int128_make128(o0, o1);
|
|
||||||
|
|
||||||
success = int128_eq(oldv, cmpv);
|
|
||||||
if (success) {
|
|
||||||
helper_be_stq_mmu(env, addr + 0, int128_gethi(newv), oi1, ra);
|
|
||||||
helper_be_stq_mmu(env, addr + 8, int128_getlo(newv), oi1, ra);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mem_idx = cpu_mmu_index(env, false);
|
||||||
|
oi = make_memop_idx(MO_LEQ | MO_ALIGN_16, mem_idx);
|
||||||
|
|
||||||
|
cmpv = int128_make128(env->exclusive_val, env->exclusive_high);
|
||||||
|
newv = int128_make128(new_lo, new_hi);
|
||||||
|
oldv = helper_atomic_cmpxchgo_le_mmu(env, addr, cmpv, newv, oi, ra);
|
||||||
|
|
||||||
|
success = int128_eq(oldv, cmpv);
|
||||||
return !success;
|
return !success;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t HELPER(paired_cmpxchg64_be)(CPUARMState *env, uint64_t addr,
|
uint64_t HELPER(paired_cmpxchg64_be)(CPUARMState *env, uint64_t addr,
|
||||||
uint64_t new_lo, uint64_t new_hi)
|
uint64_t new_lo, uint64_t new_hi)
|
||||||
{
|
{
|
||||||
return do_paired_cmpxchg64_be(env, addr, new_lo, new_hi, false, GETPC());
|
/*
|
||||||
|
* High and low need to be switched here because this is not actually a
|
||||||
|
* 128bit store but two doublewords stored consecutively
|
||||||
|
*/
|
||||||
|
Int128 cmpv = int128_make128(env->exclusive_val, env->exclusive_high);
|
||||||
|
Int128 newv = int128_make128(new_lo, new_hi);
|
||||||
|
Int128 oldv;
|
||||||
|
uintptr_t ra = GETPC();
|
||||||
|
uint64_t o0, o1;
|
||||||
|
bool success;
|
||||||
|
|
||||||
|
#ifdef CONFIG_USER_ONLY
|
||||||
|
/* ??? Enforce alignment. */
|
||||||
|
uint64_t *haddr = g2h(addr);
|
||||||
|
|
||||||
|
helper_retaddr = ra;
|
||||||
|
o1 = ldq_be_p(haddr + 0);
|
||||||
|
o0 = ldq_be_p(haddr + 1);
|
||||||
|
oldv = int128_make128(o0, o1);
|
||||||
|
|
||||||
|
success = int128_eq(oldv, cmpv);
|
||||||
|
if (success) {
|
||||||
|
stq_be_p(haddr + 0, int128_gethi(newv));
|
||||||
|
stq_be_p(haddr + 1, int128_getlo(newv));
|
||||||
|
}
|
||||||
|
helper_retaddr = 0;
|
||||||
|
#else
|
||||||
|
int mem_idx = cpu_mmu_index(env, false);
|
||||||
|
TCGMemOpIdx oi0 = make_memop_idx(MO_BEQ | MO_ALIGN_16, mem_idx);
|
||||||
|
TCGMemOpIdx oi1 = make_memop_idx(MO_BEQ, mem_idx);
|
||||||
|
|
||||||
|
o1 = helper_be_ldq_mmu(env, addr + 0, oi0, ra);
|
||||||
|
o0 = helper_be_ldq_mmu(env, addr + 8, oi1, ra);
|
||||||
|
oldv = int128_make128(o0, o1);
|
||||||
|
|
||||||
|
success = int128_eq(oldv, cmpv);
|
||||||
|
if (success) {
|
||||||
|
helper_be_stq_mmu(env, addr + 0, int128_gethi(newv), oi1, ra);
|
||||||
|
helper_be_stq_mmu(env, addr + 8, int128_getlo(newv), oi1, ra);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return !success;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t HELPER(paired_cmpxchg64_be_parallel)(CPUARMState *env, uint64_t addr,
|
uint64_t HELPER(paired_cmpxchg64_be_parallel)(CPUARMState *env, uint64_t addr,
|
||||||
uint64_t new_lo, uint64_t new_hi)
|
uint64_t new_lo, uint64_t new_hi)
|
||||||
{
|
{
|
||||||
return do_paired_cmpxchg64_be(env, addr, new_lo, new_hi, true, GETPC());
|
Int128 oldv, cmpv, newv;
|
||||||
|
uintptr_t ra = GETPC();
|
||||||
|
bool success;
|
||||||
|
int mem_idx;
|
||||||
|
TCGMemOpIdx oi;
|
||||||
|
|
||||||
|
if (!HAVE_CMPXCHG128) {
|
||||||
|
cpu_loop_exit_atomic(ENV_GET_CPU(env), ra);
|
||||||
|
}
|
||||||
|
|
||||||
|
mem_idx = cpu_mmu_index(env, false);
|
||||||
|
oi = make_memop_idx(MO_BEQ | MO_ALIGN_16, mem_idx);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* High and low need to be switched here because this is not actually a
|
||||||
|
* 128bit store but two doublewords stored consecutively
|
||||||
|
*/
|
||||||
|
cmpv = int128_make128(env->exclusive_high, env->exclusive_val);
|
||||||
|
newv = int128_make128(new_hi, new_lo);
|
||||||
|
oldv = helper_atomic_cmpxchgo_be_mmu(env, addr, cmpv, newv, oi, ra);
|
||||||
|
|
||||||
|
success = int128_eq(oldv, cmpv);
|
||||||
|
return !success;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Writes back the old data into Rs. */
|
/* Writes back the old data into Rs. */
|
||||||
void HELPER(casp_le_parallel)(CPUARMState *env, uint32_t rs, uint64_t addr,
|
void HELPER(casp_le_parallel)(CPUARMState *env, uint32_t rs, uint64_t addr,
|
||||||
uint64_t new_lo, uint64_t new_hi)
|
uint64_t new_lo, uint64_t new_hi)
|
||||||
{
|
{
|
||||||
uintptr_t ra = GETPC();
|
|
||||||
#ifndef CONFIG_ATOMIC128
|
|
||||||
cpu_loop_exit_atomic(ENV_GET_CPU(env), ra);
|
|
||||||
#else
|
|
||||||
Int128 oldv, cmpv, newv;
|
Int128 oldv, cmpv, newv;
|
||||||
|
uintptr_t ra = GETPC();
|
||||||
|
int mem_idx;
|
||||||
|
TCGMemOpIdx oi;
|
||||||
|
|
||||||
|
if (!HAVE_CMPXCHG128) {
|
||||||
|
cpu_loop_exit_atomic(ENV_GET_CPU(env), ra);
|
||||||
|
}
|
||||||
|
|
||||||
|
mem_idx = cpu_mmu_index(env, false);
|
||||||
|
oi = make_memop_idx(MO_LEQ | MO_ALIGN_16, mem_idx);
|
||||||
|
|
||||||
cmpv = int128_make128(env->xregs[rs], env->xregs[rs + 1]);
|
cmpv = int128_make128(env->xregs[rs], env->xregs[rs + 1]);
|
||||||
newv = int128_make128(new_lo, new_hi);
|
newv = int128_make128(new_lo, new_hi);
|
||||||
|
|
||||||
int mem_idx = cpu_mmu_index(env, false);
|
|
||||||
TCGMemOpIdx oi = make_memop_idx(MO_LEQ | MO_ALIGN_16, mem_idx);
|
|
||||||
oldv = helper_atomic_cmpxchgo_le_mmu(env, addr, cmpv, newv, oi, ra);
|
oldv = helper_atomic_cmpxchgo_le_mmu(env, addr, cmpv, newv, oi, ra);
|
||||||
|
|
||||||
env->xregs[rs] = int128_getlo(oldv);
|
env->xregs[rs] = int128_getlo(oldv);
|
||||||
env->xregs[rs + 1] = int128_gethi(oldv);
|
env->xregs[rs + 1] = int128_gethi(oldv);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void HELPER(casp_be_parallel)(CPUARMState *env, uint32_t rs, uint64_t addr,
|
void HELPER(casp_be_parallel)(CPUARMState *env, uint32_t rs, uint64_t addr,
|
||||||
uint64_t new_hi, uint64_t new_lo)
|
uint64_t new_hi, uint64_t new_lo)
|
||||||
{
|
{
|
||||||
uintptr_t ra = GETPC();
|
|
||||||
#ifndef CONFIG_ATOMIC128
|
|
||||||
cpu_loop_exit_atomic(ENV_GET_CPU(env), ra);
|
|
||||||
#else
|
|
||||||
Int128 oldv, cmpv, newv;
|
Int128 oldv, cmpv, newv;
|
||||||
|
uintptr_t ra = GETPC();
|
||||||
|
int mem_idx;
|
||||||
|
TCGMemOpIdx oi;
|
||||||
|
|
||||||
|
if (!HAVE_CMPXCHG128) {
|
||||||
|
cpu_loop_exit_atomic(ENV_GET_CPU(env), ra);
|
||||||
|
}
|
||||||
|
|
||||||
|
mem_idx = cpu_mmu_index(env, false);
|
||||||
|
oi = make_memop_idx(MO_LEQ | MO_ALIGN_16, mem_idx);
|
||||||
|
|
||||||
cmpv = int128_make128(env->xregs[rs + 1], env->xregs[rs]);
|
cmpv = int128_make128(env->xregs[rs + 1], env->xregs[rs]);
|
||||||
newv = int128_make128(new_lo, new_hi);
|
newv = int128_make128(new_lo, new_hi);
|
||||||
|
|
||||||
int mem_idx = cpu_mmu_index(env, false);
|
|
||||||
TCGMemOpIdx oi = make_memop_idx(MO_LEQ | MO_ALIGN_16, mem_idx);
|
|
||||||
oldv = helper_atomic_cmpxchgo_be_mmu(env, addr, cmpv, newv, oi, ra);
|
oldv = helper_atomic_cmpxchgo_be_mmu(env, addr, cmpv, newv, oi, ra);
|
||||||
|
|
||||||
env->xregs[rs + 1] = int128_getlo(oldv);
|
env->xregs[rs + 1] = int128_getlo(oldv);
|
||||||
env->xregs[rs] = int128_gethi(oldv);
|
env->xregs[rs] = int128_gethi(oldv);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Reference in New Issue