xref: /openbmc/qemu/accel/tcg/atomic_template.h (revision c3e83e376cf028fade97072d86f33e4a92ddf9a2)
110f7d4d5SPhilippe Mathieu-Daudé /*
210f7d4d5SPhilippe Mathieu-Daudé  * Atomic helper templates
310f7d4d5SPhilippe Mathieu-Daudé  * Included from tcg-runtime.c and cputlb.c.
410f7d4d5SPhilippe Mathieu-Daudé  *
510f7d4d5SPhilippe Mathieu-Daudé  * Copyright (c) 2016 Red Hat, Inc
610f7d4d5SPhilippe Mathieu-Daudé  *
710f7d4d5SPhilippe Mathieu-Daudé  * This library is free software; you can redistribute it and/or
810f7d4d5SPhilippe Mathieu-Daudé  * modify it under the terms of the GNU Lesser General Public
910f7d4d5SPhilippe Mathieu-Daudé  * License as published by the Free Software Foundation; either
10fb0343d5SThomas Huth  * version 2.1 of the License, or (at your option) any later version.
1110f7d4d5SPhilippe Mathieu-Daudé  *
1210f7d4d5SPhilippe Mathieu-Daudé  * This library is distributed in the hope that it will be useful,
1310f7d4d5SPhilippe Mathieu-Daudé  * but WITHOUT ANY WARRANTY; without even the implied warranty of
1410f7d4d5SPhilippe Mathieu-Daudé  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1510f7d4d5SPhilippe Mathieu-Daudé  * Lesser General Public License for more details.
1610f7d4d5SPhilippe Mathieu-Daudé  *
1710f7d4d5SPhilippe Mathieu-Daudé  * You should have received a copy of the GNU Lesser General Public
1810f7d4d5SPhilippe Mathieu-Daudé  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
1910f7d4d5SPhilippe Mathieu-Daudé  */
2010f7d4d5SPhilippe Mathieu-Daudé 
21e6d86bedSEmilio G. Cota #include "qemu/plugin.h"
22d071f4cdSEmilio G. Cota #include "trace/mem.h"
23d071f4cdSEmilio G. Cota 
2410f7d4d5SPhilippe Mathieu-Daudé #if DATA_SIZE == 16
2510f7d4d5SPhilippe Mathieu-Daudé # define SUFFIX     o
2610f7d4d5SPhilippe Mathieu-Daudé # define DATA_TYPE  Int128
2710f7d4d5SPhilippe Mathieu-Daudé # define BSWAP      bswap128
28d071f4cdSEmilio G. Cota # define SHIFT      4
2910f7d4d5SPhilippe Mathieu-Daudé #elif DATA_SIZE == 8
3010f7d4d5SPhilippe Mathieu-Daudé # define SUFFIX     q
319ef0c6d6SRichard Henderson # define DATA_TYPE  aligned_uint64_t
329ef0c6d6SRichard Henderson # define SDATA_TYPE aligned_int64_t
3310f7d4d5SPhilippe Mathieu-Daudé # define BSWAP      bswap64
34d071f4cdSEmilio G. Cota # define SHIFT      3
3510f7d4d5SPhilippe Mathieu-Daudé #elif DATA_SIZE == 4
3610f7d4d5SPhilippe Mathieu-Daudé # define SUFFIX     l
3710f7d4d5SPhilippe Mathieu-Daudé # define DATA_TYPE  uint32_t
385507c2bfSRichard Henderson # define SDATA_TYPE int32_t
3910f7d4d5SPhilippe Mathieu-Daudé # define BSWAP      bswap32
40d071f4cdSEmilio G. Cota # define SHIFT      2
4110f7d4d5SPhilippe Mathieu-Daudé #elif DATA_SIZE == 2
4210f7d4d5SPhilippe Mathieu-Daudé # define SUFFIX     w
4310f7d4d5SPhilippe Mathieu-Daudé # define DATA_TYPE  uint16_t
445507c2bfSRichard Henderson # define SDATA_TYPE int16_t
4510f7d4d5SPhilippe Mathieu-Daudé # define BSWAP      bswap16
46d071f4cdSEmilio G. Cota # define SHIFT      1
4710f7d4d5SPhilippe Mathieu-Daudé #elif DATA_SIZE == 1
4810f7d4d5SPhilippe Mathieu-Daudé # define SUFFIX     b
4910f7d4d5SPhilippe Mathieu-Daudé # define DATA_TYPE  uint8_t
505507c2bfSRichard Henderson # define SDATA_TYPE int8_t
5110f7d4d5SPhilippe Mathieu-Daudé # define BSWAP
52d071f4cdSEmilio G. Cota # define SHIFT      0
5310f7d4d5SPhilippe Mathieu-Daudé #else
5410f7d4d5SPhilippe Mathieu-Daudé # error unsupported data size
5510f7d4d5SPhilippe Mathieu-Daudé #endif
5610f7d4d5SPhilippe Mathieu-Daudé 
5710f7d4d5SPhilippe Mathieu-Daudé #if DATA_SIZE >= 4
5810f7d4d5SPhilippe Mathieu-Daudé # define ABI_TYPE  DATA_TYPE
5910f7d4d5SPhilippe Mathieu-Daudé #else
6010f7d4d5SPhilippe Mathieu-Daudé # define ABI_TYPE  uint32_t
6110f7d4d5SPhilippe Mathieu-Daudé #endif
6210f7d4d5SPhilippe Mathieu-Daudé 
6310f7d4d5SPhilippe Mathieu-Daudé /* Define host-endian atomic operations.  Note that END is used within
6410f7d4d5SPhilippe Mathieu-Daudé    the ATOMIC_NAME macro, and redefined below.  */
6510f7d4d5SPhilippe Mathieu-Daudé #if DATA_SIZE == 1
6610f7d4d5SPhilippe Mathieu-Daudé # define END
6710f7d4d5SPhilippe Mathieu-Daudé #elif defined(HOST_WORDS_BIGENDIAN)
6810f7d4d5SPhilippe Mathieu-Daudé # define END  _be
6910f7d4d5SPhilippe Mathieu-Daudé #else
7010f7d4d5SPhilippe Mathieu-Daudé # define END  _le
7110f7d4d5SPhilippe Mathieu-Daudé #endif
7210f7d4d5SPhilippe Mathieu-Daudé 
7310f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr,
7448688fafSRichard Henderson                               ABI_TYPE cmpv, ABI_TYPE newv,
759002ffcbSRichard Henderson                               MemOpIdx oi, uintptr_t retaddr)
7610f7d4d5SPhilippe Mathieu-Daudé {
77a754f7f3SRichard Henderson     DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,
78a754f7f3SRichard Henderson                                          PAGE_READ | PAGE_WRITE, retaddr);
79d071f4cdSEmilio G. Cota     DATA_TYPE ret;
80d071f4cdSEmilio G. Cota 
81*c3e83e37SRichard Henderson     atomic_trace_rmw_pre(env, addr, oi);
82e6cd4bb5SRichard Henderson #if DATA_SIZE == 16
83e6cd4bb5SRichard Henderson     ret = atomic16_cmpxchg(haddr, cmpv, newv);
84e6cd4bb5SRichard Henderson #else
85d73415a3SStefan Hajnoczi     ret = qatomic_cmpxchg__nocheck(haddr, cmpv, newv);
86e6cd4bb5SRichard Henderson #endif
87ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
88*c3e83e37SRichard Henderson     atomic_trace_rmw_post(env, addr, oi);
89ec603b55SRichard Henderson     return ret;
9010f7d4d5SPhilippe Mathieu-Daudé }
9110f7d4d5SPhilippe Mathieu-Daudé 
9210f7d4d5SPhilippe Mathieu-Daudé #if DATA_SIZE >= 16
93e6cd4bb5SRichard Henderson #if HAVE_ATOMIC128
9448688fafSRichard Henderson ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr,
959002ffcbSRichard Henderson                          MemOpIdx oi, uintptr_t retaddr)
9610f7d4d5SPhilippe Mathieu-Daudé {
97a754f7f3SRichard Henderson     DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,
98a754f7f3SRichard Henderson                                          PAGE_READ, retaddr);
99a754f7f3SRichard Henderson     DATA_TYPE val;
100d071f4cdSEmilio G. Cota 
101*c3e83e37SRichard Henderson     atomic_trace_ld_pre(env, addr, oi);
102e6cd4bb5SRichard Henderson     val = atomic16_read(haddr);
103ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
104*c3e83e37SRichard Henderson     atomic_trace_ld_post(env, addr, oi);
10510f7d4d5SPhilippe Mathieu-Daudé     return val;
10610f7d4d5SPhilippe Mathieu-Daudé }
10710f7d4d5SPhilippe Mathieu-Daudé 
10848688fafSRichard Henderson void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr, ABI_TYPE val,
1099002ffcbSRichard Henderson                      MemOpIdx oi, uintptr_t retaddr)
11010f7d4d5SPhilippe Mathieu-Daudé {
111a754f7f3SRichard Henderson     DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,
112a754f7f3SRichard Henderson                                          PAGE_WRITE, retaddr);
113d071f4cdSEmilio G. Cota 
114*c3e83e37SRichard Henderson     atomic_trace_st_pre(env, addr, oi);
115e6cd4bb5SRichard Henderson     atomic16_set(haddr, val);
116ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
117*c3e83e37SRichard Henderson     atomic_trace_st_post(env, addr, oi);
11810f7d4d5SPhilippe Mathieu-Daudé }
119e6cd4bb5SRichard Henderson #endif
12010f7d4d5SPhilippe Mathieu-Daudé #else
12148688fafSRichard Henderson ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr, ABI_TYPE val,
1229002ffcbSRichard Henderson                            MemOpIdx oi, uintptr_t retaddr)
12310f7d4d5SPhilippe Mathieu-Daudé {
124a754f7f3SRichard Henderson     DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,
125a754f7f3SRichard Henderson                                          PAGE_READ | PAGE_WRITE, retaddr);
126d071f4cdSEmilio G. Cota     DATA_TYPE ret;
127d071f4cdSEmilio G. Cota 
128*c3e83e37SRichard Henderson     atomic_trace_rmw_pre(env, addr, oi);
129d73415a3SStefan Hajnoczi     ret = qatomic_xchg__nocheck(haddr, val);
130ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
131*c3e83e37SRichard Henderson     atomic_trace_rmw_post(env, addr, oi);
132ec603b55SRichard Henderson     return ret;
13310f7d4d5SPhilippe Mathieu-Daudé }
13410f7d4d5SPhilippe Mathieu-Daudé 
13510f7d4d5SPhilippe Mathieu-Daudé #define GEN_ATOMIC_HELPER(X)                                        \
13610f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr,       \
1379002ffcbSRichard Henderson                         ABI_TYPE val, MemOpIdx oi, uintptr_t retaddr) \
13810f7d4d5SPhilippe Mathieu-Daudé {                                                                   \
139a754f7f3SRichard Henderson     DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,  \
140a754f7f3SRichard Henderson                                          PAGE_READ | PAGE_WRITE, retaddr); \
141d071f4cdSEmilio G. Cota     DATA_TYPE ret;                                                  \
142*c3e83e37SRichard Henderson     atomic_trace_rmw_pre(env, addr, oi);                            \
143d73415a3SStefan Hajnoczi     ret = qatomic_##X(haddr, val);                                  \
144ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;                                             \
145*c3e83e37SRichard Henderson     atomic_trace_rmw_post(env, addr, oi);                           \
146ec603b55SRichard Henderson     return ret;                                                     \
147ec603b55SRichard Henderson }
14810f7d4d5SPhilippe Mathieu-Daudé 
14910f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_add)
15010f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_and)
15110f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_or)
15210f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_xor)
15310f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(add_fetch)
15410f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(and_fetch)
15510f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(or_fetch)
15610f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(xor_fetch)
15710f7d4d5SPhilippe Mathieu-Daudé 
15810f7d4d5SPhilippe Mathieu-Daudé #undef GEN_ATOMIC_HELPER
1595507c2bfSRichard Henderson 
160a754f7f3SRichard Henderson /*
161a754f7f3SRichard Henderson  * These helpers are, as a whole, full barriers.  Within the helper,
1625507c2bfSRichard Henderson  * the leading barrier is explicit and the trailing barrier is within
1635507c2bfSRichard Henderson  * cmpxchg primitive.
164d071f4cdSEmilio G. Cota  *
165d071f4cdSEmilio G. Cota  * Trace this load + RMW loop as a single RMW op. This way, regardless
166d071f4cdSEmilio G. Cota  * of CF_PARALLEL's value, we'll trace just a read and a write.
1675507c2bfSRichard Henderson  */
1685507c2bfSRichard Henderson #define GEN_ATOMIC_HELPER_FN(X, FN, XDATA_TYPE, RET)                \
1695507c2bfSRichard Henderson ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr,       \
1709002ffcbSRichard Henderson                         ABI_TYPE xval, MemOpIdx oi, uintptr_t retaddr) \
1715507c2bfSRichard Henderson {                                                                   \
172a754f7f3SRichard Henderson     XDATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, \
173a754f7f3SRichard Henderson                                           PAGE_READ | PAGE_WRITE, retaddr); \
1745507c2bfSRichard Henderson     XDATA_TYPE cmp, old, new, val = xval;                           \
175*c3e83e37SRichard Henderson     atomic_trace_rmw_pre(env, addr, oi);                            \
1765507c2bfSRichard Henderson     smp_mb();                                                       \
177d73415a3SStefan Hajnoczi     cmp = qatomic_read__nocheck(haddr);                             \
1785507c2bfSRichard Henderson     do {                                                            \
1795507c2bfSRichard Henderson         old = cmp; new = FN(old, val);                              \
180d73415a3SStefan Hajnoczi         cmp = qatomic_cmpxchg__nocheck(haddr, old, new);            \
1815507c2bfSRichard Henderson     } while (cmp != old);                                           \
1825507c2bfSRichard Henderson     ATOMIC_MMU_CLEANUP;                                             \
183*c3e83e37SRichard Henderson     atomic_trace_rmw_post(env, addr, oi);                           \
1845507c2bfSRichard Henderson     return RET;                                                     \
1855507c2bfSRichard Henderson }
1865507c2bfSRichard Henderson 
1875507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_smin, MIN, SDATA_TYPE, old)
1885507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_umin, MIN,  DATA_TYPE, old)
1895507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_smax, MAX, SDATA_TYPE, old)
1905507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_umax, MAX,  DATA_TYPE, old)
1915507c2bfSRichard Henderson 
1925507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(smin_fetch, MIN, SDATA_TYPE, new)
1935507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(umin_fetch, MIN,  DATA_TYPE, new)
1945507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(smax_fetch, MAX, SDATA_TYPE, new)
1955507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(umax_fetch, MAX,  DATA_TYPE, new)
1965507c2bfSRichard Henderson 
1975507c2bfSRichard Henderson #undef GEN_ATOMIC_HELPER_FN
19810f7d4d5SPhilippe Mathieu-Daudé #endif /* DATA SIZE >= 16 */
19910f7d4d5SPhilippe Mathieu-Daudé 
20010f7d4d5SPhilippe Mathieu-Daudé #undef END
20110f7d4d5SPhilippe Mathieu-Daudé 
20210f7d4d5SPhilippe Mathieu-Daudé #if DATA_SIZE > 1
20310f7d4d5SPhilippe Mathieu-Daudé 
20410f7d4d5SPhilippe Mathieu-Daudé /* Define reverse-host-endian atomic operations.  Note that END is used
20510f7d4d5SPhilippe Mathieu-Daudé    within the ATOMIC_NAME macro.  */
20610f7d4d5SPhilippe Mathieu-Daudé #ifdef HOST_WORDS_BIGENDIAN
20710f7d4d5SPhilippe Mathieu-Daudé # define END  _le
20810f7d4d5SPhilippe Mathieu-Daudé #else
20910f7d4d5SPhilippe Mathieu-Daudé # define END  _be
21010f7d4d5SPhilippe Mathieu-Daudé #endif
21110f7d4d5SPhilippe Mathieu-Daudé 
21210f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr,
21348688fafSRichard Henderson                               ABI_TYPE cmpv, ABI_TYPE newv,
2149002ffcbSRichard Henderson                               MemOpIdx oi, uintptr_t retaddr)
21510f7d4d5SPhilippe Mathieu-Daudé {
216a754f7f3SRichard Henderson     DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,
217a754f7f3SRichard Henderson                                          PAGE_READ | PAGE_WRITE, retaddr);
218d071f4cdSEmilio G. Cota     DATA_TYPE ret;
219d071f4cdSEmilio G. Cota 
220*c3e83e37SRichard Henderson     atomic_trace_rmw_pre(env, addr, oi);
221e6cd4bb5SRichard Henderson #if DATA_SIZE == 16
222e6cd4bb5SRichard Henderson     ret = atomic16_cmpxchg(haddr, BSWAP(cmpv), BSWAP(newv));
223e6cd4bb5SRichard Henderson #else
224d73415a3SStefan Hajnoczi     ret = qatomic_cmpxchg__nocheck(haddr, BSWAP(cmpv), BSWAP(newv));
225e6cd4bb5SRichard Henderson #endif
226ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
227*c3e83e37SRichard Henderson     atomic_trace_rmw_post(env, addr, oi);
228ec603b55SRichard Henderson     return BSWAP(ret);
22910f7d4d5SPhilippe Mathieu-Daudé }
23010f7d4d5SPhilippe Mathieu-Daudé 
23110f7d4d5SPhilippe Mathieu-Daudé #if DATA_SIZE >= 16
232e6cd4bb5SRichard Henderson #if HAVE_ATOMIC128
23348688fafSRichard Henderson ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr,
2349002ffcbSRichard Henderson                          MemOpIdx oi, uintptr_t retaddr)
23510f7d4d5SPhilippe Mathieu-Daudé {
236a754f7f3SRichard Henderson     DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,
237a754f7f3SRichard Henderson                                          PAGE_READ, retaddr);
238a754f7f3SRichard Henderson     DATA_TYPE val;
239d071f4cdSEmilio G. Cota 
240*c3e83e37SRichard Henderson     atomic_trace_ld_pre(env, addr, oi);
241e6cd4bb5SRichard Henderson     val = atomic16_read(haddr);
242ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
243*c3e83e37SRichard Henderson     atomic_trace_ld_post(env, addr, oi);
24410f7d4d5SPhilippe Mathieu-Daudé     return BSWAP(val);
24510f7d4d5SPhilippe Mathieu-Daudé }
24610f7d4d5SPhilippe Mathieu-Daudé 
24748688fafSRichard Henderson void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr, ABI_TYPE val,
2489002ffcbSRichard Henderson                      MemOpIdx oi, uintptr_t retaddr)
24910f7d4d5SPhilippe Mathieu-Daudé {
250a754f7f3SRichard Henderson     DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,
251a754f7f3SRichard Henderson                                          PAGE_WRITE, retaddr);
252d071f4cdSEmilio G. Cota 
253*c3e83e37SRichard Henderson     atomic_trace_st_pre(env, addr, oi);
254cfec3885SEmilio G. Cota     val = BSWAP(val);
255e6cd4bb5SRichard Henderson     atomic16_set(haddr, val);
256ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
257*c3e83e37SRichard Henderson     atomic_trace_st_post(env, addr, oi);
25810f7d4d5SPhilippe Mathieu-Daudé }
259e6cd4bb5SRichard Henderson #endif
26010f7d4d5SPhilippe Mathieu-Daudé #else
26148688fafSRichard Henderson ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr, ABI_TYPE val,
2629002ffcbSRichard Henderson                            MemOpIdx oi, uintptr_t retaddr)
26310f7d4d5SPhilippe Mathieu-Daudé {
264a754f7f3SRichard Henderson     DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,
265a754f7f3SRichard Henderson                                          PAGE_READ | PAGE_WRITE, retaddr);
266d071f4cdSEmilio G. Cota     ABI_TYPE ret;
267d071f4cdSEmilio G. Cota 
268*c3e83e37SRichard Henderson     atomic_trace_rmw_pre(env, addr, oi);
269d73415a3SStefan Hajnoczi     ret = qatomic_xchg__nocheck(haddr, BSWAP(val));
270ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
271*c3e83e37SRichard Henderson     atomic_trace_rmw_post(env, addr, oi);
272ec603b55SRichard Henderson     return BSWAP(ret);
27310f7d4d5SPhilippe Mathieu-Daudé }
27410f7d4d5SPhilippe Mathieu-Daudé 
27510f7d4d5SPhilippe Mathieu-Daudé #define GEN_ATOMIC_HELPER(X)                                        \
27610f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr,       \
2779002ffcbSRichard Henderson                         ABI_TYPE val, MemOpIdx oi, uintptr_t retaddr) \
27810f7d4d5SPhilippe Mathieu-Daudé {                                                                   \
279a754f7f3SRichard Henderson     DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,  \
280a754f7f3SRichard Henderson                                          PAGE_READ | PAGE_WRITE, retaddr); \
281d071f4cdSEmilio G. Cota     DATA_TYPE ret;                                                  \
282*c3e83e37SRichard Henderson     atomic_trace_rmw_pre(env, addr, oi);                            \
283d73415a3SStefan Hajnoczi     ret = qatomic_##X(haddr, BSWAP(val));                           \
284ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;                                             \
285*c3e83e37SRichard Henderson     atomic_trace_rmw_post(env, addr, oi);                           \
286ec603b55SRichard Henderson     return BSWAP(ret);                                              \
28710f7d4d5SPhilippe Mathieu-Daudé }
28810f7d4d5SPhilippe Mathieu-Daudé 
28910f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_and)
29010f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_or)
29110f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_xor)
29210f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(and_fetch)
29310f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(or_fetch)
29410f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(xor_fetch)
29510f7d4d5SPhilippe Mathieu-Daudé 
29610f7d4d5SPhilippe Mathieu-Daudé #undef GEN_ATOMIC_HELPER
29710f7d4d5SPhilippe Mathieu-Daudé 
2985507c2bfSRichard Henderson /* These helpers are, as a whole, full barriers.  Within the helper,
2995507c2bfSRichard Henderson  * the leading barrier is explicit and the trailing barrier is within
3005507c2bfSRichard Henderson  * cmpxchg primitive.
301d071f4cdSEmilio G. Cota  *
302d071f4cdSEmilio G. Cota  * Trace this load + RMW loop as a single RMW op. This way, regardless
303d071f4cdSEmilio G. Cota  * of CF_PARALLEL's value, we'll trace just a read and a write.
3045507c2bfSRichard Henderson  */
3055507c2bfSRichard Henderson #define GEN_ATOMIC_HELPER_FN(X, FN, XDATA_TYPE, RET)                \
3065507c2bfSRichard Henderson ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr,       \
3079002ffcbSRichard Henderson                         ABI_TYPE xval, MemOpIdx oi, uintptr_t retaddr) \
3085507c2bfSRichard Henderson {                                                                   \
309a754f7f3SRichard Henderson     XDATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, \
310a754f7f3SRichard Henderson                                           PAGE_READ | PAGE_WRITE, retaddr); \
3115507c2bfSRichard Henderson     XDATA_TYPE ldo, ldn, old, new, val = xval;                      \
312*c3e83e37SRichard Henderson     atomic_trace_rmw_pre(env, addr, oi);                            \
3135507c2bfSRichard Henderson     smp_mb();                                                       \
314d73415a3SStefan Hajnoczi     ldn = qatomic_read__nocheck(haddr);                             \
3155507c2bfSRichard Henderson     do {                                                            \
3165507c2bfSRichard Henderson         ldo = ldn; old = BSWAP(ldo); new = FN(old, val);            \
317d73415a3SStefan Hajnoczi         ldn = qatomic_cmpxchg__nocheck(haddr, ldo, BSWAP(new));     \
3185507c2bfSRichard Henderson     } while (ldo != ldn);                                           \
3195507c2bfSRichard Henderson     ATOMIC_MMU_CLEANUP;                                             \
320*c3e83e37SRichard Henderson     atomic_trace_rmw_post(env, addr, oi);                           \
3215507c2bfSRichard Henderson     return RET;                                                     \
3225507c2bfSRichard Henderson }
3235507c2bfSRichard Henderson 
3245507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_smin, MIN, SDATA_TYPE, old)
3255507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_umin, MIN,  DATA_TYPE, old)
3265507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_smax, MAX, SDATA_TYPE, old)
3275507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_umax, MAX,  DATA_TYPE, old)
3285507c2bfSRichard Henderson 
3295507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(smin_fetch, MIN, SDATA_TYPE, new)
3305507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(umin_fetch, MIN,  DATA_TYPE, new)
3315507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(smax_fetch, MAX, SDATA_TYPE, new)
3325507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(umax_fetch, MAX,  DATA_TYPE, new)
3335507c2bfSRichard Henderson 
33458edf9eeSRichard Henderson /* Note that for addition, we need to use a separate cmpxchg loop instead
33558edf9eeSRichard Henderson    of bswaps for the reverse-host-endian helpers.  */
33658edf9eeSRichard Henderson #define ADD(X, Y)   (X + Y)
33758edf9eeSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_add, ADD, DATA_TYPE, old)
33858edf9eeSRichard Henderson GEN_ATOMIC_HELPER_FN(add_fetch, ADD, DATA_TYPE, new)
33958edf9eeSRichard Henderson #undef ADD
34058edf9eeSRichard Henderson 
3415507c2bfSRichard Henderson #undef GEN_ATOMIC_HELPER_FN
34210f7d4d5SPhilippe Mathieu-Daudé #endif /* DATA_SIZE >= 16 */
34310f7d4d5SPhilippe Mathieu-Daudé 
34410f7d4d5SPhilippe Mathieu-Daudé #undef END
34510f7d4d5SPhilippe Mathieu-Daudé #endif /* DATA_SIZE > 1 */
34610f7d4d5SPhilippe Mathieu-Daudé 
34710f7d4d5SPhilippe Mathieu-Daudé #undef BSWAP
34810f7d4d5SPhilippe Mathieu-Daudé #undef ABI_TYPE
34910f7d4d5SPhilippe Mathieu-Daudé #undef DATA_TYPE
3505507c2bfSRichard Henderson #undef SDATA_TYPE
35110f7d4d5SPhilippe Mathieu-Daudé #undef SUFFIX
35210f7d4d5SPhilippe Mathieu-Daudé #undef DATA_SIZE
353d071f4cdSEmilio G. Cota #undef SHIFT
354