xref: /openbmc/qemu/accel/tcg/atomic_template.h (revision 48688fafeb6e9f462837abb39a9c286e39d398e4)
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
10fb0343d5SThomas Huth  * version 2.1 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é 
21e6d86bedSEmilio G. Cota #include "qemu/plugin.h"
22d071f4cdSEmilio G. Cota #include "trace/mem.h"
23d071f4cdSEmilio G. Cota 
2410f7d4d5SPhilippe Mathieu-Daudé #if DATA_SIZE == 16
2510f7d4d5SPhilippe Mathieu-Daudé # define SUFFIX     o
2610f7d4d5SPhilippe Mathieu-Daudé # define DATA_TYPE  Int128
2710f7d4d5SPhilippe Mathieu-Daudé # define BSWAP      bswap128
28d071f4cdSEmilio G. Cota # define SHIFT      4
2910f7d4d5SPhilippe Mathieu-Daudé #elif DATA_SIZE == 8
3010f7d4d5SPhilippe Mathieu-Daudé # define SUFFIX     q
319ef0c6d6SRichard Henderson # define DATA_TYPE  aligned_uint64_t
329ef0c6d6SRichard Henderson # define SDATA_TYPE aligned_int64_t
3310f7d4d5SPhilippe Mathieu-Daudé # define BSWAP      bswap64
34d071f4cdSEmilio G. Cota # define SHIFT      3
3510f7d4d5SPhilippe Mathieu-Daudé #elif DATA_SIZE == 4
3610f7d4d5SPhilippe Mathieu-Daudé # define SUFFIX     l
3710f7d4d5SPhilippe Mathieu-Daudé # define DATA_TYPE  uint32_t
385507c2bfSRichard Henderson # define SDATA_TYPE int32_t
3910f7d4d5SPhilippe Mathieu-Daudé # define BSWAP      bswap32
40d071f4cdSEmilio G. Cota # define SHIFT      2
4110f7d4d5SPhilippe Mathieu-Daudé #elif DATA_SIZE == 2
4210f7d4d5SPhilippe Mathieu-Daudé # define SUFFIX     w
4310f7d4d5SPhilippe Mathieu-Daudé # define DATA_TYPE  uint16_t
445507c2bfSRichard Henderson # define SDATA_TYPE int16_t
4510f7d4d5SPhilippe Mathieu-Daudé # define BSWAP      bswap16
46d071f4cdSEmilio G. Cota # define SHIFT      1
4710f7d4d5SPhilippe Mathieu-Daudé #elif DATA_SIZE == 1
4810f7d4d5SPhilippe Mathieu-Daudé # define SUFFIX     b
4910f7d4d5SPhilippe Mathieu-Daudé # define DATA_TYPE  uint8_t
505507c2bfSRichard Henderson # define SDATA_TYPE int8_t
5110f7d4d5SPhilippe Mathieu-Daudé # define BSWAP
52d071f4cdSEmilio G. Cota # define SHIFT      0
5310f7d4d5SPhilippe Mathieu-Daudé #else
5410f7d4d5SPhilippe Mathieu-Daudé # error unsupported data size
5510f7d4d5SPhilippe Mathieu-Daudé #endif
5610f7d4d5SPhilippe Mathieu-Daudé 
5710f7d4d5SPhilippe Mathieu-Daudé #if DATA_SIZE >= 4
5810f7d4d5SPhilippe Mathieu-Daudé # define ABI_TYPE  DATA_TYPE
5910f7d4d5SPhilippe Mathieu-Daudé #else
6010f7d4d5SPhilippe Mathieu-Daudé # define ABI_TYPE  uint32_t
6110f7d4d5SPhilippe Mathieu-Daudé #endif
6210f7d4d5SPhilippe Mathieu-Daudé 
6310f7d4d5SPhilippe Mathieu-Daudé /* Define host-endian atomic operations.  Note that END is used within
6410f7d4d5SPhilippe Mathieu-Daudé    the ATOMIC_NAME macro, and redefined below.  */
6510f7d4d5SPhilippe Mathieu-Daudé #if DATA_SIZE == 1
6610f7d4d5SPhilippe Mathieu-Daudé # define END
6710f7d4d5SPhilippe Mathieu-Daudé #elif defined(HOST_WORDS_BIGENDIAN)
6810f7d4d5SPhilippe Mathieu-Daudé # define END  _be
6910f7d4d5SPhilippe Mathieu-Daudé #else
7010f7d4d5SPhilippe Mathieu-Daudé # define END  _le
7110f7d4d5SPhilippe Mathieu-Daudé #endif
7210f7d4d5SPhilippe Mathieu-Daudé 
7310f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr,
74*48688fafSRichard Henderson                               ABI_TYPE cmpv, ABI_TYPE newv,
75*48688fafSRichard Henderson                               TCGMemOpIdx oi, uintptr_t retaddr)
7610f7d4d5SPhilippe Mathieu-Daudé {
7734d49937SPeter Maydell     ATOMIC_MMU_DECLS;
7808dff435SRichard Henderson     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP_RW;
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;
9210f7d4d5SPhilippe Mathieu-Daudé }
9310f7d4d5SPhilippe Mathieu-Daudé 
9410f7d4d5SPhilippe Mathieu-Daudé #if DATA_SIZE >= 16
95e6cd4bb5SRichard Henderson #if HAVE_ATOMIC128
96*48688fafSRichard Henderson ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr,
97*48688fafSRichard Henderson                          TCGMemOpIdx oi, uintptr_t retaddr)
9810f7d4d5SPhilippe Mathieu-Daudé {
9934d49937SPeter Maydell     ATOMIC_MMU_DECLS;
10008dff435SRichard Henderson     DATA_TYPE val, *haddr = ATOMIC_MMU_LOOKUP_R;
1014e6b1384SRichard Henderson     uint16_t info = trace_mem_build_info(SHIFT, false, 0, false,
102cfec3885SEmilio G. Cota                                          ATOMIC_MMU_IDX);
103d071f4cdSEmilio G. Cota 
104cfec3885SEmilio G. Cota     atomic_trace_ld_pre(env, addr, info);
105e6cd4bb5SRichard Henderson     val = atomic16_read(haddr);
106ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
107cfec3885SEmilio G. Cota     atomic_trace_ld_post(env, addr, info);
10810f7d4d5SPhilippe Mathieu-Daudé     return val;
10910f7d4d5SPhilippe Mathieu-Daudé }
11010f7d4d5SPhilippe Mathieu-Daudé 
111*48688fafSRichard Henderson void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr, ABI_TYPE val,
112*48688fafSRichard Henderson                      TCGMemOpIdx oi, uintptr_t retaddr)
11310f7d4d5SPhilippe Mathieu-Daudé {
11434d49937SPeter Maydell     ATOMIC_MMU_DECLS;
11508dff435SRichard Henderson     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP_W;
1164e6b1384SRichard Henderson     uint16_t info = trace_mem_build_info(SHIFT, false, 0, true,
117cfec3885SEmilio G. Cota                                          ATOMIC_MMU_IDX);
118d071f4cdSEmilio G. Cota 
119cfec3885SEmilio G. Cota     atomic_trace_st_pre(env, addr, info);
120e6cd4bb5SRichard Henderson     atomic16_set(haddr, val);
121ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
122cfec3885SEmilio G. Cota     atomic_trace_st_post(env, addr, info);
12310f7d4d5SPhilippe Mathieu-Daudé }
124e6cd4bb5SRichard Henderson #endif
12510f7d4d5SPhilippe Mathieu-Daudé #else
126*48688fafSRichard Henderson ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr, ABI_TYPE val,
127*48688fafSRichard Henderson                            TCGMemOpIdx oi, uintptr_t retaddr)
12810f7d4d5SPhilippe Mathieu-Daudé {
12934d49937SPeter Maydell     ATOMIC_MMU_DECLS;
13008dff435SRichard Henderson     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP_RW;
131d071f4cdSEmilio G. Cota     DATA_TYPE ret;
1324e6b1384SRichard Henderson     uint16_t info = trace_mem_build_info(SHIFT, false, 0, false,
133cfec3885SEmilio G. Cota                                          ATOMIC_MMU_IDX);
134d071f4cdSEmilio G. Cota 
135cfec3885SEmilio G. Cota     atomic_trace_rmw_pre(env, addr, info);
136d73415a3SStefan Hajnoczi     ret = qatomic_xchg__nocheck(haddr, val);
137ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
138cfec3885SEmilio G. Cota     atomic_trace_rmw_post(env, addr, info);
139ec603b55SRichard Henderson     return ret;
14010f7d4d5SPhilippe Mathieu-Daudé }
14110f7d4d5SPhilippe Mathieu-Daudé 
14210f7d4d5SPhilippe Mathieu-Daudé #define GEN_ATOMIC_HELPER(X)                                        \
14310f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr,       \
144*48688fafSRichard Henderson                         ABI_TYPE val, TCGMemOpIdx oi, uintptr_t retaddr) \
14510f7d4d5SPhilippe Mathieu-Daudé {                                                                   \
14634d49937SPeter Maydell     ATOMIC_MMU_DECLS;                                               \
14708dff435SRichard Henderson     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP_RW;                        \
148d071f4cdSEmilio G. Cota     DATA_TYPE ret;                                                  \
1494e6b1384SRichard Henderson     uint16_t info = trace_mem_build_info(SHIFT, false, 0, false,    \
150cfec3885SEmilio G. Cota                                          ATOMIC_MMU_IDX);           \
151cfec3885SEmilio G. Cota     atomic_trace_rmw_pre(env, addr, info);                          \
152d73415a3SStefan Hajnoczi     ret = qatomic_##X(haddr, val);                                  \
153ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;                                             \
154cfec3885SEmilio G. Cota     atomic_trace_rmw_post(env, addr, info);                         \
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.
172d071f4cdSEmilio G. Cota  *
173d071f4cdSEmilio G. Cota  * Trace this load + RMW loop as a single RMW op. This way, regardless
174d071f4cdSEmilio 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,       \
178*48688fafSRichard Henderson                         ABI_TYPE xval, TCGMemOpIdx oi, uintptr_t retaddr) \
1795507c2bfSRichard Henderson {                                                                   \
1805507c2bfSRichard Henderson     ATOMIC_MMU_DECLS;                                               \
18108dff435SRichard Henderson     XDATA_TYPE *haddr = ATOMIC_MMU_LOOKUP_RW;                       \
1825507c2bfSRichard Henderson     XDATA_TYPE cmp, old, new, val = xval;                           \
1834e6b1384SRichard Henderson     uint16_t info = trace_mem_build_info(SHIFT, false, 0, false,    \
184cfec3885SEmilio G. Cota                                          ATOMIC_MMU_IDX);           \
185cfec3885SEmilio G. Cota     atomic_trace_rmw_pre(env, addr, info);                          \
1865507c2bfSRichard Henderson     smp_mb();                                                       \
187d73415a3SStefan Hajnoczi     cmp = qatomic_read__nocheck(haddr);                             \
1885507c2bfSRichard Henderson     do {                                                            \
1895507c2bfSRichard Henderson         old = cmp; new = FN(old, val);                              \
190d73415a3SStefan Hajnoczi         cmp = qatomic_cmpxchg__nocheck(haddr, old, new);            \
1915507c2bfSRichard Henderson     } while (cmp != old);                                           \
1925507c2bfSRichard Henderson     ATOMIC_MMU_CLEANUP;                                             \
193cfec3885SEmilio G. Cota     atomic_trace_rmw_post(env, addr, info);                         \
1945507c2bfSRichard Henderson     return RET;                                                     \
1955507c2bfSRichard Henderson }
1965507c2bfSRichard Henderson 
1975507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_smin, MIN, SDATA_TYPE, old)
1985507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_umin, MIN,  DATA_TYPE, old)
1995507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_smax, MAX, SDATA_TYPE, old)
2005507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_umax, MAX,  DATA_TYPE, old)
2015507c2bfSRichard Henderson 
2025507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(smin_fetch, MIN, SDATA_TYPE, new)
2035507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(umin_fetch, MIN,  DATA_TYPE, new)
2045507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(smax_fetch, MAX, SDATA_TYPE, new)
2055507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(umax_fetch, MAX,  DATA_TYPE, new)
2065507c2bfSRichard Henderson 
2075507c2bfSRichard Henderson #undef GEN_ATOMIC_HELPER_FN
20810f7d4d5SPhilippe Mathieu-Daudé #endif /* DATA SIZE >= 16 */
20910f7d4d5SPhilippe Mathieu-Daudé 
21010f7d4d5SPhilippe Mathieu-Daudé #undef END
21110f7d4d5SPhilippe Mathieu-Daudé 
21210f7d4d5SPhilippe Mathieu-Daudé #if DATA_SIZE > 1
21310f7d4d5SPhilippe Mathieu-Daudé 
21410f7d4d5SPhilippe Mathieu-Daudé /* Define reverse-host-endian atomic operations.  Note that END is used
21510f7d4d5SPhilippe Mathieu-Daudé    within the ATOMIC_NAME macro.  */
21610f7d4d5SPhilippe Mathieu-Daudé #ifdef HOST_WORDS_BIGENDIAN
21710f7d4d5SPhilippe Mathieu-Daudé # define END  _le
21810f7d4d5SPhilippe Mathieu-Daudé #else
21910f7d4d5SPhilippe Mathieu-Daudé # define END  _be
22010f7d4d5SPhilippe Mathieu-Daudé #endif
22110f7d4d5SPhilippe Mathieu-Daudé 
22210f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr,
223*48688fafSRichard Henderson                               ABI_TYPE cmpv, ABI_TYPE newv,
224*48688fafSRichard Henderson                               TCGMemOpIdx oi, uintptr_t retaddr)
22510f7d4d5SPhilippe Mathieu-Daudé {
22634d49937SPeter Maydell     ATOMIC_MMU_DECLS;
22708dff435SRichard Henderson     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP_RW;
228d071f4cdSEmilio G. Cota     DATA_TYPE ret;
2294e6b1384SRichard Henderson     uint16_t info = trace_mem_build_info(SHIFT, false, MO_BSWAP, false,
230cfec3885SEmilio G. Cota                                          ATOMIC_MMU_IDX);
231d071f4cdSEmilio G. Cota 
232cfec3885SEmilio G. Cota     atomic_trace_rmw_pre(env, addr, info);
233e6cd4bb5SRichard Henderson #if DATA_SIZE == 16
234e6cd4bb5SRichard Henderson     ret = atomic16_cmpxchg(haddr, BSWAP(cmpv), BSWAP(newv));
235e6cd4bb5SRichard Henderson #else
236d73415a3SStefan Hajnoczi     ret = qatomic_cmpxchg__nocheck(haddr, BSWAP(cmpv), BSWAP(newv));
237e6cd4bb5SRichard Henderson #endif
238ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
239cfec3885SEmilio G. Cota     atomic_trace_rmw_post(env, addr, info);
240ec603b55SRichard Henderson     return BSWAP(ret);
24110f7d4d5SPhilippe Mathieu-Daudé }
24210f7d4d5SPhilippe Mathieu-Daudé 
24310f7d4d5SPhilippe Mathieu-Daudé #if DATA_SIZE >= 16
244e6cd4bb5SRichard Henderson #if HAVE_ATOMIC128
245*48688fafSRichard Henderson ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr,
246*48688fafSRichard Henderson                          TCGMemOpIdx oi, uintptr_t retaddr)
24710f7d4d5SPhilippe Mathieu-Daudé {
24834d49937SPeter Maydell     ATOMIC_MMU_DECLS;
24908dff435SRichard Henderson     DATA_TYPE val, *haddr = ATOMIC_MMU_LOOKUP_R;
2504e6b1384SRichard Henderson     uint16_t info = trace_mem_build_info(SHIFT, false, MO_BSWAP, false,
251cfec3885SEmilio G. Cota                                          ATOMIC_MMU_IDX);
252d071f4cdSEmilio G. Cota 
253cfec3885SEmilio G. Cota     atomic_trace_ld_pre(env, addr, info);
254e6cd4bb5SRichard Henderson     val = atomic16_read(haddr);
255ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
256cfec3885SEmilio G. Cota     atomic_trace_ld_post(env, addr, info);
25710f7d4d5SPhilippe Mathieu-Daudé     return BSWAP(val);
25810f7d4d5SPhilippe Mathieu-Daudé }
25910f7d4d5SPhilippe Mathieu-Daudé 
260*48688fafSRichard Henderson void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr, ABI_TYPE val,
261*48688fafSRichard Henderson                      TCGMemOpIdx oi, uintptr_t retaddr)
26210f7d4d5SPhilippe Mathieu-Daudé {
26334d49937SPeter Maydell     ATOMIC_MMU_DECLS;
26408dff435SRichard Henderson     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP_W;
2654e6b1384SRichard Henderson     uint16_t info = trace_mem_build_info(SHIFT, false, MO_BSWAP, true,
266cfec3885SEmilio G. Cota                                          ATOMIC_MMU_IDX);
267d071f4cdSEmilio G. Cota 
268cfec3885SEmilio G. Cota     val = BSWAP(val);
269cfec3885SEmilio G. Cota     atomic_trace_st_pre(env, addr, info);
27010f7d4d5SPhilippe Mathieu-Daudé     val = BSWAP(val);
271e6cd4bb5SRichard Henderson     atomic16_set(haddr, val);
272ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
273cfec3885SEmilio G. Cota     atomic_trace_st_post(env, addr, info);
27410f7d4d5SPhilippe Mathieu-Daudé }
275e6cd4bb5SRichard Henderson #endif
27610f7d4d5SPhilippe Mathieu-Daudé #else
277*48688fafSRichard Henderson ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr, ABI_TYPE val,
278*48688fafSRichard Henderson                            TCGMemOpIdx oi, uintptr_t retaddr)
27910f7d4d5SPhilippe Mathieu-Daudé {
28034d49937SPeter Maydell     ATOMIC_MMU_DECLS;
28108dff435SRichard Henderson     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP_RW;
282d071f4cdSEmilio G. Cota     ABI_TYPE ret;
2834e6b1384SRichard Henderson     uint16_t info = trace_mem_build_info(SHIFT, false, MO_BSWAP, false,
284cfec3885SEmilio G. Cota                                          ATOMIC_MMU_IDX);
285d071f4cdSEmilio G. Cota 
286cfec3885SEmilio G. Cota     atomic_trace_rmw_pre(env, addr, info);
287d73415a3SStefan Hajnoczi     ret = qatomic_xchg__nocheck(haddr, BSWAP(val));
288ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
289cfec3885SEmilio G. Cota     atomic_trace_rmw_post(env, addr, info);
290ec603b55SRichard Henderson     return BSWAP(ret);
29110f7d4d5SPhilippe Mathieu-Daudé }
29210f7d4d5SPhilippe Mathieu-Daudé 
29310f7d4d5SPhilippe Mathieu-Daudé #define GEN_ATOMIC_HELPER(X)                                        \
29410f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr,       \
295*48688fafSRichard Henderson                         ABI_TYPE val, TCGMemOpIdx oi, uintptr_t retaddr) \
29610f7d4d5SPhilippe Mathieu-Daudé {                                                                   \
29734d49937SPeter Maydell     ATOMIC_MMU_DECLS;                                               \
29808dff435SRichard Henderson     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP_RW;                        \
299d071f4cdSEmilio G. Cota     DATA_TYPE ret;                                                  \
3004e6b1384SRichard Henderson     uint16_t info = trace_mem_build_info(SHIFT, false, MO_BSWAP,    \
3014e6b1384SRichard Henderson                                          false, ATOMIC_MMU_IDX);    \
302cfec3885SEmilio G. Cota     atomic_trace_rmw_pre(env, addr, info);                          \
303d73415a3SStefan Hajnoczi     ret = qatomic_##X(haddr, BSWAP(val));                           \
304ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;                                             \
305cfec3885SEmilio G. Cota     atomic_trace_rmw_post(env, addr, info);                         \
306ec603b55SRichard Henderson     return BSWAP(ret);                                              \
30710f7d4d5SPhilippe Mathieu-Daudé }
30810f7d4d5SPhilippe Mathieu-Daudé 
30910f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_and)
31010f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_or)
31110f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_xor)
31210f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(and_fetch)
31310f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(or_fetch)
31410f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(xor_fetch)
31510f7d4d5SPhilippe Mathieu-Daudé 
31610f7d4d5SPhilippe Mathieu-Daudé #undef GEN_ATOMIC_HELPER
31710f7d4d5SPhilippe Mathieu-Daudé 
3185507c2bfSRichard Henderson /* These helpers are, as a whole, full barriers.  Within the helper,
3195507c2bfSRichard Henderson  * the leading barrier is explicit and the trailing barrier is within
3205507c2bfSRichard Henderson  * cmpxchg primitive.
321d071f4cdSEmilio G. Cota  *
322d071f4cdSEmilio G. Cota  * Trace this load + RMW loop as a single RMW op. This way, regardless
323d071f4cdSEmilio G. Cota  * of CF_PARALLEL's value, we'll trace just a read and a write.
3245507c2bfSRichard Henderson  */
3255507c2bfSRichard Henderson #define GEN_ATOMIC_HELPER_FN(X, FN, XDATA_TYPE, RET)                \
3265507c2bfSRichard Henderson ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr,       \
327*48688fafSRichard Henderson                         ABI_TYPE xval, TCGMemOpIdx oi, uintptr_t retaddr) \
3285507c2bfSRichard Henderson {                                                                   \
3295507c2bfSRichard Henderson     ATOMIC_MMU_DECLS;                                               \
33008dff435SRichard Henderson     XDATA_TYPE *haddr = ATOMIC_MMU_LOOKUP_RW;                       \
3315507c2bfSRichard Henderson     XDATA_TYPE ldo, ldn, old, new, val = xval;                      \
3324e6b1384SRichard Henderson     uint16_t info = trace_mem_build_info(SHIFT, false, MO_BSWAP,    \
3334e6b1384SRichard Henderson                                          false, ATOMIC_MMU_IDX);    \
334cfec3885SEmilio G. Cota     atomic_trace_rmw_pre(env, addr, info);                          \
3355507c2bfSRichard Henderson     smp_mb();                                                       \
336d73415a3SStefan Hajnoczi     ldn = qatomic_read__nocheck(haddr);                             \
3375507c2bfSRichard Henderson     do {                                                            \
3385507c2bfSRichard Henderson         ldo = ldn; old = BSWAP(ldo); new = FN(old, val);            \
339d73415a3SStefan Hajnoczi         ldn = qatomic_cmpxchg__nocheck(haddr, ldo, BSWAP(new));     \
3405507c2bfSRichard Henderson     } while (ldo != ldn);                                           \
3415507c2bfSRichard Henderson     ATOMIC_MMU_CLEANUP;                                             \
342cfec3885SEmilio G. Cota     atomic_trace_rmw_post(env, addr, info);                         \
3435507c2bfSRichard Henderson     return RET;                                                     \
3445507c2bfSRichard Henderson }
3455507c2bfSRichard Henderson 
3465507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_smin, MIN, SDATA_TYPE, old)
3475507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_umin, MIN,  DATA_TYPE, old)
3485507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_smax, MAX, SDATA_TYPE, old)
3495507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_umax, MAX,  DATA_TYPE, old)
3505507c2bfSRichard Henderson 
3515507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(smin_fetch, MIN, SDATA_TYPE, new)
3525507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(umin_fetch, MIN,  DATA_TYPE, new)
3535507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(smax_fetch, MAX, SDATA_TYPE, new)
3545507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(umax_fetch, MAX,  DATA_TYPE, new)
3555507c2bfSRichard Henderson 
35658edf9eeSRichard Henderson /* Note that for addition, we need to use a separate cmpxchg loop instead
35758edf9eeSRichard Henderson    of bswaps for the reverse-host-endian helpers.  */
35858edf9eeSRichard Henderson #define ADD(X, Y)   (X + Y)
35958edf9eeSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_add, ADD, DATA_TYPE, old)
36058edf9eeSRichard Henderson GEN_ATOMIC_HELPER_FN(add_fetch, ADD, DATA_TYPE, new)
36158edf9eeSRichard Henderson #undef ADD
36258edf9eeSRichard Henderson 
3635507c2bfSRichard Henderson #undef GEN_ATOMIC_HELPER_FN
36410f7d4d5SPhilippe Mathieu-Daudé #endif /* DATA_SIZE >= 16 */
36510f7d4d5SPhilippe Mathieu-Daudé 
36610f7d4d5SPhilippe Mathieu-Daudé #undef END
36710f7d4d5SPhilippe Mathieu-Daudé #endif /* DATA_SIZE > 1 */
36810f7d4d5SPhilippe Mathieu-Daudé 
36910f7d4d5SPhilippe Mathieu-Daudé #undef BSWAP
37010f7d4d5SPhilippe Mathieu-Daudé #undef ABI_TYPE
37110f7d4d5SPhilippe Mathieu-Daudé #undef DATA_TYPE
3725507c2bfSRichard Henderson #undef SDATA_TYPE
37310f7d4d5SPhilippe Mathieu-Daudé #undef SUFFIX
37410f7d4d5SPhilippe Mathieu-Daudé #undef DATA_SIZE
375d071f4cdSEmilio G. Cota #undef SHIFT
376