1c482cb11SRichard Henderson /* 2c482cb11SRichard Henderson * Atomic helper templates 3c482cb11SRichard Henderson * Included from tcg-runtime.c and cputlb.c. 4c482cb11SRichard Henderson * 5c482cb11SRichard Henderson * Copyright (c) 2016 Red Hat, Inc 6c482cb11SRichard Henderson * 7c482cb11SRichard Henderson * This library is free software; you can redistribute it and/or 8c482cb11SRichard Henderson * modify it under the terms of the GNU Lesser General Public 9c482cb11SRichard Henderson * License as published by the Free Software Foundation; either 10fb0343d5SThomas Huth * version 2.1 of the License, or (at your option) any later version. 11c482cb11SRichard Henderson * 12c482cb11SRichard Henderson * This library is distributed in the hope that it will be useful, 13c482cb11SRichard Henderson * but WITHOUT ANY WARRANTY; without even the implied warranty of 14c482cb11SRichard Henderson * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15c482cb11SRichard Henderson * Lesser General Public License for more details. 16c482cb11SRichard Henderson * 17c482cb11SRichard Henderson * You should have received a copy of the GNU Lesser General Public 18c482cb11SRichard Henderson * License along with this library; if not, see <http://www.gnu.org/licenses/>. 19c482cb11SRichard Henderson */ 20c482cb11SRichard Henderson 21d071f4cdSEmilio G. Cota #include "trace/mem.h" 22d071f4cdSEmilio G. Cota 237ebee43eSRichard Henderson #if DATA_SIZE == 16 247ebee43eSRichard Henderson # define SUFFIX o 257ebee43eSRichard Henderson # define DATA_TYPE Int128 267ebee43eSRichard Henderson # define BSWAP bswap128 27d071f4cdSEmilio G. Cota # define SHIFT 4 287ebee43eSRichard Henderson #elif DATA_SIZE == 8 29c482cb11SRichard Henderson # define SUFFIX q 30c482cb11SRichard Henderson # define DATA_TYPE uint64_t 315507c2bfSRichard Henderson # define SDATA_TYPE int64_t 32c482cb11SRichard Henderson # define BSWAP bswap64 33d071f4cdSEmilio G. Cota # define SHIFT 3 34c482cb11SRichard Henderson #elif DATA_SIZE == 4 35c482cb11SRichard Henderson # define SUFFIX l 36c482cb11SRichard Henderson # define DATA_TYPE uint32_t 375507c2bfSRichard Henderson # define SDATA_TYPE int32_t 38c482cb11SRichard Henderson # define BSWAP bswap32 39d071f4cdSEmilio G. Cota # define SHIFT 2 40c482cb11SRichard Henderson #elif DATA_SIZE == 2 41c482cb11SRichard Henderson # define SUFFIX w 42c482cb11SRichard Henderson # define DATA_TYPE uint16_t 435507c2bfSRichard Henderson # define SDATA_TYPE int16_t 44c482cb11SRichard Henderson # define BSWAP bswap16 45d071f4cdSEmilio G. Cota # define SHIFT 1 46c482cb11SRichard Henderson #elif DATA_SIZE == 1 47c482cb11SRichard Henderson # define SUFFIX b 48c482cb11SRichard Henderson # define DATA_TYPE uint8_t 495507c2bfSRichard Henderson # define SDATA_TYPE int8_t 50c482cb11SRichard Henderson # define BSWAP 51d071f4cdSEmilio G. Cota # define SHIFT 0 52c482cb11SRichard Henderson #else 53c482cb11SRichard Henderson # error unsupported data size 54c482cb11SRichard Henderson #endif 55c482cb11SRichard Henderson 56c482cb11SRichard Henderson #if DATA_SIZE >= 4 57c482cb11SRichard Henderson # define ABI_TYPE DATA_TYPE 58c482cb11SRichard Henderson #else 59c482cb11SRichard Henderson # define ABI_TYPE uint32_t 60c482cb11SRichard Henderson #endif 61c482cb11SRichard Henderson 62c482cb11SRichard Henderson /* Define host-endian atomic operations. Note that END is used within 63c482cb11SRichard Henderson the ATOMIC_NAME macro, and redefined below. */ 64c482cb11SRichard Henderson #if DATA_SIZE == 1 65c482cb11SRichard Henderson # define END 66d071f4cdSEmilio G. Cota # define MEND _be /* either le or be would be fine */ 67c482cb11SRichard Henderson #elif defined(HOST_WORDS_BIGENDIAN) 68c482cb11SRichard Henderson # define END _be 69d071f4cdSEmilio G. Cota # define MEND _be 70c482cb11SRichard Henderson #else 71c482cb11SRichard Henderson # define END _le 72d071f4cdSEmilio G. Cota # define MEND _le 73c482cb11SRichard Henderson #endif 74c482cb11SRichard Henderson 75c482cb11SRichard Henderson ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr, 76c482cb11SRichard Henderson ABI_TYPE cmpv, ABI_TYPE newv EXTRA_ARGS) 77c482cb11SRichard Henderson { 7834d49937SPeter Maydell ATOMIC_MMU_DECLS; 79c482cb11SRichard Henderson DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; 80d071f4cdSEmilio G. Cota DATA_TYPE ret; 81*cfec3885SEmilio G. Cota uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, false, 82*cfec3885SEmilio G. Cota ATOMIC_MMU_IDX); 83d071f4cdSEmilio G. Cota 84*cfec3885SEmilio G. Cota atomic_trace_rmw_pre(env, addr, info); 85e6cd4bb5SRichard Henderson #if DATA_SIZE == 16 86e6cd4bb5SRichard Henderson ret = atomic16_cmpxchg(haddr, cmpv, newv); 87e6cd4bb5SRichard Henderson #else 88d071f4cdSEmilio G. Cota ret = atomic_cmpxchg__nocheck(haddr, cmpv, newv); 89e6cd4bb5SRichard Henderson #endif 90ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; 91*cfec3885SEmilio G. Cota atomic_trace_rmw_post(env, addr, info); 92ec603b55SRichard Henderson return ret; 93c482cb11SRichard Henderson } 94c482cb11SRichard Henderson 957ebee43eSRichard Henderson #if DATA_SIZE >= 16 96e6cd4bb5SRichard Henderson #if HAVE_ATOMIC128 977ebee43eSRichard Henderson ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr EXTRA_ARGS) 987ebee43eSRichard Henderson { 9934d49937SPeter Maydell ATOMIC_MMU_DECLS; 1007ebee43eSRichard Henderson DATA_TYPE val, *haddr = ATOMIC_MMU_LOOKUP; 101*cfec3885SEmilio G. Cota uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, false, 102*cfec3885SEmilio G. Cota ATOMIC_MMU_IDX); 103d071f4cdSEmilio G. Cota 104*cfec3885SEmilio G. Cota atomic_trace_ld_pre(env, addr, info); 105e6cd4bb5SRichard Henderson val = atomic16_read(haddr); 106ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; 107*cfec3885SEmilio G. Cota atomic_trace_ld_post(env, addr, info); 1087ebee43eSRichard Henderson return val; 1097ebee43eSRichard Henderson } 1107ebee43eSRichard Henderson 1117ebee43eSRichard Henderson void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr, 1127ebee43eSRichard Henderson ABI_TYPE val EXTRA_ARGS) 1137ebee43eSRichard Henderson { 11434d49937SPeter Maydell ATOMIC_MMU_DECLS; 1157ebee43eSRichard Henderson DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; 116*cfec3885SEmilio G. Cota uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, true, 117*cfec3885SEmilio G. Cota ATOMIC_MMU_IDX); 118d071f4cdSEmilio G. Cota 119*cfec3885SEmilio G. Cota atomic_trace_st_pre(env, addr, info); 120e6cd4bb5SRichard Henderson atomic16_set(haddr, val); 121ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; 122*cfec3885SEmilio G. Cota atomic_trace_st_post(env, addr, info); 1237ebee43eSRichard Henderson } 124e6cd4bb5SRichard Henderson #endif 1257ebee43eSRichard Henderson #else 126c482cb11SRichard Henderson ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr, 127c482cb11SRichard Henderson ABI_TYPE val EXTRA_ARGS) 128c482cb11SRichard Henderson { 12934d49937SPeter Maydell ATOMIC_MMU_DECLS; 130c482cb11SRichard Henderson DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; 131d071f4cdSEmilio G. Cota DATA_TYPE ret; 132*cfec3885SEmilio G. Cota uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, false, 133*cfec3885SEmilio G. Cota ATOMIC_MMU_IDX); 134d071f4cdSEmilio G. Cota 135*cfec3885SEmilio G. Cota atomic_trace_rmw_pre(env, addr, info); 136d071f4cdSEmilio G. Cota ret = atomic_xchg__nocheck(haddr, val); 137ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; 138*cfec3885SEmilio G. Cota atomic_trace_rmw_post(env, addr, info); 139ec603b55SRichard Henderson return ret; 140c482cb11SRichard Henderson } 141c482cb11SRichard Henderson 142c482cb11SRichard Henderson #define GEN_ATOMIC_HELPER(X) \ 143c482cb11SRichard Henderson ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \ 144c482cb11SRichard Henderson ABI_TYPE val EXTRA_ARGS) \ 145c482cb11SRichard Henderson { \ 14634d49937SPeter Maydell ATOMIC_MMU_DECLS; \ 147c482cb11SRichard Henderson DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; \ 148d071f4cdSEmilio G. Cota DATA_TYPE ret; \ 149*cfec3885SEmilio G. Cota uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, \ 150*cfec3885SEmilio G. Cota false, \ 151*cfec3885SEmilio G. Cota ATOMIC_MMU_IDX); \ 152d071f4cdSEmilio G. Cota \ 153*cfec3885SEmilio G. Cota atomic_trace_rmw_pre(env, addr, info); \ 154d071f4cdSEmilio G. Cota ret = atomic_##X(haddr, val); \ 155ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; \ 156*cfec3885SEmilio G. Cota atomic_trace_rmw_post(env, addr, info); \ 157ec603b55SRichard Henderson return ret; \ 158ec603b55SRichard Henderson } 159c482cb11SRichard Henderson 160c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_add) 161c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_and) 162c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_or) 163c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_xor) 164c482cb11SRichard Henderson GEN_ATOMIC_HELPER(add_fetch) 165c482cb11SRichard Henderson GEN_ATOMIC_HELPER(and_fetch) 166c482cb11SRichard Henderson GEN_ATOMIC_HELPER(or_fetch) 167c482cb11SRichard Henderson GEN_ATOMIC_HELPER(xor_fetch) 168c482cb11SRichard Henderson 169c482cb11SRichard Henderson #undef GEN_ATOMIC_HELPER 1705507c2bfSRichard Henderson 1715507c2bfSRichard Henderson /* These helpers are, as a whole, full barriers. Within the helper, 1725507c2bfSRichard Henderson * the leading barrier is explicit and the trailing barrier is within 1735507c2bfSRichard Henderson * cmpxchg primitive. 174d071f4cdSEmilio G. Cota * 175d071f4cdSEmilio G. Cota * Trace this load + RMW loop as a single RMW op. This way, regardless 176d071f4cdSEmilio G. Cota * of CF_PARALLEL's value, we'll trace just a read and a write. 1775507c2bfSRichard Henderson */ 1785507c2bfSRichard Henderson #define GEN_ATOMIC_HELPER_FN(X, FN, XDATA_TYPE, RET) \ 1795507c2bfSRichard Henderson ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \ 1805507c2bfSRichard Henderson ABI_TYPE xval EXTRA_ARGS) \ 1815507c2bfSRichard Henderson { \ 1825507c2bfSRichard Henderson ATOMIC_MMU_DECLS; \ 1835507c2bfSRichard Henderson XDATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; \ 1845507c2bfSRichard Henderson XDATA_TYPE cmp, old, new, val = xval; \ 185*cfec3885SEmilio G. Cota uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, \ 186*cfec3885SEmilio G. Cota false, \ 187*cfec3885SEmilio G. Cota ATOMIC_MMU_IDX); \ 188d071f4cdSEmilio G. Cota \ 189*cfec3885SEmilio G. Cota atomic_trace_rmw_pre(env, addr, info); \ 1905507c2bfSRichard Henderson smp_mb(); \ 1915507c2bfSRichard Henderson cmp = atomic_read__nocheck(haddr); \ 1925507c2bfSRichard Henderson do { \ 1935507c2bfSRichard Henderson old = cmp; new = FN(old, val); \ 1945507c2bfSRichard Henderson cmp = atomic_cmpxchg__nocheck(haddr, old, new); \ 1955507c2bfSRichard Henderson } while (cmp != old); \ 1965507c2bfSRichard Henderson ATOMIC_MMU_CLEANUP; \ 197*cfec3885SEmilio G. Cota atomic_trace_rmw_post(env, addr, info); \ 1985507c2bfSRichard Henderson return RET; \ 1995507c2bfSRichard Henderson } 2005507c2bfSRichard Henderson 2015507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_smin, MIN, SDATA_TYPE, old) 2025507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_umin, MIN, DATA_TYPE, old) 2035507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_smax, MAX, SDATA_TYPE, old) 2045507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_umax, MAX, DATA_TYPE, old) 2055507c2bfSRichard Henderson 2065507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(smin_fetch, MIN, SDATA_TYPE, new) 2075507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(umin_fetch, MIN, DATA_TYPE, new) 2085507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(smax_fetch, MAX, SDATA_TYPE, new) 2095507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(umax_fetch, MAX, DATA_TYPE, new) 2105507c2bfSRichard Henderson 2115507c2bfSRichard Henderson #undef GEN_ATOMIC_HELPER_FN 2127ebee43eSRichard Henderson #endif /* DATA SIZE >= 16 */ 2137ebee43eSRichard Henderson 214c482cb11SRichard Henderson #undef END 215d071f4cdSEmilio G. Cota #undef MEND 216c482cb11SRichard Henderson 217c482cb11SRichard Henderson #if DATA_SIZE > 1 218c482cb11SRichard Henderson 219c482cb11SRichard Henderson /* Define reverse-host-endian atomic operations. Note that END is used 220c482cb11SRichard Henderson within the ATOMIC_NAME macro. */ 221c482cb11SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN 222c482cb11SRichard Henderson # define END _le 223d071f4cdSEmilio G. Cota # define MEND _le 224c482cb11SRichard Henderson #else 225c482cb11SRichard Henderson # define END _be 226d071f4cdSEmilio G. Cota # define MEND _be 227c482cb11SRichard Henderson #endif 228c482cb11SRichard Henderson 229c482cb11SRichard Henderson ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr, 230c482cb11SRichard Henderson ABI_TYPE cmpv, ABI_TYPE newv EXTRA_ARGS) 231c482cb11SRichard Henderson { 23234d49937SPeter Maydell ATOMIC_MMU_DECLS; 233c482cb11SRichard Henderson DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; 234d071f4cdSEmilio G. Cota DATA_TYPE ret; 235*cfec3885SEmilio G. Cota uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, 236*cfec3885SEmilio G. Cota false, 237*cfec3885SEmilio G. Cota ATOMIC_MMU_IDX); 238d071f4cdSEmilio G. Cota 239*cfec3885SEmilio G. Cota atomic_trace_rmw_pre(env, addr, info); 240e6cd4bb5SRichard Henderson #if DATA_SIZE == 16 241e6cd4bb5SRichard Henderson ret = atomic16_cmpxchg(haddr, BSWAP(cmpv), BSWAP(newv)); 242e6cd4bb5SRichard Henderson #else 243d071f4cdSEmilio G. Cota ret = atomic_cmpxchg__nocheck(haddr, BSWAP(cmpv), BSWAP(newv)); 244e6cd4bb5SRichard Henderson #endif 245ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; 246*cfec3885SEmilio G. Cota atomic_trace_rmw_post(env, addr, info); 247ec603b55SRichard Henderson return BSWAP(ret); 248c482cb11SRichard Henderson } 249c482cb11SRichard Henderson 2507ebee43eSRichard Henderson #if DATA_SIZE >= 16 251e6cd4bb5SRichard Henderson #if HAVE_ATOMIC128 2527ebee43eSRichard Henderson ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr EXTRA_ARGS) 2537ebee43eSRichard Henderson { 25434d49937SPeter Maydell ATOMIC_MMU_DECLS; 2557ebee43eSRichard Henderson DATA_TYPE val, *haddr = ATOMIC_MMU_LOOKUP; 256*cfec3885SEmilio G. Cota uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, 257*cfec3885SEmilio G. Cota false, 258*cfec3885SEmilio G. Cota ATOMIC_MMU_IDX); 259d071f4cdSEmilio G. Cota 260*cfec3885SEmilio G. Cota atomic_trace_ld_pre(env, addr, info); 261e6cd4bb5SRichard Henderson val = atomic16_read(haddr); 262ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; 263*cfec3885SEmilio G. Cota atomic_trace_ld_post(env, addr, info); 2647ebee43eSRichard Henderson return BSWAP(val); 2657ebee43eSRichard Henderson } 2667ebee43eSRichard Henderson 2677ebee43eSRichard Henderson void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr, 2687ebee43eSRichard Henderson ABI_TYPE val EXTRA_ARGS) 2697ebee43eSRichard Henderson { 27034d49937SPeter Maydell ATOMIC_MMU_DECLS; 2717ebee43eSRichard Henderson DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; 272*cfec3885SEmilio G. Cota uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, 273*cfec3885SEmilio G. Cota true, 274*cfec3885SEmilio G. Cota ATOMIC_MMU_IDX); 275d071f4cdSEmilio G. Cota 276*cfec3885SEmilio G. Cota val = BSWAP(val); 277*cfec3885SEmilio G. Cota atomic_trace_st_pre(env, addr, info); 2787ebee43eSRichard Henderson val = BSWAP(val); 279e6cd4bb5SRichard Henderson atomic16_set(haddr, val); 280ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; 281*cfec3885SEmilio G. Cota atomic_trace_st_post(env, addr, info); 2827ebee43eSRichard Henderson } 283e6cd4bb5SRichard Henderson #endif 2847ebee43eSRichard Henderson #else 285c482cb11SRichard Henderson ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr, 286c482cb11SRichard Henderson ABI_TYPE val EXTRA_ARGS) 287c482cb11SRichard Henderson { 28834d49937SPeter Maydell ATOMIC_MMU_DECLS; 289c482cb11SRichard Henderson DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; 290d071f4cdSEmilio G. Cota ABI_TYPE ret; 291*cfec3885SEmilio G. Cota uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, 292*cfec3885SEmilio G. Cota false, 293*cfec3885SEmilio G. Cota ATOMIC_MMU_IDX); 294d071f4cdSEmilio G. Cota 295*cfec3885SEmilio G. Cota atomic_trace_rmw_pre(env, addr, info); 296d071f4cdSEmilio G. Cota ret = atomic_xchg__nocheck(haddr, BSWAP(val)); 297ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; 298*cfec3885SEmilio G. Cota atomic_trace_rmw_post(env, addr, info); 299ec603b55SRichard Henderson return BSWAP(ret); 300c482cb11SRichard Henderson } 301c482cb11SRichard Henderson 302c482cb11SRichard Henderson #define GEN_ATOMIC_HELPER(X) \ 303c482cb11SRichard Henderson ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \ 304c482cb11SRichard Henderson ABI_TYPE val EXTRA_ARGS) \ 305c482cb11SRichard Henderson { \ 30634d49937SPeter Maydell ATOMIC_MMU_DECLS; \ 307c482cb11SRichard Henderson DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; \ 308d071f4cdSEmilio G. Cota DATA_TYPE ret; \ 309*cfec3885SEmilio G. Cota uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, \ 310*cfec3885SEmilio G. Cota false, \ 311*cfec3885SEmilio G. Cota ATOMIC_MMU_IDX); \ 312d071f4cdSEmilio G. Cota \ 313*cfec3885SEmilio G. Cota atomic_trace_rmw_pre(env, addr, info); \ 314d071f4cdSEmilio G. Cota ret = atomic_##X(haddr, BSWAP(val)); \ 315ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; \ 316*cfec3885SEmilio G. Cota atomic_trace_rmw_post(env, addr, info); \ 317ec603b55SRichard Henderson return BSWAP(ret); \ 318c482cb11SRichard Henderson } 319c482cb11SRichard Henderson 320c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_and) 321c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_or) 322c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_xor) 323c482cb11SRichard Henderson GEN_ATOMIC_HELPER(and_fetch) 324c482cb11SRichard Henderson GEN_ATOMIC_HELPER(or_fetch) 325c482cb11SRichard Henderson GEN_ATOMIC_HELPER(xor_fetch) 326c482cb11SRichard Henderson 327c482cb11SRichard Henderson #undef GEN_ATOMIC_HELPER 328c482cb11SRichard Henderson 3295507c2bfSRichard Henderson /* These helpers are, as a whole, full barriers. Within the helper, 3305507c2bfSRichard Henderson * the leading barrier is explicit and the trailing barrier is within 3315507c2bfSRichard Henderson * cmpxchg primitive. 332d071f4cdSEmilio G. Cota * 333d071f4cdSEmilio G. Cota * Trace this load + RMW loop as a single RMW op. This way, regardless 334d071f4cdSEmilio G. Cota * of CF_PARALLEL's value, we'll trace just a read and a write. 3355507c2bfSRichard Henderson */ 3365507c2bfSRichard Henderson #define GEN_ATOMIC_HELPER_FN(X, FN, XDATA_TYPE, RET) \ 3375507c2bfSRichard Henderson ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \ 3385507c2bfSRichard Henderson ABI_TYPE xval EXTRA_ARGS) \ 3395507c2bfSRichard Henderson { \ 3405507c2bfSRichard Henderson ATOMIC_MMU_DECLS; \ 3415507c2bfSRichard Henderson XDATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; \ 3425507c2bfSRichard Henderson XDATA_TYPE ldo, ldn, old, new, val = xval; \ 343*cfec3885SEmilio G. Cota uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, \ 344*cfec3885SEmilio G. Cota false, \ 345*cfec3885SEmilio G. Cota ATOMIC_MMU_IDX); \ 346d071f4cdSEmilio G. Cota \ 347*cfec3885SEmilio G. Cota atomic_trace_rmw_pre(env, addr, info); \ 3485507c2bfSRichard Henderson smp_mb(); \ 3495507c2bfSRichard Henderson ldn = atomic_read__nocheck(haddr); \ 3505507c2bfSRichard Henderson do { \ 3515507c2bfSRichard Henderson ldo = ldn; old = BSWAP(ldo); new = FN(old, val); \ 3525507c2bfSRichard Henderson ldn = atomic_cmpxchg__nocheck(haddr, ldo, BSWAP(new)); \ 3535507c2bfSRichard Henderson } while (ldo != ldn); \ 3545507c2bfSRichard Henderson ATOMIC_MMU_CLEANUP; \ 355*cfec3885SEmilio G. Cota atomic_trace_rmw_post(env, addr, info); \ 3565507c2bfSRichard Henderson return RET; \ 3575507c2bfSRichard Henderson } 3585507c2bfSRichard Henderson 3595507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_smin, MIN, SDATA_TYPE, old) 3605507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_umin, MIN, DATA_TYPE, old) 3615507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_smax, MAX, SDATA_TYPE, old) 3625507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_umax, MAX, DATA_TYPE, old) 3635507c2bfSRichard Henderson 3645507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(smin_fetch, MIN, SDATA_TYPE, new) 3655507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(umin_fetch, MIN, DATA_TYPE, new) 3665507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(smax_fetch, MAX, SDATA_TYPE, new) 3675507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(umax_fetch, MAX, DATA_TYPE, new) 3685507c2bfSRichard Henderson 36958edf9eeSRichard Henderson /* Note that for addition, we need to use a separate cmpxchg loop instead 37058edf9eeSRichard Henderson of bswaps for the reverse-host-endian helpers. */ 37158edf9eeSRichard Henderson #define ADD(X, Y) (X + Y) 37258edf9eeSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_add, ADD, DATA_TYPE, old) 37358edf9eeSRichard Henderson GEN_ATOMIC_HELPER_FN(add_fetch, ADD, DATA_TYPE, new) 37458edf9eeSRichard Henderson #undef ADD 37558edf9eeSRichard Henderson 3765507c2bfSRichard Henderson #undef GEN_ATOMIC_HELPER_FN 3777ebee43eSRichard Henderson #endif /* DATA_SIZE >= 16 */ 378c482cb11SRichard Henderson 379c482cb11SRichard Henderson #undef END 380d071f4cdSEmilio G. Cota #undef MEND 381c482cb11SRichard Henderson #endif /* DATA_SIZE > 1 */ 382c482cb11SRichard Henderson 383c482cb11SRichard Henderson #undef BSWAP 384c482cb11SRichard Henderson #undef ABI_TYPE 385c482cb11SRichard Henderson #undef DATA_TYPE 3865507c2bfSRichard Henderson #undef SDATA_TYPE 387c482cb11SRichard Henderson #undef SUFFIX 388c482cb11SRichard Henderson #undef DATA_SIZE 389d071f4cdSEmilio G. Cota #undef SHIFT 390