xref: /openbmc/qemu/accel/tcg/atomic_template.h (revision e6d86bed50d20101c565e149c33e07a5cc764c72)
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é 
21*e6d86bedSEmilio 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
67d071f4cdSEmilio G. Cota # define MEND _be /* either le or be would be fine */
6810f7d4d5SPhilippe Mathieu-Daudé #elif defined(HOST_WORDS_BIGENDIAN)
6910f7d4d5SPhilippe Mathieu-Daudé # define END  _be
70d071f4cdSEmilio G. Cota # define MEND _be
7110f7d4d5SPhilippe Mathieu-Daudé #else
7210f7d4d5SPhilippe Mathieu-Daudé # define END  _le
73d071f4cdSEmilio G. Cota # define MEND _le
7410f7d4d5SPhilippe Mathieu-Daudé #endif
7510f7d4d5SPhilippe Mathieu-Daudé 
7610f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr,
7710f7d4d5SPhilippe Mathieu-Daudé                               ABI_TYPE cmpv, ABI_TYPE newv EXTRA_ARGS)
7810f7d4d5SPhilippe Mathieu-Daudé {
7934d49937SPeter Maydell     ATOMIC_MMU_DECLS;
8010f7d4d5SPhilippe Mathieu-Daudé     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
81d071f4cdSEmilio G. Cota     DATA_TYPE ret;
82cfec3885SEmilio G. Cota     uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, false,
83cfec3885SEmilio G. Cota                                                            ATOMIC_MMU_IDX);
84d071f4cdSEmilio G. Cota 
85cfec3885SEmilio G. Cota     atomic_trace_rmw_pre(env, addr, info);
86e6cd4bb5SRichard Henderson #if DATA_SIZE == 16
87e6cd4bb5SRichard Henderson     ret = atomic16_cmpxchg(haddr, cmpv, newv);
88e6cd4bb5SRichard Henderson #else
89d071f4cdSEmilio G. Cota     ret = atomic_cmpxchg__nocheck(haddr, cmpv, newv);
90e6cd4bb5SRichard Henderson #endif
91ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
92cfec3885SEmilio G. Cota     atomic_trace_rmw_post(env, addr, info);
93ec603b55SRichard Henderson     return ret;
9410f7d4d5SPhilippe Mathieu-Daudé }
9510f7d4d5SPhilippe Mathieu-Daudé 
9610f7d4d5SPhilippe Mathieu-Daudé #if DATA_SIZE >= 16
97e6cd4bb5SRichard Henderson #if HAVE_ATOMIC128
9810f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr EXTRA_ARGS)
9910f7d4d5SPhilippe Mathieu-Daudé {
10034d49937SPeter Maydell     ATOMIC_MMU_DECLS;
10110f7d4d5SPhilippe Mathieu-Daudé     DATA_TYPE val, *haddr = ATOMIC_MMU_LOOKUP;
102cfec3885SEmilio G. Cota     uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, 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);
10910f7d4d5SPhilippe Mathieu-Daudé     return val;
11010f7d4d5SPhilippe Mathieu-Daudé }
11110f7d4d5SPhilippe Mathieu-Daudé 
11210f7d4d5SPhilippe Mathieu-Daudé void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr,
11310f7d4d5SPhilippe Mathieu-Daudé                      ABI_TYPE val EXTRA_ARGS)
11410f7d4d5SPhilippe Mathieu-Daudé {
11534d49937SPeter Maydell     ATOMIC_MMU_DECLS;
11610f7d4d5SPhilippe Mathieu-Daudé     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
117cfec3885SEmilio G. Cota     uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, 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);
12410f7d4d5SPhilippe Mathieu-Daudé }
125e6cd4bb5SRichard Henderson #endif
12610f7d4d5SPhilippe Mathieu-Daudé #else
12710f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr,
12810f7d4d5SPhilippe Mathieu-Daudé                            ABI_TYPE val EXTRA_ARGS)
12910f7d4d5SPhilippe Mathieu-Daudé {
13034d49937SPeter Maydell     ATOMIC_MMU_DECLS;
13110f7d4d5SPhilippe Mathieu-Daudé     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
132d071f4cdSEmilio G. Cota     DATA_TYPE ret;
133cfec3885SEmilio G. Cota     uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, false,
134cfec3885SEmilio G. Cota                                                           ATOMIC_MMU_IDX);
135d071f4cdSEmilio G. Cota 
136cfec3885SEmilio G. Cota     atomic_trace_rmw_pre(env, addr, info);
137d071f4cdSEmilio G. Cota     ret = atomic_xchg__nocheck(haddr, val);
138ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
139cfec3885SEmilio G. Cota     atomic_trace_rmw_post(env, addr, info);
140ec603b55SRichard Henderson     return ret;
14110f7d4d5SPhilippe Mathieu-Daudé }
14210f7d4d5SPhilippe Mathieu-Daudé 
14310f7d4d5SPhilippe Mathieu-Daudé #define GEN_ATOMIC_HELPER(X)                                        \
14410f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr,       \
14510f7d4d5SPhilippe Mathieu-Daudé                         ABI_TYPE val EXTRA_ARGS)                    \
14610f7d4d5SPhilippe Mathieu-Daudé {                                                                   \
14734d49937SPeter Maydell     ATOMIC_MMU_DECLS;                                               \
14810f7d4d5SPhilippe Mathieu-Daudé     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;                           \
149d071f4cdSEmilio G. Cota     DATA_TYPE ret;                                                  \
150cfec3885SEmilio G. Cota     uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT,   \
151cfec3885SEmilio G. Cota                                                            false,   \
152cfec3885SEmilio G. Cota                                                            ATOMIC_MMU_IDX); \
153d071f4cdSEmilio G. Cota                                                                     \
154cfec3885SEmilio G. Cota     atomic_trace_rmw_pre(env, addr, info);                          \
155d071f4cdSEmilio G. Cota     ret = atomic_##X(haddr, val);                                   \
156ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;                                             \
157cfec3885SEmilio G. Cota     atomic_trace_rmw_post(env, addr, info);                         \
158ec603b55SRichard Henderson     return ret;                                                     \
159ec603b55SRichard Henderson }
16010f7d4d5SPhilippe Mathieu-Daudé 
16110f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_add)
16210f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_and)
16310f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_or)
16410f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_xor)
16510f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(add_fetch)
16610f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(and_fetch)
16710f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(or_fetch)
16810f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(xor_fetch)
16910f7d4d5SPhilippe Mathieu-Daudé 
17010f7d4d5SPhilippe Mathieu-Daudé #undef GEN_ATOMIC_HELPER
1715507c2bfSRichard Henderson 
1725507c2bfSRichard Henderson /* These helpers are, as a whole, full barriers.  Within the helper,
1735507c2bfSRichard Henderson  * the leading barrier is explicit and the trailing barrier is within
1745507c2bfSRichard Henderson  * cmpxchg primitive.
175d071f4cdSEmilio G. Cota  *
176d071f4cdSEmilio G. Cota  * Trace this load + RMW loop as a single RMW op. This way, regardless
177d071f4cdSEmilio G. Cota  * of CF_PARALLEL's value, we'll trace just a read and a write.
1785507c2bfSRichard Henderson  */
1795507c2bfSRichard Henderson #define GEN_ATOMIC_HELPER_FN(X, FN, XDATA_TYPE, RET)                \
1805507c2bfSRichard Henderson ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr,       \
1815507c2bfSRichard Henderson                         ABI_TYPE xval EXTRA_ARGS)                   \
1825507c2bfSRichard Henderson {                                                                   \
1835507c2bfSRichard Henderson     ATOMIC_MMU_DECLS;                                               \
1845507c2bfSRichard Henderson     XDATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;                          \
1855507c2bfSRichard Henderson     XDATA_TYPE cmp, old, new, val = xval;                           \
186cfec3885SEmilio G. Cota     uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT,   \
187cfec3885SEmilio G. Cota                                                            false,   \
188cfec3885SEmilio G. Cota                                                            ATOMIC_MMU_IDX); \
189d071f4cdSEmilio G. Cota                                                                     \
190cfec3885SEmilio G. Cota     atomic_trace_rmw_pre(env, addr, info);                          \
1915507c2bfSRichard Henderson     smp_mb();                                                       \
1925507c2bfSRichard Henderson     cmp = atomic_read__nocheck(haddr);                              \
1935507c2bfSRichard Henderson     do {                                                            \
1945507c2bfSRichard Henderson         old = cmp; new = FN(old, val);                              \
1955507c2bfSRichard Henderson         cmp = atomic_cmpxchg__nocheck(haddr, old, new);             \
1965507c2bfSRichard Henderson     } while (cmp != old);                                           \
1975507c2bfSRichard Henderson     ATOMIC_MMU_CLEANUP;                                             \
198cfec3885SEmilio G. Cota     atomic_trace_rmw_post(env, addr, info);                         \
1995507c2bfSRichard Henderson     return RET;                                                     \
2005507c2bfSRichard Henderson }
2015507c2bfSRichard Henderson 
2025507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_smin, MIN, SDATA_TYPE, old)
2035507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_umin, MIN,  DATA_TYPE, old)
2045507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_smax, MAX, SDATA_TYPE, old)
2055507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_umax, MAX,  DATA_TYPE, old)
2065507c2bfSRichard Henderson 
2075507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(smin_fetch, MIN, SDATA_TYPE, new)
2085507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(umin_fetch, MIN,  DATA_TYPE, new)
2095507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(smax_fetch, MAX, SDATA_TYPE, new)
2105507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(umax_fetch, MAX,  DATA_TYPE, new)
2115507c2bfSRichard Henderson 
2125507c2bfSRichard Henderson #undef GEN_ATOMIC_HELPER_FN
21310f7d4d5SPhilippe Mathieu-Daudé #endif /* DATA SIZE >= 16 */
21410f7d4d5SPhilippe Mathieu-Daudé 
21510f7d4d5SPhilippe Mathieu-Daudé #undef END
216d071f4cdSEmilio G. Cota #undef MEND
21710f7d4d5SPhilippe Mathieu-Daudé 
21810f7d4d5SPhilippe Mathieu-Daudé #if DATA_SIZE > 1
21910f7d4d5SPhilippe Mathieu-Daudé 
22010f7d4d5SPhilippe Mathieu-Daudé /* Define reverse-host-endian atomic operations.  Note that END is used
22110f7d4d5SPhilippe Mathieu-Daudé    within the ATOMIC_NAME macro.  */
22210f7d4d5SPhilippe Mathieu-Daudé #ifdef HOST_WORDS_BIGENDIAN
22310f7d4d5SPhilippe Mathieu-Daudé # define END  _le
224d071f4cdSEmilio G. Cota # define MEND _le
22510f7d4d5SPhilippe Mathieu-Daudé #else
22610f7d4d5SPhilippe Mathieu-Daudé # define END  _be
227d071f4cdSEmilio G. Cota # define MEND _be
22810f7d4d5SPhilippe Mathieu-Daudé #endif
22910f7d4d5SPhilippe Mathieu-Daudé 
23010f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr,
23110f7d4d5SPhilippe Mathieu-Daudé                               ABI_TYPE cmpv, ABI_TYPE newv EXTRA_ARGS)
23210f7d4d5SPhilippe Mathieu-Daudé {
23334d49937SPeter Maydell     ATOMIC_MMU_DECLS;
23410f7d4d5SPhilippe Mathieu-Daudé     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
235d071f4cdSEmilio G. Cota     DATA_TYPE ret;
236cfec3885SEmilio G. Cota     uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT,
237cfec3885SEmilio G. Cota                                                            false,
238cfec3885SEmilio G. Cota                                                            ATOMIC_MMU_IDX);
239d071f4cdSEmilio G. Cota 
240cfec3885SEmilio G. Cota     atomic_trace_rmw_pre(env, addr, info);
241e6cd4bb5SRichard Henderson #if DATA_SIZE == 16
242e6cd4bb5SRichard Henderson     ret = atomic16_cmpxchg(haddr, BSWAP(cmpv), BSWAP(newv));
243e6cd4bb5SRichard Henderson #else
244d071f4cdSEmilio G. Cota     ret = atomic_cmpxchg__nocheck(haddr, BSWAP(cmpv), BSWAP(newv));
245e6cd4bb5SRichard Henderson #endif
246ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
247cfec3885SEmilio G. Cota     atomic_trace_rmw_post(env, addr, info);
248ec603b55SRichard Henderson     return BSWAP(ret);
24910f7d4d5SPhilippe Mathieu-Daudé }
25010f7d4d5SPhilippe Mathieu-Daudé 
25110f7d4d5SPhilippe Mathieu-Daudé #if DATA_SIZE >= 16
252e6cd4bb5SRichard Henderson #if HAVE_ATOMIC128
25310f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr EXTRA_ARGS)
25410f7d4d5SPhilippe Mathieu-Daudé {
25534d49937SPeter Maydell     ATOMIC_MMU_DECLS;
25610f7d4d5SPhilippe Mathieu-Daudé     DATA_TYPE val, *haddr = ATOMIC_MMU_LOOKUP;
257cfec3885SEmilio G. Cota     uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT,
258cfec3885SEmilio G. Cota                                                            false,
259cfec3885SEmilio G. Cota                                                            ATOMIC_MMU_IDX);
260d071f4cdSEmilio G. Cota 
261cfec3885SEmilio G. Cota     atomic_trace_ld_pre(env, addr, info);
262e6cd4bb5SRichard Henderson     val = atomic16_read(haddr);
263ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
264cfec3885SEmilio G. Cota     atomic_trace_ld_post(env, addr, info);
26510f7d4d5SPhilippe Mathieu-Daudé     return BSWAP(val);
26610f7d4d5SPhilippe Mathieu-Daudé }
26710f7d4d5SPhilippe Mathieu-Daudé 
26810f7d4d5SPhilippe Mathieu-Daudé void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr,
26910f7d4d5SPhilippe Mathieu-Daudé                      ABI_TYPE val EXTRA_ARGS)
27010f7d4d5SPhilippe Mathieu-Daudé {
27134d49937SPeter Maydell     ATOMIC_MMU_DECLS;
27210f7d4d5SPhilippe Mathieu-Daudé     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
273cfec3885SEmilio G. Cota     uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT,
274cfec3885SEmilio G. Cota                                                            true,
275cfec3885SEmilio G. Cota                                                            ATOMIC_MMU_IDX);
276d071f4cdSEmilio G. Cota 
277cfec3885SEmilio G. Cota     val = BSWAP(val);
278cfec3885SEmilio G. Cota     atomic_trace_st_pre(env, addr, info);
27910f7d4d5SPhilippe Mathieu-Daudé     val = BSWAP(val);
280e6cd4bb5SRichard Henderson     atomic16_set(haddr, val);
281ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
282cfec3885SEmilio G. Cota     atomic_trace_st_post(env, addr, info);
28310f7d4d5SPhilippe Mathieu-Daudé }
284e6cd4bb5SRichard Henderson #endif
28510f7d4d5SPhilippe Mathieu-Daudé #else
28610f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr,
28710f7d4d5SPhilippe Mathieu-Daudé                            ABI_TYPE val EXTRA_ARGS)
28810f7d4d5SPhilippe Mathieu-Daudé {
28934d49937SPeter Maydell     ATOMIC_MMU_DECLS;
29010f7d4d5SPhilippe Mathieu-Daudé     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
291d071f4cdSEmilio G. Cota     ABI_TYPE ret;
292cfec3885SEmilio G. Cota     uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT,
293cfec3885SEmilio G. Cota                                                            false,
294cfec3885SEmilio G. Cota                                                            ATOMIC_MMU_IDX);
295d071f4cdSEmilio G. Cota 
296cfec3885SEmilio G. Cota     atomic_trace_rmw_pre(env, addr, info);
297d071f4cdSEmilio G. Cota     ret = atomic_xchg__nocheck(haddr, BSWAP(val));
298ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
299cfec3885SEmilio G. Cota     atomic_trace_rmw_post(env, addr, info);
300ec603b55SRichard Henderson     return BSWAP(ret);
30110f7d4d5SPhilippe Mathieu-Daudé }
30210f7d4d5SPhilippe Mathieu-Daudé 
30310f7d4d5SPhilippe Mathieu-Daudé #define GEN_ATOMIC_HELPER(X)                                        \
30410f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr,       \
30510f7d4d5SPhilippe Mathieu-Daudé                         ABI_TYPE val EXTRA_ARGS)                    \
30610f7d4d5SPhilippe Mathieu-Daudé {                                                                   \
30734d49937SPeter Maydell     ATOMIC_MMU_DECLS;                                               \
30810f7d4d5SPhilippe Mathieu-Daudé     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;                           \
309d071f4cdSEmilio G. Cota     DATA_TYPE ret;                                                  \
310cfec3885SEmilio G. Cota     uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT,   \
311cfec3885SEmilio G. Cota                                                            false,   \
312cfec3885SEmilio G. Cota                                                            ATOMIC_MMU_IDX); \
313d071f4cdSEmilio G. Cota                                                                     \
314cfec3885SEmilio G. Cota     atomic_trace_rmw_pre(env, addr, info);                          \
315d071f4cdSEmilio G. Cota     ret = atomic_##X(haddr, BSWAP(val));                            \
316ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;                                             \
317cfec3885SEmilio G. Cota     atomic_trace_rmw_post(env, addr, info);                         \
318ec603b55SRichard Henderson     return BSWAP(ret);                                              \
31910f7d4d5SPhilippe Mathieu-Daudé }
32010f7d4d5SPhilippe Mathieu-Daudé 
32110f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_and)
32210f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_or)
32310f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_xor)
32410f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(and_fetch)
32510f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(or_fetch)
32610f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(xor_fetch)
32710f7d4d5SPhilippe Mathieu-Daudé 
32810f7d4d5SPhilippe Mathieu-Daudé #undef GEN_ATOMIC_HELPER
32910f7d4d5SPhilippe Mathieu-Daudé 
3305507c2bfSRichard Henderson /* These helpers are, as a whole, full barriers.  Within the helper,
3315507c2bfSRichard Henderson  * the leading barrier is explicit and the trailing barrier is within
3325507c2bfSRichard Henderson  * cmpxchg primitive.
333d071f4cdSEmilio G. Cota  *
334d071f4cdSEmilio G. Cota  * Trace this load + RMW loop as a single RMW op. This way, regardless
335d071f4cdSEmilio G. Cota  * of CF_PARALLEL's value, we'll trace just a read and a write.
3365507c2bfSRichard Henderson  */
3375507c2bfSRichard Henderson #define GEN_ATOMIC_HELPER_FN(X, FN, XDATA_TYPE, RET)                \
3385507c2bfSRichard Henderson ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr,       \
3395507c2bfSRichard Henderson                         ABI_TYPE xval EXTRA_ARGS)                   \
3405507c2bfSRichard Henderson {                                                                   \
3415507c2bfSRichard Henderson     ATOMIC_MMU_DECLS;                                               \
3425507c2bfSRichard Henderson     XDATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;                          \
3435507c2bfSRichard Henderson     XDATA_TYPE ldo, ldn, old, new, val = xval;                      \
344cfec3885SEmilio G. Cota     uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT,   \
345cfec3885SEmilio G. Cota                                                            false,   \
346cfec3885SEmilio G. Cota                                                            ATOMIC_MMU_IDX); \
347d071f4cdSEmilio G. Cota                                                                     \
348cfec3885SEmilio G. Cota     atomic_trace_rmw_pre(env, addr, info);                          \
3495507c2bfSRichard Henderson     smp_mb();                                                       \
3505507c2bfSRichard Henderson     ldn = atomic_read__nocheck(haddr);                              \
3515507c2bfSRichard Henderson     do {                                                            \
3525507c2bfSRichard Henderson         ldo = ldn; old = BSWAP(ldo); new = FN(old, val);            \
3535507c2bfSRichard Henderson         ldn = atomic_cmpxchg__nocheck(haddr, ldo, BSWAP(new));      \
3545507c2bfSRichard Henderson     } while (ldo != ldn);                                           \
3555507c2bfSRichard Henderson     ATOMIC_MMU_CLEANUP;                                             \
356cfec3885SEmilio G. Cota     atomic_trace_rmw_post(env, addr, info);                         \
3575507c2bfSRichard Henderson     return RET;                                                     \
3585507c2bfSRichard Henderson }
3595507c2bfSRichard Henderson 
3605507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_smin, MIN, SDATA_TYPE, old)
3615507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_umin, MIN,  DATA_TYPE, old)
3625507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_smax, MAX, SDATA_TYPE, old)
3635507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_umax, MAX,  DATA_TYPE, old)
3645507c2bfSRichard Henderson 
3655507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(smin_fetch, MIN, SDATA_TYPE, new)
3665507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(umin_fetch, MIN,  DATA_TYPE, new)
3675507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(smax_fetch, MAX, SDATA_TYPE, new)
3685507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(umax_fetch, MAX,  DATA_TYPE, new)
3695507c2bfSRichard Henderson 
37058edf9eeSRichard Henderson /* Note that for addition, we need to use a separate cmpxchg loop instead
37158edf9eeSRichard Henderson    of bswaps for the reverse-host-endian helpers.  */
37258edf9eeSRichard Henderson #define ADD(X, Y)   (X + Y)
37358edf9eeSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_add, ADD, DATA_TYPE, old)
37458edf9eeSRichard Henderson GEN_ATOMIC_HELPER_FN(add_fetch, ADD, DATA_TYPE, new)
37558edf9eeSRichard Henderson #undef ADD
37658edf9eeSRichard Henderson 
3775507c2bfSRichard Henderson #undef GEN_ATOMIC_HELPER_FN
37810f7d4d5SPhilippe Mathieu-Daudé #endif /* DATA_SIZE >= 16 */
37910f7d4d5SPhilippe Mathieu-Daudé 
38010f7d4d5SPhilippe Mathieu-Daudé #undef END
381d071f4cdSEmilio G. Cota #undef MEND
38210f7d4d5SPhilippe Mathieu-Daudé #endif /* DATA_SIZE > 1 */
38310f7d4d5SPhilippe Mathieu-Daudé 
38410f7d4d5SPhilippe Mathieu-Daudé #undef BSWAP
38510f7d4d5SPhilippe Mathieu-Daudé #undef ABI_TYPE
38610f7d4d5SPhilippe Mathieu-Daudé #undef DATA_TYPE
3875507c2bfSRichard Henderson #undef SDATA_TYPE
38810f7d4d5SPhilippe Mathieu-Daudé #undef SUFFIX
38910f7d4d5SPhilippe Mathieu-Daudé #undef DATA_SIZE
390d071f4cdSEmilio G. Cota #undef SHIFT
391