From c482cb117cc418115ca9c6d21a7a2315414c0a40 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 28 Jun 2016 11:37:27 -0700 Subject: tcg: Add atomic helpers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add all of cmpxchg, op_fetch, fetch_op, and xchg. Handle both endian-ness, and sizes up to 8. Handle expanding non-atomically, when emulating in serial. Reviewed-by: Emilio G. Cota Reviewed-by: Alex Bennée Signed-off-by: Richard Henderson --- atomic_template.h | 177 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 177 insertions(+) create mode 100644 atomic_template.h (limited to 'atomic_template.h') diff --git a/atomic_template.h b/atomic_template.h new file mode 100644 index 0000000000..cf83725403 --- /dev/null +++ b/atomic_template.h @@ -0,0 +1,177 @@ +/* + * Atomic helper templates + * Included from tcg-runtime.c and cputlb.c. + * + * Copyright (c) 2016 Red Hat, Inc + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +#if DATA_SIZE == 8 +# define SUFFIX q +# define DATA_TYPE uint64_t +# define BSWAP bswap64 +#elif DATA_SIZE == 4 +# define SUFFIX l +# define DATA_TYPE uint32_t +# define BSWAP bswap32 +#elif DATA_SIZE == 2 +# define SUFFIX w +# define DATA_TYPE uint16_t +# define BSWAP bswap16 +#elif DATA_SIZE == 1 +# define SUFFIX b +# define DATA_TYPE uint8_t +# define BSWAP +#else +# error unsupported data size +#endif + +#if DATA_SIZE >= 4 +# define ABI_TYPE DATA_TYPE +#else +# define ABI_TYPE uint32_t +#endif + +/* Define host-endian atomic operations. Note that END is used within + the ATOMIC_NAME macro, and redefined below. */ +#if DATA_SIZE == 1 +# define END +#elif defined(HOST_WORDS_BIGENDIAN) +# define END _be +#else +# define END _le +#endif + +ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr, + ABI_TYPE cmpv, ABI_TYPE newv EXTRA_ARGS) +{ + DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; + return atomic_cmpxchg__nocheck(haddr, cmpv, newv); +} + +ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr, + ABI_TYPE val EXTRA_ARGS) +{ + DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; + return atomic_xchg__nocheck(haddr, val); +} + +#define GEN_ATOMIC_HELPER(X) \ +ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \ + ABI_TYPE val EXTRA_ARGS) \ +{ \ + DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; \ + return atomic_##X(haddr, val); \ +} \ + +GEN_ATOMIC_HELPER(fetch_add) +GEN_ATOMIC_HELPER(fetch_and) +GEN_ATOMIC_HELPER(fetch_or) +GEN_ATOMIC_HELPER(fetch_xor) +GEN_ATOMIC_HELPER(add_fetch) +GEN_ATOMIC_HELPER(and_fetch) +GEN_ATOMIC_HELPER(or_fetch) +GEN_ATOMIC_HELPER(xor_fetch) + +#undef GEN_ATOMIC_HELPER +#undef END + +#if DATA_SIZE > 1 + +/* Define reverse-host-endian atomic operations. Note that END is used + within the ATOMIC_NAME macro. */ +#ifdef HOST_WORDS_BIGENDIAN +# define END _le +#else +# define END _be +#endif + +ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr, + ABI_TYPE cmpv, ABI_TYPE newv EXTRA_ARGS) +{ + DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; + return BSWAP(atomic_cmpxchg__nocheck(haddr, BSWAP(cmpv), BSWAP(newv))); +} + +ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr, + ABI_TYPE val EXTRA_ARGS) +{ + DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; + return BSWAP(atomic_xchg__nocheck(haddr, BSWAP(val))); +} + +#define GEN_ATOMIC_HELPER(X) \ +ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \ + ABI_TYPE val EXTRA_ARGS) \ +{ \ + DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; \ + return BSWAP(atomic_##X(haddr, BSWAP(val))); \ +} + +GEN_ATOMIC_HELPER(fetch_and) +GEN_ATOMIC_HELPER(fetch_or) +GEN_ATOMIC_HELPER(fetch_xor) +GEN_ATOMIC_HELPER(and_fetch) +GEN_ATOMIC_HELPER(or_fetch) +GEN_ATOMIC_HELPER(xor_fetch) + +#undef GEN_ATOMIC_HELPER + +/* Note that for addition, we need to use a separate cmpxchg loop instead + of bswaps for the reverse-host-endian helpers. */ +ABI_TYPE ATOMIC_NAME(fetch_add)(CPUArchState *env, target_ulong addr, + ABI_TYPE val EXTRA_ARGS) +{ + DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; + DATA_TYPE ldo, ldn, ret, sto; + + ldo = atomic_read__nocheck(haddr); + while (1) { + ret = BSWAP(ldo); + sto = BSWAP(ret + val); + ldn = atomic_cmpxchg__nocheck(haddr, ldo, sto); + if (ldn == ldo) { + return ret; + } + ldo = ldn; + } +} + +ABI_TYPE ATOMIC_NAME(add_fetch)(CPUArchState *env, target_ulong addr, + ABI_TYPE val EXTRA_ARGS) +{ + DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; + DATA_TYPE ldo, ldn, ret, sto; + + ldo = atomic_read__nocheck(haddr); + while (1) { + ret = BSWAP(ldo) + val; + sto = BSWAP(ret); + ldn = atomic_cmpxchg__nocheck(haddr, ldo, sto); + if (ldn == ldo) { + return ret; + } + ldo = ldn; + } +} + +#undef END +#endif /* DATA_SIZE > 1 */ + +#undef BSWAP +#undef ABI_TYPE +#undef DATA_TYPE +#undef SUFFIX +#undef DATA_SIZE -- cgit v1.2.3