xref: /qemu/accel/tcg/atomic_template.h (revision cfec388518d299e77d26b93d92c33442f4daa62b)
1c482cb11SRichard Henderson /*
2c482cb11SRichard Henderson  * Atomic helper templates
3c482cb11SRichard Henderson  * Included from tcg-runtime.c and cputlb.c.
4c482cb11SRichard Henderson  *
5c482cb11SRichard Henderson  * Copyright (c) 2016 Red Hat, Inc
6c482cb11SRichard Henderson  *
7c482cb11SRichard Henderson  * This library is free software; you can redistribute it and/or
8c482cb11SRichard Henderson  * modify it under the terms of the GNU Lesser General Public
9c482cb11SRichard Henderson  * License as published by the Free Software Foundation; either
10fb0343d5SThomas Huth  * version 2.1 of the License, or (at your option) any later version.
11c482cb11SRichard Henderson  *
12c482cb11SRichard Henderson  * This library is distributed in the hope that it will be useful,
13c482cb11SRichard Henderson  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14c482cb11SRichard Henderson  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15c482cb11SRichard Henderson  * Lesser General Public License for more details.
16c482cb11SRichard Henderson  *
17c482cb11SRichard Henderson  * You should have received a copy of the GNU Lesser General Public
18c482cb11SRichard Henderson  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19c482cb11SRichard Henderson  */
20c482cb11SRichard Henderson 
21d071f4cdSEmilio G. Cota #include "trace/mem.h"
22d071f4cdSEmilio G. Cota 
237ebee43eSRichard Henderson #if DATA_SIZE == 16
247ebee43eSRichard Henderson # define SUFFIX     o
257ebee43eSRichard Henderson # define DATA_TYPE  Int128
267ebee43eSRichard Henderson # define BSWAP      bswap128
27d071f4cdSEmilio G. Cota # define SHIFT      4
287ebee43eSRichard Henderson #elif DATA_SIZE == 8
29c482cb11SRichard Henderson # define SUFFIX     q
30c482cb11SRichard Henderson # define DATA_TYPE  uint64_t
315507c2bfSRichard Henderson # define SDATA_TYPE int64_t
32c482cb11SRichard Henderson # define BSWAP      bswap64
33d071f4cdSEmilio G. Cota # define SHIFT      3
34c482cb11SRichard Henderson #elif DATA_SIZE == 4
35c482cb11SRichard Henderson # define SUFFIX     l
36c482cb11SRichard Henderson # define DATA_TYPE  uint32_t
375507c2bfSRichard Henderson # define SDATA_TYPE int32_t
38c482cb11SRichard Henderson # define BSWAP      bswap32
39d071f4cdSEmilio G. Cota # define SHIFT      2
40c482cb11SRichard Henderson #elif DATA_SIZE == 2
41c482cb11SRichard Henderson # define SUFFIX     w
42c482cb11SRichard Henderson # define DATA_TYPE  uint16_t
435507c2bfSRichard Henderson # define SDATA_TYPE int16_t
44c482cb11SRichard Henderson # define BSWAP      bswap16
45d071f4cdSEmilio G. Cota # define SHIFT      1
46c482cb11SRichard Henderson #elif DATA_SIZE == 1
47c482cb11SRichard Henderson # define SUFFIX     b
48c482cb11SRichard Henderson # define DATA_TYPE  uint8_t
495507c2bfSRichard Henderson # define SDATA_TYPE int8_t
50c482cb11SRichard Henderson # define BSWAP
51d071f4cdSEmilio G. Cota # define SHIFT      0
52c482cb11SRichard Henderson #else
53c482cb11SRichard Henderson # error unsupported data size
54c482cb11SRichard Henderson #endif
55c482cb11SRichard Henderson 
56c482cb11SRichard Henderson #if DATA_SIZE >= 4
57c482cb11SRichard Henderson # define ABI_TYPE  DATA_TYPE
58c482cb11SRichard Henderson #else
59c482cb11SRichard Henderson # define ABI_TYPE  uint32_t
60c482cb11SRichard Henderson #endif
61c482cb11SRichard Henderson 
62c482cb11SRichard Henderson /* Define host-endian atomic operations.  Note that END is used within
63c482cb11SRichard Henderson    the ATOMIC_NAME macro, and redefined below.  */
64c482cb11SRichard Henderson #if DATA_SIZE == 1
65c482cb11SRichard Henderson # define END
66d071f4cdSEmilio G. Cota # define MEND _be /* either le or be would be fine */
67c482cb11SRichard Henderson #elif defined(HOST_WORDS_BIGENDIAN)
68c482cb11SRichard Henderson # define END  _be
69d071f4cdSEmilio G. Cota # define MEND _be
70c482cb11SRichard Henderson #else
71c482cb11SRichard Henderson # define END  _le
72d071f4cdSEmilio G. Cota # define MEND _le
73c482cb11SRichard Henderson #endif
74c482cb11SRichard Henderson 
75c482cb11SRichard Henderson ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr,
76c482cb11SRichard Henderson                               ABI_TYPE cmpv, ABI_TYPE newv EXTRA_ARGS)
77c482cb11SRichard Henderson {
7834d49937SPeter Maydell     ATOMIC_MMU_DECLS;
79c482cb11SRichard Henderson     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
80d071f4cdSEmilio G. Cota     DATA_TYPE ret;
81*cfec3885SEmilio G. Cota     uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, false,
82*cfec3885SEmilio G. Cota                                                            ATOMIC_MMU_IDX);
83d071f4cdSEmilio G. Cota 
84*cfec3885SEmilio G. Cota     atomic_trace_rmw_pre(env, addr, info);
85e6cd4bb5SRichard Henderson #if DATA_SIZE == 16
86e6cd4bb5SRichard Henderson     ret = atomic16_cmpxchg(haddr, cmpv, newv);
87e6cd4bb5SRichard Henderson #else
88d071f4cdSEmilio G. Cota     ret = atomic_cmpxchg__nocheck(haddr, cmpv, newv);
89e6cd4bb5SRichard Henderson #endif
90ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
91*cfec3885SEmilio G. Cota     atomic_trace_rmw_post(env, addr, info);
92ec603b55SRichard Henderson     return ret;
93c482cb11SRichard Henderson }
94c482cb11SRichard Henderson 
957ebee43eSRichard Henderson #if DATA_SIZE >= 16
96e6cd4bb5SRichard Henderson #if HAVE_ATOMIC128
977ebee43eSRichard Henderson ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr EXTRA_ARGS)
987ebee43eSRichard Henderson {
9934d49937SPeter Maydell     ATOMIC_MMU_DECLS;
1007ebee43eSRichard Henderson     DATA_TYPE val, *haddr = ATOMIC_MMU_LOOKUP;
101*cfec3885SEmilio G. Cota     uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, false,
102*cfec3885SEmilio G. Cota                                                            ATOMIC_MMU_IDX);
103d071f4cdSEmilio G. Cota 
104*cfec3885SEmilio G. Cota     atomic_trace_ld_pre(env, addr, info);
105e6cd4bb5SRichard Henderson     val = atomic16_read(haddr);
106ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
107*cfec3885SEmilio G. Cota     atomic_trace_ld_post(env, addr, info);
1087ebee43eSRichard Henderson     return val;
1097ebee43eSRichard Henderson }
1107ebee43eSRichard Henderson 
1117ebee43eSRichard Henderson void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr,
1127ebee43eSRichard Henderson                      ABI_TYPE val EXTRA_ARGS)
1137ebee43eSRichard Henderson {
11434d49937SPeter Maydell     ATOMIC_MMU_DECLS;
1157ebee43eSRichard Henderson     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
116*cfec3885SEmilio G. Cota     uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, true,
117*cfec3885SEmilio G. Cota                                                           ATOMIC_MMU_IDX);
118d071f4cdSEmilio G. Cota 
119*cfec3885SEmilio G. Cota     atomic_trace_st_pre(env, addr, info);
120e6cd4bb5SRichard Henderson     atomic16_set(haddr, val);
121ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
122*cfec3885SEmilio G. Cota     atomic_trace_st_post(env, addr, info);
1237ebee43eSRichard Henderson }
124e6cd4bb5SRichard Henderson #endif
1257ebee43eSRichard Henderson #else
126c482cb11SRichard Henderson ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr,
127c482cb11SRichard Henderson                            ABI_TYPE val EXTRA_ARGS)
128c482cb11SRichard Henderson {
12934d49937SPeter Maydell     ATOMIC_MMU_DECLS;
130c482cb11SRichard Henderson     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
131d071f4cdSEmilio G. Cota     DATA_TYPE ret;
132*cfec3885SEmilio G. Cota     uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, false,
133*cfec3885SEmilio G. Cota                                                           ATOMIC_MMU_IDX);
134d071f4cdSEmilio G. Cota 
135*cfec3885SEmilio G. Cota     atomic_trace_rmw_pre(env, addr, info);
136d071f4cdSEmilio G. Cota     ret = atomic_xchg__nocheck(haddr, val);
137ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
138*cfec3885SEmilio G. Cota     atomic_trace_rmw_post(env, addr, info);
139ec603b55SRichard Henderson     return ret;
140c482cb11SRichard Henderson }
141c482cb11SRichard Henderson 
142c482cb11SRichard Henderson #define GEN_ATOMIC_HELPER(X)                                        \
143c482cb11SRichard Henderson ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr,       \
144c482cb11SRichard Henderson                         ABI_TYPE val EXTRA_ARGS)                    \
145c482cb11SRichard Henderson {                                                                   \
14634d49937SPeter Maydell     ATOMIC_MMU_DECLS;                                               \
147c482cb11SRichard Henderson     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;                           \
148d071f4cdSEmilio G. Cota     DATA_TYPE ret;                                                  \
149*cfec3885SEmilio G. Cota     uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT,   \
150*cfec3885SEmilio G. Cota                                                            false,   \
151*cfec3885SEmilio G. Cota                                                            ATOMIC_MMU_IDX); \
152d071f4cdSEmilio G. Cota                                                                     \
153*cfec3885SEmilio G. Cota     atomic_trace_rmw_pre(env, addr, info);                          \
154d071f4cdSEmilio G. Cota     ret = atomic_##X(haddr, val);                                   \
155ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;                                             \
156*cfec3885SEmilio G. Cota     atomic_trace_rmw_post(env, addr, info);                         \
157ec603b55SRichard Henderson     return ret;                                                     \
158ec603b55SRichard Henderson }
159c482cb11SRichard Henderson 
160c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_add)
161c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_and)
162c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_or)
163c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_xor)
164c482cb11SRichard Henderson GEN_ATOMIC_HELPER(add_fetch)
165c482cb11SRichard Henderson GEN_ATOMIC_HELPER(and_fetch)
166c482cb11SRichard Henderson GEN_ATOMIC_HELPER(or_fetch)
167c482cb11SRichard Henderson GEN_ATOMIC_HELPER(xor_fetch)
168c482cb11SRichard Henderson 
169c482cb11SRichard Henderson #undef GEN_ATOMIC_HELPER
1705507c2bfSRichard Henderson 
1715507c2bfSRichard Henderson /* These helpers are, as a whole, full barriers.  Within the helper,
1725507c2bfSRichard Henderson  * the leading barrier is explicit and the trailing barrier is within
1735507c2bfSRichard Henderson  * cmpxchg primitive.
174d071f4cdSEmilio G. Cota  *
175d071f4cdSEmilio G. Cota  * Trace this load + RMW loop as a single RMW op. This way, regardless
176d071f4cdSEmilio G. Cota  * of CF_PARALLEL's value, we'll trace just a read and a write.
1775507c2bfSRichard Henderson  */
1785507c2bfSRichard Henderson #define GEN_ATOMIC_HELPER_FN(X, FN, XDATA_TYPE, RET)                \
1795507c2bfSRichard Henderson ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr,       \
1805507c2bfSRichard Henderson                         ABI_TYPE xval EXTRA_ARGS)                   \
1815507c2bfSRichard Henderson {                                                                   \
1825507c2bfSRichard Henderson     ATOMIC_MMU_DECLS;                                               \
1835507c2bfSRichard Henderson     XDATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;                          \
1845507c2bfSRichard Henderson     XDATA_TYPE cmp, old, new, val = xval;                           \
185*cfec3885SEmilio G. Cota     uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT,   \
186*cfec3885SEmilio G. Cota                                                            false,   \
187*cfec3885SEmilio G. Cota                                                            ATOMIC_MMU_IDX); \
188d071f4cdSEmilio G. Cota                                                                     \
189*cfec3885SEmilio G. Cota     atomic_trace_rmw_pre(env, addr, info);                          \
1905507c2bfSRichard Henderson     smp_mb();                                                       \
1915507c2bfSRichard Henderson     cmp = atomic_read__nocheck(haddr);                              \
1925507c2bfSRichard Henderson     do {                                                            \
1935507c2bfSRichard Henderson         old = cmp; new = FN(old, val);                              \
1945507c2bfSRichard Henderson         cmp = atomic_cmpxchg__nocheck(haddr, old, new);             \
1955507c2bfSRichard Henderson     } while (cmp != old);                                           \
1965507c2bfSRichard Henderson     ATOMIC_MMU_CLEANUP;                                             \
197*cfec3885SEmilio G. Cota     atomic_trace_rmw_post(env, addr, info);                         \
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
2127ebee43eSRichard Henderson #endif /* DATA SIZE >= 16 */
2137ebee43eSRichard Henderson 
214c482cb11SRichard Henderson #undef END
215d071f4cdSEmilio G. Cota #undef MEND
216c482cb11SRichard Henderson 
217c482cb11SRichard Henderson #if DATA_SIZE > 1
218c482cb11SRichard Henderson 
219c482cb11SRichard Henderson /* Define reverse-host-endian atomic operations.  Note that END is used
220c482cb11SRichard Henderson    within the ATOMIC_NAME macro.  */
221c482cb11SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN
222c482cb11SRichard Henderson # define END  _le
223d071f4cdSEmilio G. Cota # define MEND _le
224c482cb11SRichard Henderson #else
225c482cb11SRichard Henderson # define END  _be
226d071f4cdSEmilio G. Cota # define MEND _be
227c482cb11SRichard Henderson #endif
228c482cb11SRichard Henderson 
229c482cb11SRichard Henderson ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr,
230c482cb11SRichard Henderson                               ABI_TYPE cmpv, ABI_TYPE newv EXTRA_ARGS)
231c482cb11SRichard Henderson {
23234d49937SPeter Maydell     ATOMIC_MMU_DECLS;
233c482cb11SRichard Henderson     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
234d071f4cdSEmilio G. Cota     DATA_TYPE ret;
235*cfec3885SEmilio G. Cota     uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT,
236*cfec3885SEmilio G. Cota                                                            false,
237*cfec3885SEmilio G. Cota                                                            ATOMIC_MMU_IDX);
238d071f4cdSEmilio G. Cota 
239*cfec3885SEmilio G. Cota     atomic_trace_rmw_pre(env, addr, info);
240e6cd4bb5SRichard Henderson #if DATA_SIZE == 16
241e6cd4bb5SRichard Henderson     ret = atomic16_cmpxchg(haddr, BSWAP(cmpv), BSWAP(newv));
242e6cd4bb5SRichard Henderson #else
243d071f4cdSEmilio G. Cota     ret = atomic_cmpxchg__nocheck(haddr, BSWAP(cmpv), BSWAP(newv));
244e6cd4bb5SRichard Henderson #endif
245ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
246*cfec3885SEmilio G. Cota     atomic_trace_rmw_post(env, addr, info);
247ec603b55SRichard Henderson     return BSWAP(ret);
248c482cb11SRichard Henderson }
249c482cb11SRichard Henderson 
2507ebee43eSRichard Henderson #if DATA_SIZE >= 16
251e6cd4bb5SRichard Henderson #if HAVE_ATOMIC128
2527ebee43eSRichard Henderson ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr EXTRA_ARGS)
2537ebee43eSRichard Henderson {
25434d49937SPeter Maydell     ATOMIC_MMU_DECLS;
2557ebee43eSRichard Henderson     DATA_TYPE val, *haddr = ATOMIC_MMU_LOOKUP;
256*cfec3885SEmilio G. Cota     uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT,
257*cfec3885SEmilio G. Cota                                                            false,
258*cfec3885SEmilio G. Cota                                                            ATOMIC_MMU_IDX);
259d071f4cdSEmilio G. Cota 
260*cfec3885SEmilio G. Cota     atomic_trace_ld_pre(env, addr, info);
261e6cd4bb5SRichard Henderson     val = atomic16_read(haddr);
262ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
263*cfec3885SEmilio G. Cota     atomic_trace_ld_post(env, addr, info);
2647ebee43eSRichard Henderson     return BSWAP(val);
2657ebee43eSRichard Henderson }
2667ebee43eSRichard Henderson 
2677ebee43eSRichard Henderson void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr,
2687ebee43eSRichard Henderson                      ABI_TYPE val EXTRA_ARGS)
2697ebee43eSRichard Henderson {
27034d49937SPeter Maydell     ATOMIC_MMU_DECLS;
2717ebee43eSRichard Henderson     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
272*cfec3885SEmilio G. Cota     uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT,
273*cfec3885SEmilio G. Cota                                                            true,
274*cfec3885SEmilio G. Cota                                                            ATOMIC_MMU_IDX);
275d071f4cdSEmilio G. Cota 
276*cfec3885SEmilio G. Cota     val = BSWAP(val);
277*cfec3885SEmilio G. Cota     atomic_trace_st_pre(env, addr, info);
2787ebee43eSRichard Henderson     val = BSWAP(val);
279e6cd4bb5SRichard Henderson     atomic16_set(haddr, val);
280ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
281*cfec3885SEmilio G. Cota     atomic_trace_st_post(env, addr, info);
2827ebee43eSRichard Henderson }
283e6cd4bb5SRichard Henderson #endif
2847ebee43eSRichard Henderson #else
285c482cb11SRichard Henderson ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr,
286c482cb11SRichard Henderson                            ABI_TYPE val EXTRA_ARGS)
287c482cb11SRichard Henderson {
28834d49937SPeter Maydell     ATOMIC_MMU_DECLS;
289c482cb11SRichard Henderson     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
290d071f4cdSEmilio G. Cota     ABI_TYPE ret;
291*cfec3885SEmilio G. Cota     uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT,
292*cfec3885SEmilio G. Cota                                                            false,
293*cfec3885SEmilio G. Cota                                                            ATOMIC_MMU_IDX);
294d071f4cdSEmilio G. Cota 
295*cfec3885SEmilio G. Cota     atomic_trace_rmw_pre(env, addr, info);
296d071f4cdSEmilio G. Cota     ret = atomic_xchg__nocheck(haddr, BSWAP(val));
297ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
298*cfec3885SEmilio G. Cota     atomic_trace_rmw_post(env, addr, info);
299ec603b55SRichard Henderson     return BSWAP(ret);
300c482cb11SRichard Henderson }
301c482cb11SRichard Henderson 
302c482cb11SRichard Henderson #define GEN_ATOMIC_HELPER(X)                                        \
303c482cb11SRichard Henderson ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr,       \
304c482cb11SRichard Henderson                         ABI_TYPE val EXTRA_ARGS)                    \
305c482cb11SRichard Henderson {                                                                   \
30634d49937SPeter Maydell     ATOMIC_MMU_DECLS;                                               \
307c482cb11SRichard Henderson     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;                           \
308d071f4cdSEmilio G. Cota     DATA_TYPE ret;                                                  \
309*cfec3885SEmilio G. Cota     uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT,   \
310*cfec3885SEmilio G. Cota                                                            false,   \
311*cfec3885SEmilio G. Cota                                                            ATOMIC_MMU_IDX); \
312d071f4cdSEmilio G. Cota                                                                     \
313*cfec3885SEmilio G. Cota     atomic_trace_rmw_pre(env, addr, info);                          \
314d071f4cdSEmilio G. Cota     ret = atomic_##X(haddr, BSWAP(val));                            \
315ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;                                             \
316*cfec3885SEmilio G. Cota     atomic_trace_rmw_post(env, addr, info);                         \
317ec603b55SRichard Henderson     return BSWAP(ret);                                              \
318c482cb11SRichard Henderson }
319c482cb11SRichard Henderson 
320c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_and)
321c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_or)
322c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_xor)
323c482cb11SRichard Henderson GEN_ATOMIC_HELPER(and_fetch)
324c482cb11SRichard Henderson GEN_ATOMIC_HELPER(or_fetch)
325c482cb11SRichard Henderson GEN_ATOMIC_HELPER(xor_fetch)
326c482cb11SRichard Henderson 
327c482cb11SRichard Henderson #undef GEN_ATOMIC_HELPER
328c482cb11SRichard Henderson 
3295507c2bfSRichard Henderson /* These helpers are, as a whole, full barriers.  Within the helper,
3305507c2bfSRichard Henderson  * the leading barrier is explicit and the trailing barrier is within
3315507c2bfSRichard Henderson  * cmpxchg primitive.
332d071f4cdSEmilio G. Cota  *
333d071f4cdSEmilio G. Cota  * Trace this load + RMW loop as a single RMW op. This way, regardless
334d071f4cdSEmilio G. Cota  * of CF_PARALLEL's value, we'll trace just a read and a write.
3355507c2bfSRichard Henderson  */
3365507c2bfSRichard Henderson #define GEN_ATOMIC_HELPER_FN(X, FN, XDATA_TYPE, RET)                \
3375507c2bfSRichard Henderson ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr,       \
3385507c2bfSRichard Henderson                         ABI_TYPE xval EXTRA_ARGS)                   \
3395507c2bfSRichard Henderson {                                                                   \
3405507c2bfSRichard Henderson     ATOMIC_MMU_DECLS;                                               \
3415507c2bfSRichard Henderson     XDATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;                          \
3425507c2bfSRichard Henderson     XDATA_TYPE ldo, ldn, old, new, val = xval;                      \
343*cfec3885SEmilio G. Cota     uint16_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT,   \
344*cfec3885SEmilio G. Cota                                                            false,   \
345*cfec3885SEmilio G. Cota                                                            ATOMIC_MMU_IDX); \
346d071f4cdSEmilio G. Cota                                                                     \
347*cfec3885SEmilio G. Cota     atomic_trace_rmw_pre(env, addr, info);                          \
3485507c2bfSRichard Henderson     smp_mb();                                                       \
3495507c2bfSRichard Henderson     ldn = atomic_read__nocheck(haddr);                              \
3505507c2bfSRichard Henderson     do {                                                            \
3515507c2bfSRichard Henderson         ldo = ldn; old = BSWAP(ldo); new = FN(old, val);            \
3525507c2bfSRichard Henderson         ldn = atomic_cmpxchg__nocheck(haddr, ldo, BSWAP(new));      \
3535507c2bfSRichard Henderson     } while (ldo != ldn);                                           \
3545507c2bfSRichard Henderson     ATOMIC_MMU_CLEANUP;                                             \
355*cfec3885SEmilio G. Cota     atomic_trace_rmw_post(env, addr, info);                         \
3565507c2bfSRichard Henderson     return RET;                                                     \
3575507c2bfSRichard Henderson }
3585507c2bfSRichard Henderson 
3595507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_smin, MIN, SDATA_TYPE, old)
3605507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_umin, MIN,  DATA_TYPE, old)
3615507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_smax, MAX, SDATA_TYPE, old)
3625507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_umax, MAX,  DATA_TYPE, old)
3635507c2bfSRichard Henderson 
3645507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(smin_fetch, MIN, SDATA_TYPE, new)
3655507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(umin_fetch, MIN,  DATA_TYPE, new)
3665507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(smax_fetch, MAX, SDATA_TYPE, new)
3675507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(umax_fetch, MAX,  DATA_TYPE, new)
3685507c2bfSRichard Henderson 
36958edf9eeSRichard Henderson /* Note that for addition, we need to use a separate cmpxchg loop instead
37058edf9eeSRichard Henderson    of bswaps for the reverse-host-endian helpers.  */
37158edf9eeSRichard Henderson #define ADD(X, Y)   (X + Y)
37258edf9eeSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_add, ADD, DATA_TYPE, old)
37358edf9eeSRichard Henderson GEN_ATOMIC_HELPER_FN(add_fetch, ADD, DATA_TYPE, new)
37458edf9eeSRichard Henderson #undef ADD
37558edf9eeSRichard Henderson 
3765507c2bfSRichard Henderson #undef GEN_ATOMIC_HELPER_FN
3777ebee43eSRichard Henderson #endif /* DATA_SIZE >= 16 */
378c482cb11SRichard Henderson 
379c482cb11SRichard Henderson #undef END
380d071f4cdSEmilio G. Cota #undef MEND
381c482cb11SRichard Henderson #endif /* DATA_SIZE > 1 */
382c482cb11SRichard Henderson 
383c482cb11SRichard Henderson #undef BSWAP
384c482cb11SRichard Henderson #undef ABI_TYPE
385c482cb11SRichard Henderson #undef DATA_TYPE
3865507c2bfSRichard Henderson #undef SDATA_TYPE
387c482cb11SRichard Henderson #undef SUFFIX
388c482cb11SRichard Henderson #undef DATA_SIZE
389d071f4cdSEmilio G. Cota #undef SHIFT
390