xref: /openbmc/qemu/accel/tcg/atomic_template.h (revision 5507c2bf35aa6b4705939349184e71afd5e058b2)
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
1010f7d4d5SPhilippe Mathieu-Daudé  * version 2 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é 
2110f7d4d5SPhilippe Mathieu-Daudé #if DATA_SIZE == 16
2210f7d4d5SPhilippe Mathieu-Daudé # define SUFFIX     o
2310f7d4d5SPhilippe Mathieu-Daudé # define DATA_TYPE  Int128
2410f7d4d5SPhilippe Mathieu-Daudé # define BSWAP      bswap128
2510f7d4d5SPhilippe Mathieu-Daudé #elif DATA_SIZE == 8
2610f7d4d5SPhilippe Mathieu-Daudé # define SUFFIX     q
2710f7d4d5SPhilippe Mathieu-Daudé # define DATA_TYPE  uint64_t
28*5507c2bfSRichard Henderson # define SDATA_TYPE int64_t
2910f7d4d5SPhilippe Mathieu-Daudé # define BSWAP      bswap64
3010f7d4d5SPhilippe Mathieu-Daudé #elif DATA_SIZE == 4
3110f7d4d5SPhilippe Mathieu-Daudé # define SUFFIX     l
3210f7d4d5SPhilippe Mathieu-Daudé # define DATA_TYPE  uint32_t
33*5507c2bfSRichard Henderson # define SDATA_TYPE int32_t
3410f7d4d5SPhilippe Mathieu-Daudé # define BSWAP      bswap32
3510f7d4d5SPhilippe Mathieu-Daudé #elif DATA_SIZE == 2
3610f7d4d5SPhilippe Mathieu-Daudé # define SUFFIX     w
3710f7d4d5SPhilippe Mathieu-Daudé # define DATA_TYPE  uint16_t
38*5507c2bfSRichard Henderson # define SDATA_TYPE int16_t
3910f7d4d5SPhilippe Mathieu-Daudé # define BSWAP      bswap16
4010f7d4d5SPhilippe Mathieu-Daudé #elif DATA_SIZE == 1
4110f7d4d5SPhilippe Mathieu-Daudé # define SUFFIX     b
4210f7d4d5SPhilippe Mathieu-Daudé # define DATA_TYPE  uint8_t
43*5507c2bfSRichard Henderson # define SDATA_TYPE int8_t
4410f7d4d5SPhilippe Mathieu-Daudé # define BSWAP
4510f7d4d5SPhilippe Mathieu-Daudé #else
4610f7d4d5SPhilippe Mathieu-Daudé # error unsupported data size
4710f7d4d5SPhilippe Mathieu-Daudé #endif
4810f7d4d5SPhilippe Mathieu-Daudé 
4910f7d4d5SPhilippe Mathieu-Daudé #if DATA_SIZE >= 4
5010f7d4d5SPhilippe Mathieu-Daudé # define ABI_TYPE  DATA_TYPE
5110f7d4d5SPhilippe Mathieu-Daudé #else
5210f7d4d5SPhilippe Mathieu-Daudé # define ABI_TYPE  uint32_t
5310f7d4d5SPhilippe Mathieu-Daudé #endif
5410f7d4d5SPhilippe Mathieu-Daudé 
5510f7d4d5SPhilippe Mathieu-Daudé /* Define host-endian atomic operations.  Note that END is used within
5610f7d4d5SPhilippe Mathieu-Daudé    the ATOMIC_NAME macro, and redefined below.  */
5710f7d4d5SPhilippe Mathieu-Daudé #if DATA_SIZE == 1
5810f7d4d5SPhilippe Mathieu-Daudé # define END
5910f7d4d5SPhilippe Mathieu-Daudé #elif defined(HOST_WORDS_BIGENDIAN)
6010f7d4d5SPhilippe Mathieu-Daudé # define END  _be
6110f7d4d5SPhilippe Mathieu-Daudé #else
6210f7d4d5SPhilippe Mathieu-Daudé # define END  _le
6310f7d4d5SPhilippe Mathieu-Daudé #endif
6410f7d4d5SPhilippe Mathieu-Daudé 
6510f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr,
6610f7d4d5SPhilippe Mathieu-Daudé                               ABI_TYPE cmpv, ABI_TYPE newv EXTRA_ARGS)
6710f7d4d5SPhilippe Mathieu-Daudé {
6834d49937SPeter Maydell     ATOMIC_MMU_DECLS;
6910f7d4d5SPhilippe Mathieu-Daudé     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
70ec603b55SRichard Henderson     DATA_TYPE ret = atomic_cmpxchg__nocheck(haddr, cmpv, newv);
71ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
72ec603b55SRichard Henderson     return ret;
7310f7d4d5SPhilippe Mathieu-Daudé }
7410f7d4d5SPhilippe Mathieu-Daudé 
7510f7d4d5SPhilippe Mathieu-Daudé #if DATA_SIZE >= 16
7610f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr EXTRA_ARGS)
7710f7d4d5SPhilippe Mathieu-Daudé {
7834d49937SPeter Maydell     ATOMIC_MMU_DECLS;
7910f7d4d5SPhilippe Mathieu-Daudé     DATA_TYPE val, *haddr = ATOMIC_MMU_LOOKUP;
8010f7d4d5SPhilippe Mathieu-Daudé     __atomic_load(haddr, &val, __ATOMIC_RELAXED);
81ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
8210f7d4d5SPhilippe Mathieu-Daudé     return val;
8310f7d4d5SPhilippe Mathieu-Daudé }
8410f7d4d5SPhilippe Mathieu-Daudé 
8510f7d4d5SPhilippe Mathieu-Daudé void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr,
8610f7d4d5SPhilippe Mathieu-Daudé                      ABI_TYPE val EXTRA_ARGS)
8710f7d4d5SPhilippe Mathieu-Daudé {
8834d49937SPeter Maydell     ATOMIC_MMU_DECLS;
8910f7d4d5SPhilippe Mathieu-Daudé     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
9010f7d4d5SPhilippe Mathieu-Daudé     __atomic_store(haddr, &val, __ATOMIC_RELAXED);
91ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
9210f7d4d5SPhilippe Mathieu-Daudé }
9310f7d4d5SPhilippe Mathieu-Daudé #else
9410f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr,
9510f7d4d5SPhilippe Mathieu-Daudé                            ABI_TYPE val EXTRA_ARGS)
9610f7d4d5SPhilippe Mathieu-Daudé {
9734d49937SPeter Maydell     ATOMIC_MMU_DECLS;
9810f7d4d5SPhilippe Mathieu-Daudé     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
99ec603b55SRichard Henderson     DATA_TYPE ret = atomic_xchg__nocheck(haddr, val);
100ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
101ec603b55SRichard Henderson     return ret;
10210f7d4d5SPhilippe Mathieu-Daudé }
10310f7d4d5SPhilippe Mathieu-Daudé 
10410f7d4d5SPhilippe Mathieu-Daudé #define GEN_ATOMIC_HELPER(X)                                        \
10510f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr,       \
10610f7d4d5SPhilippe Mathieu-Daudé                  ABI_TYPE val EXTRA_ARGS)                           \
10710f7d4d5SPhilippe Mathieu-Daudé {                                                                   \
10834d49937SPeter Maydell     ATOMIC_MMU_DECLS;                                               \
10910f7d4d5SPhilippe Mathieu-Daudé     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;                           \
110ec603b55SRichard Henderson     DATA_TYPE ret = atomic_##X(haddr, val);                         \
111ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;                                             \
112ec603b55SRichard Henderson     return ret;                                                     \
113ec603b55SRichard Henderson }
11410f7d4d5SPhilippe Mathieu-Daudé 
11510f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_add)
11610f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_and)
11710f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_or)
11810f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_xor)
11910f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(add_fetch)
12010f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(and_fetch)
12110f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(or_fetch)
12210f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(xor_fetch)
12310f7d4d5SPhilippe Mathieu-Daudé 
12410f7d4d5SPhilippe Mathieu-Daudé #undef GEN_ATOMIC_HELPER
125*5507c2bfSRichard Henderson 
126*5507c2bfSRichard Henderson /* These helpers are, as a whole, full barriers.  Within the helper,
127*5507c2bfSRichard Henderson  * the leading barrier is explicit and the trailing barrier is within
128*5507c2bfSRichard Henderson  * cmpxchg primitive.
129*5507c2bfSRichard Henderson  */
130*5507c2bfSRichard Henderson #define GEN_ATOMIC_HELPER_FN(X, FN, XDATA_TYPE, RET)                \
131*5507c2bfSRichard Henderson ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr,       \
132*5507c2bfSRichard Henderson                         ABI_TYPE xval EXTRA_ARGS)                   \
133*5507c2bfSRichard Henderson {                                                                   \
134*5507c2bfSRichard Henderson     ATOMIC_MMU_DECLS;                                               \
135*5507c2bfSRichard Henderson     XDATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;                          \
136*5507c2bfSRichard Henderson     XDATA_TYPE cmp, old, new, val = xval;                           \
137*5507c2bfSRichard Henderson     smp_mb();                                                       \
138*5507c2bfSRichard Henderson     cmp = atomic_read__nocheck(haddr);                              \
139*5507c2bfSRichard Henderson     do {                                                            \
140*5507c2bfSRichard Henderson         old = cmp; new = FN(old, val);                              \
141*5507c2bfSRichard Henderson         cmp = atomic_cmpxchg__nocheck(haddr, old, new);             \
142*5507c2bfSRichard Henderson     } while (cmp != old);                                           \
143*5507c2bfSRichard Henderson     ATOMIC_MMU_CLEANUP;                                             \
144*5507c2bfSRichard Henderson     return RET;                                                     \
145*5507c2bfSRichard Henderson }
146*5507c2bfSRichard Henderson 
147*5507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_smin, MIN, SDATA_TYPE, old)
148*5507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_umin, MIN,  DATA_TYPE, old)
149*5507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_smax, MAX, SDATA_TYPE, old)
150*5507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_umax, MAX,  DATA_TYPE, old)
151*5507c2bfSRichard Henderson 
152*5507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(smin_fetch, MIN, SDATA_TYPE, new)
153*5507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(umin_fetch, MIN,  DATA_TYPE, new)
154*5507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(smax_fetch, MAX, SDATA_TYPE, new)
155*5507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(umax_fetch, MAX,  DATA_TYPE, new)
156*5507c2bfSRichard Henderson 
157*5507c2bfSRichard Henderson #undef GEN_ATOMIC_HELPER_FN
15810f7d4d5SPhilippe Mathieu-Daudé #endif /* DATA SIZE >= 16 */
15910f7d4d5SPhilippe Mathieu-Daudé 
16010f7d4d5SPhilippe Mathieu-Daudé #undef END
16110f7d4d5SPhilippe Mathieu-Daudé 
16210f7d4d5SPhilippe Mathieu-Daudé #if DATA_SIZE > 1
16310f7d4d5SPhilippe Mathieu-Daudé 
16410f7d4d5SPhilippe Mathieu-Daudé /* Define reverse-host-endian atomic operations.  Note that END is used
16510f7d4d5SPhilippe Mathieu-Daudé    within the ATOMIC_NAME macro.  */
16610f7d4d5SPhilippe Mathieu-Daudé #ifdef HOST_WORDS_BIGENDIAN
16710f7d4d5SPhilippe Mathieu-Daudé # define END  _le
16810f7d4d5SPhilippe Mathieu-Daudé #else
16910f7d4d5SPhilippe Mathieu-Daudé # define END  _be
17010f7d4d5SPhilippe Mathieu-Daudé #endif
17110f7d4d5SPhilippe Mathieu-Daudé 
17210f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr,
17310f7d4d5SPhilippe Mathieu-Daudé                               ABI_TYPE cmpv, ABI_TYPE newv EXTRA_ARGS)
17410f7d4d5SPhilippe Mathieu-Daudé {
17534d49937SPeter Maydell     ATOMIC_MMU_DECLS;
17610f7d4d5SPhilippe Mathieu-Daudé     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
177ec603b55SRichard Henderson     DATA_TYPE ret = atomic_cmpxchg__nocheck(haddr, BSWAP(cmpv), BSWAP(newv));
178ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
179ec603b55SRichard Henderson     return BSWAP(ret);
18010f7d4d5SPhilippe Mathieu-Daudé }
18110f7d4d5SPhilippe Mathieu-Daudé 
18210f7d4d5SPhilippe Mathieu-Daudé #if DATA_SIZE >= 16
18310f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr EXTRA_ARGS)
18410f7d4d5SPhilippe Mathieu-Daudé {
18534d49937SPeter Maydell     ATOMIC_MMU_DECLS;
18610f7d4d5SPhilippe Mathieu-Daudé     DATA_TYPE val, *haddr = ATOMIC_MMU_LOOKUP;
18710f7d4d5SPhilippe Mathieu-Daudé     __atomic_load(haddr, &val, __ATOMIC_RELAXED);
188ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
18910f7d4d5SPhilippe Mathieu-Daudé     return BSWAP(val);
19010f7d4d5SPhilippe Mathieu-Daudé }
19110f7d4d5SPhilippe Mathieu-Daudé 
19210f7d4d5SPhilippe Mathieu-Daudé void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr,
19310f7d4d5SPhilippe Mathieu-Daudé                      ABI_TYPE val EXTRA_ARGS)
19410f7d4d5SPhilippe Mathieu-Daudé {
19534d49937SPeter Maydell     ATOMIC_MMU_DECLS;
19610f7d4d5SPhilippe Mathieu-Daudé     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
19710f7d4d5SPhilippe Mathieu-Daudé     val = BSWAP(val);
19810f7d4d5SPhilippe Mathieu-Daudé     __atomic_store(haddr, &val, __ATOMIC_RELAXED);
199ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
20010f7d4d5SPhilippe Mathieu-Daudé }
20110f7d4d5SPhilippe Mathieu-Daudé #else
20210f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr,
20310f7d4d5SPhilippe Mathieu-Daudé                            ABI_TYPE val EXTRA_ARGS)
20410f7d4d5SPhilippe Mathieu-Daudé {
20534d49937SPeter Maydell     ATOMIC_MMU_DECLS;
20610f7d4d5SPhilippe Mathieu-Daudé     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
207ec603b55SRichard Henderson     ABI_TYPE ret = atomic_xchg__nocheck(haddr, BSWAP(val));
208ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
209ec603b55SRichard Henderson     return BSWAP(ret);
21010f7d4d5SPhilippe Mathieu-Daudé }
21110f7d4d5SPhilippe Mathieu-Daudé 
21210f7d4d5SPhilippe Mathieu-Daudé #define GEN_ATOMIC_HELPER(X)                                        \
21310f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr,       \
21410f7d4d5SPhilippe Mathieu-Daudé                  ABI_TYPE val EXTRA_ARGS)                           \
21510f7d4d5SPhilippe Mathieu-Daudé {                                                                   \
21634d49937SPeter Maydell     ATOMIC_MMU_DECLS;                                               \
21710f7d4d5SPhilippe Mathieu-Daudé     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;                           \
218ec603b55SRichard Henderson     DATA_TYPE ret = atomic_##X(haddr, BSWAP(val));                  \
219ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;                                             \
220ec603b55SRichard Henderson     return BSWAP(ret);                                              \
22110f7d4d5SPhilippe Mathieu-Daudé }
22210f7d4d5SPhilippe Mathieu-Daudé 
22310f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_and)
22410f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_or)
22510f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_xor)
22610f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(and_fetch)
22710f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(or_fetch)
22810f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(xor_fetch)
22910f7d4d5SPhilippe Mathieu-Daudé 
23010f7d4d5SPhilippe Mathieu-Daudé #undef GEN_ATOMIC_HELPER
23110f7d4d5SPhilippe Mathieu-Daudé 
23210f7d4d5SPhilippe Mathieu-Daudé /* Note that for addition, we need to use a separate cmpxchg loop instead
23310f7d4d5SPhilippe Mathieu-Daudé    of bswaps for the reverse-host-endian helpers.  */
23410f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(fetch_add)(CPUArchState *env, target_ulong addr,
23510f7d4d5SPhilippe Mathieu-Daudé                          ABI_TYPE val EXTRA_ARGS)
23610f7d4d5SPhilippe Mathieu-Daudé {
23734d49937SPeter Maydell     ATOMIC_MMU_DECLS;
23810f7d4d5SPhilippe Mathieu-Daudé     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
23910f7d4d5SPhilippe Mathieu-Daudé     DATA_TYPE ldo, ldn, ret, sto;
24010f7d4d5SPhilippe Mathieu-Daudé 
24110f7d4d5SPhilippe Mathieu-Daudé     ldo = atomic_read__nocheck(haddr);
24210f7d4d5SPhilippe Mathieu-Daudé     while (1) {
24310f7d4d5SPhilippe Mathieu-Daudé         ret = BSWAP(ldo);
24410f7d4d5SPhilippe Mathieu-Daudé         sto = BSWAP(ret + val);
24510f7d4d5SPhilippe Mathieu-Daudé         ldn = atomic_cmpxchg__nocheck(haddr, ldo, sto);
24610f7d4d5SPhilippe Mathieu-Daudé         if (ldn == ldo) {
247ec603b55SRichard Henderson             ATOMIC_MMU_CLEANUP;
24810f7d4d5SPhilippe Mathieu-Daudé             return ret;
24910f7d4d5SPhilippe Mathieu-Daudé         }
25010f7d4d5SPhilippe Mathieu-Daudé         ldo = ldn;
25110f7d4d5SPhilippe Mathieu-Daudé     }
25210f7d4d5SPhilippe Mathieu-Daudé }
25310f7d4d5SPhilippe Mathieu-Daudé 
25410f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(add_fetch)(CPUArchState *env, target_ulong addr,
25510f7d4d5SPhilippe Mathieu-Daudé                          ABI_TYPE val EXTRA_ARGS)
25610f7d4d5SPhilippe Mathieu-Daudé {
25734d49937SPeter Maydell     ATOMIC_MMU_DECLS;
25810f7d4d5SPhilippe Mathieu-Daudé     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
25910f7d4d5SPhilippe Mathieu-Daudé     DATA_TYPE ldo, ldn, ret, sto;
26010f7d4d5SPhilippe Mathieu-Daudé 
26110f7d4d5SPhilippe Mathieu-Daudé     ldo = atomic_read__nocheck(haddr);
26210f7d4d5SPhilippe Mathieu-Daudé     while (1) {
26310f7d4d5SPhilippe Mathieu-Daudé         ret = BSWAP(ldo) + val;
26410f7d4d5SPhilippe Mathieu-Daudé         sto = BSWAP(ret);
26510f7d4d5SPhilippe Mathieu-Daudé         ldn = atomic_cmpxchg__nocheck(haddr, ldo, sto);
26610f7d4d5SPhilippe Mathieu-Daudé         if (ldn == ldo) {
267ec603b55SRichard Henderson             ATOMIC_MMU_CLEANUP;
26810f7d4d5SPhilippe Mathieu-Daudé             return ret;
26910f7d4d5SPhilippe Mathieu-Daudé         }
27010f7d4d5SPhilippe Mathieu-Daudé         ldo = ldn;
27110f7d4d5SPhilippe Mathieu-Daudé     }
27210f7d4d5SPhilippe Mathieu-Daudé }
273*5507c2bfSRichard Henderson 
274*5507c2bfSRichard Henderson /* These helpers are, as a whole, full barriers.  Within the helper,
275*5507c2bfSRichard Henderson  * the leading barrier is explicit and the trailing barrier is within
276*5507c2bfSRichard Henderson  * cmpxchg primitive.
277*5507c2bfSRichard Henderson  */
278*5507c2bfSRichard Henderson #define GEN_ATOMIC_HELPER_FN(X, FN, XDATA_TYPE, RET)                \
279*5507c2bfSRichard Henderson ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr,       \
280*5507c2bfSRichard Henderson                         ABI_TYPE xval EXTRA_ARGS)                   \
281*5507c2bfSRichard Henderson {                                                                   \
282*5507c2bfSRichard Henderson     ATOMIC_MMU_DECLS;                                               \
283*5507c2bfSRichard Henderson     XDATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;                          \
284*5507c2bfSRichard Henderson     XDATA_TYPE ldo, ldn, old, new, val = xval;                      \
285*5507c2bfSRichard Henderson     smp_mb();                                                       \
286*5507c2bfSRichard Henderson     ldn = atomic_read__nocheck(haddr);                              \
287*5507c2bfSRichard Henderson     do {                                                            \
288*5507c2bfSRichard Henderson         ldo = ldn; old = BSWAP(ldo); new = FN(old, val);            \
289*5507c2bfSRichard Henderson         ldn = atomic_cmpxchg__nocheck(haddr, ldo, BSWAP(new));      \
290*5507c2bfSRichard Henderson     } while (ldo != ldn);                                           \
291*5507c2bfSRichard Henderson     ATOMIC_MMU_CLEANUP;                                             \
292*5507c2bfSRichard Henderson     return RET;                                                     \
293*5507c2bfSRichard Henderson }
294*5507c2bfSRichard Henderson 
295*5507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_smin, MIN, SDATA_TYPE, old)
296*5507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_umin, MIN,  DATA_TYPE, old)
297*5507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_smax, MAX, SDATA_TYPE, old)
298*5507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_umax, MAX,  DATA_TYPE, old)
299*5507c2bfSRichard Henderson 
300*5507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(smin_fetch, MIN, SDATA_TYPE, new)
301*5507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(umin_fetch, MIN,  DATA_TYPE, new)
302*5507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(smax_fetch, MAX, SDATA_TYPE, new)
303*5507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(umax_fetch, MAX,  DATA_TYPE, new)
304*5507c2bfSRichard Henderson 
305*5507c2bfSRichard Henderson #undef GEN_ATOMIC_HELPER_FN
30610f7d4d5SPhilippe Mathieu-Daudé #endif /* DATA_SIZE >= 16 */
30710f7d4d5SPhilippe Mathieu-Daudé 
30810f7d4d5SPhilippe Mathieu-Daudé #undef END
30910f7d4d5SPhilippe Mathieu-Daudé #endif /* DATA_SIZE > 1 */
31010f7d4d5SPhilippe Mathieu-Daudé 
31110f7d4d5SPhilippe Mathieu-Daudé #undef BSWAP
31210f7d4d5SPhilippe Mathieu-Daudé #undef ABI_TYPE
31310f7d4d5SPhilippe Mathieu-Daudé #undef DATA_TYPE
314*5507c2bfSRichard Henderson #undef SDATA_TYPE
31510f7d4d5SPhilippe Mathieu-Daudé #undef SUFFIX
31610f7d4d5SPhilippe Mathieu-Daudé #undef DATA_SIZE
317