xref: /qemu/accel/tcg/atomic_template.h (revision fb0343d5b4dd4b9b9e96e563d913a3e0c709fe4e)
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
10*fb0343d5SThomas Huth  * version 2.1 of the License, or (at your option) any later version.
11c482cb11SRichard Henderson  *
12c482cb11SRichard Henderson  * This library is distributed in the hope that it will be useful,
13c482cb11SRichard Henderson  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14c482cb11SRichard Henderson  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15c482cb11SRichard Henderson  * Lesser General Public License for more details.
16c482cb11SRichard Henderson  *
17c482cb11SRichard Henderson  * You should have received a copy of the GNU Lesser General Public
18c482cb11SRichard Henderson  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19c482cb11SRichard Henderson  */
20c482cb11SRichard Henderson 
21d071f4cdSEmilio G. Cota #include "trace/mem.h"
22d071f4cdSEmilio G. Cota 
237ebee43eSRichard Henderson #if DATA_SIZE == 16
247ebee43eSRichard Henderson # define SUFFIX     o
257ebee43eSRichard Henderson # define DATA_TYPE  Int128
267ebee43eSRichard Henderson # define BSWAP      bswap128
27d071f4cdSEmilio G. Cota # define SHIFT      4
287ebee43eSRichard Henderson #elif DATA_SIZE == 8
29c482cb11SRichard Henderson # define SUFFIX     q
30c482cb11SRichard Henderson # define DATA_TYPE  uint64_t
315507c2bfSRichard Henderson # define SDATA_TYPE int64_t
32c482cb11SRichard Henderson # define BSWAP      bswap64
33d071f4cdSEmilio G. Cota # define SHIFT      3
34c482cb11SRichard Henderson #elif DATA_SIZE == 4
35c482cb11SRichard Henderson # define SUFFIX     l
36c482cb11SRichard Henderson # define DATA_TYPE  uint32_t
375507c2bfSRichard Henderson # define SDATA_TYPE int32_t
38c482cb11SRichard Henderson # define BSWAP      bswap32
39d071f4cdSEmilio G. Cota # define SHIFT      2
40c482cb11SRichard Henderson #elif DATA_SIZE == 2
41c482cb11SRichard Henderson # define SUFFIX     w
42c482cb11SRichard Henderson # define DATA_TYPE  uint16_t
435507c2bfSRichard Henderson # define SDATA_TYPE int16_t
44c482cb11SRichard Henderson # define BSWAP      bswap16
45d071f4cdSEmilio G. Cota # define SHIFT      1
46c482cb11SRichard Henderson #elif DATA_SIZE == 1
47c482cb11SRichard Henderson # define SUFFIX     b
48c482cb11SRichard Henderson # define DATA_TYPE  uint8_t
495507c2bfSRichard Henderson # define SDATA_TYPE int8_t
50c482cb11SRichard Henderson # define BSWAP
51d071f4cdSEmilio G. Cota # define SHIFT      0
52c482cb11SRichard Henderson #else
53c482cb11SRichard Henderson # error unsupported data size
54c482cb11SRichard Henderson #endif
55c482cb11SRichard Henderson 
56c482cb11SRichard Henderson #if DATA_SIZE >= 4
57c482cb11SRichard Henderson # define ABI_TYPE  DATA_TYPE
58c482cb11SRichard Henderson #else
59c482cb11SRichard Henderson # define ABI_TYPE  uint32_t
60c482cb11SRichard Henderson #endif
61c482cb11SRichard Henderson 
62d071f4cdSEmilio G. Cota #define ATOMIC_TRACE_RMW do {                                           \
63d071f4cdSEmilio G. Cota         uint8_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, false); \
64d071f4cdSEmilio G. Cota                                                                         \
65d071f4cdSEmilio G. Cota         trace_guest_mem_before_exec(ENV_GET_CPU(env), addr, info);      \
66d071f4cdSEmilio G. Cota         trace_guest_mem_before_exec(ENV_GET_CPU(env), addr,             \
67d071f4cdSEmilio G. Cota                                     info | TRACE_MEM_ST);               \
68d071f4cdSEmilio G. Cota     } while (0)
69d071f4cdSEmilio G. Cota 
70d071f4cdSEmilio G. Cota #define ATOMIC_TRACE_LD do {                                            \
71d071f4cdSEmilio G. Cota         uint8_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, false); \
72d071f4cdSEmilio G. Cota                                                                         \
73d071f4cdSEmilio G. Cota         trace_guest_mem_before_exec(ENV_GET_CPU(env), addr, info);      \
74d071f4cdSEmilio G. Cota     } while (0)
75d071f4cdSEmilio G. Cota 
76d071f4cdSEmilio G. Cota # define ATOMIC_TRACE_ST do {                                           \
77d071f4cdSEmilio G. Cota         uint8_t info = glue(trace_mem_build_info_no_se, MEND)(SHIFT, true); \
78d071f4cdSEmilio G. Cota                                                                         \
79d071f4cdSEmilio G. Cota         trace_guest_mem_before_exec(ENV_GET_CPU(env), addr, info);      \
80d071f4cdSEmilio G. Cota     } while (0)
81d071f4cdSEmilio G. Cota 
82c482cb11SRichard Henderson /* Define host-endian atomic operations.  Note that END is used within
83c482cb11SRichard Henderson    the ATOMIC_NAME macro, and redefined below.  */
84c482cb11SRichard Henderson #if DATA_SIZE == 1
85c482cb11SRichard Henderson # define END
86d071f4cdSEmilio G. Cota # define MEND _be /* either le or be would be fine */
87c482cb11SRichard Henderson #elif defined(HOST_WORDS_BIGENDIAN)
88c482cb11SRichard Henderson # define END  _be
89d071f4cdSEmilio G. Cota # define MEND _be
90c482cb11SRichard Henderson #else
91c482cb11SRichard Henderson # define END  _le
92d071f4cdSEmilio G. Cota # define MEND _le
93c482cb11SRichard Henderson #endif
94c482cb11SRichard Henderson 
95c482cb11SRichard Henderson ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr,
96c482cb11SRichard Henderson                               ABI_TYPE cmpv, ABI_TYPE newv EXTRA_ARGS)
97c482cb11SRichard Henderson {
9834d49937SPeter Maydell     ATOMIC_MMU_DECLS;
99c482cb11SRichard Henderson     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
100d071f4cdSEmilio G. Cota     DATA_TYPE ret;
101d071f4cdSEmilio G. Cota 
102d071f4cdSEmilio G. Cota     ATOMIC_TRACE_RMW;
103e6cd4bb5SRichard Henderson #if DATA_SIZE == 16
104e6cd4bb5SRichard Henderson     ret = atomic16_cmpxchg(haddr, cmpv, newv);
105e6cd4bb5SRichard Henderson #else
106d071f4cdSEmilio G. Cota     ret = atomic_cmpxchg__nocheck(haddr, cmpv, newv);
107e6cd4bb5SRichard Henderson #endif
108ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
109ec603b55SRichard Henderson     return ret;
110c482cb11SRichard Henderson }
111c482cb11SRichard Henderson 
1127ebee43eSRichard Henderson #if DATA_SIZE >= 16
113e6cd4bb5SRichard Henderson #if HAVE_ATOMIC128
1147ebee43eSRichard Henderson ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr EXTRA_ARGS)
1157ebee43eSRichard Henderson {
11634d49937SPeter Maydell     ATOMIC_MMU_DECLS;
1177ebee43eSRichard Henderson     DATA_TYPE val, *haddr = ATOMIC_MMU_LOOKUP;
118d071f4cdSEmilio G. Cota 
119d071f4cdSEmilio G. Cota     ATOMIC_TRACE_LD;
120e6cd4bb5SRichard Henderson     val = atomic16_read(haddr);
121ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
1227ebee43eSRichard Henderson     return val;
1237ebee43eSRichard Henderson }
1247ebee43eSRichard Henderson 
1257ebee43eSRichard Henderson void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr,
1267ebee43eSRichard Henderson                      ABI_TYPE val EXTRA_ARGS)
1277ebee43eSRichard Henderson {
12834d49937SPeter Maydell     ATOMIC_MMU_DECLS;
1297ebee43eSRichard Henderson     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
130d071f4cdSEmilio G. Cota 
131d071f4cdSEmilio G. Cota     ATOMIC_TRACE_ST;
132e6cd4bb5SRichard Henderson     atomic16_set(haddr, val);
133ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
1347ebee43eSRichard Henderson }
135e6cd4bb5SRichard Henderson #endif
1367ebee43eSRichard Henderson #else
137c482cb11SRichard Henderson ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr,
138c482cb11SRichard Henderson                            ABI_TYPE val EXTRA_ARGS)
139c482cb11SRichard Henderson {
14034d49937SPeter Maydell     ATOMIC_MMU_DECLS;
141c482cb11SRichard Henderson     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
142d071f4cdSEmilio G. Cota     DATA_TYPE ret;
143d071f4cdSEmilio G. Cota 
144d071f4cdSEmilio G. Cota     ATOMIC_TRACE_RMW;
145d071f4cdSEmilio G. Cota     ret = atomic_xchg__nocheck(haddr, val);
146ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
147ec603b55SRichard Henderson     return ret;
148c482cb11SRichard Henderson }
149c482cb11SRichard Henderson 
150c482cb11SRichard Henderson #define GEN_ATOMIC_HELPER(X)                                        \
151c482cb11SRichard Henderson ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr,       \
152c482cb11SRichard Henderson                  ABI_TYPE val EXTRA_ARGS)                           \
153c482cb11SRichard Henderson {                                                                   \
15434d49937SPeter Maydell     ATOMIC_MMU_DECLS;                                               \
155c482cb11SRichard Henderson     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;                           \
156d071f4cdSEmilio G. Cota     DATA_TYPE ret;                                                  \
157d071f4cdSEmilio G. Cota                                                                     \
158d071f4cdSEmilio G. Cota     ATOMIC_TRACE_RMW;                                               \
159d071f4cdSEmilio G. Cota     ret = atomic_##X(haddr, val);                                   \
160ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;                                             \
161ec603b55SRichard Henderson     return ret;                                                     \
162ec603b55SRichard Henderson }
163c482cb11SRichard Henderson 
164c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_add)
165c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_and)
166c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_or)
167c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_xor)
168c482cb11SRichard Henderson GEN_ATOMIC_HELPER(add_fetch)
169c482cb11SRichard Henderson GEN_ATOMIC_HELPER(and_fetch)
170c482cb11SRichard Henderson GEN_ATOMIC_HELPER(or_fetch)
171c482cb11SRichard Henderson GEN_ATOMIC_HELPER(xor_fetch)
172c482cb11SRichard Henderson 
173c482cb11SRichard Henderson #undef GEN_ATOMIC_HELPER
1745507c2bfSRichard Henderson 
1755507c2bfSRichard Henderson /* These helpers are, as a whole, full barriers.  Within the helper,
1765507c2bfSRichard Henderson  * the leading barrier is explicit and the trailing barrier is within
1775507c2bfSRichard Henderson  * cmpxchg primitive.
178d071f4cdSEmilio G. Cota  *
179d071f4cdSEmilio G. Cota  * Trace this load + RMW loop as a single RMW op. This way, regardless
180d071f4cdSEmilio G. Cota  * of CF_PARALLEL's value, we'll trace just a read and a write.
1815507c2bfSRichard Henderson  */
1825507c2bfSRichard Henderson #define GEN_ATOMIC_HELPER_FN(X, FN, XDATA_TYPE, RET)                \
1835507c2bfSRichard Henderson ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr,       \
1845507c2bfSRichard Henderson                         ABI_TYPE xval EXTRA_ARGS)                   \
1855507c2bfSRichard Henderson {                                                                   \
1865507c2bfSRichard Henderson     ATOMIC_MMU_DECLS;                                               \
1875507c2bfSRichard Henderson     XDATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;                          \
1885507c2bfSRichard Henderson     XDATA_TYPE cmp, old, new, val = xval;                           \
189d071f4cdSEmilio G. Cota                                                                     \
190d071f4cdSEmilio G. Cota     ATOMIC_TRACE_RMW;                                               \
1915507c2bfSRichard Henderson     smp_mb();                                                       \
1925507c2bfSRichard Henderson     cmp = atomic_read__nocheck(haddr);                              \
1935507c2bfSRichard Henderson     do {                                                            \
1945507c2bfSRichard Henderson         old = cmp; new = FN(old, val);                              \
1955507c2bfSRichard Henderson         cmp = atomic_cmpxchg__nocheck(haddr, old, new);             \
1965507c2bfSRichard Henderson     } while (cmp != old);                                           \
1975507c2bfSRichard Henderson     ATOMIC_MMU_CLEANUP;                                             \
1985507c2bfSRichard Henderson     return RET;                                                     \
1995507c2bfSRichard Henderson }
2005507c2bfSRichard Henderson 
2015507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_smin, MIN, SDATA_TYPE, old)
2025507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_umin, MIN,  DATA_TYPE, old)
2035507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_smax, MAX, SDATA_TYPE, old)
2045507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_umax, MAX,  DATA_TYPE, old)
2055507c2bfSRichard Henderson 
2065507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(smin_fetch, MIN, SDATA_TYPE, new)
2075507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(umin_fetch, MIN,  DATA_TYPE, new)
2085507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(smax_fetch, MAX, SDATA_TYPE, new)
2095507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(umax_fetch, MAX,  DATA_TYPE, new)
2105507c2bfSRichard Henderson 
2115507c2bfSRichard Henderson #undef GEN_ATOMIC_HELPER_FN
2127ebee43eSRichard Henderson #endif /* DATA SIZE >= 16 */
2137ebee43eSRichard Henderson 
214c482cb11SRichard Henderson #undef END
215d071f4cdSEmilio G. Cota #undef MEND
216c482cb11SRichard Henderson 
217c482cb11SRichard Henderson #if DATA_SIZE > 1
218c482cb11SRichard Henderson 
219c482cb11SRichard Henderson /* Define reverse-host-endian atomic operations.  Note that END is used
220c482cb11SRichard Henderson    within the ATOMIC_NAME macro.  */
221c482cb11SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN
222c482cb11SRichard Henderson # define END  _le
223d071f4cdSEmilio G. Cota # define MEND _le
224c482cb11SRichard Henderson #else
225c482cb11SRichard Henderson # define END  _be
226d071f4cdSEmilio G. Cota # define MEND _be
227c482cb11SRichard Henderson #endif
228c482cb11SRichard Henderson 
229c482cb11SRichard Henderson ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr,
230c482cb11SRichard Henderson                               ABI_TYPE cmpv, ABI_TYPE newv EXTRA_ARGS)
231c482cb11SRichard Henderson {
23234d49937SPeter Maydell     ATOMIC_MMU_DECLS;
233c482cb11SRichard Henderson     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
234d071f4cdSEmilio G. Cota     DATA_TYPE ret;
235d071f4cdSEmilio G. Cota 
236d071f4cdSEmilio G. Cota     ATOMIC_TRACE_RMW;
237e6cd4bb5SRichard Henderson #if DATA_SIZE == 16
238e6cd4bb5SRichard Henderson     ret = atomic16_cmpxchg(haddr, BSWAP(cmpv), BSWAP(newv));
239e6cd4bb5SRichard Henderson #else
240d071f4cdSEmilio G. Cota     ret = atomic_cmpxchg__nocheck(haddr, BSWAP(cmpv), BSWAP(newv));
241e6cd4bb5SRichard Henderson #endif
242ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
243ec603b55SRichard Henderson     return BSWAP(ret);
244c482cb11SRichard Henderson }
245c482cb11SRichard Henderson 
2467ebee43eSRichard Henderson #if DATA_SIZE >= 16
247e6cd4bb5SRichard Henderson #if HAVE_ATOMIC128
2487ebee43eSRichard Henderson ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr EXTRA_ARGS)
2497ebee43eSRichard Henderson {
25034d49937SPeter Maydell     ATOMIC_MMU_DECLS;
2517ebee43eSRichard Henderson     DATA_TYPE val, *haddr = ATOMIC_MMU_LOOKUP;
252d071f4cdSEmilio G. Cota 
253d071f4cdSEmilio G. Cota     ATOMIC_TRACE_LD;
254e6cd4bb5SRichard Henderson     val = atomic16_read(haddr);
255ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
2567ebee43eSRichard Henderson     return BSWAP(val);
2577ebee43eSRichard Henderson }
2587ebee43eSRichard Henderson 
2597ebee43eSRichard Henderson void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr,
2607ebee43eSRichard Henderson                      ABI_TYPE val EXTRA_ARGS)
2617ebee43eSRichard Henderson {
26234d49937SPeter Maydell     ATOMIC_MMU_DECLS;
2637ebee43eSRichard Henderson     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
264d071f4cdSEmilio G. Cota 
265d071f4cdSEmilio G. Cota     ATOMIC_TRACE_ST;
2667ebee43eSRichard Henderson     val = BSWAP(val);
267e6cd4bb5SRichard Henderson     atomic16_set(haddr, val);
268ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
2697ebee43eSRichard Henderson }
270e6cd4bb5SRichard Henderson #endif
2717ebee43eSRichard Henderson #else
272c482cb11SRichard Henderson ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr,
273c482cb11SRichard Henderson                            ABI_TYPE val EXTRA_ARGS)
274c482cb11SRichard Henderson {
27534d49937SPeter Maydell     ATOMIC_MMU_DECLS;
276c482cb11SRichard Henderson     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
277d071f4cdSEmilio G. Cota     ABI_TYPE ret;
278d071f4cdSEmilio G. Cota 
279d071f4cdSEmilio G. Cota     ATOMIC_TRACE_RMW;
280d071f4cdSEmilio G. Cota     ret = atomic_xchg__nocheck(haddr, BSWAP(val));
281ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
282ec603b55SRichard Henderson     return BSWAP(ret);
283c482cb11SRichard Henderson }
284c482cb11SRichard Henderson 
285c482cb11SRichard Henderson #define GEN_ATOMIC_HELPER(X)                                        \
286c482cb11SRichard Henderson ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr,       \
287c482cb11SRichard Henderson                  ABI_TYPE val EXTRA_ARGS)                           \
288c482cb11SRichard Henderson {                                                                   \
28934d49937SPeter Maydell     ATOMIC_MMU_DECLS;                                               \
290c482cb11SRichard Henderson     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;                           \
291d071f4cdSEmilio G. Cota     DATA_TYPE ret;                                                  \
292d071f4cdSEmilio G. Cota                                                                     \
293d071f4cdSEmilio G. Cota     ATOMIC_TRACE_RMW;                                               \
294d071f4cdSEmilio G. Cota     ret = atomic_##X(haddr, BSWAP(val));                            \
295ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;                                             \
296ec603b55SRichard Henderson     return BSWAP(ret);                                              \
297c482cb11SRichard Henderson }
298c482cb11SRichard Henderson 
299c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_and)
300c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_or)
301c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_xor)
302c482cb11SRichard Henderson GEN_ATOMIC_HELPER(and_fetch)
303c482cb11SRichard Henderson GEN_ATOMIC_HELPER(or_fetch)
304c482cb11SRichard Henderson GEN_ATOMIC_HELPER(xor_fetch)
305c482cb11SRichard Henderson 
306c482cb11SRichard Henderson #undef GEN_ATOMIC_HELPER
307c482cb11SRichard Henderson 
3085507c2bfSRichard Henderson /* These helpers are, as a whole, full barriers.  Within the helper,
3095507c2bfSRichard Henderson  * the leading barrier is explicit and the trailing barrier is within
3105507c2bfSRichard Henderson  * cmpxchg primitive.
311d071f4cdSEmilio G. Cota  *
312d071f4cdSEmilio G. Cota  * Trace this load + RMW loop as a single RMW op. This way, regardless
313d071f4cdSEmilio G. Cota  * of CF_PARALLEL's value, we'll trace just a read and a write.
3145507c2bfSRichard Henderson  */
3155507c2bfSRichard Henderson #define GEN_ATOMIC_HELPER_FN(X, FN, XDATA_TYPE, RET)                \
3165507c2bfSRichard Henderson ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr,       \
3175507c2bfSRichard Henderson                         ABI_TYPE xval EXTRA_ARGS)                   \
3185507c2bfSRichard Henderson {                                                                   \
3195507c2bfSRichard Henderson     ATOMIC_MMU_DECLS;                                               \
3205507c2bfSRichard Henderson     XDATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;                          \
3215507c2bfSRichard Henderson     XDATA_TYPE ldo, ldn, old, new, val = xval;                      \
322d071f4cdSEmilio G. Cota                                                                     \
323d071f4cdSEmilio G. Cota     ATOMIC_TRACE_RMW;                                               \
3245507c2bfSRichard Henderson     smp_mb();                                                       \
3255507c2bfSRichard Henderson     ldn = atomic_read__nocheck(haddr);                              \
3265507c2bfSRichard Henderson     do {                                                            \
3275507c2bfSRichard Henderson         ldo = ldn; old = BSWAP(ldo); new = FN(old, val);            \
3285507c2bfSRichard Henderson         ldn = atomic_cmpxchg__nocheck(haddr, ldo, BSWAP(new));      \
3295507c2bfSRichard Henderson     } while (ldo != ldn);                                           \
3305507c2bfSRichard Henderson     ATOMIC_MMU_CLEANUP;                                             \
3315507c2bfSRichard Henderson     return RET;                                                     \
3325507c2bfSRichard Henderson }
3335507c2bfSRichard Henderson 
3345507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_smin, MIN, SDATA_TYPE, old)
3355507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_umin, MIN,  DATA_TYPE, old)
3365507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_smax, MAX, SDATA_TYPE, old)
3375507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_umax, MAX,  DATA_TYPE, old)
3385507c2bfSRichard Henderson 
3395507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(smin_fetch, MIN, SDATA_TYPE, new)
3405507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(umin_fetch, MIN,  DATA_TYPE, new)
3415507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(smax_fetch, MAX, SDATA_TYPE, new)
3425507c2bfSRichard Henderson GEN_ATOMIC_HELPER_FN(umax_fetch, MAX,  DATA_TYPE, new)
3435507c2bfSRichard Henderson 
34458edf9eeSRichard Henderson /* Note that for addition, we need to use a separate cmpxchg loop instead
34558edf9eeSRichard Henderson    of bswaps for the reverse-host-endian helpers.  */
34658edf9eeSRichard Henderson #define ADD(X, Y)   (X + Y)
34758edf9eeSRichard Henderson GEN_ATOMIC_HELPER_FN(fetch_add, ADD, DATA_TYPE, old)
34858edf9eeSRichard Henderson GEN_ATOMIC_HELPER_FN(add_fetch, ADD, DATA_TYPE, new)
34958edf9eeSRichard Henderson #undef ADD
35058edf9eeSRichard Henderson 
3515507c2bfSRichard Henderson #undef GEN_ATOMIC_HELPER_FN
3527ebee43eSRichard Henderson #endif /* DATA_SIZE >= 16 */
353c482cb11SRichard Henderson 
354c482cb11SRichard Henderson #undef END
355d071f4cdSEmilio G. Cota #undef MEND
356c482cb11SRichard Henderson #endif /* DATA_SIZE > 1 */
357c482cb11SRichard Henderson 
358d071f4cdSEmilio G. Cota #undef ATOMIC_TRACE_ST
359d071f4cdSEmilio G. Cota #undef ATOMIC_TRACE_LD
360d071f4cdSEmilio G. Cota #undef ATOMIC_TRACE_RMW
361d071f4cdSEmilio G. Cota 
362c482cb11SRichard Henderson #undef BSWAP
363c482cb11SRichard Henderson #undef ABI_TYPE
364c482cb11SRichard Henderson #undef DATA_TYPE
3655507c2bfSRichard Henderson #undef SDATA_TYPE
366c482cb11SRichard Henderson #undef SUFFIX
367c482cb11SRichard Henderson #undef DATA_SIZE
368d071f4cdSEmilio G. Cota #undef SHIFT
369