xref: /openbmc/qemu/accel/tcg/atomic_template.h (revision a5dd9ee060b0ad65239889a62e93a33276055981)
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 
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
309ef0c6d6SRichard Henderson # define DATA_TYPE  aligned_uint64_t
319ef0c6d6SRichard Henderson # define SDATA_TYPE aligned_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é 
56*b709da5dSPierrick Bouvier #if DATA_SIZE == 16
57*b709da5dSPierrick Bouvier # define VALUE_LOW(val) int128_getlo(val)
58*b709da5dSPierrick Bouvier # define VALUE_HIGH(val) int128_gethi(val)
59*b709da5dSPierrick Bouvier #else
60*b709da5dSPierrick Bouvier # define VALUE_LOW(val) val
61*b709da5dSPierrick Bouvier # define VALUE_HIGH(val) 0
62*b709da5dSPierrick Bouvier #endif
63*b709da5dSPierrick Bouvier 
6410f7d4d5SPhilippe Mathieu-Daudé #if DATA_SIZE >= 4
6510f7d4d5SPhilippe Mathieu-Daudé # define ABI_TYPE  DATA_TYPE
6610f7d4d5SPhilippe Mathieu-Daudé #else
6710f7d4d5SPhilippe Mathieu-Daudé # define ABI_TYPE  uint32_t
6810f7d4d5SPhilippe Mathieu-Daudé #endif
6910f7d4d5SPhilippe Mathieu-Daudé 
7010f7d4d5SPhilippe Mathieu-Daudé /* Define host-endian atomic operations.  Note that END is used within
7110f7d4d5SPhilippe Mathieu-Daudé    the ATOMIC_NAME macro, and redefined below.  */
7210f7d4d5SPhilippe Mathieu-Daudé #if DATA_SIZE == 1
7310f7d4d5SPhilippe Mathieu-Daudé # define END
74e03b5686SMarc-André Lureau #elif HOST_BIG_ENDIAN
7510f7d4d5SPhilippe Mathieu-Daudé # define END  _be
7610f7d4d5SPhilippe Mathieu-Daudé #else
7710f7d4d5SPhilippe Mathieu-Daudé # define END  _le
7810f7d4d5SPhilippe Mathieu-Daudé #endif
7910f7d4d5SPhilippe Mathieu-Daudé 
ATOMIC_NAME(cmpxchg)80022b9bceSAnton Johansson ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, abi_ptr addr,
8148688fafSRichard Henderson                               ABI_TYPE cmpv, ABI_TYPE newv,
829002ffcbSRichard Henderson                               MemOpIdx oi, uintptr_t retaddr)
8310f7d4d5SPhilippe Mathieu-Daudé {
84d560225fSAnton Johansson     DATA_TYPE *haddr = atomic_mmu_lookup(env_cpu(env), addr, oi,
85d560225fSAnton Johansson                                          DATA_SIZE, retaddr);
86d071f4cdSEmilio G. Cota     DATA_TYPE ret;
87d071f4cdSEmilio G. Cota 
88e6cd4bb5SRichard Henderson #if DATA_SIZE == 16
89e6cd4bb5SRichard Henderson     ret = atomic16_cmpxchg(haddr, cmpv, newv);
90e6cd4bb5SRichard Henderson #else
91d73415a3SStefan Hajnoczi     ret = qatomic_cmpxchg__nocheck(haddr, cmpv, newv);
92e6cd4bb5SRichard Henderson #endif
93ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
94*b709da5dSPierrick Bouvier     atomic_trace_rmw_post(env, addr,
95*b709da5dSPierrick Bouvier                           VALUE_LOW(ret),
96*b709da5dSPierrick Bouvier                           VALUE_HIGH(ret),
97*b709da5dSPierrick Bouvier                           VALUE_LOW(newv),
98*b709da5dSPierrick Bouvier                           VALUE_HIGH(newv),
99*b709da5dSPierrick Bouvier                           oi);
100ec603b55SRichard Henderson     return ret;
10110f7d4d5SPhilippe Mathieu-Daudé }
10210f7d4d5SPhilippe Mathieu-Daudé 
103ec4a9629SRichard Henderson #if DATA_SIZE < 16
ATOMIC_NAME(xchg)104022b9bceSAnton Johansson ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, abi_ptr addr, ABI_TYPE val,
1059002ffcbSRichard Henderson                            MemOpIdx oi, uintptr_t retaddr)
10610f7d4d5SPhilippe Mathieu-Daudé {
107d560225fSAnton Johansson     DATA_TYPE *haddr = atomic_mmu_lookup(env_cpu(env), addr, oi,
108d560225fSAnton Johansson                                          DATA_SIZE, retaddr);
109d071f4cdSEmilio G. Cota     DATA_TYPE ret;
110d071f4cdSEmilio G. Cota 
111d73415a3SStefan Hajnoczi     ret = qatomic_xchg__nocheck(haddr, val);
112ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
113*b709da5dSPierrick Bouvier     atomic_trace_rmw_post(env, addr,
114*b709da5dSPierrick Bouvier                           VALUE_LOW(ret),
115*b709da5dSPierrick Bouvier                           VALUE_HIGH(ret),
116*b709da5dSPierrick Bouvier                           VALUE_LOW(val),
117*b709da5dSPierrick Bouvier                           VALUE_HIGH(val),
118*b709da5dSPierrick Bouvier                           oi);
119ec603b55SRichard Henderson     return ret;
12010f7d4d5SPhilippe Mathieu-Daudé }
12110f7d4d5SPhilippe Mathieu-Daudé 
12210f7d4d5SPhilippe Mathieu-Daudé #define GEN_ATOMIC_HELPER(X)                                        \
123022b9bceSAnton Johansson ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, abi_ptr addr,            \
1249002ffcbSRichard Henderson                         ABI_TYPE val, MemOpIdx oi, uintptr_t retaddr) \
12510f7d4d5SPhilippe Mathieu-Daudé {                                                                   \
1267bedee32SRichard Henderson     DATA_TYPE *haddr, ret;                                          \
127d560225fSAnton Johansson     haddr = atomic_mmu_lookup(env_cpu(env), addr, oi, DATA_SIZE, retaddr);   \
128d73415a3SStefan Hajnoczi     ret = qatomic_##X(haddr, val);                                  \
129ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;                                             \
130*b709da5dSPierrick Bouvier     atomic_trace_rmw_post(env, addr,                                \
131*b709da5dSPierrick Bouvier                           VALUE_LOW(ret),                           \
132*b709da5dSPierrick Bouvier                           VALUE_HIGH(ret),                          \
133*b709da5dSPierrick Bouvier                           VALUE_LOW(val),                           \
134*b709da5dSPierrick Bouvier                           VALUE_HIGH(val),                          \
135*b709da5dSPierrick Bouvier                           oi);                                      \
136ec603b55SRichard Henderson     return ret;                                                     \
137ec603b55SRichard Henderson }
13810f7d4d5SPhilippe Mathieu-Daudé 
13910f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_add)
GEN_ATOMIC_HELPER(fetch_and)14010f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_and)
14110f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_or)
14210f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_xor)
14310f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(add_fetch)
14410f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(and_fetch)
14510f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(or_fetch)
14610f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(xor_fetch)
14710f7d4d5SPhilippe Mathieu-Daudé 
14810f7d4d5SPhilippe Mathieu-Daudé #undef GEN_ATOMIC_HELPER
1495507c2bfSRichard Henderson 
150a754f7f3SRichard Henderson /*
151a754f7f3SRichard Henderson  * These helpers are, as a whole, full barriers.  Within the helper,
1525507c2bfSRichard Henderson  * the leading barrier is explicit and the trailing barrier is within
1535507c2bfSRichard Henderson  * cmpxchg primitive.
154d071f4cdSEmilio G. Cota  *
155d071f4cdSEmilio G. Cota  * Trace this load + RMW loop as a single RMW op. This way, regardless
156d071f4cdSEmilio G. Cota  * of CF_PARALLEL's value, we'll trace just a read and a write.
1575507c2bfSRichard Henderson  */
1585507c2bfSRichard Henderson #define GEN_ATOMIC_HELPER_FN(X, FN, XDATA_TYPE, RET)                \
159022b9bceSAnton Johansson ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, abi_ptr addr,            \
1609002ffcbSRichard Henderson                         ABI_TYPE xval, MemOpIdx oi, uintptr_t retaddr) \
1615507c2bfSRichard Henderson {                                                                   \
1627bedee32SRichard Henderson     XDATA_TYPE *haddr, cmp, old, new, val = xval;                   \
163d560225fSAnton Johansson     haddr = atomic_mmu_lookup(env_cpu(env), addr, oi, DATA_SIZE, retaddr);   \
1645507c2bfSRichard Henderson     smp_mb();                                                       \
165d73415a3SStefan Hajnoczi     cmp = qatomic_read__nocheck(haddr);                             \
1665507c2bfSRichard Henderson     do {                                                            \
1675507c2bfSRichard Henderson         old = cmp; new = FN(old, val);                              \
168d73415a3SStefan Hajnoczi         cmp = qatomic_cmpxchg__nocheck(haddr, old, new);            \
1695507c2bfSRichard Henderson     } while (cmp != old);                                           \
1705507c2bfSRichard Henderson     ATOMIC_MMU_CLEANUP;                                             \
171*b709da5dSPierrick Bouvier     atomic_trace_rmw_post(env, addr,                                \
172*b709da5dSPierrick Bouvier                           VALUE_LOW(old),                           \
173*b709da5dSPierrick Bouvier                           VALUE_HIGH(old),                          \
174*b709da5dSPierrick Bouvier                           VALUE_LOW(xval),                          \
175*b709da5dSPierrick Bouvier                           VALUE_HIGH(xval),                         \
176*b709da5dSPierrick Bouvier                           oi);                                      \
1775507c2bfSRichard Henderson     return RET;                                                     \
1785507c2bfSRichard Henderson }
1795507c2bfSRichard Henderson 
1805507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_smin, MIN, SDATA_TYPE, old)
1815507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_umin, MIN,  DATA_TYPE, old)
1825507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_smax, MAX, SDATA_TYPE, old)
1835507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_umax, MAX,  DATA_TYPE, old)
1845507c2bfSRichard Henderson 
1855507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(smin_fetch, MIN, SDATA_TYPE, new)
1865507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(umin_fetch, MIN,  DATA_TYPE, new)
1875507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(smax_fetch, MAX, SDATA_TYPE, new)
1885507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(umax_fetch, MAX,  DATA_TYPE, new)
1895507c2bfSRichard Henderson 
1905507c2bfSRichard Henderson #undef GEN_ATOMIC_HELPER_FN
191ec4a9629SRichard Henderson #endif /* DATA SIZE < 16 */
19210f7d4d5SPhilippe Mathieu-Daudé 
19310f7d4d5SPhilippe Mathieu-Daudé #undef END
19410f7d4d5SPhilippe Mathieu-Daudé 
19510f7d4d5SPhilippe Mathieu-Daudé #if DATA_SIZE > 1
19610f7d4d5SPhilippe Mathieu-Daudé 
19710f7d4d5SPhilippe Mathieu-Daudé /* Define reverse-host-endian atomic operations.  Note that END is used
19810f7d4d5SPhilippe Mathieu-Daudé    within the ATOMIC_NAME macro.  */
199e03b5686SMarc-André Lureau #if HOST_BIG_ENDIAN
20010f7d4d5SPhilippe Mathieu-Daudé # define END  _le
20110f7d4d5SPhilippe Mathieu-Daudé #else
20210f7d4d5SPhilippe Mathieu-Daudé # define END  _be
20310f7d4d5SPhilippe Mathieu-Daudé #endif
20410f7d4d5SPhilippe Mathieu-Daudé 
205022b9bceSAnton Johansson ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, abi_ptr addr,
20648688fafSRichard Henderson                               ABI_TYPE cmpv, ABI_TYPE newv,
2079002ffcbSRichard Henderson                               MemOpIdx oi, uintptr_t retaddr)
20810f7d4d5SPhilippe Mathieu-Daudé {
209d560225fSAnton Johansson     DATA_TYPE *haddr = atomic_mmu_lookup(env_cpu(env), addr, oi,
210d560225fSAnton Johansson                                          DATA_SIZE, retaddr);
211d071f4cdSEmilio G. Cota     DATA_TYPE ret;
212d071f4cdSEmilio G. Cota 
213e6cd4bb5SRichard Henderson #if DATA_SIZE == 16
214e6cd4bb5SRichard Henderson     ret = atomic16_cmpxchg(haddr, BSWAP(cmpv), BSWAP(newv));
215e6cd4bb5SRichard Henderson #else
216d73415a3SStefan Hajnoczi     ret = qatomic_cmpxchg__nocheck(haddr, BSWAP(cmpv), BSWAP(newv));
217e6cd4bb5SRichard Henderson #endif
218ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
219*b709da5dSPierrick Bouvier     atomic_trace_rmw_post(env, addr,
220*b709da5dSPierrick Bouvier                           VALUE_LOW(ret),
221*b709da5dSPierrick Bouvier                           VALUE_HIGH(ret),
222*b709da5dSPierrick Bouvier                           VALUE_LOW(newv),
223*b709da5dSPierrick Bouvier                           VALUE_HIGH(newv),
224*b709da5dSPierrick Bouvier                           oi);
225ec603b55SRichard Henderson     return BSWAP(ret);
22610f7d4d5SPhilippe Mathieu-Daudé }
22710f7d4d5SPhilippe Mathieu-Daudé 
228ec4a9629SRichard Henderson #if DATA_SIZE < 16
ATOMIC_NAME(xchg)229022b9bceSAnton Johansson ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, abi_ptr addr, ABI_TYPE val,
2309002ffcbSRichard Henderson                            MemOpIdx oi, uintptr_t retaddr)
23110f7d4d5SPhilippe Mathieu-Daudé {
232d560225fSAnton Johansson     DATA_TYPE *haddr = atomic_mmu_lookup(env_cpu(env), addr, oi,
233d560225fSAnton Johansson                                          DATA_SIZE, retaddr);
234d071f4cdSEmilio G. Cota     ABI_TYPE ret;
235d071f4cdSEmilio G. Cota 
236d73415a3SStefan Hajnoczi     ret = qatomic_xchg__nocheck(haddr, BSWAP(val));
237ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
238*b709da5dSPierrick Bouvier     atomic_trace_rmw_post(env, addr,
239*b709da5dSPierrick Bouvier                           VALUE_LOW(ret),
240*b709da5dSPierrick Bouvier                           VALUE_HIGH(ret),
241*b709da5dSPierrick Bouvier                           VALUE_LOW(val),
242*b709da5dSPierrick Bouvier                           VALUE_HIGH(val),
243*b709da5dSPierrick Bouvier                           oi);
244ec603b55SRichard Henderson     return BSWAP(ret);
24510f7d4d5SPhilippe Mathieu-Daudé }
24610f7d4d5SPhilippe Mathieu-Daudé 
24710f7d4d5SPhilippe Mathieu-Daudé #define GEN_ATOMIC_HELPER(X)                                        \
248022b9bceSAnton Johansson ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, abi_ptr addr,            \
2499002ffcbSRichard Henderson                         ABI_TYPE val, MemOpIdx oi, uintptr_t retaddr) \
25010f7d4d5SPhilippe Mathieu-Daudé {                                                                   \
2517bedee32SRichard Henderson     DATA_TYPE *haddr, ret;                                          \
252d560225fSAnton Johansson     haddr = atomic_mmu_lookup(env_cpu(env), addr, oi, DATA_SIZE, retaddr);   \
253d73415a3SStefan Hajnoczi     ret = qatomic_##X(haddr, BSWAP(val));                           \
254ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;                                             \
255*b709da5dSPierrick Bouvier     atomic_trace_rmw_post(env, addr,                                \
256*b709da5dSPierrick Bouvier                           VALUE_LOW(ret),                           \
257*b709da5dSPierrick Bouvier                           VALUE_HIGH(ret),                          \
258*b709da5dSPierrick Bouvier                           VALUE_LOW(val),                           \
259*b709da5dSPierrick Bouvier                           VALUE_HIGH(val),                          \
260*b709da5dSPierrick Bouvier                           oi);                                      \
261ec603b55SRichard Henderson     return BSWAP(ret);                                              \
26210f7d4d5SPhilippe Mathieu-Daudé }
26310f7d4d5SPhilippe Mathieu-Daudé 
26410f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_and)
26510f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_or)
26610f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_xor)
26710f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(and_fetch)
26810f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(or_fetch)
26910f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(xor_fetch)
27010f7d4d5SPhilippe Mathieu-Daudé 
27110f7d4d5SPhilippe Mathieu-Daudé #undef GEN_ATOMIC_HELPER
27210f7d4d5SPhilippe Mathieu-Daudé 
2735507c2bfSRichard Henderson /* These helpers are, as a whole, full barriers.  Within the helper,
2745507c2bfSRichard Henderson  * the leading barrier is explicit and the trailing barrier is within
2755507c2bfSRichard Henderson  * cmpxchg primitive.
276d071f4cdSEmilio G. Cota  *
277d071f4cdSEmilio G. Cota  * Trace this load + RMW loop as a single RMW op. This way, regardless
278d071f4cdSEmilio G. Cota  * of CF_PARALLEL's value, we'll trace just a read and a write.
2795507c2bfSRichard Henderson  */
2805507c2bfSRichard Henderson #define GEN_ATOMIC_HELPER_FN(X, FN, XDATA_TYPE, RET)                \
281022b9bceSAnton Johansson ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, abi_ptr addr,            \
2829002ffcbSRichard Henderson                         ABI_TYPE xval, MemOpIdx oi, uintptr_t retaddr) \
2835507c2bfSRichard Henderson {                                                                   \
2847bedee32SRichard Henderson     XDATA_TYPE *haddr, ldo, ldn, old, new, val = xval;              \
285d560225fSAnton Johansson     haddr = atomic_mmu_lookup(env_cpu(env), addr, oi, DATA_SIZE, retaddr);   \
2865507c2bfSRichard Henderson     smp_mb();                                                       \
287d73415a3SStefan Hajnoczi     ldn = qatomic_read__nocheck(haddr);                             \
2885507c2bfSRichard Henderson     do {                                                            \
2895507c2bfSRichard Henderson         ldo = ldn; old = BSWAP(ldo); new = FN(old, val);            \
290d73415a3SStefan Hajnoczi         ldn = qatomic_cmpxchg__nocheck(haddr, ldo, BSWAP(new));     \
2915507c2bfSRichard Henderson     } while (ldo != ldn);                                           \
2925507c2bfSRichard Henderson     ATOMIC_MMU_CLEANUP;                                             \
293*b709da5dSPierrick Bouvier     atomic_trace_rmw_post(env, addr,                                \
294*b709da5dSPierrick Bouvier                           VALUE_LOW(old),                           \
295*b709da5dSPierrick Bouvier                           VALUE_HIGH(old),                          \
296*b709da5dSPierrick Bouvier                           VALUE_LOW(xval),                          \
297*b709da5dSPierrick Bouvier                           VALUE_HIGH(xval),                         \
298*b709da5dSPierrick Bouvier                           oi);                                      \
2995507c2bfSRichard Henderson     return RET;                                                     \
3005507c2bfSRichard Henderson }
3015507c2bfSRichard Henderson 
3025507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_smin, MIN, SDATA_TYPE, old)
3035507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_umin, MIN,  DATA_TYPE, old)
3045507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_smax, MAX, SDATA_TYPE, old)
3055507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_umax, MAX,  DATA_TYPE, old)
3065507c2bfSRichard Henderson 
3075507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(smin_fetch, MIN, SDATA_TYPE, new)
3085507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(umin_fetch, MIN,  DATA_TYPE, new)
3095507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(smax_fetch, MAX, SDATA_TYPE, new)
3105507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(umax_fetch, MAX,  DATA_TYPE, new)
3115507c2bfSRichard Henderson 
31258edf9eeSRichard Henderson /* Note that for addition, we need to use a separate cmpxchg loop instead
31358edf9eeSRichard Henderson    of bswaps for the reverse-host-endian helpers.  */
31458edf9eeSRichard Henderson #define ADD(X, Y)   (X + Y)
31558edf9eeSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_add, ADD, DATA_TYPE, old)
31658edf9eeSRichard Henderson GEN_ATOMIC_HELPER_FN(add_fetch, ADD, DATA_TYPE, new)
31758edf9eeSRichard Henderson #undef ADD
31858edf9eeSRichard Henderson 
3195507c2bfSRichard Henderson #undef GEN_ATOMIC_HELPER_FN
320ec4a9629SRichard Henderson #endif /* DATA_SIZE < 16 */
32110f7d4d5SPhilippe Mathieu-Daudé 
32210f7d4d5SPhilippe Mathieu-Daudé #undef END
32310f7d4d5SPhilippe Mathieu-Daudé #endif /* DATA_SIZE > 1 */
32410f7d4d5SPhilippe Mathieu-Daudé 
32510f7d4d5SPhilippe Mathieu-Daudé #undef BSWAP
32610f7d4d5SPhilippe Mathieu-Daudé #undef ABI_TYPE
32710f7d4d5SPhilippe Mathieu-Daudé #undef DATA_TYPE
3285507c2bfSRichard Henderson #undef SDATA_TYPE
32910f7d4d5SPhilippe Mathieu-Daudé #undef SUFFIX
33010f7d4d5SPhilippe Mathieu-Daudé #undef DATA_SIZE
331d071f4cdSEmilio G. Cota #undef SHIFT
332*b709da5dSPierrick Bouvier #undef VALUE_LOW
333*b709da5dSPierrick Bouvier #undef VALUE_HIGH
334