xref: /openbmc/qemu/accel/tcg/atomic_template.h (revision fb0343d5b4dd4b9b9e96e563d913a3e0c709fe4e)
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
10*fb0343d5SThomas 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é 
21d071f4cdSEmilio G. Cota #include "trace/mem.h"
22d071f4cdSEmilio G. Cota 
2310f7d4d5SPhilippe Mathieu-Daudé #if DATA_SIZE == 16
2410f7d4d5SPhilippe Mathieu-Daudé # define SUFFIX     o
2510f7d4d5SPhilippe Mathieu-Daudé # define DATA_TYPE  Int128
2610f7d4d5SPhilippe Mathieu-Daudé # define BSWAP      bswap128
27d071f4cdSEmilio G. Cota # define SHIFT      4
2810f7d4d5SPhilippe Mathieu-Daudé #elif DATA_SIZE == 8
2910f7d4d5SPhilippe Mathieu-Daudé # define SUFFIX     q
3010f7d4d5SPhilippe Mathieu-Daudé # define DATA_TYPE  uint64_t
315507c2bfSRichard Henderson # define SDATA_TYPE int64_t
3210f7d4d5SPhilippe Mathieu-Daudé # define BSWAP      bswap64
33d071f4cdSEmilio G. Cota # define SHIFT      3
3410f7d4d5SPhilippe Mathieu-Daudé #elif DATA_SIZE == 4
3510f7d4d5SPhilippe Mathieu-Daudé # define SUFFIX     l
3610f7d4d5SPhilippe Mathieu-Daudé # define DATA_TYPE  uint32_t
375507c2bfSRichard Henderson # define SDATA_TYPE int32_t
3810f7d4d5SPhilippe Mathieu-Daudé # define BSWAP      bswap32
39d071f4cdSEmilio G. Cota # define SHIFT      2
4010f7d4d5SPhilippe Mathieu-Daudé #elif DATA_SIZE == 2
4110f7d4d5SPhilippe Mathieu-Daudé # define SUFFIX     w
4210f7d4d5SPhilippe Mathieu-Daudé # define DATA_TYPE  uint16_t
435507c2bfSRichard Henderson # define SDATA_TYPE int16_t
4410f7d4d5SPhilippe Mathieu-Daudé # define BSWAP      bswap16
45d071f4cdSEmilio G. Cota # define SHIFT      1
4610f7d4d5SPhilippe Mathieu-Daudé #elif DATA_SIZE == 1
4710f7d4d5SPhilippe Mathieu-Daudé # define SUFFIX     b
4810f7d4d5SPhilippe Mathieu-Daudé # define DATA_TYPE  uint8_t
495507c2bfSRichard Henderson # define SDATA_TYPE int8_t
5010f7d4d5SPhilippe Mathieu-Daudé # define BSWAP
51d071f4cdSEmilio G. Cota # define SHIFT      0
5210f7d4d5SPhilippe Mathieu-Daudé #else
5310f7d4d5SPhilippe Mathieu-Daudé # error unsupported data size
5410f7d4d5SPhilippe Mathieu-Daudé #endif
5510f7d4d5SPhilippe Mathieu-Daudé 
5610f7d4d5SPhilippe Mathieu-Daudé #if DATA_SIZE >= 4
5710f7d4d5SPhilippe Mathieu-Daudé # define ABI_TYPE  DATA_TYPE
5810f7d4d5SPhilippe Mathieu-Daudé #else
5910f7d4d5SPhilippe Mathieu-Daudé # define ABI_TYPE  uint32_t
6010f7d4d5SPhilippe Mathieu-Daudé #endif
6110f7d4d5SPhilippe Mathieu-Daudé 
62d071f4cdSEmilio G. Cota #define ATOMIC_TRACE_RMW do {                                           \
63d071f4cdSEmilio G. Cota         uint8_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, false); \
64d071f4cdSEmilio G. Cota                                                                         \
65d071f4cdSEmilio G. Cota         trace_guest_mem_before_exec(ENV_GET_CPU(env), addr, info);      \
66d071f4cdSEmilio G. Cota         trace_guest_mem_before_exec(ENV_GET_CPU(env), addr,             \
67d071f4cdSEmilio G. Cota                                     info | TRACE_MEM_ST);               \
68d071f4cdSEmilio G. Cota     } while (0)
69d071f4cdSEmilio G. Cota 
70d071f4cdSEmilio G. Cota #define ATOMIC_TRACE_LD do {                                            \
71d071f4cdSEmilio G. Cota         uint8_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, false); \
72d071f4cdSEmilio G. Cota                                                                         \
73d071f4cdSEmilio G. Cota         trace_guest_mem_before_exec(ENV_GET_CPU(env), addr, info);      \
74d071f4cdSEmilio G. Cota     } while (0)
75d071f4cdSEmilio G. Cota 
76d071f4cdSEmilio G. Cota # define ATOMIC_TRACE_ST do {                                           \
77d071f4cdSEmilio G. Cota         uint8_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, true); \
78d071f4cdSEmilio G. Cota                                                                         \
79d071f4cdSEmilio G. Cota         trace_guest_mem_before_exec(ENV_GET_CPU(env), addr, info);      \
80d071f4cdSEmilio G. Cota     } while (0)
81d071f4cdSEmilio G. Cota 
8210f7d4d5SPhilippe Mathieu-Daudé /* Define host-endian atomic operations.  Note that END is used within
8310f7d4d5SPhilippe Mathieu-Daudé    the ATOMIC_NAME macro, and redefined below.  */
8410f7d4d5SPhilippe Mathieu-Daudé #if DATA_SIZE == 1
8510f7d4d5SPhilippe Mathieu-Daudé # define END
86d071f4cdSEmilio G. Cota # define MEND _be /* either le or be would be fine */
8710f7d4d5SPhilippe Mathieu-Daudé #elif defined(HOST_WORDS_BIGENDIAN)
8810f7d4d5SPhilippe Mathieu-Daudé # define END  _be
89d071f4cdSEmilio G. Cota # define MEND _be
9010f7d4d5SPhilippe Mathieu-Daudé #else
9110f7d4d5SPhilippe Mathieu-Daudé # define END  _le
92d071f4cdSEmilio G. Cota # define MEND _le
9310f7d4d5SPhilippe Mathieu-Daudé #endif
9410f7d4d5SPhilippe Mathieu-Daudé 
9510f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr,
9610f7d4d5SPhilippe Mathieu-Daudé                               ABI_TYPE cmpv, ABI_TYPE newv EXTRA_ARGS)
9710f7d4d5SPhilippe Mathieu-Daudé {
9834d49937SPeter Maydell     ATOMIC_MMU_DECLS;
9910f7d4d5SPhilippe Mathieu-Daudé     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
100d071f4cdSEmilio G. Cota     DATA_TYPE ret;
101d071f4cdSEmilio G. Cota 
102d071f4cdSEmilio G. Cota     ATOMIC_TRACE_RMW;
103e6cd4bb5SRichard Henderson #if DATA_SIZE == 16
104e6cd4bb5SRichard Henderson     ret = atomic16_cmpxchg(haddr, cmpv, newv);
105e6cd4bb5SRichard Henderson #else
106d071f4cdSEmilio G. Cota     ret = atomic_cmpxchg__nocheck(haddr, cmpv, newv);
107e6cd4bb5SRichard Henderson #endif
108ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
109ec603b55SRichard Henderson     return ret;
11010f7d4d5SPhilippe Mathieu-Daudé }
11110f7d4d5SPhilippe Mathieu-Daudé 
11210f7d4d5SPhilippe Mathieu-Daudé #if DATA_SIZE >= 16
113e6cd4bb5SRichard Henderson #if HAVE_ATOMIC128
11410f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr EXTRA_ARGS)
11510f7d4d5SPhilippe Mathieu-Daudé {
11634d49937SPeter Maydell     ATOMIC_MMU_DECLS;
11710f7d4d5SPhilippe Mathieu-Daudé     DATA_TYPE val, *haddr = ATOMIC_MMU_LOOKUP;
118d071f4cdSEmilio G. Cota 
119d071f4cdSEmilio G. Cota     ATOMIC_TRACE_LD;
120e6cd4bb5SRichard Henderson     val = atomic16_read(haddr);
121ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
12210f7d4d5SPhilippe Mathieu-Daudé     return val;
12310f7d4d5SPhilippe Mathieu-Daudé }
12410f7d4d5SPhilippe Mathieu-Daudé 
12510f7d4d5SPhilippe Mathieu-Daudé void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr,
12610f7d4d5SPhilippe Mathieu-Daudé                      ABI_TYPE val EXTRA_ARGS)
12710f7d4d5SPhilippe Mathieu-Daudé {
12834d49937SPeter Maydell     ATOMIC_MMU_DECLS;
12910f7d4d5SPhilippe Mathieu-Daudé     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
130d071f4cdSEmilio G. Cota 
131d071f4cdSEmilio G. Cota     ATOMIC_TRACE_ST;
132e6cd4bb5SRichard Henderson     atomic16_set(haddr, val);
133ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
13410f7d4d5SPhilippe Mathieu-Daudé }
135e6cd4bb5SRichard Henderson #endif
13610f7d4d5SPhilippe Mathieu-Daudé #else
13710f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr,
13810f7d4d5SPhilippe Mathieu-Daudé                            ABI_TYPE val EXTRA_ARGS)
13910f7d4d5SPhilippe Mathieu-Daudé {
14034d49937SPeter Maydell     ATOMIC_MMU_DECLS;
14110f7d4d5SPhilippe Mathieu-Daudé     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
142d071f4cdSEmilio G. Cota     DATA_TYPE ret;
143d071f4cdSEmilio G. Cota 
144d071f4cdSEmilio G. Cota     ATOMIC_TRACE_RMW;
145d071f4cdSEmilio G. Cota     ret = atomic_xchg__nocheck(haddr, val);
146ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
147ec603b55SRichard Henderson     return ret;
14810f7d4d5SPhilippe Mathieu-Daudé }
14910f7d4d5SPhilippe Mathieu-Daudé 
15010f7d4d5SPhilippe Mathieu-Daudé #define GEN_ATOMIC_HELPER(X)                                        \
15110f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr,       \
15210f7d4d5SPhilippe Mathieu-Daudé                  ABI_TYPE val EXTRA_ARGS)                           \
15310f7d4d5SPhilippe Mathieu-Daudé {                                                                   \
15434d49937SPeter Maydell     ATOMIC_MMU_DECLS;                                               \
15510f7d4d5SPhilippe Mathieu-Daudé     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;                           \
156d071f4cdSEmilio G. Cota     DATA_TYPE ret;                                                  \
157d071f4cdSEmilio G. Cota                                                                     \
158d071f4cdSEmilio G. Cota     ATOMIC_TRACE_RMW;                                               \
159d071f4cdSEmilio G. Cota     ret = atomic_##X(haddr, val);                                   \
160ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;                                             \
161ec603b55SRichard Henderson     return ret;                                                     \
162ec603b55SRichard Henderson }
16310f7d4d5SPhilippe Mathieu-Daudé 
16410f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_add)
16510f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_and)
16610f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_or)
16710f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_xor)
16810f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(add_fetch)
16910f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(and_fetch)
17010f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(or_fetch)
17110f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(xor_fetch)
17210f7d4d5SPhilippe Mathieu-Daudé 
17310f7d4d5SPhilippe Mathieu-Daudé #undef GEN_ATOMIC_HELPER
1745507c2bfSRichard Henderson 
1755507c2bfSRichard Henderson /* These helpers are, as a whole, full barriers.  Within the helper,
1765507c2bfSRichard Henderson  * the leading barrier is explicit and the trailing barrier is within
1775507c2bfSRichard Henderson  * cmpxchg primitive.
178d071f4cdSEmilio G. Cota  *
179d071f4cdSEmilio G. Cota  * Trace this load + RMW loop as a single RMW op. This way, regardless
180d071f4cdSEmilio G. Cota  * of CF_PARALLEL's value, we'll trace just a read and a write.
1815507c2bfSRichard Henderson  */
1825507c2bfSRichard Henderson #define GEN_ATOMIC_HELPER_FN(X, FN, XDATA_TYPE, RET)                \
1835507c2bfSRichard Henderson ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr,       \
1845507c2bfSRichard Henderson                         ABI_TYPE xval EXTRA_ARGS)                   \
1855507c2bfSRichard Henderson {                                                                   \
1865507c2bfSRichard Henderson     ATOMIC_MMU_DECLS;                                               \
1875507c2bfSRichard Henderson     XDATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;                          \
1885507c2bfSRichard Henderson     XDATA_TYPE cmp, old, new, val = xval;                           \
189d071f4cdSEmilio G. Cota                                                                     \
190d071f4cdSEmilio G. Cota     ATOMIC_TRACE_RMW;                                               \
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;                                             \
1985507c2bfSRichard Henderson     return RET;                                                     \
1995507c2bfSRichard Henderson }
2005507c2bfSRichard Henderson 
2015507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_smin, MIN, SDATA_TYPE, old)
2025507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_umin, MIN,  DATA_TYPE, old)
2035507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_smax, MAX, SDATA_TYPE, old)
2045507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_umax, MAX,  DATA_TYPE, old)
2055507c2bfSRichard Henderson 
2065507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(smin_fetch, MIN, SDATA_TYPE, new)
2075507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(umin_fetch, MIN,  DATA_TYPE, new)
2085507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(smax_fetch, MAX, SDATA_TYPE, new)
2095507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(umax_fetch, MAX,  DATA_TYPE, new)
2105507c2bfSRichard Henderson 
2115507c2bfSRichard Henderson #undef GEN_ATOMIC_HELPER_FN
21210f7d4d5SPhilippe Mathieu-Daudé #endif /* DATA SIZE >= 16 */
21310f7d4d5SPhilippe Mathieu-Daudé 
21410f7d4d5SPhilippe Mathieu-Daudé #undef END
215d071f4cdSEmilio G. Cota #undef MEND
21610f7d4d5SPhilippe Mathieu-Daudé 
21710f7d4d5SPhilippe Mathieu-Daudé #if DATA_SIZE > 1
21810f7d4d5SPhilippe Mathieu-Daudé 
21910f7d4d5SPhilippe Mathieu-Daudé /* Define reverse-host-endian atomic operations.  Note that END is used
22010f7d4d5SPhilippe Mathieu-Daudé    within the ATOMIC_NAME macro.  */
22110f7d4d5SPhilippe Mathieu-Daudé #ifdef HOST_WORDS_BIGENDIAN
22210f7d4d5SPhilippe Mathieu-Daudé # define END  _le
223d071f4cdSEmilio G. Cota # define MEND _le
22410f7d4d5SPhilippe Mathieu-Daudé #else
22510f7d4d5SPhilippe Mathieu-Daudé # define END  _be
226d071f4cdSEmilio G. Cota # define MEND _be
22710f7d4d5SPhilippe Mathieu-Daudé #endif
22810f7d4d5SPhilippe Mathieu-Daudé 
22910f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr,
23010f7d4d5SPhilippe Mathieu-Daudé                               ABI_TYPE cmpv, ABI_TYPE newv EXTRA_ARGS)
23110f7d4d5SPhilippe Mathieu-Daudé {
23234d49937SPeter Maydell     ATOMIC_MMU_DECLS;
23310f7d4d5SPhilippe Mathieu-Daudé     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
234d071f4cdSEmilio G. Cota     DATA_TYPE ret;
235d071f4cdSEmilio G. Cota 
236d071f4cdSEmilio G. Cota     ATOMIC_TRACE_RMW;
237e6cd4bb5SRichard Henderson #if DATA_SIZE == 16
238e6cd4bb5SRichard Henderson     ret = atomic16_cmpxchg(haddr, BSWAP(cmpv), BSWAP(newv));
239e6cd4bb5SRichard Henderson #else
240d071f4cdSEmilio G. Cota     ret = atomic_cmpxchg__nocheck(haddr, BSWAP(cmpv), BSWAP(newv));
241e6cd4bb5SRichard Henderson #endif
242ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
243ec603b55SRichard Henderson     return BSWAP(ret);
24410f7d4d5SPhilippe Mathieu-Daudé }
24510f7d4d5SPhilippe Mathieu-Daudé 
24610f7d4d5SPhilippe Mathieu-Daudé #if DATA_SIZE >= 16
247e6cd4bb5SRichard Henderson #if HAVE_ATOMIC128
24810f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr EXTRA_ARGS)
24910f7d4d5SPhilippe Mathieu-Daudé {
25034d49937SPeter Maydell     ATOMIC_MMU_DECLS;
25110f7d4d5SPhilippe Mathieu-Daudé     DATA_TYPE val, *haddr = ATOMIC_MMU_LOOKUP;
252d071f4cdSEmilio G. Cota 
253d071f4cdSEmilio G. Cota     ATOMIC_TRACE_LD;
254e6cd4bb5SRichard Henderson     val = atomic16_read(haddr);
255ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
25610f7d4d5SPhilippe Mathieu-Daudé     return BSWAP(val);
25710f7d4d5SPhilippe Mathieu-Daudé }
25810f7d4d5SPhilippe Mathieu-Daudé 
25910f7d4d5SPhilippe Mathieu-Daudé void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr,
26010f7d4d5SPhilippe Mathieu-Daudé                      ABI_TYPE val EXTRA_ARGS)
26110f7d4d5SPhilippe Mathieu-Daudé {
26234d49937SPeter Maydell     ATOMIC_MMU_DECLS;
26310f7d4d5SPhilippe Mathieu-Daudé     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
264d071f4cdSEmilio G. Cota 
265d071f4cdSEmilio G. Cota     ATOMIC_TRACE_ST;
26610f7d4d5SPhilippe Mathieu-Daudé     val = BSWAP(val);
267e6cd4bb5SRichard Henderson     atomic16_set(haddr, val);
268ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
26910f7d4d5SPhilippe Mathieu-Daudé }
270e6cd4bb5SRichard Henderson #endif
27110f7d4d5SPhilippe Mathieu-Daudé #else
27210f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr,
27310f7d4d5SPhilippe Mathieu-Daudé                            ABI_TYPE val EXTRA_ARGS)
27410f7d4d5SPhilippe Mathieu-Daudé {
27534d49937SPeter Maydell     ATOMIC_MMU_DECLS;
27610f7d4d5SPhilippe Mathieu-Daudé     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
277d071f4cdSEmilio G. Cota     ABI_TYPE ret;
278d071f4cdSEmilio G. Cota 
279d071f4cdSEmilio G. Cota     ATOMIC_TRACE_RMW;
280d071f4cdSEmilio G. Cota     ret = atomic_xchg__nocheck(haddr, BSWAP(val));
281ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
282ec603b55SRichard Henderson     return BSWAP(ret);
28310f7d4d5SPhilippe Mathieu-Daudé }
28410f7d4d5SPhilippe Mathieu-Daudé 
28510f7d4d5SPhilippe Mathieu-Daudé #define GEN_ATOMIC_HELPER(X)                                        \
28610f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(X)(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     DATA_TYPE ret;                                                  \
292d071f4cdSEmilio G. Cota                                                                     \
293d071f4cdSEmilio G. Cota     ATOMIC_TRACE_RMW;                                               \
294d071f4cdSEmilio G. Cota     ret = atomic_##X(haddr, BSWAP(val));                            \
295ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;                                             \
296ec603b55SRichard Henderson     return BSWAP(ret);                                              \
29710f7d4d5SPhilippe Mathieu-Daudé }
29810f7d4d5SPhilippe Mathieu-Daudé 
29910f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_and)
30010f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_or)
30110f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_xor)
30210f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(and_fetch)
30310f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(or_fetch)
30410f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(xor_fetch)
30510f7d4d5SPhilippe Mathieu-Daudé 
30610f7d4d5SPhilippe Mathieu-Daudé #undef GEN_ATOMIC_HELPER
30710f7d4d5SPhilippe Mathieu-Daudé 
3085507c2bfSRichard Henderson /* These helpers are, as a whole, full barriers.  Within the helper,
3095507c2bfSRichard Henderson  * the leading barrier is explicit and the trailing barrier is within
3105507c2bfSRichard Henderson  * cmpxchg primitive.
311d071f4cdSEmilio G. Cota  *
312d071f4cdSEmilio G. Cota  * Trace this load + RMW loop as a single RMW op. This way, regardless
313d071f4cdSEmilio G. Cota  * of CF_PARALLEL's value, we'll trace just a read and a write.
3145507c2bfSRichard Henderson  */
3155507c2bfSRichard Henderson #define GEN_ATOMIC_HELPER_FN(X, FN, XDATA_TYPE, RET)                \
3165507c2bfSRichard Henderson ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr,       \
3175507c2bfSRichard Henderson                         ABI_TYPE xval EXTRA_ARGS)                   \
3185507c2bfSRichard Henderson {                                                                   \
3195507c2bfSRichard Henderson     ATOMIC_MMU_DECLS;                                               \
3205507c2bfSRichard Henderson     XDATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;                          \
3215507c2bfSRichard Henderson     XDATA_TYPE ldo, ldn, old, new, val = xval;                      \
322d071f4cdSEmilio G. Cota                                                                     \
323d071f4cdSEmilio G. Cota     ATOMIC_TRACE_RMW;                                               \
3245507c2bfSRichard Henderson     smp_mb();                                                       \
3255507c2bfSRichard Henderson     ldn = atomic_read__nocheck(haddr);                              \
3265507c2bfSRichard Henderson     do {                                                            \
3275507c2bfSRichard Henderson         ldo = ldn; old = BSWAP(ldo); new = FN(old, val);            \
3285507c2bfSRichard Henderson         ldn = atomic_cmpxchg__nocheck(haddr, ldo, BSWAP(new));      \
3295507c2bfSRichard Henderson     } while (ldo != ldn);                                           \
3305507c2bfSRichard Henderson     ATOMIC_MMU_CLEANUP;                                             \
3315507c2bfSRichard Henderson     return RET;                                                     \
3325507c2bfSRichard Henderson }
3335507c2bfSRichard Henderson 
3345507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_smin, MIN, SDATA_TYPE, old)
3355507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_umin, MIN,  DATA_TYPE, old)
3365507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_smax, MAX, SDATA_TYPE, old)
3375507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_umax, MAX,  DATA_TYPE, old)
3385507c2bfSRichard Henderson 
3395507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(smin_fetch, MIN, SDATA_TYPE, new)
3405507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(umin_fetch, MIN,  DATA_TYPE, new)
3415507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(smax_fetch, MAX, SDATA_TYPE, new)
3425507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(umax_fetch, MAX,  DATA_TYPE, new)
3435507c2bfSRichard Henderson 
34458edf9eeSRichard Henderson /* Note that for addition, we need to use a separate cmpxchg loop instead
34558edf9eeSRichard Henderson    of bswaps for the reverse-host-endian helpers.  */
34658edf9eeSRichard Henderson #define ADD(X, Y)   (X + Y)
34758edf9eeSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_add, ADD, DATA_TYPE, old)
34858edf9eeSRichard Henderson GEN_ATOMIC_HELPER_FN(add_fetch, ADD, DATA_TYPE, new)
34958edf9eeSRichard Henderson #undef ADD
35058edf9eeSRichard Henderson 
3515507c2bfSRichard Henderson #undef GEN_ATOMIC_HELPER_FN
35210f7d4d5SPhilippe Mathieu-Daudé #endif /* DATA_SIZE >= 16 */
35310f7d4d5SPhilippe Mathieu-Daudé 
35410f7d4d5SPhilippe Mathieu-Daudé #undef END
355d071f4cdSEmilio G. Cota #undef MEND
35610f7d4d5SPhilippe Mathieu-Daudé #endif /* DATA_SIZE > 1 */
35710f7d4d5SPhilippe Mathieu-Daudé 
358d071f4cdSEmilio G. Cota #undef ATOMIC_TRACE_ST
359d071f4cdSEmilio G. Cota #undef ATOMIC_TRACE_LD
360d071f4cdSEmilio G. Cota #undef ATOMIC_TRACE_RMW
361d071f4cdSEmilio G. Cota 
36210f7d4d5SPhilippe Mathieu-Daudé #undef BSWAP
36310f7d4d5SPhilippe Mathieu-Daudé #undef ABI_TYPE
36410f7d4d5SPhilippe Mathieu-Daudé #undef DATA_TYPE
3655507c2bfSRichard Henderson #undef SDATA_TYPE
36610f7d4d5SPhilippe Mathieu-Daudé #undef SUFFIX
36710f7d4d5SPhilippe Mathieu-Daudé #undef DATA_SIZE
368d071f4cdSEmilio G. Cota #undef SHIFT
369