xref: /qemu/accel/tcg/atomic_template.h (revision a754f7f34e9c74adf65a0149c5e2382077a6e594)
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 
21e6d86bedSEmilio G. Cota #include "qemu/plugin.h"
22d071f4cdSEmilio G. Cota #include "trace/mem.h"
23d071f4cdSEmilio G. Cota 
247ebee43eSRichard Henderson #if DATA_SIZE == 16
257ebee43eSRichard Henderson # define SUFFIX     o
267ebee43eSRichard Henderson # define DATA_TYPE  Int128
277ebee43eSRichard Henderson # define BSWAP      bswap128
28d071f4cdSEmilio G. Cota # define SHIFT      4
297ebee43eSRichard Henderson #elif DATA_SIZE == 8
30c482cb11SRichard Henderson # define SUFFIX     q
319ef0c6d6SRichard Henderson # define DATA_TYPE  aligned_uint64_t
329ef0c6d6SRichard Henderson # define SDATA_TYPE aligned_int64_t
33c482cb11SRichard Henderson # define BSWAP      bswap64
34d071f4cdSEmilio G. Cota # define SHIFT      3
35c482cb11SRichard Henderson #elif DATA_SIZE == 4
36c482cb11SRichard Henderson # define SUFFIX     l
37c482cb11SRichard Henderson # define DATA_TYPE  uint32_t
385507c2bfSRichard Henderson # define SDATA_TYPE int32_t
39c482cb11SRichard Henderson # define BSWAP      bswap32
40d071f4cdSEmilio G. Cota # define SHIFT      2
41c482cb11SRichard Henderson #elif DATA_SIZE == 2
42c482cb11SRichard Henderson # define SUFFIX     w
43c482cb11SRichard Henderson # define DATA_TYPE  uint16_t
445507c2bfSRichard Henderson # define SDATA_TYPE int16_t
45c482cb11SRichard Henderson # define BSWAP      bswap16
46d071f4cdSEmilio G. Cota # define SHIFT      1
47c482cb11SRichard Henderson #elif DATA_SIZE == 1
48c482cb11SRichard Henderson # define SUFFIX     b
49c482cb11SRichard Henderson # define DATA_TYPE  uint8_t
505507c2bfSRichard Henderson # define SDATA_TYPE int8_t
51c482cb11SRichard Henderson # define BSWAP
52d071f4cdSEmilio G. Cota # define SHIFT      0
53c482cb11SRichard Henderson #else
54c482cb11SRichard Henderson # error unsupported data size
55c482cb11SRichard Henderson #endif
56c482cb11SRichard Henderson 
57c482cb11SRichard Henderson #if DATA_SIZE >= 4
58c482cb11SRichard Henderson # define ABI_TYPE  DATA_TYPE
59c482cb11SRichard Henderson #else
60c482cb11SRichard Henderson # define ABI_TYPE  uint32_t
61c482cb11SRichard Henderson #endif
62c482cb11SRichard Henderson 
63c482cb11SRichard Henderson /* Define host-endian atomic operations.  Note that END is used within
64c482cb11SRichard Henderson    the ATOMIC_NAME macro, and redefined below.  */
65c482cb11SRichard Henderson #if DATA_SIZE == 1
66c482cb11SRichard Henderson # define END
67c482cb11SRichard Henderson #elif defined(HOST_WORDS_BIGENDIAN)
68c482cb11SRichard Henderson # define END  _be
69c482cb11SRichard Henderson #else
70c482cb11SRichard Henderson # define END  _le
71c482cb11SRichard Henderson #endif
72c482cb11SRichard Henderson 
73c482cb11SRichard Henderson ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr,
7448688fafSRichard Henderson                               ABI_TYPE cmpv, ABI_TYPE newv,
7548688fafSRichard Henderson                               TCGMemOpIdx oi, uintptr_t retaddr)
76c482cb11SRichard Henderson {
77*a754f7f3SRichard Henderson     DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,
78*a754f7f3SRichard Henderson                                          PAGE_READ | PAGE_WRITE, retaddr);
79d071f4cdSEmilio G. Cota     DATA_TYPE ret;
804e6b1384SRichard Henderson     uint16_t info = trace_mem_build_info(SHIFT, false, 0, false,
81cfec3885SEmilio G. Cota                                          ATOMIC_MMU_IDX);
82d071f4cdSEmilio G. Cota 
83cfec3885SEmilio G. Cota     atomic_trace_rmw_pre(env, addr, info);
84e6cd4bb5SRichard Henderson #if DATA_SIZE == 16
85e6cd4bb5SRichard Henderson     ret = atomic16_cmpxchg(haddr, cmpv, newv);
86e6cd4bb5SRichard Henderson #else
87d73415a3SStefan Hajnoczi     ret = qatomic_cmpxchg__nocheck(haddr, cmpv, newv);
88e6cd4bb5SRichard Henderson #endif
89ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
90cfec3885SEmilio G. Cota     atomic_trace_rmw_post(env, addr, info);
91ec603b55SRichard Henderson     return ret;
92c482cb11SRichard Henderson }
93c482cb11SRichard Henderson 
947ebee43eSRichard Henderson #if DATA_SIZE >= 16
95e6cd4bb5SRichard Henderson #if HAVE_ATOMIC128
9648688fafSRichard Henderson ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr,
9748688fafSRichard Henderson                          TCGMemOpIdx oi, uintptr_t retaddr)
987ebee43eSRichard Henderson {
99*a754f7f3SRichard Henderson     DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,
100*a754f7f3SRichard Henderson                                          PAGE_READ, retaddr);
101*a754f7f3SRichard Henderson     DATA_TYPE val;
1024e6b1384SRichard Henderson     uint16_t info = trace_mem_build_info(SHIFT, false, 0, 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);
1097ebee43eSRichard Henderson     return val;
1107ebee43eSRichard Henderson }
1117ebee43eSRichard Henderson 
11248688fafSRichard Henderson void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr, ABI_TYPE val,
11348688fafSRichard Henderson                      TCGMemOpIdx oi, uintptr_t retaddr)
1147ebee43eSRichard Henderson {
115*a754f7f3SRichard Henderson     DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,
116*a754f7f3SRichard Henderson                                          PAGE_WRITE, retaddr);
1174e6b1384SRichard Henderson     uint16_t info = trace_mem_build_info(SHIFT, false, 0, 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);
1247ebee43eSRichard Henderson }
125e6cd4bb5SRichard Henderson #endif
1267ebee43eSRichard Henderson #else
12748688fafSRichard Henderson ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr, ABI_TYPE val,
12848688fafSRichard Henderson                            TCGMemOpIdx oi, uintptr_t retaddr)
129c482cb11SRichard Henderson {
130*a754f7f3SRichard Henderson     DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,
131*a754f7f3SRichard Henderson                                          PAGE_READ | PAGE_WRITE, retaddr);
132d071f4cdSEmilio G. Cota     DATA_TYPE ret;
1334e6b1384SRichard Henderson     uint16_t info = trace_mem_build_info(SHIFT, false, 0, false,
134cfec3885SEmilio G. Cota                                          ATOMIC_MMU_IDX);
135d071f4cdSEmilio G. Cota 
136cfec3885SEmilio G. Cota     atomic_trace_rmw_pre(env, addr, info);
137d73415a3SStefan Hajnoczi     ret = qatomic_xchg__nocheck(haddr, val);
138ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
139cfec3885SEmilio G. Cota     atomic_trace_rmw_post(env, addr, info);
140ec603b55SRichard Henderson     return ret;
141c482cb11SRichard Henderson }
142c482cb11SRichard Henderson 
143c482cb11SRichard Henderson #define GEN_ATOMIC_HELPER(X)                                        \
144c482cb11SRichard Henderson ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr,       \
14548688fafSRichard Henderson                         ABI_TYPE val, TCGMemOpIdx oi, uintptr_t retaddr) \
146c482cb11SRichard Henderson {                                                                   \
147*a754f7f3SRichard Henderson     DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,  \
148*a754f7f3SRichard Henderson                                          PAGE_READ | PAGE_WRITE, retaddr); \
149d071f4cdSEmilio G. Cota     DATA_TYPE ret;                                                  \
1504e6b1384SRichard Henderson     uint16_t info = trace_mem_build_info(SHIFT, false, 0, false,    \
151cfec3885SEmilio G. Cota                                          ATOMIC_MMU_IDX);           \
152cfec3885SEmilio G. Cota     atomic_trace_rmw_pre(env, addr, info);                          \
153d73415a3SStefan Hajnoczi     ret = qatomic_##X(haddr, val);                                  \
154ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;                                             \
155cfec3885SEmilio G. Cota     atomic_trace_rmw_post(env, addr, info);                         \
156ec603b55SRichard Henderson     return ret;                                                     \
157ec603b55SRichard Henderson }
158c482cb11SRichard Henderson 
159c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_add)
160c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_and)
161c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_or)
162c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_xor)
163c482cb11SRichard Henderson GEN_ATOMIC_HELPER(add_fetch)
164c482cb11SRichard Henderson GEN_ATOMIC_HELPER(and_fetch)
165c482cb11SRichard Henderson GEN_ATOMIC_HELPER(or_fetch)
166c482cb11SRichard Henderson GEN_ATOMIC_HELPER(xor_fetch)
167c482cb11SRichard Henderson 
168c482cb11SRichard Henderson #undef GEN_ATOMIC_HELPER
1695507c2bfSRichard Henderson 
170*a754f7f3SRichard Henderson /*
171*a754f7f3SRichard 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,       \
18048688fafSRichard Henderson                         ABI_TYPE xval, TCGMemOpIdx oi, uintptr_t retaddr) \
1815507c2bfSRichard Henderson {                                                                   \
182*a754f7f3SRichard Henderson     XDATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, \
183*a754f7f3SRichard Henderson                                           PAGE_READ | PAGE_WRITE, retaddr); \
1845507c2bfSRichard Henderson     XDATA_TYPE cmp, old, new, val = xval;                           \
1854e6b1384SRichard Henderson     uint16_t info = trace_mem_build_info(SHIFT, false, 0, false,    \
186cfec3885SEmilio G. Cota                                          ATOMIC_MMU_IDX);           \
187cfec3885SEmilio G. Cota     atomic_trace_rmw_pre(env, addr, info);                          \
1885507c2bfSRichard Henderson     smp_mb();                                                       \
189d73415a3SStefan Hajnoczi     cmp = qatomic_read__nocheck(haddr);                             \
1905507c2bfSRichard Henderson     do {                                                            \
1915507c2bfSRichard Henderson         old = cmp; new = FN(old, val);                              \
192d73415a3SStefan Hajnoczi         cmp = qatomic_cmpxchg__nocheck(haddr, old, new);            \
1935507c2bfSRichard Henderson     } while (cmp != old);                                           \
1945507c2bfSRichard Henderson     ATOMIC_MMU_CLEANUP;                                             \
195cfec3885SEmilio G. Cota     atomic_trace_rmw_post(env, addr, info);                         \
1965507c2bfSRichard Henderson     return RET;                                                     \
1975507c2bfSRichard Henderson }
1985507c2bfSRichard Henderson 
1995507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_smin, MIN, SDATA_TYPE, old)
2005507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_umin, MIN,  DATA_TYPE, old)
2015507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_smax, MAX, SDATA_TYPE, old)
2025507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_umax, MAX,  DATA_TYPE, old)
2035507c2bfSRichard Henderson 
2045507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(smin_fetch, MIN, SDATA_TYPE, new)
2055507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(umin_fetch, MIN,  DATA_TYPE, new)
2065507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(smax_fetch, MAX, SDATA_TYPE, new)
2075507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(umax_fetch, MAX,  DATA_TYPE, new)
2085507c2bfSRichard Henderson 
2095507c2bfSRichard Henderson #undef GEN_ATOMIC_HELPER_FN
2107ebee43eSRichard Henderson #endif /* DATA SIZE >= 16 */
2117ebee43eSRichard Henderson 
212c482cb11SRichard Henderson #undef END
213c482cb11SRichard Henderson 
214c482cb11SRichard Henderson #if DATA_SIZE > 1
215c482cb11SRichard Henderson 
216c482cb11SRichard Henderson /* Define reverse-host-endian atomic operations.  Note that END is used
217c482cb11SRichard Henderson    within the ATOMIC_NAME macro.  */
218c482cb11SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN
219c482cb11SRichard Henderson # define END  _le
220c482cb11SRichard Henderson #else
221c482cb11SRichard Henderson # define END  _be
222c482cb11SRichard Henderson #endif
223c482cb11SRichard Henderson 
224c482cb11SRichard Henderson ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr,
22548688fafSRichard Henderson                               ABI_TYPE cmpv, ABI_TYPE newv,
22648688fafSRichard Henderson                               TCGMemOpIdx oi, uintptr_t retaddr)
227c482cb11SRichard Henderson {
228*a754f7f3SRichard Henderson     DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,
229*a754f7f3SRichard Henderson                                          PAGE_READ | PAGE_WRITE, retaddr);
230d071f4cdSEmilio G. Cota     DATA_TYPE ret;
2314e6b1384SRichard Henderson     uint16_t info = trace_mem_build_info(SHIFT, false, MO_BSWAP, false,
232cfec3885SEmilio G. Cota                                          ATOMIC_MMU_IDX);
233d071f4cdSEmilio G. Cota 
234cfec3885SEmilio G. Cota     atomic_trace_rmw_pre(env, addr, info);
235e6cd4bb5SRichard Henderson #if DATA_SIZE == 16
236e6cd4bb5SRichard Henderson     ret = atomic16_cmpxchg(haddr, BSWAP(cmpv), BSWAP(newv));
237e6cd4bb5SRichard Henderson #else
238d73415a3SStefan Hajnoczi     ret = qatomic_cmpxchg__nocheck(haddr, BSWAP(cmpv), BSWAP(newv));
239e6cd4bb5SRichard Henderson #endif
240ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
241cfec3885SEmilio G. Cota     atomic_trace_rmw_post(env, addr, info);
242ec603b55SRichard Henderson     return BSWAP(ret);
243c482cb11SRichard Henderson }
244c482cb11SRichard Henderson 
2457ebee43eSRichard Henderson #if DATA_SIZE >= 16
246e6cd4bb5SRichard Henderson #if HAVE_ATOMIC128
24748688fafSRichard Henderson ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr,
24848688fafSRichard Henderson                          TCGMemOpIdx oi, uintptr_t retaddr)
2497ebee43eSRichard Henderson {
250*a754f7f3SRichard Henderson     DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,
251*a754f7f3SRichard Henderson                                          PAGE_READ, retaddr);
252*a754f7f3SRichard Henderson     DATA_TYPE val;
2534e6b1384SRichard Henderson     uint16_t info = trace_mem_build_info(SHIFT, false, MO_BSWAP, false,
254cfec3885SEmilio G. Cota                                          ATOMIC_MMU_IDX);
255d071f4cdSEmilio G. Cota 
256cfec3885SEmilio G. Cota     atomic_trace_ld_pre(env, addr, info);
257e6cd4bb5SRichard Henderson     val = atomic16_read(haddr);
258ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
259cfec3885SEmilio G. Cota     atomic_trace_ld_post(env, addr, info);
2607ebee43eSRichard Henderson     return BSWAP(val);
2617ebee43eSRichard Henderson }
2627ebee43eSRichard Henderson 
26348688fafSRichard Henderson void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr, ABI_TYPE val,
26448688fafSRichard Henderson                      TCGMemOpIdx oi, uintptr_t retaddr)
2657ebee43eSRichard Henderson {
266*a754f7f3SRichard Henderson     DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,
267*a754f7f3SRichard Henderson                                          PAGE_WRITE, retaddr);
2684e6b1384SRichard Henderson     uint16_t info = trace_mem_build_info(SHIFT, false, MO_BSWAP, true,
269cfec3885SEmilio G. Cota                                          ATOMIC_MMU_IDX);
270d071f4cdSEmilio G. Cota 
271cfec3885SEmilio G. Cota     val = BSWAP(val);
272cfec3885SEmilio G. Cota     atomic_trace_st_pre(env, addr, info);
2737ebee43eSRichard Henderson     val = BSWAP(val);
274e6cd4bb5SRichard Henderson     atomic16_set(haddr, val);
275ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
276cfec3885SEmilio G. Cota     atomic_trace_st_post(env, addr, info);
2777ebee43eSRichard Henderson }
278e6cd4bb5SRichard Henderson #endif
2797ebee43eSRichard Henderson #else
28048688fafSRichard Henderson ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr, ABI_TYPE val,
28148688fafSRichard Henderson                            TCGMemOpIdx oi, uintptr_t retaddr)
282c482cb11SRichard Henderson {
283*a754f7f3SRichard Henderson     DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,
284*a754f7f3SRichard Henderson                                          PAGE_READ | PAGE_WRITE, retaddr);
285d071f4cdSEmilio G. Cota     ABI_TYPE ret;
2864e6b1384SRichard Henderson     uint16_t info = trace_mem_build_info(SHIFT, false, MO_BSWAP, false,
287cfec3885SEmilio G. Cota                                          ATOMIC_MMU_IDX);
288d071f4cdSEmilio G. Cota 
289cfec3885SEmilio G. Cota     atomic_trace_rmw_pre(env, addr, info);
290d73415a3SStefan Hajnoczi     ret = qatomic_xchg__nocheck(haddr, BSWAP(val));
291ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
292cfec3885SEmilio G. Cota     atomic_trace_rmw_post(env, addr, info);
293ec603b55SRichard Henderson     return BSWAP(ret);
294c482cb11SRichard Henderson }
295c482cb11SRichard Henderson 
296c482cb11SRichard Henderson #define GEN_ATOMIC_HELPER(X)                                        \
297c482cb11SRichard Henderson ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr,       \
29848688fafSRichard Henderson                         ABI_TYPE val, TCGMemOpIdx oi, uintptr_t retaddr) \
299c482cb11SRichard Henderson {                                                                   \
300*a754f7f3SRichard Henderson     DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,  \
301*a754f7f3SRichard Henderson                                          PAGE_READ | PAGE_WRITE, retaddr); \
302d071f4cdSEmilio G. Cota     DATA_TYPE ret;                                                  \
3034e6b1384SRichard Henderson     uint16_t info = trace_mem_build_info(SHIFT, false, MO_BSWAP,    \
3044e6b1384SRichard Henderson                                          false, ATOMIC_MMU_IDX);    \
305cfec3885SEmilio G. Cota     atomic_trace_rmw_pre(env, addr, info);                          \
306d73415a3SStefan Hajnoczi     ret = qatomic_##X(haddr, BSWAP(val));                           \
307ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;                                             \
308cfec3885SEmilio G. Cota     atomic_trace_rmw_post(env, addr, info);                         \
309ec603b55SRichard Henderson     return BSWAP(ret);                                              \
310c482cb11SRichard Henderson }
311c482cb11SRichard Henderson 
312c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_and)
313c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_or)
314c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_xor)
315c482cb11SRichard Henderson GEN_ATOMIC_HELPER(and_fetch)
316c482cb11SRichard Henderson GEN_ATOMIC_HELPER(or_fetch)
317c482cb11SRichard Henderson GEN_ATOMIC_HELPER(xor_fetch)
318c482cb11SRichard Henderson 
319c482cb11SRichard Henderson #undef GEN_ATOMIC_HELPER
320c482cb11SRichard Henderson 
3215507c2bfSRichard Henderson /* These helpers are, as a whole, full barriers.  Within the helper,
3225507c2bfSRichard Henderson  * the leading barrier is explicit and the trailing barrier is within
3235507c2bfSRichard Henderson  * cmpxchg primitive.
324d071f4cdSEmilio G. Cota  *
325d071f4cdSEmilio G. Cota  * Trace this load + RMW loop as a single RMW op. This way, regardless
326d071f4cdSEmilio G. Cota  * of CF_PARALLEL's value, we'll trace just a read and a write.
3275507c2bfSRichard Henderson  */
3285507c2bfSRichard Henderson #define GEN_ATOMIC_HELPER_FN(X, FN, XDATA_TYPE, RET)                \
3295507c2bfSRichard Henderson ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr,       \
33048688fafSRichard Henderson                         ABI_TYPE xval, TCGMemOpIdx oi, uintptr_t retaddr) \
3315507c2bfSRichard Henderson {                                                                   \
332*a754f7f3SRichard Henderson     XDATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, \
333*a754f7f3SRichard Henderson                                           PAGE_READ | PAGE_WRITE, retaddr); \
3345507c2bfSRichard Henderson     XDATA_TYPE ldo, ldn, old, new, val = xval;                      \
3354e6b1384SRichard Henderson     uint16_t info = trace_mem_build_info(SHIFT, false, MO_BSWAP,    \
3364e6b1384SRichard Henderson                                          false, ATOMIC_MMU_IDX);    \
337cfec3885SEmilio G. Cota     atomic_trace_rmw_pre(env, addr, info);                          \
3385507c2bfSRichard Henderson     smp_mb();                                                       \
339d73415a3SStefan Hajnoczi     ldn = qatomic_read__nocheck(haddr);                             \
3405507c2bfSRichard Henderson     do {                                                            \
3415507c2bfSRichard Henderson         ldo = ldn; old = BSWAP(ldo); new = FN(old, val);            \
342d73415a3SStefan Hajnoczi         ldn = qatomic_cmpxchg__nocheck(haddr, ldo, BSWAP(new));     \
3435507c2bfSRichard Henderson     } while (ldo != ldn);                                           \
3445507c2bfSRichard Henderson     ATOMIC_MMU_CLEANUP;                                             \
345cfec3885SEmilio G. Cota     atomic_trace_rmw_post(env, addr, info);                         \
3465507c2bfSRichard Henderson     return RET;                                                     \
3475507c2bfSRichard Henderson }
3485507c2bfSRichard Henderson 
3495507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_smin, MIN, SDATA_TYPE, old)
3505507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_umin, MIN,  DATA_TYPE, old)
3515507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_smax, MAX, SDATA_TYPE, old)
3525507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_umax, MAX,  DATA_TYPE, old)
3535507c2bfSRichard Henderson 
3545507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(smin_fetch, MIN, SDATA_TYPE, new)
3555507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(umin_fetch, MIN,  DATA_TYPE, new)
3565507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(smax_fetch, MAX, SDATA_TYPE, new)
3575507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(umax_fetch, MAX,  DATA_TYPE, new)
3585507c2bfSRichard Henderson 
35958edf9eeSRichard Henderson /* Note that for addition, we need to use a separate cmpxchg loop instead
36058edf9eeSRichard Henderson    of bswaps for the reverse-host-endian helpers.  */
36158edf9eeSRichard Henderson #define ADD(X, Y)   (X + Y)
36258edf9eeSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_add, ADD, DATA_TYPE, old)
36358edf9eeSRichard Henderson GEN_ATOMIC_HELPER_FN(add_fetch, ADD, DATA_TYPE, new)
36458edf9eeSRichard Henderson #undef ADD
36558edf9eeSRichard Henderson 
3665507c2bfSRichard Henderson #undef GEN_ATOMIC_HELPER_FN
3677ebee43eSRichard Henderson #endif /* DATA_SIZE >= 16 */
368c482cb11SRichard Henderson 
369c482cb11SRichard Henderson #undef END
370c482cb11SRichard Henderson #endif /* DATA_SIZE > 1 */
371c482cb11SRichard Henderson 
372c482cb11SRichard Henderson #undef BSWAP
373c482cb11SRichard Henderson #undef ABI_TYPE
374c482cb11SRichard Henderson #undef DATA_TYPE
3755507c2bfSRichard Henderson #undef SDATA_TYPE
376c482cb11SRichard Henderson #undef SUFFIX
377c482cb11SRichard Henderson #undef DATA_SIZE
378d071f4cdSEmilio G. Cota #undef SHIFT
379