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 21e6d86bedSEmilio G. Cota #include "qemu/plugin.h" 22d071f4cdSEmilio G. Cota #include "trace/mem.h" 23d071f4cdSEmilio G. Cota 247ebee43eSRichard Henderson #if DATA_SIZE == 16 257ebee43eSRichard Henderson # define SUFFIX o 267ebee43eSRichard Henderson # define DATA_TYPE Int128 277ebee43eSRichard Henderson # define BSWAP bswap128 28d071f4cdSEmilio G. Cota # define SHIFT 4 297ebee43eSRichard Henderson #elif DATA_SIZE == 8 30c482cb11SRichard Henderson # define SUFFIX q 319ef0c6d6SRichard Henderson # define DATA_TYPE aligned_uint64_t 329ef0c6d6SRichard Henderson # define SDATA_TYPE aligned_int64_t 33c482cb11SRichard Henderson # define BSWAP bswap64 34d071f4cdSEmilio G. Cota # define SHIFT 3 35c482cb11SRichard Henderson #elif DATA_SIZE == 4 36c482cb11SRichard Henderson # define SUFFIX l 37c482cb11SRichard Henderson # define DATA_TYPE uint32_t 385507c2bfSRichard Henderson # define SDATA_TYPE int32_t 39c482cb11SRichard Henderson # define BSWAP bswap32 40d071f4cdSEmilio G. Cota # define SHIFT 2 41c482cb11SRichard Henderson #elif DATA_SIZE == 2 42c482cb11SRichard Henderson # define SUFFIX w 43c482cb11SRichard Henderson # define DATA_TYPE uint16_t 445507c2bfSRichard Henderson # define SDATA_TYPE int16_t 45c482cb11SRichard Henderson # define BSWAP bswap16 46d071f4cdSEmilio G. Cota # define SHIFT 1 47c482cb11SRichard Henderson #elif DATA_SIZE == 1 48c482cb11SRichard Henderson # define SUFFIX b 49c482cb11SRichard Henderson # define DATA_TYPE uint8_t 505507c2bfSRichard Henderson # define SDATA_TYPE int8_t 51c482cb11SRichard Henderson # define BSWAP 52d071f4cdSEmilio G. Cota # define SHIFT 0 53c482cb11SRichard Henderson #else 54c482cb11SRichard Henderson # error unsupported data size 55c482cb11SRichard Henderson #endif 56c482cb11SRichard Henderson 57c482cb11SRichard Henderson #if DATA_SIZE >= 4 58c482cb11SRichard Henderson # define ABI_TYPE DATA_TYPE 59c482cb11SRichard Henderson #else 60c482cb11SRichard Henderson # define ABI_TYPE uint32_t 61c482cb11SRichard Henderson #endif 62c482cb11SRichard Henderson 63c482cb11SRichard Henderson /* Define host-endian atomic operations. Note that END is used within 64c482cb11SRichard Henderson the ATOMIC_NAME macro, and redefined below. */ 65c482cb11SRichard Henderson #if DATA_SIZE == 1 66c482cb11SRichard Henderson # define END 67c482cb11SRichard Henderson #elif defined(HOST_WORDS_BIGENDIAN) 68c482cb11SRichard Henderson # define END _be 69c482cb11SRichard Henderson #else 70c482cb11SRichard Henderson # define END _le 71c482cb11SRichard Henderson #endif 72c482cb11SRichard Henderson 73c482cb11SRichard Henderson ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr, 7448688fafSRichard Henderson ABI_TYPE cmpv, ABI_TYPE newv, 7548688fafSRichard Henderson TCGMemOpIdx oi, uintptr_t retaddr) 76c482cb11SRichard Henderson { 77*a754f7f3SRichard Henderson DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, 78*a754f7f3SRichard Henderson PAGE_READ | PAGE_WRITE, retaddr); 79d071f4cdSEmilio G. Cota DATA_TYPE ret; 804e6b1384SRichard Henderson uint16_t info = trace_mem_build_info(SHIFT, false, 0, false, 81cfec3885SEmilio G. Cota ATOMIC_MMU_IDX); 82d071f4cdSEmilio G. Cota 83cfec3885SEmilio G. Cota atomic_trace_rmw_pre(env, addr, info); 84e6cd4bb5SRichard Henderson #if DATA_SIZE == 16 85e6cd4bb5SRichard Henderson ret = atomic16_cmpxchg(haddr, cmpv, newv); 86e6cd4bb5SRichard Henderson #else 87d73415a3SStefan Hajnoczi ret = qatomic_cmpxchg__nocheck(haddr, cmpv, newv); 88e6cd4bb5SRichard Henderson #endif 89ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; 90cfec3885SEmilio G. Cota atomic_trace_rmw_post(env, addr, info); 91ec603b55SRichard Henderson return ret; 92c482cb11SRichard Henderson } 93c482cb11SRichard Henderson 947ebee43eSRichard Henderson #if DATA_SIZE >= 16 95e6cd4bb5SRichard Henderson #if HAVE_ATOMIC128 9648688fafSRichard Henderson ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr, 9748688fafSRichard Henderson TCGMemOpIdx oi, uintptr_t retaddr) 987ebee43eSRichard Henderson { 99*a754f7f3SRichard Henderson DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, 100*a754f7f3SRichard Henderson PAGE_READ, retaddr); 101*a754f7f3SRichard Henderson DATA_TYPE val; 1024e6b1384SRichard Henderson uint16_t info = trace_mem_build_info(SHIFT, false, 0, false, 103cfec3885SEmilio G. Cota ATOMIC_MMU_IDX); 104d071f4cdSEmilio G. Cota 105cfec3885SEmilio G. Cota atomic_trace_ld_pre(env, addr, info); 106e6cd4bb5SRichard Henderson val = atomic16_read(haddr); 107ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; 108cfec3885SEmilio G. Cota atomic_trace_ld_post(env, addr, info); 1097ebee43eSRichard Henderson return val; 1107ebee43eSRichard Henderson } 1117ebee43eSRichard Henderson 11248688fafSRichard Henderson void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr, ABI_TYPE val, 11348688fafSRichard Henderson TCGMemOpIdx oi, uintptr_t retaddr) 1147ebee43eSRichard Henderson { 115*a754f7f3SRichard Henderson DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, 116*a754f7f3SRichard Henderson PAGE_WRITE, retaddr); 1174e6b1384SRichard Henderson uint16_t info = trace_mem_build_info(SHIFT, false, 0, true, 118cfec3885SEmilio G. Cota ATOMIC_MMU_IDX); 119d071f4cdSEmilio G. Cota 120cfec3885SEmilio G. Cota atomic_trace_st_pre(env, addr, info); 121e6cd4bb5SRichard Henderson atomic16_set(haddr, val); 122ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; 123cfec3885SEmilio G. Cota atomic_trace_st_post(env, addr, info); 1247ebee43eSRichard Henderson } 125e6cd4bb5SRichard Henderson #endif 1267ebee43eSRichard Henderson #else 12748688fafSRichard Henderson ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr, ABI_TYPE val, 12848688fafSRichard Henderson TCGMemOpIdx oi, uintptr_t retaddr) 129c482cb11SRichard Henderson { 130*a754f7f3SRichard Henderson DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, 131*a754f7f3SRichard Henderson PAGE_READ | PAGE_WRITE, retaddr); 132d071f4cdSEmilio G. Cota DATA_TYPE ret; 1334e6b1384SRichard Henderson uint16_t info = trace_mem_build_info(SHIFT, false, 0, false, 134cfec3885SEmilio G. Cota ATOMIC_MMU_IDX); 135d071f4cdSEmilio G. Cota 136cfec3885SEmilio G. Cota atomic_trace_rmw_pre(env, addr, info); 137d73415a3SStefan Hajnoczi ret = qatomic_xchg__nocheck(haddr, val); 138ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; 139cfec3885SEmilio G. Cota atomic_trace_rmw_post(env, addr, info); 140ec603b55SRichard Henderson return ret; 141c482cb11SRichard Henderson } 142c482cb11SRichard Henderson 143c482cb11SRichard Henderson #define GEN_ATOMIC_HELPER(X) \ 144c482cb11SRichard Henderson ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \ 14548688fafSRichard Henderson ABI_TYPE val, TCGMemOpIdx oi, uintptr_t retaddr) \ 146c482cb11SRichard Henderson { \ 147*a754f7f3SRichard Henderson DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, \ 148*a754f7f3SRichard Henderson PAGE_READ | PAGE_WRITE, retaddr); \ 149d071f4cdSEmilio G. Cota DATA_TYPE ret; \ 1504e6b1384SRichard Henderson uint16_t info = trace_mem_build_info(SHIFT, false, 0, false, \ 151cfec3885SEmilio G. Cota ATOMIC_MMU_IDX); \ 152cfec3885SEmilio G. Cota atomic_trace_rmw_pre(env, addr, info); \ 153d73415a3SStefan Hajnoczi ret = qatomic_##X(haddr, val); \ 154ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; \ 155cfec3885SEmilio G. Cota atomic_trace_rmw_post(env, addr, info); \ 156ec603b55SRichard Henderson return ret; \ 157ec603b55SRichard Henderson } 158c482cb11SRichard Henderson 159c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_add) 160c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_and) 161c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_or) 162c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_xor) 163c482cb11SRichard Henderson GEN_ATOMIC_HELPER(add_fetch) 164c482cb11SRichard Henderson GEN_ATOMIC_HELPER(and_fetch) 165c482cb11SRichard Henderson GEN_ATOMIC_HELPER(or_fetch) 166c482cb11SRichard Henderson GEN_ATOMIC_HELPER(xor_fetch) 167c482cb11SRichard Henderson 168c482cb11SRichard Henderson #undef GEN_ATOMIC_HELPER 1695507c2bfSRichard Henderson 170*a754f7f3SRichard Henderson /* 171*a754f7f3SRichard 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, \ 18048688fafSRichard Henderson ABI_TYPE xval, TCGMemOpIdx oi, uintptr_t retaddr) \ 1815507c2bfSRichard Henderson { \ 182*a754f7f3SRichard Henderson XDATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, \ 183*a754f7f3SRichard Henderson PAGE_READ | PAGE_WRITE, retaddr); \ 1845507c2bfSRichard Henderson XDATA_TYPE cmp, old, new, val = xval; \ 1854e6b1384SRichard Henderson uint16_t info = trace_mem_build_info(SHIFT, false, 0, false, \ 186cfec3885SEmilio G. Cota ATOMIC_MMU_IDX); \ 187cfec3885SEmilio G. Cota atomic_trace_rmw_pre(env, addr, info); \ 1885507c2bfSRichard Henderson smp_mb(); \ 189d73415a3SStefan Hajnoczi cmp = qatomic_read__nocheck(haddr); \ 1905507c2bfSRichard Henderson do { \ 1915507c2bfSRichard Henderson old = cmp; new = FN(old, val); \ 192d73415a3SStefan Hajnoczi cmp = qatomic_cmpxchg__nocheck(haddr, old, new); \ 1935507c2bfSRichard Henderson } while (cmp != old); \ 1945507c2bfSRichard Henderson ATOMIC_MMU_CLEANUP; \ 195cfec3885SEmilio G. Cota atomic_trace_rmw_post(env, addr, info); \ 1965507c2bfSRichard Henderson return RET; \ 1975507c2bfSRichard Henderson } 1985507c2bfSRichard Henderson 1995507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_smin, MIN, SDATA_TYPE, old) 2005507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_umin, MIN, DATA_TYPE, old) 2015507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_smax, MAX, SDATA_TYPE, old) 2025507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_umax, MAX, DATA_TYPE, old) 2035507c2bfSRichard Henderson 2045507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(smin_fetch, MIN, SDATA_TYPE, new) 2055507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(umin_fetch, MIN, DATA_TYPE, new) 2065507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(smax_fetch, MAX, SDATA_TYPE, new) 2075507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(umax_fetch, MAX, DATA_TYPE, new) 2085507c2bfSRichard Henderson 2095507c2bfSRichard Henderson #undef GEN_ATOMIC_HELPER_FN 2107ebee43eSRichard Henderson #endif /* DATA SIZE >= 16 */ 2117ebee43eSRichard Henderson 212c482cb11SRichard Henderson #undef END 213c482cb11SRichard Henderson 214c482cb11SRichard Henderson #if DATA_SIZE > 1 215c482cb11SRichard Henderson 216c482cb11SRichard Henderson /* Define reverse-host-endian atomic operations. Note that END is used 217c482cb11SRichard Henderson within the ATOMIC_NAME macro. */ 218c482cb11SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN 219c482cb11SRichard Henderson # define END _le 220c482cb11SRichard Henderson #else 221c482cb11SRichard Henderson # define END _be 222c482cb11SRichard Henderson #endif 223c482cb11SRichard Henderson 224c482cb11SRichard Henderson ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr, 22548688fafSRichard Henderson ABI_TYPE cmpv, ABI_TYPE newv, 22648688fafSRichard Henderson TCGMemOpIdx oi, uintptr_t retaddr) 227c482cb11SRichard Henderson { 228*a754f7f3SRichard Henderson DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, 229*a754f7f3SRichard Henderson PAGE_READ | PAGE_WRITE, retaddr); 230d071f4cdSEmilio G. Cota DATA_TYPE ret; 2314e6b1384SRichard Henderson uint16_t info = trace_mem_build_info(SHIFT, false, MO_BSWAP, false, 232cfec3885SEmilio G. Cota ATOMIC_MMU_IDX); 233d071f4cdSEmilio G. Cota 234cfec3885SEmilio G. Cota atomic_trace_rmw_pre(env, addr, info); 235e6cd4bb5SRichard Henderson #if DATA_SIZE == 16 236e6cd4bb5SRichard Henderson ret = atomic16_cmpxchg(haddr, BSWAP(cmpv), BSWAP(newv)); 237e6cd4bb5SRichard Henderson #else 238d73415a3SStefan Hajnoczi ret = qatomic_cmpxchg__nocheck(haddr, BSWAP(cmpv), BSWAP(newv)); 239e6cd4bb5SRichard Henderson #endif 240ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; 241cfec3885SEmilio G. Cota atomic_trace_rmw_post(env, addr, info); 242ec603b55SRichard Henderson return BSWAP(ret); 243c482cb11SRichard Henderson } 244c482cb11SRichard Henderson 2457ebee43eSRichard Henderson #if DATA_SIZE >= 16 246e6cd4bb5SRichard Henderson #if HAVE_ATOMIC128 24748688fafSRichard Henderson ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr, 24848688fafSRichard Henderson TCGMemOpIdx oi, uintptr_t retaddr) 2497ebee43eSRichard Henderson { 250*a754f7f3SRichard Henderson DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, 251*a754f7f3SRichard Henderson PAGE_READ, retaddr); 252*a754f7f3SRichard Henderson DATA_TYPE val; 2534e6b1384SRichard Henderson uint16_t info = trace_mem_build_info(SHIFT, false, MO_BSWAP, false, 254cfec3885SEmilio G. Cota ATOMIC_MMU_IDX); 255d071f4cdSEmilio G. Cota 256cfec3885SEmilio G. Cota atomic_trace_ld_pre(env, addr, info); 257e6cd4bb5SRichard Henderson val = atomic16_read(haddr); 258ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; 259cfec3885SEmilio G. Cota atomic_trace_ld_post(env, addr, info); 2607ebee43eSRichard Henderson return BSWAP(val); 2617ebee43eSRichard Henderson } 2627ebee43eSRichard Henderson 26348688fafSRichard Henderson void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr, ABI_TYPE val, 26448688fafSRichard Henderson TCGMemOpIdx oi, uintptr_t retaddr) 2657ebee43eSRichard Henderson { 266*a754f7f3SRichard Henderson DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, 267*a754f7f3SRichard Henderson PAGE_WRITE, retaddr); 2684e6b1384SRichard Henderson uint16_t info = trace_mem_build_info(SHIFT, false, MO_BSWAP, true, 269cfec3885SEmilio G. Cota ATOMIC_MMU_IDX); 270d071f4cdSEmilio G. Cota 271cfec3885SEmilio G. Cota val = BSWAP(val); 272cfec3885SEmilio G. Cota atomic_trace_st_pre(env, addr, info); 2737ebee43eSRichard Henderson val = BSWAP(val); 274e6cd4bb5SRichard Henderson atomic16_set(haddr, val); 275ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; 276cfec3885SEmilio G. Cota atomic_trace_st_post(env, addr, info); 2777ebee43eSRichard Henderson } 278e6cd4bb5SRichard Henderson #endif 2797ebee43eSRichard Henderson #else 28048688fafSRichard Henderson ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr, ABI_TYPE val, 28148688fafSRichard Henderson TCGMemOpIdx oi, uintptr_t retaddr) 282c482cb11SRichard Henderson { 283*a754f7f3SRichard Henderson DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, 284*a754f7f3SRichard Henderson PAGE_READ | PAGE_WRITE, retaddr); 285d071f4cdSEmilio G. Cota ABI_TYPE ret; 2864e6b1384SRichard Henderson uint16_t info = trace_mem_build_info(SHIFT, false, MO_BSWAP, false, 287cfec3885SEmilio G. Cota ATOMIC_MMU_IDX); 288d071f4cdSEmilio G. Cota 289cfec3885SEmilio G. Cota atomic_trace_rmw_pre(env, addr, info); 290d73415a3SStefan Hajnoczi ret = qatomic_xchg__nocheck(haddr, BSWAP(val)); 291ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; 292cfec3885SEmilio G. Cota atomic_trace_rmw_post(env, addr, info); 293ec603b55SRichard Henderson return BSWAP(ret); 294c482cb11SRichard Henderson } 295c482cb11SRichard Henderson 296c482cb11SRichard Henderson #define GEN_ATOMIC_HELPER(X) \ 297c482cb11SRichard Henderson ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \ 29848688fafSRichard Henderson ABI_TYPE val, TCGMemOpIdx oi, uintptr_t retaddr) \ 299c482cb11SRichard Henderson { \ 300*a754f7f3SRichard Henderson DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, \ 301*a754f7f3SRichard Henderson PAGE_READ | PAGE_WRITE, retaddr); \ 302d071f4cdSEmilio G. Cota DATA_TYPE ret; \ 3034e6b1384SRichard Henderson uint16_t info = trace_mem_build_info(SHIFT, false, MO_BSWAP, \ 3044e6b1384SRichard Henderson false, ATOMIC_MMU_IDX); \ 305cfec3885SEmilio G. Cota atomic_trace_rmw_pre(env, addr, info); \ 306d73415a3SStefan Hajnoczi ret = qatomic_##X(haddr, BSWAP(val)); \ 307ec603b55SRichard Henderson ATOMIC_MMU_CLEANUP; \ 308cfec3885SEmilio G. Cota atomic_trace_rmw_post(env, addr, info); \ 309ec603b55SRichard Henderson return BSWAP(ret); \ 310c482cb11SRichard Henderson } 311c482cb11SRichard Henderson 312c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_and) 313c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_or) 314c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_xor) 315c482cb11SRichard Henderson GEN_ATOMIC_HELPER(and_fetch) 316c482cb11SRichard Henderson GEN_ATOMIC_HELPER(or_fetch) 317c482cb11SRichard Henderson GEN_ATOMIC_HELPER(xor_fetch) 318c482cb11SRichard Henderson 319c482cb11SRichard Henderson #undef GEN_ATOMIC_HELPER 320c482cb11SRichard Henderson 3215507c2bfSRichard Henderson /* These helpers are, as a whole, full barriers. Within the helper, 3225507c2bfSRichard Henderson * the leading barrier is explicit and the trailing barrier is within 3235507c2bfSRichard Henderson * cmpxchg primitive. 324d071f4cdSEmilio G. Cota * 325d071f4cdSEmilio G. Cota * Trace this load + RMW loop as a single RMW op. This way, regardless 326d071f4cdSEmilio G. Cota * of CF_PARALLEL's value, we'll trace just a read and a write. 3275507c2bfSRichard Henderson */ 3285507c2bfSRichard Henderson #define GEN_ATOMIC_HELPER_FN(X, FN, XDATA_TYPE, RET) \ 3295507c2bfSRichard Henderson ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \ 33048688fafSRichard Henderson ABI_TYPE xval, TCGMemOpIdx oi, uintptr_t retaddr) \ 3315507c2bfSRichard Henderson { \ 332*a754f7f3SRichard Henderson XDATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, \ 333*a754f7f3SRichard Henderson PAGE_READ | PAGE_WRITE, retaddr); \ 3345507c2bfSRichard Henderson XDATA_TYPE ldo, ldn, old, new, val = xval; \ 3354e6b1384SRichard Henderson uint16_t info = trace_mem_build_info(SHIFT, false, MO_BSWAP, \ 3364e6b1384SRichard Henderson false, ATOMIC_MMU_IDX); \ 337cfec3885SEmilio G. Cota atomic_trace_rmw_pre(env, addr, info); \ 3385507c2bfSRichard Henderson smp_mb(); \ 339d73415a3SStefan Hajnoczi ldn = qatomic_read__nocheck(haddr); \ 3405507c2bfSRichard Henderson do { \ 3415507c2bfSRichard Henderson ldo = ldn; old = BSWAP(ldo); new = FN(old, val); \ 342d73415a3SStefan Hajnoczi ldn = qatomic_cmpxchg__nocheck(haddr, ldo, BSWAP(new)); \ 3435507c2bfSRichard Henderson } while (ldo != ldn); \ 3445507c2bfSRichard Henderson ATOMIC_MMU_CLEANUP; \ 345cfec3885SEmilio G. Cota atomic_trace_rmw_post(env, addr, info); \ 3465507c2bfSRichard Henderson return RET; \ 3475507c2bfSRichard Henderson } 3485507c2bfSRichard Henderson 3495507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_smin, MIN, SDATA_TYPE, old) 3505507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_umin, MIN, DATA_TYPE, old) 3515507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_smax, MAX, SDATA_TYPE, old) 3525507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_umax, MAX, DATA_TYPE, old) 3535507c2bfSRichard Henderson 3545507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(smin_fetch, MIN, SDATA_TYPE, new) 3555507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(umin_fetch, MIN, DATA_TYPE, new) 3565507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(smax_fetch, MAX, SDATA_TYPE, new) 3575507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(umax_fetch, MAX, DATA_TYPE, new) 3585507c2bfSRichard Henderson 35958edf9eeSRichard Henderson /* Note that for addition, we need to use a separate cmpxchg loop instead 36058edf9eeSRichard Henderson of bswaps for the reverse-host-endian helpers. */ 36158edf9eeSRichard Henderson #define ADD(X, Y) (X + Y) 36258edf9eeSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_add, ADD, DATA_TYPE, old) 36358edf9eeSRichard Henderson GEN_ATOMIC_HELPER_FN(add_fetch, ADD, DATA_TYPE, new) 36458edf9eeSRichard Henderson #undef ADD 36558edf9eeSRichard Henderson 3665507c2bfSRichard Henderson #undef GEN_ATOMIC_HELPER_FN 3677ebee43eSRichard Henderson #endif /* DATA_SIZE >= 16 */ 368c482cb11SRichard Henderson 369c482cb11SRichard Henderson #undef END 370c482cb11SRichard Henderson #endif /* DATA_SIZE > 1 */ 371c482cb11SRichard Henderson 372c482cb11SRichard Henderson #undef BSWAP 373c482cb11SRichard Henderson #undef ABI_TYPE 374c482cb11SRichard Henderson #undef DATA_TYPE 3755507c2bfSRichard Henderson #undef SDATA_TYPE 376c482cb11SRichard Henderson #undef SUFFIX 377c482cb11SRichard Henderson #undef DATA_SIZE 378d071f4cdSEmilio G. Cota #undef SHIFT 379