110f7d4d5SPhilippe Mathieu-Daudé /* 210f7d4d5SPhilippe Mathieu-Daudé * Atomic helper templates 310f7d4d5SPhilippe Mathieu-Daudé * Included from tcg-runtime.c and cputlb.c. 410f7d4d5SPhilippe Mathieu-Daudé * 510f7d4d5SPhilippe Mathieu-Daudé * Copyright (c) 2016 Red Hat, Inc 610f7d4d5SPhilippe Mathieu-Daudé * 710f7d4d5SPhilippe Mathieu-Daudé * This library is free software; you can redistribute it and/or 810f7d4d5SPhilippe Mathieu-Daudé * modify it under the terms of the GNU Lesser General Public 910f7d4d5SPhilippe Mathieu-Daudé * License as published by the Free Software Foundation; either 1010f7d4d5SPhilippe Mathieu-Daudé * version 2 of the License, or (at your option) any later version. 1110f7d4d5SPhilippe Mathieu-Daudé * 1210f7d4d5SPhilippe Mathieu-Daudé * This library is distributed in the hope that it will be useful, 1310f7d4d5SPhilippe Mathieu-Daudé * but WITHOUT ANY WARRANTY; without even the implied warranty of 1410f7d4d5SPhilippe Mathieu-Daudé * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1510f7d4d5SPhilippe Mathieu-Daudé * Lesser General Public License for more details. 1610f7d4d5SPhilippe Mathieu-Daudé * 1710f7d4d5SPhilippe Mathieu-Daudé * You should have received a copy of the GNU Lesser General Public 1810f7d4d5SPhilippe Mathieu-Daudé * License along with this library; if not, see <http://www.gnu.org/licenses/>. 1910f7d4d5SPhilippe Mathieu-Daudé */ 2010f7d4d5SPhilippe Mathieu-Daudé 21*d071f4cdSEmilio G. Cota #include "trace/mem.h" 22*d071f4cdSEmilio G. Cota 2310f7d4d5SPhilippe Mathieu-Daudé #if DATA_SIZE == 16 2410f7d4d5SPhilippe Mathieu-Daudé # define SUFFIX o 2510f7d4d5SPhilippe Mathieu-Daudé # define DATA_TYPE Int128 2610f7d4d5SPhilippe Mathieu-Daudé # define BSWAP bswap128 27*d071f4cdSEmilio G. Cota # define SHIFT 4 2810f7d4d5SPhilippe Mathieu-Daudé #elif DATA_SIZE == 8 2910f7d4d5SPhilippe Mathieu-Daudé # define SUFFIX q 3010f7d4d5SPhilippe Mathieu-Daudé # define DATA_TYPE uint64_t 315507c2bfSRichard Henderson # define SDATA_TYPE int64_t 3210f7d4d5SPhilippe Mathieu-Daudé # define BSWAP bswap64 33*d071f4cdSEmilio G. Cota # define SHIFT 3 3410f7d4d5SPhilippe Mathieu-Daudé #elif DATA_SIZE == 4 3510f7d4d5SPhilippe Mathieu-Daudé # define SUFFIX l 3610f7d4d5SPhilippe Mathieu-Daudé # define DATA_TYPE uint32_t 375507c2bfSRichard Henderson # define SDATA_TYPE int32_t 3810f7d4d5SPhilippe Mathieu-Daudé # define BSWAP bswap32 39*d071f4cdSEmilio G. Cota # define SHIFT 2 4010f7d4d5SPhilippe Mathieu-Daudé #elif DATA_SIZE == 2 4110f7d4d5SPhilippe Mathieu-Daudé # define SUFFIX w 4210f7d4d5SPhilippe Mathieu-Daudé # define DATA_TYPE uint16_t 435507c2bfSRichard Henderson # define SDATA_TYPE int16_t 4410f7d4d5SPhilippe Mathieu-Daudé # define BSWAP bswap16 45*d071f4cdSEmilio G. Cota # define SHIFT 1 4610f7d4d5SPhilippe Mathieu-Daudé #elif DATA_SIZE == 1 4710f7d4d5SPhilippe Mathieu-Daudé # define SUFFIX b 4810f7d4d5SPhilippe Mathieu-Daudé # define DATA_TYPE uint8_t 495507c2bfSRichard Henderson # define SDATA_TYPE int8_t 5010f7d4d5SPhilippe Mathieu-Daudé # define BSWAP 51*d071f4cdSEmilio G. Cota # define SHIFT 0 5210f7d4d5SPhilippe Mathieu-Daudé #else 5310f7d4d5SPhilippe Mathieu-Daudé # error unsupported data size 5410f7d4d5SPhilippe Mathieu-Daudé #endif 5510f7d4d5SPhilippe Mathieu-Daudé 5610f7d4d5SPhilippe Mathieu-Daudé #if DATA_SIZE >= 4 5710f7d4d5SPhilippe Mathieu-Daudé # define ABI_TYPE DATA_TYPE 5810f7d4d5SPhilippe Mathieu-Daudé #else 5910f7d4d5SPhilippe Mathieu-Daudé # define ABI_TYPE uint32_t 6010f7d4d5SPhilippe Mathieu-Daudé #endif 6110f7d4d5SPhilippe Mathieu-Daudé 62*d071f4cdSEmilio G. Cota #define ATOMIC_TRACE_RMW do { \ 63*d071f4cdSEmilio G. Cota uint8_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, false); \ 64*d071f4cdSEmilio G. Cota \ 65*d071f4cdSEmilio G. Cota trace_guest_mem_before_exec(ENV_GET_CPU(env), addr, info); \ 66*d071f4cdSEmilio G. Cota trace_guest_mem_before_exec(ENV_GET_CPU(env), addr, \ 67*d071f4cdSEmilio G. Cota info | TRACE_MEM_ST); \ 68*d071f4cdSEmilio G. Cota } while (0) 69*d071f4cdSEmilio G. Cota 70*d071f4cdSEmilio G. Cota #define ATOMIC_TRACE_LD do { \ 71*d071f4cdSEmilio G. Cota uint8_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, false); \ 72*d071f4cdSEmilio G. Cota \ 73*d071f4cdSEmilio G. Cota trace_guest_mem_before_exec(ENV_GET_CPU(env), addr, info); \ 74*d071f4cdSEmilio G. Cota } while (0) 75*d071f4cdSEmilio G. Cota 76*d071f4cdSEmilio G. Cota # define ATOMIC_TRACE_ST do { \ 77*d071f4cdSEmilio G. Cota uint8_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, true); \ 78*d071f4cdSEmilio G. Cota \ 79*d071f4cdSEmilio G. Cota trace_guest_mem_before_exec(ENV_GET_CPU(env), addr, info); \ 80*d071f4cdSEmilio G. Cota } while (0) 81*d071f4cdSEmilio G. Cota 8210f7d4d5SPhilippe Mathieu-Daudé /* Define host-endian atomic operations. Note that END is used within 8310f7d4d5SPhilippe Mathieu-Daudé the ATOMIC_NAME macro, and redefined below. */ 8410f7d4d5SPhilippe Mathieu-Daudé #if DATA_SIZE == 1 8510f7d4d5SPhilippe Mathieu-Daudé # define END 86*d071f4cdSEmilio G. Cota # define MEND _be /* either le or be would be fine */ 8710f7d4d5SPhilippe Mathieu-Daudé #elif defined(HOST_WORDS_BIGENDIAN) 8810f7d4d5SPhilippe Mathieu-Daudé # define END _be 89*d071f4cdSEmilio G. Cota # define MEND _be 9010f7d4d5SPhilippe Mathieu-Daudé #else 9110f7d4d5SPhilippe Mathieu-Daudé # define END _le 92*d071f4cdSEmilio G. Cota # define MEND _le 9310f7d4d5SPhilippe Mathieu-Daudé #endif 9410f7d4d5SPhilippe Mathieu-Daudé 9510f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr, 9610f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE cmpv, ABI_TYPE newv EXTRA_ARGS) 9710f7d4d5SPhilippe Mathieu-Daudé { 9834d49937SPeter Maydell ATOMIC_MMU_DECLS; 9910f7d4d5SPhilippe Mathieu-Daudé DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; 100*d071f4cdSEmilio G. Cota DATA_TYPE ret; 101*d071f4cdSEmilio G. Cota 102*d071f4cdSEmilio G. Cota ATOMIC_TRACE_RMW; 103*d071f4cdSEmilio G. Cota ret = atomic_cmpxchg__nocheck(haddr, cmpv, newv); 104ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; 105ec603b55SRichard Henderson return ret; 10610f7d4d5SPhilippe Mathieu-Daudé } 10710f7d4d5SPhilippe Mathieu-Daudé 10810f7d4d5SPhilippe Mathieu-Daudé #if DATA_SIZE >= 16 10910f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr EXTRA_ARGS) 11010f7d4d5SPhilippe Mathieu-Daudé { 11134d49937SPeter Maydell ATOMIC_MMU_DECLS; 11210f7d4d5SPhilippe Mathieu-Daudé DATA_TYPE val, *haddr = ATOMIC_MMU_LOOKUP; 113*d071f4cdSEmilio G. Cota 114*d071f4cdSEmilio G. Cota ATOMIC_TRACE_LD; 11510f7d4d5SPhilippe Mathieu-Daudé __atomic_load(haddr, &val, __ATOMIC_RELAXED); 116ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; 11710f7d4d5SPhilippe Mathieu-Daudé return val; 11810f7d4d5SPhilippe Mathieu-Daudé } 11910f7d4d5SPhilippe Mathieu-Daudé 12010f7d4d5SPhilippe Mathieu-Daudé void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr, 12110f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE val EXTRA_ARGS) 12210f7d4d5SPhilippe Mathieu-Daudé { 12334d49937SPeter Maydell ATOMIC_MMU_DECLS; 12410f7d4d5SPhilippe Mathieu-Daudé DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; 125*d071f4cdSEmilio G. Cota 126*d071f4cdSEmilio G. Cota ATOMIC_TRACE_ST; 12710f7d4d5SPhilippe Mathieu-Daudé __atomic_store(haddr, &val, __ATOMIC_RELAXED); 128ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; 12910f7d4d5SPhilippe Mathieu-Daudé } 13010f7d4d5SPhilippe Mathieu-Daudé #else 13110f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr, 13210f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE val EXTRA_ARGS) 13310f7d4d5SPhilippe Mathieu-Daudé { 13434d49937SPeter Maydell ATOMIC_MMU_DECLS; 13510f7d4d5SPhilippe Mathieu-Daudé DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; 136*d071f4cdSEmilio G. Cota DATA_TYPE ret; 137*d071f4cdSEmilio G. Cota 138*d071f4cdSEmilio G. Cota ATOMIC_TRACE_RMW; 139*d071f4cdSEmilio G. Cota ret = atomic_xchg__nocheck(haddr, val); 140ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; 141ec603b55SRichard Henderson return ret; 14210f7d4d5SPhilippe Mathieu-Daudé } 14310f7d4d5SPhilippe Mathieu-Daudé 14410f7d4d5SPhilippe Mathieu-Daudé #define GEN_ATOMIC_HELPER(X) \ 14510f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \ 14610f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE val EXTRA_ARGS) \ 14710f7d4d5SPhilippe Mathieu-Daudé { \ 14834d49937SPeter Maydell ATOMIC_MMU_DECLS; \ 14910f7d4d5SPhilippe Mathieu-Daudé DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; \ 150*d071f4cdSEmilio G. Cota DATA_TYPE ret; \ 151*d071f4cdSEmilio G. Cota \ 152*d071f4cdSEmilio G. Cota ATOMIC_TRACE_RMW; \ 153*d071f4cdSEmilio G. Cota ret = atomic_##X(haddr, val); \ 154ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; \ 155ec603b55SRichard Henderson return ret; \ 156ec603b55SRichard Henderson } 15710f7d4d5SPhilippe Mathieu-Daudé 15810f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_add) 15910f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_and) 16010f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_or) 16110f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_xor) 16210f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(add_fetch) 16310f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(and_fetch) 16410f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(or_fetch) 16510f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(xor_fetch) 16610f7d4d5SPhilippe Mathieu-Daudé 16710f7d4d5SPhilippe Mathieu-Daudé #undef GEN_ATOMIC_HELPER 1685507c2bfSRichard Henderson 1695507c2bfSRichard Henderson /* These helpers are, as a whole, full barriers. Within the helper, 1705507c2bfSRichard Henderson * the leading barrier is explicit and the trailing barrier is within 1715507c2bfSRichard Henderson * cmpxchg primitive. 172*d071f4cdSEmilio G. Cota * 173*d071f4cdSEmilio G. Cota * Trace this load + RMW loop as a single RMW op. This way, regardless 174*d071f4cdSEmilio G. Cota * of CF_PARALLEL's value, we'll trace just a read and a write. 1755507c2bfSRichard Henderson */ 1765507c2bfSRichard Henderson #define GEN_ATOMIC_HELPER_FN(X, FN, XDATA_TYPE, RET) \ 1775507c2bfSRichard Henderson ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \ 1785507c2bfSRichard Henderson ABI_TYPE xval EXTRA_ARGS) \ 1795507c2bfSRichard Henderson { \ 1805507c2bfSRichard Henderson ATOMIC_MMU_DECLS; \ 1815507c2bfSRichard Henderson XDATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; \ 1825507c2bfSRichard Henderson XDATA_TYPE cmp, old, new, val = xval; \ 183*d071f4cdSEmilio G. Cota \ 184*d071f4cdSEmilio G. Cota ATOMIC_TRACE_RMW; \ 1855507c2bfSRichard Henderson smp_mb(); \ 1865507c2bfSRichard Henderson cmp = atomic_read__nocheck(haddr); \ 1875507c2bfSRichard Henderson do { \ 1885507c2bfSRichard Henderson old = cmp; new = FN(old, val); \ 1895507c2bfSRichard Henderson cmp = atomic_cmpxchg__nocheck(haddr, old, new); \ 1905507c2bfSRichard Henderson } while (cmp != old); \ 1915507c2bfSRichard Henderson ATOMIC_MMU_CLEANUP; \ 1925507c2bfSRichard Henderson return RET; \ 1935507c2bfSRichard Henderson } 1945507c2bfSRichard Henderson 1955507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_smin, MIN, SDATA_TYPE, old) 1965507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_umin, MIN, DATA_TYPE, old) 1975507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_smax, MAX, SDATA_TYPE, old) 1985507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_umax, MAX, DATA_TYPE, old) 1995507c2bfSRichard Henderson 2005507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(smin_fetch, MIN, SDATA_TYPE, new) 2015507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(umin_fetch, MIN, DATA_TYPE, new) 2025507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(smax_fetch, MAX, SDATA_TYPE, new) 2035507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(umax_fetch, MAX, DATA_TYPE, new) 2045507c2bfSRichard Henderson 2055507c2bfSRichard Henderson #undef GEN_ATOMIC_HELPER_FN 20610f7d4d5SPhilippe Mathieu-Daudé #endif /* DATA SIZE >= 16 */ 20710f7d4d5SPhilippe Mathieu-Daudé 20810f7d4d5SPhilippe Mathieu-Daudé #undef END 209*d071f4cdSEmilio G. Cota #undef MEND 21010f7d4d5SPhilippe Mathieu-Daudé 21110f7d4d5SPhilippe Mathieu-Daudé #if DATA_SIZE > 1 21210f7d4d5SPhilippe Mathieu-Daudé 21310f7d4d5SPhilippe Mathieu-Daudé /* Define reverse-host-endian atomic operations. Note that END is used 21410f7d4d5SPhilippe Mathieu-Daudé within the ATOMIC_NAME macro. */ 21510f7d4d5SPhilippe Mathieu-Daudé #ifdef HOST_WORDS_BIGENDIAN 21610f7d4d5SPhilippe Mathieu-Daudé # define END _le 217*d071f4cdSEmilio G. Cota # define MEND _le 21810f7d4d5SPhilippe Mathieu-Daudé #else 21910f7d4d5SPhilippe Mathieu-Daudé # define END _be 220*d071f4cdSEmilio G. Cota # define MEND _be 22110f7d4d5SPhilippe Mathieu-Daudé #endif 22210f7d4d5SPhilippe Mathieu-Daudé 22310f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr, 22410f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE cmpv, ABI_TYPE newv EXTRA_ARGS) 22510f7d4d5SPhilippe Mathieu-Daudé { 22634d49937SPeter Maydell ATOMIC_MMU_DECLS; 22710f7d4d5SPhilippe Mathieu-Daudé DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; 228*d071f4cdSEmilio G. Cota DATA_TYPE ret; 229*d071f4cdSEmilio G. Cota 230*d071f4cdSEmilio G. Cota ATOMIC_TRACE_RMW; 231*d071f4cdSEmilio G. Cota ret = atomic_cmpxchg__nocheck(haddr, BSWAP(cmpv), BSWAP(newv)); 232ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; 233ec603b55SRichard Henderson return BSWAP(ret); 23410f7d4d5SPhilippe Mathieu-Daudé } 23510f7d4d5SPhilippe Mathieu-Daudé 23610f7d4d5SPhilippe Mathieu-Daudé #if DATA_SIZE >= 16 23710f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr EXTRA_ARGS) 23810f7d4d5SPhilippe Mathieu-Daudé { 23934d49937SPeter Maydell ATOMIC_MMU_DECLS; 24010f7d4d5SPhilippe Mathieu-Daudé DATA_TYPE val, *haddr = ATOMIC_MMU_LOOKUP; 241*d071f4cdSEmilio G. Cota 242*d071f4cdSEmilio G. Cota ATOMIC_TRACE_LD; 24310f7d4d5SPhilippe Mathieu-Daudé __atomic_load(haddr, &val, __ATOMIC_RELAXED); 244ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; 24510f7d4d5SPhilippe Mathieu-Daudé return BSWAP(val); 24610f7d4d5SPhilippe Mathieu-Daudé } 24710f7d4d5SPhilippe Mathieu-Daudé 24810f7d4d5SPhilippe Mathieu-Daudé void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr, 24910f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE val EXTRA_ARGS) 25010f7d4d5SPhilippe Mathieu-Daudé { 25134d49937SPeter Maydell ATOMIC_MMU_DECLS; 25210f7d4d5SPhilippe Mathieu-Daudé DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; 253*d071f4cdSEmilio G. Cota 254*d071f4cdSEmilio G. Cota ATOMIC_TRACE_ST; 25510f7d4d5SPhilippe Mathieu-Daudé val = BSWAP(val); 25610f7d4d5SPhilippe Mathieu-Daudé __atomic_store(haddr, &val, __ATOMIC_RELAXED); 257ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; 25810f7d4d5SPhilippe Mathieu-Daudé } 25910f7d4d5SPhilippe Mathieu-Daudé #else 26010f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr, 26110f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE val EXTRA_ARGS) 26210f7d4d5SPhilippe Mathieu-Daudé { 26334d49937SPeter Maydell ATOMIC_MMU_DECLS; 26410f7d4d5SPhilippe Mathieu-Daudé DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; 265*d071f4cdSEmilio G. Cota ABI_TYPE ret; 266*d071f4cdSEmilio G. Cota 267*d071f4cdSEmilio G. Cota ATOMIC_TRACE_RMW; 268*d071f4cdSEmilio G. Cota ret = atomic_xchg__nocheck(haddr, BSWAP(val)); 269ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; 270ec603b55SRichard Henderson return BSWAP(ret); 27110f7d4d5SPhilippe Mathieu-Daudé } 27210f7d4d5SPhilippe Mathieu-Daudé 27310f7d4d5SPhilippe Mathieu-Daudé #define GEN_ATOMIC_HELPER(X) \ 27410f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \ 27510f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE val EXTRA_ARGS) \ 27610f7d4d5SPhilippe Mathieu-Daudé { \ 27734d49937SPeter Maydell ATOMIC_MMU_DECLS; \ 27810f7d4d5SPhilippe Mathieu-Daudé DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; \ 279*d071f4cdSEmilio G. Cota DATA_TYPE ret; \ 280*d071f4cdSEmilio G. Cota \ 281*d071f4cdSEmilio G. Cota ATOMIC_TRACE_RMW; \ 282*d071f4cdSEmilio G. Cota ret = atomic_##X(haddr, BSWAP(val)); \ 283ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; \ 284ec603b55SRichard Henderson return BSWAP(ret); \ 28510f7d4d5SPhilippe Mathieu-Daudé } 28610f7d4d5SPhilippe Mathieu-Daudé 28710f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_and) 28810f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_or) 28910f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_xor) 29010f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(and_fetch) 29110f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(or_fetch) 29210f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(xor_fetch) 29310f7d4d5SPhilippe Mathieu-Daudé 29410f7d4d5SPhilippe Mathieu-Daudé #undef GEN_ATOMIC_HELPER 29510f7d4d5SPhilippe Mathieu-Daudé 2965507c2bfSRichard Henderson /* These helpers are, as a whole, full barriers. Within the helper, 2975507c2bfSRichard Henderson * the leading barrier is explicit and the trailing barrier is within 2985507c2bfSRichard Henderson * cmpxchg primitive. 299*d071f4cdSEmilio G. Cota * 300*d071f4cdSEmilio G. Cota * Trace this load + RMW loop as a single RMW op. This way, regardless 301*d071f4cdSEmilio G. Cota * of CF_PARALLEL's value, we'll trace just a read and a write. 3025507c2bfSRichard Henderson */ 3035507c2bfSRichard Henderson #define GEN_ATOMIC_HELPER_FN(X, FN, XDATA_TYPE, RET) \ 3045507c2bfSRichard Henderson ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \ 3055507c2bfSRichard Henderson ABI_TYPE xval EXTRA_ARGS) \ 3065507c2bfSRichard Henderson { \ 3075507c2bfSRichard Henderson ATOMIC_MMU_DECLS; \ 3085507c2bfSRichard Henderson XDATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; \ 3095507c2bfSRichard Henderson XDATA_TYPE ldo, ldn, old, new, val = xval; \ 310*d071f4cdSEmilio G. Cota \ 311*d071f4cdSEmilio G. Cota ATOMIC_TRACE_RMW; \ 3125507c2bfSRichard Henderson smp_mb(); \ 3135507c2bfSRichard Henderson ldn = atomic_read__nocheck(haddr); \ 3145507c2bfSRichard Henderson do { \ 3155507c2bfSRichard Henderson ldo = ldn; old = BSWAP(ldo); new = FN(old, val); \ 3165507c2bfSRichard Henderson ldn = atomic_cmpxchg__nocheck(haddr, ldo, BSWAP(new)); \ 3175507c2bfSRichard Henderson } while (ldo != ldn); \ 3185507c2bfSRichard Henderson ATOMIC_MMU_CLEANUP; \ 3195507c2bfSRichard Henderson return RET; \ 3205507c2bfSRichard Henderson } 3215507c2bfSRichard Henderson 3225507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_smin, MIN, SDATA_TYPE, old) 3235507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_umin, MIN, DATA_TYPE, old) 3245507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_smax, MAX, SDATA_TYPE, old) 3255507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_umax, MAX, DATA_TYPE, old) 3265507c2bfSRichard Henderson 3275507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(smin_fetch, MIN, SDATA_TYPE, new) 3285507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(umin_fetch, MIN, DATA_TYPE, new) 3295507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(smax_fetch, MAX, SDATA_TYPE, new) 3305507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(umax_fetch, MAX, DATA_TYPE, new) 3315507c2bfSRichard Henderson 33258edf9eeSRichard Henderson /* Note that for addition, we need to use a separate cmpxchg loop instead 33358edf9eeSRichard Henderson of bswaps for the reverse-host-endian helpers. */ 33458edf9eeSRichard Henderson #define ADD(X, Y) (X + Y) 33558edf9eeSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_add, ADD, DATA_TYPE, old) 33658edf9eeSRichard Henderson GEN_ATOMIC_HELPER_FN(add_fetch, ADD, DATA_TYPE, new) 33758edf9eeSRichard Henderson #undef ADD 33858edf9eeSRichard Henderson 3395507c2bfSRichard Henderson #undef GEN_ATOMIC_HELPER_FN 34010f7d4d5SPhilippe Mathieu-Daudé #endif /* DATA_SIZE >= 16 */ 34110f7d4d5SPhilippe Mathieu-Daudé 34210f7d4d5SPhilippe Mathieu-Daudé #undef END 343*d071f4cdSEmilio G. Cota #undef MEND 34410f7d4d5SPhilippe Mathieu-Daudé #endif /* DATA_SIZE > 1 */ 34510f7d4d5SPhilippe Mathieu-Daudé 346*d071f4cdSEmilio G. Cota #undef ATOMIC_TRACE_ST 347*d071f4cdSEmilio G. Cota #undef ATOMIC_TRACE_LD 348*d071f4cdSEmilio G. Cota #undef ATOMIC_TRACE_RMW 349*d071f4cdSEmilio G. Cota 35010f7d4d5SPhilippe Mathieu-Daudé #undef BSWAP 35110f7d4d5SPhilippe Mathieu-Daudé #undef ABI_TYPE 35210f7d4d5SPhilippe Mathieu-Daudé #undef DATA_TYPE 3535507c2bfSRichard Henderson #undef SDATA_TYPE 35410f7d4d5SPhilippe Mathieu-Daudé #undef SUFFIX 35510f7d4d5SPhilippe Mathieu-Daudé #undef DATA_SIZE 356*d071f4cdSEmilio G. Cota #undef SHIFT 357