xref: /qemu/accel/tcg/atomic_template.h (revision ec603b5584fa71213ef8f324fe89e4b27cc9d2bc)
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
10c482cb11SRichard Henderson  * version 2 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 
217ebee43eSRichard Henderson #if DATA_SIZE == 16
227ebee43eSRichard Henderson # define SUFFIX     o
237ebee43eSRichard Henderson # define DATA_TYPE  Int128
247ebee43eSRichard Henderson # define BSWAP      bswap128
257ebee43eSRichard Henderson #elif DATA_SIZE == 8
26c482cb11SRichard Henderson # define SUFFIX     q
27c482cb11SRichard Henderson # define DATA_TYPE  uint64_t
28c482cb11SRichard Henderson # define BSWAP      bswap64
29c482cb11SRichard Henderson #elif DATA_SIZE == 4
30c482cb11SRichard Henderson # define SUFFIX     l
31c482cb11SRichard Henderson # define DATA_TYPE  uint32_t
32c482cb11SRichard Henderson # define BSWAP      bswap32
33c482cb11SRichard Henderson #elif DATA_SIZE == 2
34c482cb11SRichard Henderson # define SUFFIX     w
35c482cb11SRichard Henderson # define DATA_TYPE  uint16_t
36c482cb11SRichard Henderson # define BSWAP      bswap16
37c482cb11SRichard Henderson #elif DATA_SIZE == 1
38c482cb11SRichard Henderson # define SUFFIX     b
39c482cb11SRichard Henderson # define DATA_TYPE  uint8_t
40c482cb11SRichard Henderson # define BSWAP
41c482cb11SRichard Henderson #else
42c482cb11SRichard Henderson # error unsupported data size
43c482cb11SRichard Henderson #endif
44c482cb11SRichard Henderson 
45c482cb11SRichard Henderson #if DATA_SIZE >= 4
46c482cb11SRichard Henderson # define ABI_TYPE  DATA_TYPE
47c482cb11SRichard Henderson #else
48c482cb11SRichard Henderson # define ABI_TYPE  uint32_t
49c482cb11SRichard Henderson #endif
50c482cb11SRichard Henderson 
51c482cb11SRichard Henderson /* Define host-endian atomic operations.  Note that END is used within
52c482cb11SRichard Henderson    the ATOMIC_NAME macro, and redefined below.  */
53c482cb11SRichard Henderson #if DATA_SIZE == 1
54c482cb11SRichard Henderson # define END
55c482cb11SRichard Henderson #elif defined(HOST_WORDS_BIGENDIAN)
56c482cb11SRichard Henderson # define END  _be
57c482cb11SRichard Henderson #else
58c482cb11SRichard Henderson # define END  _le
59c482cb11SRichard Henderson #endif
60c482cb11SRichard Henderson 
61c482cb11SRichard Henderson ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr,
62c482cb11SRichard Henderson                               ABI_TYPE cmpv, ABI_TYPE newv EXTRA_ARGS)
63c482cb11SRichard Henderson {
64c482cb11SRichard Henderson     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
65*ec603b55SRichard Henderson     DATA_TYPE ret = atomic_cmpxchg__nocheck(haddr, cmpv, newv);
66*ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
67*ec603b55SRichard Henderson     return ret;
68c482cb11SRichard Henderson }
69c482cb11SRichard Henderson 
707ebee43eSRichard Henderson #if DATA_SIZE >= 16
717ebee43eSRichard Henderson ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr EXTRA_ARGS)
727ebee43eSRichard Henderson {
737ebee43eSRichard Henderson     DATA_TYPE val, *haddr = ATOMIC_MMU_LOOKUP;
747ebee43eSRichard Henderson     __atomic_load(haddr, &val, __ATOMIC_RELAXED);
75*ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
767ebee43eSRichard Henderson     return val;
777ebee43eSRichard Henderson }
787ebee43eSRichard Henderson 
797ebee43eSRichard Henderson void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr,
807ebee43eSRichard Henderson                      ABI_TYPE val EXTRA_ARGS)
817ebee43eSRichard Henderson {
827ebee43eSRichard Henderson     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
837ebee43eSRichard Henderson     __atomic_store(haddr, &val, __ATOMIC_RELAXED);
84*ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
857ebee43eSRichard Henderson }
867ebee43eSRichard Henderson #else
87c482cb11SRichard Henderson ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr,
88c482cb11SRichard Henderson                            ABI_TYPE val EXTRA_ARGS)
89c482cb11SRichard Henderson {
90c482cb11SRichard Henderson     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
91*ec603b55SRichard Henderson     DATA_TYPE ret = atomic_xchg__nocheck(haddr, val);
92*ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
93*ec603b55SRichard Henderson     return ret;
94c482cb11SRichard Henderson }
95c482cb11SRichard Henderson 
96c482cb11SRichard Henderson #define GEN_ATOMIC_HELPER(X)                                        \
97c482cb11SRichard Henderson ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr,       \
98c482cb11SRichard Henderson                  ABI_TYPE val EXTRA_ARGS)                           \
99c482cb11SRichard Henderson {                                                                   \
100c482cb11SRichard Henderson     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;                           \
101*ec603b55SRichard Henderson     DATA_TYPE ret = atomic_##X(haddr, val);                         \
102*ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;                                             \
103*ec603b55SRichard Henderson     return ret;                                                     \
104*ec603b55SRichard Henderson }
105c482cb11SRichard Henderson 
106c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_add)
107c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_and)
108c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_or)
109c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_xor)
110c482cb11SRichard Henderson GEN_ATOMIC_HELPER(add_fetch)
111c482cb11SRichard Henderson GEN_ATOMIC_HELPER(and_fetch)
112c482cb11SRichard Henderson GEN_ATOMIC_HELPER(or_fetch)
113c482cb11SRichard Henderson GEN_ATOMIC_HELPER(xor_fetch)
114c482cb11SRichard Henderson 
115c482cb11SRichard Henderson #undef GEN_ATOMIC_HELPER
1167ebee43eSRichard Henderson #endif /* DATA SIZE >= 16 */
1177ebee43eSRichard Henderson 
118c482cb11SRichard Henderson #undef END
119c482cb11SRichard Henderson 
120c482cb11SRichard Henderson #if DATA_SIZE > 1
121c482cb11SRichard Henderson 
122c482cb11SRichard Henderson /* Define reverse-host-endian atomic operations.  Note that END is used
123c482cb11SRichard Henderson    within the ATOMIC_NAME macro.  */
124c482cb11SRichard Henderson #ifdef HOST_WORDS_BIGENDIAN
125c482cb11SRichard Henderson # define END  _le
126c482cb11SRichard Henderson #else
127c482cb11SRichard Henderson # define END  _be
128c482cb11SRichard Henderson #endif
129c482cb11SRichard Henderson 
130c482cb11SRichard Henderson ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr,
131c482cb11SRichard Henderson                               ABI_TYPE cmpv, ABI_TYPE newv EXTRA_ARGS)
132c482cb11SRichard Henderson {
133c482cb11SRichard Henderson     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
134*ec603b55SRichard Henderson     DATA_TYPE ret = atomic_cmpxchg__nocheck(haddr, BSWAP(cmpv), BSWAP(newv));
135*ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
136*ec603b55SRichard Henderson     return BSWAP(ret);
137c482cb11SRichard Henderson }
138c482cb11SRichard Henderson 
1397ebee43eSRichard Henderson #if DATA_SIZE >= 16
1407ebee43eSRichard Henderson ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr EXTRA_ARGS)
1417ebee43eSRichard Henderson {
1427ebee43eSRichard Henderson     DATA_TYPE val, *haddr = ATOMIC_MMU_LOOKUP;
1437ebee43eSRichard Henderson     __atomic_load(haddr, &val, __ATOMIC_RELAXED);
144*ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
1457ebee43eSRichard Henderson     return BSWAP(val);
1467ebee43eSRichard Henderson }
1477ebee43eSRichard Henderson 
1487ebee43eSRichard Henderson void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr,
1497ebee43eSRichard Henderson                      ABI_TYPE val EXTRA_ARGS)
1507ebee43eSRichard Henderson {
1517ebee43eSRichard Henderson     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
1527ebee43eSRichard Henderson     val = BSWAP(val);
1537ebee43eSRichard Henderson     __atomic_store(haddr, &val, __ATOMIC_RELAXED);
154*ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
1557ebee43eSRichard Henderson }
1567ebee43eSRichard Henderson #else
157c482cb11SRichard Henderson ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr,
158c482cb11SRichard Henderson                            ABI_TYPE val EXTRA_ARGS)
159c482cb11SRichard Henderson {
160c482cb11SRichard Henderson     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
161*ec603b55SRichard Henderson     ABI_TYPE ret = atomic_xchg__nocheck(haddr, BSWAP(val));
162*ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;
163*ec603b55SRichard Henderson     return BSWAP(ret);
164c482cb11SRichard Henderson }
165c482cb11SRichard Henderson 
166c482cb11SRichard Henderson #define GEN_ATOMIC_HELPER(X)                                        \
167c482cb11SRichard Henderson ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr,       \
168c482cb11SRichard Henderson                  ABI_TYPE val EXTRA_ARGS)                           \
169c482cb11SRichard Henderson {                                                                   \
170c482cb11SRichard Henderson     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;                           \
171*ec603b55SRichard Henderson     DATA_TYPE ret = atomic_##X(haddr, BSWAP(val));                  \
172*ec603b55SRichard Henderson     ATOMIC_MMU_CLEANUP;                                             \
173*ec603b55SRichard Henderson     return BSWAP(ret);                                              \
174c482cb11SRichard Henderson }
175c482cb11SRichard Henderson 
176c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_and)
177c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_or)
178c482cb11SRichard Henderson GEN_ATOMIC_HELPER(fetch_xor)
179c482cb11SRichard Henderson GEN_ATOMIC_HELPER(and_fetch)
180c482cb11SRichard Henderson GEN_ATOMIC_HELPER(or_fetch)
181c482cb11SRichard Henderson GEN_ATOMIC_HELPER(xor_fetch)
182c482cb11SRichard Henderson 
183c482cb11SRichard Henderson #undef GEN_ATOMIC_HELPER
184c482cb11SRichard Henderson 
185c482cb11SRichard Henderson /* Note that for addition, we need to use a separate cmpxchg loop instead
186c482cb11SRichard Henderson    of bswaps for the reverse-host-endian helpers.  */
187c482cb11SRichard Henderson ABI_TYPE ATOMIC_NAME(fetch_add)(CPUArchState *env, target_ulong addr,
188c482cb11SRichard Henderson                          ABI_TYPE val EXTRA_ARGS)
189c482cb11SRichard Henderson {
190c482cb11SRichard Henderson     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
191c482cb11SRichard Henderson     DATA_TYPE ldo, ldn, ret, sto;
192c482cb11SRichard Henderson 
193c482cb11SRichard Henderson     ldo = atomic_read__nocheck(haddr);
194c482cb11SRichard Henderson     while (1) {
195c482cb11SRichard Henderson         ret = BSWAP(ldo);
196c482cb11SRichard Henderson         sto = BSWAP(ret + val);
197c482cb11SRichard Henderson         ldn = atomic_cmpxchg__nocheck(haddr, ldo, sto);
198c482cb11SRichard Henderson         if (ldn == ldo) {
199*ec603b55SRichard Henderson             ATOMIC_MMU_CLEANUP;
200c482cb11SRichard Henderson             return ret;
201c482cb11SRichard Henderson         }
202c482cb11SRichard Henderson         ldo = ldn;
203c482cb11SRichard Henderson     }
204c482cb11SRichard Henderson }
205c482cb11SRichard Henderson 
206c482cb11SRichard Henderson ABI_TYPE ATOMIC_NAME(add_fetch)(CPUArchState *env, target_ulong addr,
207c482cb11SRichard Henderson                          ABI_TYPE val EXTRA_ARGS)
208c482cb11SRichard Henderson {
209c482cb11SRichard Henderson     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
210c482cb11SRichard Henderson     DATA_TYPE ldo, ldn, ret, sto;
211c482cb11SRichard Henderson 
212c482cb11SRichard Henderson     ldo = atomic_read__nocheck(haddr);
213c482cb11SRichard Henderson     while (1) {
214c482cb11SRichard Henderson         ret = BSWAP(ldo) + val;
215c482cb11SRichard Henderson         sto = BSWAP(ret);
216c482cb11SRichard Henderson         ldn = atomic_cmpxchg__nocheck(haddr, ldo, sto);
217c482cb11SRichard Henderson         if (ldn == ldo) {
218*ec603b55SRichard Henderson             ATOMIC_MMU_CLEANUP;
219c482cb11SRichard Henderson             return ret;
220c482cb11SRichard Henderson         }
221c482cb11SRichard Henderson         ldo = ldn;
222c482cb11SRichard Henderson     }
223c482cb11SRichard Henderson }
2247ebee43eSRichard Henderson #endif /* DATA_SIZE >= 16 */
225c482cb11SRichard Henderson 
226c482cb11SRichard Henderson #undef END
227c482cb11SRichard Henderson #endif /* DATA_SIZE > 1 */
228c482cb11SRichard Henderson 
229c482cb11SRichard Henderson #undef BSWAP
230c482cb11SRichard Henderson #undef ABI_TYPE
231c482cb11SRichard Henderson #undef DATA_TYPE
232c482cb11SRichard Henderson #undef SUFFIX
233c482cb11SRichard Henderson #undef DATA_SIZE
234