Commit 1ec182c3 authored by Richard Henderson's avatar Richard Henderson
Browse files

target/arm: Convert to HAVE_CMPXCHG128

parent e1ed709f
Loading
Loading
Loading
Loading
+134 −127
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@
#include "exec/exec-all.h"
#include "exec/cpu_ldst.h"
#include "qemu/int128.h"
#include "qemu/atomic128.h"
#include "tcg.h"
#include "fpu/softfloat.h"
#include <zlib.h> /* For crc32 */
@@ -509,28 +510,15 @@ uint64_t HELPER(crc32c_64)(uint64_t acc, uint64_t val, uint32_t bytes)
    return crc32c(acc, buf, bytes) ^ 0xffffffff;
}

/* Returns 0 on success; 1 otherwise.  */
static uint64_t do_paired_cmpxchg64_le(CPUARMState *env, uint64_t addr,
                                       uint64_t new_lo, uint64_t new_hi,
                                       bool parallel, uintptr_t ra)
uint64_t HELPER(paired_cmpxchg64_le)(CPUARMState *env, uint64_t addr,
                                     uint64_t new_lo, uint64_t new_hi)
{
    Int128 oldv, cmpv, newv;
    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 {
    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.  */
@@ -562,47 +550,47 @@ static uint64_t do_paired_cmpxchg64_le(CPUARMState *env, uint64_t addr,
        helper_le_stq_mmu(env, addr + 8, int128_gethi(newv), oi1, ra);
    }
#endif
    }

    return !success;
}

uint64_t HELPER(paired_cmpxchg64_le)(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)
{
    return do_paired_cmpxchg64_le(env, addr, new_lo, new_hi, false, 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);
    }

uint64_t HELPER(paired_cmpxchg64_le_parallel)(CPUARMState *env, uint64_t addr,
                                              uint64_t new_lo, uint64_t new_hi)
{
    return do_paired_cmpxchg64_le(env, addr, new_lo, new_hi, true, GETPC());
    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;
}

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)
uint64_t HELPER(paired_cmpxchg64_be)(CPUARMState *env, uint64_t addr,
                                     uint64_t new_lo, uint64_t new_hi)
{
    Int128 oldv, cmpv, newv;
    bool success;

    /* high and low need to be switched here because this is not actually a
    /*
     * 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);

    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_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 {
    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.  */
@@ -634,64 +622,83 @@ static uint64_t do_paired_cmpxchg64_be(CPUARMState *env, uint64_t addr,
        helper_be_stq_mmu(env, addr + 8, int128_getlo(newv), oi1, ra);
    }
#endif
    }

    return !success;
}

uint64_t HELPER(paired_cmpxchg64_be)(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)
{
    return do_paired_cmpxchg64_be(env, addr, new_lo, new_hi, false, 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);
    }

uint64_t HELPER(paired_cmpxchg64_be_parallel)(CPUARMState *env, uint64_t addr,
                                     uint64_t new_lo, uint64_t new_hi)
{
    return do_paired_cmpxchg64_be(env, addr, new_lo, new_hi, true, GETPC());
    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.  */
void HELPER(casp_le_parallel)(CPUARMState *env, uint32_t rs, uint64_t addr,
                              uint64_t new_lo, uint64_t new_hi)
{
    Int128 oldv, cmpv, newv;
    uintptr_t ra = GETPC();
#ifndef CONFIG_ATOMIC128
    int mem_idx;
    TCGMemOpIdx oi;

    if (!HAVE_CMPXCHG128) {
        cpu_loop_exit_atomic(ENV_GET_CPU(env), ra);
#else
    Int128 oldv, cmpv, newv;
    }

    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]);
    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);

    env->xregs[rs] = int128_getlo(oldv);
    env->xregs[rs + 1] = int128_gethi(oldv);
#endif
}

void HELPER(casp_be_parallel)(CPUARMState *env, uint32_t rs, uint64_t addr,
                              uint64_t new_hi, uint64_t new_lo)
{
    Int128 oldv, cmpv, newv;
    uintptr_t ra = GETPC();
#ifndef CONFIG_ATOMIC128
    int mem_idx;
    TCGMemOpIdx oi;

    if (!HAVE_CMPXCHG128) {
        cpu_loop_exit_atomic(ENV_GET_CPU(env), ra);
#else
    Int128 oldv, cmpv, newv;
    }

    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]);
    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);

    env->xregs[rs + 1] = int128_getlo(oldv);
    env->xregs[rs] = int128_gethi(oldv);
#endif
}

/*