xref: /openbmc/qemu/accel/tcg/atomic_template.h (revision d73415a315471ac0b127ed3fad45c8ec5d711de1)
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
3110f7d4d5SPhilippe Mathieu-Daudé # define DATA_TYPE  uint64_t
325507c2bfSRichard Henderson # define SDATA_TYPE 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,
7410f7d4d5SPhilippe Mathieu-Daudé                               ABI_TYPE cmpv, ABI_TYPE newv EXTRA_ARGS)
7510f7d4d5SPhilippe Mathieu-Daudé {
7634d49937SPeter Maydell     ATOMIC_MMU_DECLS;
7710f7d4d5SPhilippe Mathieu-Daudé     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
78d071f4cdSEmilio G. Cota     DATA_TYPE ret;
794e6b1384SRichard Henderson     uint16_t info = trace_mem_build_info(SHIFT, false, 0, false,
80cfec3885SEmilio G. Cota                                          ATOMIC_MMU_IDX);
81d071f4cdSEmilio G. Cota 
82cfec3885SEmilio G. Cota     atomic_trace_rmw_pre(env, addr, info);
83e6cd4bb5SRichard Henderson #if DATA_SIZE == 16
84e6cd4bb5SRichard Henderson     ret = atomic16_cmpxchg(haddr, cmpv, newv);
85e6cd4bb5SRichard Henderson #else
86*d73415a3SStefan Hajnoczi     ret = qatomic_cmpxchg__nocheck(haddr, cmpv, newv);
87e6cd4bb5SRichard Henderson #endif
88ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
89cfec3885SEmilio G. Cota     atomic_trace_rmw_post(env, addr, info);
90ec603b55SRichard Henderson     return ret;
9110f7d4d5SPhilippe Mathieu-Daudé }
9210f7d4d5SPhilippe Mathieu-Daudé 
9310f7d4d5SPhilippe Mathieu-Daudé #if DATA_SIZE >= 16
94e6cd4bb5SRichard Henderson #if HAVE_ATOMIC128
9510f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr EXTRA_ARGS)
9610f7d4d5SPhilippe Mathieu-Daudé {
9734d49937SPeter Maydell     ATOMIC_MMU_DECLS;
9810f7d4d5SPhilippe Mathieu-Daudé     DATA_TYPE val, *haddr = ATOMIC_MMU_LOOKUP;
994e6b1384SRichard Henderson     uint16_t info = trace_mem_build_info(SHIFT, false, 0, false,
100cfec3885SEmilio G. Cota                                          ATOMIC_MMU_IDX);
101d071f4cdSEmilio G. Cota 
102cfec3885SEmilio G. Cota     atomic_trace_ld_pre(env, addr, info);
103e6cd4bb5SRichard Henderson     val = atomic16_read(haddr);
104ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
105cfec3885SEmilio G. Cota     atomic_trace_ld_post(env, addr, info);
10610f7d4d5SPhilippe Mathieu-Daudé     return val;
10710f7d4d5SPhilippe Mathieu-Daudé }
10810f7d4d5SPhilippe Mathieu-Daudé 
10910f7d4d5SPhilippe Mathieu-Daudé void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr,
11010f7d4d5SPhilippe Mathieu-Daudé                      ABI_TYPE val EXTRA_ARGS)
11110f7d4d5SPhilippe Mathieu-Daudé {
11234d49937SPeter Maydell     ATOMIC_MMU_DECLS;
11310f7d4d5SPhilippe Mathieu-Daudé     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
1144e6b1384SRichard Henderson     uint16_t info = trace_mem_build_info(SHIFT, false, 0, true,
115cfec3885SEmilio G. Cota                                          ATOMIC_MMU_IDX);
116d071f4cdSEmilio G. Cota 
117cfec3885SEmilio G. Cota     atomic_trace_st_pre(env, addr, info);
118e6cd4bb5SRichard Henderson     atomic16_set(haddr, val);
119ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
120cfec3885SEmilio G. Cota     atomic_trace_st_post(env, addr, info);
12110f7d4d5SPhilippe Mathieu-Daudé }
122e6cd4bb5SRichard Henderson #endif
12310f7d4d5SPhilippe Mathieu-Daudé #else
12410f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr,
12510f7d4d5SPhilippe Mathieu-Daudé                            ABI_TYPE val EXTRA_ARGS)
12610f7d4d5SPhilippe Mathieu-Daudé {
12734d49937SPeter Maydell     ATOMIC_MMU_DECLS;
12810f7d4d5SPhilippe Mathieu-Daudé     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
129d071f4cdSEmilio G. Cota     DATA_TYPE ret;
1304e6b1384SRichard Henderson     uint16_t info = trace_mem_build_info(SHIFT, false, 0, false,
131cfec3885SEmilio G. Cota                                          ATOMIC_MMU_IDX);
132d071f4cdSEmilio G. Cota 
133cfec3885SEmilio G. Cota     atomic_trace_rmw_pre(env, addr, info);
134*d73415a3SStefan Hajnoczi     ret = qatomic_xchg__nocheck(haddr, val);
135ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
136cfec3885SEmilio G. Cota     atomic_trace_rmw_post(env, addr, info);
137ec603b55SRichard Henderson     return ret;
13810f7d4d5SPhilippe Mathieu-Daudé }
13910f7d4d5SPhilippe Mathieu-Daudé 
14010f7d4d5SPhilippe Mathieu-Daudé #define GEN_ATOMIC_HELPER(X)                                        \
14110f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr,       \
14210f7d4d5SPhilippe Mathieu-Daudé                         ABI_TYPE val EXTRA_ARGS)                    \
14310f7d4d5SPhilippe Mathieu-Daudé {                                                                   \
14434d49937SPeter Maydell     ATOMIC_MMU_DECLS;                                               \
14510f7d4d5SPhilippe Mathieu-Daudé     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;                           \
146d071f4cdSEmilio G. Cota     DATA_TYPE ret;                                                  \
1474e6b1384SRichard Henderson     uint16_t info = trace_mem_build_info(SHIFT, false, 0, false,    \
148cfec3885SEmilio G. Cota                                          ATOMIC_MMU_IDX);           \
149cfec3885SEmilio G. Cota     atomic_trace_rmw_pre(env, addr, info);                          \
150*d73415a3SStefan Hajnoczi     ret = qatomic_##X(haddr, val);                                  \
151ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;                                             \
152cfec3885SEmilio G. Cota     atomic_trace_rmw_post(env, addr, info);                         \
153ec603b55SRichard Henderson     return ret;                                                     \
154ec603b55SRichard Henderson }
15510f7d4d5SPhilippe Mathieu-Daudé 
15610f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_add)
15710f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_and)
15810f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_or)
15910f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_xor)
16010f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(add_fetch)
16110f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(and_fetch)
16210f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(or_fetch)
16310f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(xor_fetch)
16410f7d4d5SPhilippe Mathieu-Daudé 
16510f7d4d5SPhilippe Mathieu-Daudé #undef GEN_ATOMIC_HELPER
1665507c2bfSRichard Henderson 
1675507c2bfSRichard Henderson /* These helpers are, as a whole, full barriers.  Within the helper,
1685507c2bfSRichard Henderson  * the leading barrier is explicit and the trailing barrier is within
1695507c2bfSRichard Henderson  * cmpxchg primitive.
170d071f4cdSEmilio G. Cota  *
171d071f4cdSEmilio G. Cota  * Trace this load + RMW loop as a single RMW op. This way, regardless
172d071f4cdSEmilio G. Cota  * of CF_PARALLEL's value, we'll trace just a read and a write.
1735507c2bfSRichard Henderson  */
1745507c2bfSRichard Henderson #define GEN_ATOMIC_HELPER_FN(X, FN, XDATA_TYPE, RET)                \
1755507c2bfSRichard Henderson ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr,       \
1765507c2bfSRichard Henderson                         ABI_TYPE xval EXTRA_ARGS)                   \
1775507c2bfSRichard Henderson {                                                                   \
1785507c2bfSRichard Henderson     ATOMIC_MMU_DECLS;                                               \
1795507c2bfSRichard Henderson     XDATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;                          \
1805507c2bfSRichard Henderson     XDATA_TYPE cmp, old, new, val = xval;                           \
1814e6b1384SRichard Henderson     uint16_t info = trace_mem_build_info(SHIFT, false, 0, false,    \
182cfec3885SEmilio G. Cota                                          ATOMIC_MMU_IDX);           \
183cfec3885SEmilio G. Cota     atomic_trace_rmw_pre(env, addr, info);                          \
1845507c2bfSRichard Henderson     smp_mb();                                                       \
185*d73415a3SStefan Hajnoczi     cmp = qatomic_read__nocheck(haddr);                             \
1865507c2bfSRichard Henderson     do {                                                            \
1875507c2bfSRichard Henderson         old = cmp; new = FN(old, val);                              \
188*d73415a3SStefan Hajnoczi         cmp = qatomic_cmpxchg__nocheck(haddr, old, new);            \
1895507c2bfSRichard Henderson     } while (cmp != old);                                           \
1905507c2bfSRichard Henderson     ATOMIC_MMU_CLEANUP;                                             \
191cfec3885SEmilio G. Cota     atomic_trace_rmw_post(env, addr, info);                         \
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
20910f7d4d5SPhilippe Mathieu-Daudé 
21010f7d4d5SPhilippe Mathieu-Daudé #if DATA_SIZE > 1
21110f7d4d5SPhilippe Mathieu-Daudé 
21210f7d4d5SPhilippe Mathieu-Daudé /* Define reverse-host-endian atomic operations.  Note that END is used
21310f7d4d5SPhilippe Mathieu-Daudé    within the ATOMIC_NAME macro.  */
21410f7d4d5SPhilippe Mathieu-Daudé #ifdef HOST_WORDS_BIGENDIAN
21510f7d4d5SPhilippe Mathieu-Daudé # define END  _le
21610f7d4d5SPhilippe Mathieu-Daudé #else
21710f7d4d5SPhilippe Mathieu-Daudé # define END  _be
21810f7d4d5SPhilippe Mathieu-Daudé #endif
21910f7d4d5SPhilippe Mathieu-Daudé 
22010f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr,
22110f7d4d5SPhilippe Mathieu-Daudé                               ABI_TYPE cmpv, ABI_TYPE newv EXTRA_ARGS)
22210f7d4d5SPhilippe Mathieu-Daudé {
22334d49937SPeter Maydell     ATOMIC_MMU_DECLS;
22410f7d4d5SPhilippe Mathieu-Daudé     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
225d071f4cdSEmilio G. Cota     DATA_TYPE ret;
2264e6b1384SRichard Henderson     uint16_t info = trace_mem_build_info(SHIFT, false, MO_BSWAP, false,
227cfec3885SEmilio G. Cota                                          ATOMIC_MMU_IDX);
228d071f4cdSEmilio G. Cota 
229cfec3885SEmilio G. Cota     atomic_trace_rmw_pre(env, addr, info);
230e6cd4bb5SRichard Henderson #if DATA_SIZE == 16
231e6cd4bb5SRichard Henderson     ret = atomic16_cmpxchg(haddr, BSWAP(cmpv), BSWAP(newv));
232e6cd4bb5SRichard Henderson #else
233*d73415a3SStefan Hajnoczi     ret = qatomic_cmpxchg__nocheck(haddr, BSWAP(cmpv), BSWAP(newv));
234e6cd4bb5SRichard Henderson #endif
235ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
236cfec3885SEmilio G. Cota     atomic_trace_rmw_post(env, addr, info);
237ec603b55SRichard Henderson     return BSWAP(ret);
23810f7d4d5SPhilippe Mathieu-Daudé }
23910f7d4d5SPhilippe Mathieu-Daudé 
24010f7d4d5SPhilippe Mathieu-Daudé #if DATA_SIZE >= 16
241e6cd4bb5SRichard Henderson #if HAVE_ATOMIC128
24210f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr EXTRA_ARGS)
24310f7d4d5SPhilippe Mathieu-Daudé {
24434d49937SPeter Maydell     ATOMIC_MMU_DECLS;
24510f7d4d5SPhilippe Mathieu-Daudé     DATA_TYPE val, *haddr = ATOMIC_MMU_LOOKUP;
2464e6b1384SRichard Henderson     uint16_t info = trace_mem_build_info(SHIFT, false, MO_BSWAP, false,
247cfec3885SEmilio G. Cota                                          ATOMIC_MMU_IDX);
248d071f4cdSEmilio G. Cota 
249cfec3885SEmilio G. Cota     atomic_trace_ld_pre(env, addr, info);
250e6cd4bb5SRichard Henderson     val = atomic16_read(haddr);
251ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
252cfec3885SEmilio G. Cota     atomic_trace_ld_post(env, addr, info);
25310f7d4d5SPhilippe Mathieu-Daudé     return BSWAP(val);
25410f7d4d5SPhilippe Mathieu-Daudé }
25510f7d4d5SPhilippe Mathieu-Daudé 
25610f7d4d5SPhilippe Mathieu-Daudé void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr,
25710f7d4d5SPhilippe Mathieu-Daudé                      ABI_TYPE val EXTRA_ARGS)
25810f7d4d5SPhilippe Mathieu-Daudé {
25934d49937SPeter Maydell     ATOMIC_MMU_DECLS;
26010f7d4d5SPhilippe Mathieu-Daudé     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
2614e6b1384SRichard Henderson     uint16_t info = trace_mem_build_info(SHIFT, false, MO_BSWAP, true,
262cfec3885SEmilio G. Cota                                          ATOMIC_MMU_IDX);
263d071f4cdSEmilio G. Cota 
264cfec3885SEmilio G. Cota     val = BSWAP(val);
265cfec3885SEmilio G. Cota     atomic_trace_st_pre(env, addr, info);
26610f7d4d5SPhilippe Mathieu-Daudé     val = BSWAP(val);
267e6cd4bb5SRichard Henderson     atomic16_set(haddr, val);
268ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
269cfec3885SEmilio G. Cota     atomic_trace_st_post(env, addr, info);
27010f7d4d5SPhilippe Mathieu-Daudé }
271e6cd4bb5SRichard Henderson #endif
27210f7d4d5SPhilippe Mathieu-Daudé #else
27310f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr,
27410f7d4d5SPhilippe Mathieu-Daudé                            ABI_TYPE val EXTRA_ARGS)
27510f7d4d5SPhilippe Mathieu-Daudé {
27634d49937SPeter Maydell     ATOMIC_MMU_DECLS;
27710f7d4d5SPhilippe Mathieu-Daudé     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
278d071f4cdSEmilio G. Cota     ABI_TYPE ret;
2794e6b1384SRichard Henderson     uint16_t info = trace_mem_build_info(SHIFT, false, MO_BSWAP, false,
280cfec3885SEmilio G. Cota                                          ATOMIC_MMU_IDX);
281d071f4cdSEmilio G. Cota 
282cfec3885SEmilio G. Cota     atomic_trace_rmw_pre(env, addr, info);
283*d73415a3SStefan Hajnoczi     ret = qatomic_xchg__nocheck(haddr, BSWAP(val));
284ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
285cfec3885SEmilio G. Cota     atomic_trace_rmw_post(env, addr, info);
286ec603b55SRichard Henderson     return BSWAP(ret);
28710f7d4d5SPhilippe Mathieu-Daudé }
28810f7d4d5SPhilippe Mathieu-Daudé 
28910f7d4d5SPhilippe Mathieu-Daudé #define GEN_ATOMIC_HELPER(X)                                        \
29010f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr,       \
29110f7d4d5SPhilippe Mathieu-Daudé                         ABI_TYPE val EXTRA_ARGS)                    \
29210f7d4d5SPhilippe Mathieu-Daudé {                                                                   \
29334d49937SPeter Maydell     ATOMIC_MMU_DECLS;                                               \
29410f7d4d5SPhilippe Mathieu-Daudé     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;                           \
295d071f4cdSEmilio G. Cota     DATA_TYPE ret;                                                  \
2964e6b1384SRichard Henderson     uint16_t info = trace_mem_build_info(SHIFT, false, MO_BSWAP,    \
2974e6b1384SRichard Henderson                                          false, ATOMIC_MMU_IDX);    \
298cfec3885SEmilio G. Cota     atomic_trace_rmw_pre(env, addr, info);                          \
299*d73415a3SStefan Hajnoczi     ret = qatomic_##X(haddr, BSWAP(val));                           \
300ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;                                             \
301cfec3885SEmilio G. Cota     atomic_trace_rmw_post(env, addr, info);                         \
302ec603b55SRichard Henderson     return BSWAP(ret);                                              \
30310f7d4d5SPhilippe Mathieu-Daudé }
30410f7d4d5SPhilippe Mathieu-Daudé 
30510f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_and)
30610f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_or)
30710f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_xor)
30810f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(and_fetch)
30910f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(or_fetch)
31010f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(xor_fetch)
31110f7d4d5SPhilippe Mathieu-Daudé 
31210f7d4d5SPhilippe Mathieu-Daudé #undef GEN_ATOMIC_HELPER
31310f7d4d5SPhilippe Mathieu-Daudé 
3145507c2bfSRichard Henderson /* These helpers are, as a whole, full barriers.  Within the helper,
3155507c2bfSRichard Henderson  * the leading barrier is explicit and the trailing barrier is within
3165507c2bfSRichard Henderson  * cmpxchg primitive.
317d071f4cdSEmilio G. Cota  *
318d071f4cdSEmilio G. Cota  * Trace this load + RMW loop as a single RMW op. This way, regardless
319d071f4cdSEmilio G. Cota  * of CF_PARALLEL's value, we'll trace just a read and a write.
3205507c2bfSRichard Henderson  */
3215507c2bfSRichard Henderson #define GEN_ATOMIC_HELPER_FN(X, FN, XDATA_TYPE, RET)                \
3225507c2bfSRichard Henderson ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr,       \
3235507c2bfSRichard Henderson                         ABI_TYPE xval EXTRA_ARGS)                   \
3245507c2bfSRichard Henderson {                                                                   \
3255507c2bfSRichard Henderson     ATOMIC_MMU_DECLS;                                               \
3265507c2bfSRichard Henderson     XDATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;                          \
3275507c2bfSRichard Henderson     XDATA_TYPE ldo, ldn, old, new, val = xval;                      \
3284e6b1384SRichard Henderson     uint16_t info = trace_mem_build_info(SHIFT, false, MO_BSWAP,    \
3294e6b1384SRichard Henderson                                          false, ATOMIC_MMU_IDX);    \
330cfec3885SEmilio G. Cota     atomic_trace_rmw_pre(env, addr, info);                          \
3315507c2bfSRichard Henderson     smp_mb();                                                       \
332*d73415a3SStefan Hajnoczi     ldn = qatomic_read__nocheck(haddr);                             \
3335507c2bfSRichard Henderson     do {                                                            \
3345507c2bfSRichard Henderson         ldo = ldn; old = BSWAP(ldo); new = FN(old, val);            \
335*d73415a3SStefan Hajnoczi         ldn = qatomic_cmpxchg__nocheck(haddr, ldo, BSWAP(new));     \
3365507c2bfSRichard Henderson     } while (ldo != ldn);                                           \
3375507c2bfSRichard Henderson     ATOMIC_MMU_CLEANUP;                                             \
338cfec3885SEmilio G. Cota     atomic_trace_rmw_post(env, addr, info);                         \
3395507c2bfSRichard Henderson     return RET;                                                     \
3405507c2bfSRichard Henderson }
3415507c2bfSRichard Henderson 
3425507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_smin, MIN, SDATA_TYPE, old)
3435507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_umin, MIN,  DATA_TYPE, old)
3445507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_smax, MAX, SDATA_TYPE, old)
3455507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_umax, MAX,  DATA_TYPE, old)
3465507c2bfSRichard Henderson 
3475507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(smin_fetch, MIN, SDATA_TYPE, new)
3485507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(umin_fetch, MIN,  DATA_TYPE, new)
3495507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(smax_fetch, MAX, SDATA_TYPE, new)
3505507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(umax_fetch, MAX,  DATA_TYPE, new)
3515507c2bfSRichard Henderson 
35258edf9eeSRichard Henderson /* Note that for addition, we need to use a separate cmpxchg loop instead
35358edf9eeSRichard Henderson    of bswaps for the reverse-host-endian helpers.  */
35458edf9eeSRichard Henderson #define ADD(X, Y)   (X + Y)
35558edf9eeSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_add, ADD, DATA_TYPE, old)
35658edf9eeSRichard Henderson GEN_ATOMIC_HELPER_FN(add_fetch, ADD, DATA_TYPE, new)
35758edf9eeSRichard Henderson #undef ADD
35858edf9eeSRichard Henderson 
3595507c2bfSRichard Henderson #undef GEN_ATOMIC_HELPER_FN
36010f7d4d5SPhilippe Mathieu-Daudé #endif /* DATA_SIZE >= 16 */
36110f7d4d5SPhilippe Mathieu-Daudé 
36210f7d4d5SPhilippe Mathieu-Daudé #undef END
36310f7d4d5SPhilippe Mathieu-Daudé #endif /* DATA_SIZE > 1 */
36410f7d4d5SPhilippe Mathieu-Daudé 
36510f7d4d5SPhilippe Mathieu-Daudé #undef BSWAP
36610f7d4d5SPhilippe Mathieu-Daudé #undef ABI_TYPE
36710f7d4d5SPhilippe Mathieu-Daudé #undef DATA_TYPE
3685507c2bfSRichard Henderson #undef SDATA_TYPE
36910f7d4d5SPhilippe Mathieu-Daudé #undef SUFFIX
37010f7d4d5SPhilippe Mathieu-Daudé #undef DATA_SIZE
371d071f4cdSEmilio G. Cota #undef SHIFT
372