xref: /openbmc/qemu/accel/tcg/atomic_template.h (revision 10f7d4d53d54fbe054333aa8e75f67f20052647a)
1*10f7d4d5SPhilippe Mathieu-Daudé /*
2*10f7d4d5SPhilippe Mathieu-Daudé  * Atomic helper templates
3*10f7d4d5SPhilippe Mathieu-Daudé  * Included from tcg-runtime.c and cputlb.c.
4*10f7d4d5SPhilippe Mathieu-Daudé  *
5*10f7d4d5SPhilippe Mathieu-Daudé  * Copyright (c) 2016 Red Hat, Inc
6*10f7d4d5SPhilippe Mathieu-Daudé  *
7*10f7d4d5SPhilippe Mathieu-Daudé  * This library is free software; you can redistribute it and/or
8*10f7d4d5SPhilippe Mathieu-Daudé  * modify it under the terms of the GNU Lesser General Public
9*10f7d4d5SPhilippe Mathieu-Daudé  * License as published by the Free Software Foundation; either
10*10f7d4d5SPhilippe Mathieu-Daudé  * version 2 of the License, or (at your option) any later version.
11*10f7d4d5SPhilippe Mathieu-Daudé  *
12*10f7d4d5SPhilippe Mathieu-Daudé  * This library is distributed in the hope that it will be useful,
13*10f7d4d5SPhilippe Mathieu-Daudé  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14*10f7d4d5SPhilippe Mathieu-Daudé  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15*10f7d4d5SPhilippe Mathieu-Daudé  * Lesser General Public License for more details.
16*10f7d4d5SPhilippe Mathieu-Daudé  *
17*10f7d4d5SPhilippe Mathieu-Daudé  * You should have received a copy of the GNU Lesser General Public
18*10f7d4d5SPhilippe Mathieu-Daudé  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19*10f7d4d5SPhilippe Mathieu-Daudé  */
20*10f7d4d5SPhilippe Mathieu-Daudé 
21*10f7d4d5SPhilippe Mathieu-Daudé #if DATA_SIZE == 16
22*10f7d4d5SPhilippe Mathieu-Daudé # define SUFFIX     o
23*10f7d4d5SPhilippe Mathieu-Daudé # define DATA_TYPE  Int128
24*10f7d4d5SPhilippe Mathieu-Daudé # define BSWAP      bswap128
25*10f7d4d5SPhilippe Mathieu-Daudé #elif DATA_SIZE == 8
26*10f7d4d5SPhilippe Mathieu-Daudé # define SUFFIX     q
27*10f7d4d5SPhilippe Mathieu-Daudé # define DATA_TYPE  uint64_t
28*10f7d4d5SPhilippe Mathieu-Daudé # define BSWAP      bswap64
29*10f7d4d5SPhilippe Mathieu-Daudé #elif DATA_SIZE == 4
30*10f7d4d5SPhilippe Mathieu-Daudé # define SUFFIX     l
31*10f7d4d5SPhilippe Mathieu-Daudé # define DATA_TYPE  uint32_t
32*10f7d4d5SPhilippe Mathieu-Daudé # define BSWAP      bswap32
33*10f7d4d5SPhilippe Mathieu-Daudé #elif DATA_SIZE == 2
34*10f7d4d5SPhilippe Mathieu-Daudé # define SUFFIX     w
35*10f7d4d5SPhilippe Mathieu-Daudé # define DATA_TYPE  uint16_t
36*10f7d4d5SPhilippe Mathieu-Daudé # define BSWAP      bswap16
37*10f7d4d5SPhilippe Mathieu-Daudé #elif DATA_SIZE == 1
38*10f7d4d5SPhilippe Mathieu-Daudé # define SUFFIX     b
39*10f7d4d5SPhilippe Mathieu-Daudé # define DATA_TYPE  uint8_t
40*10f7d4d5SPhilippe Mathieu-Daudé # define BSWAP
41*10f7d4d5SPhilippe Mathieu-Daudé #else
42*10f7d4d5SPhilippe Mathieu-Daudé # error unsupported data size
43*10f7d4d5SPhilippe Mathieu-Daudé #endif
44*10f7d4d5SPhilippe Mathieu-Daudé 
45*10f7d4d5SPhilippe Mathieu-Daudé #if DATA_SIZE >= 4
46*10f7d4d5SPhilippe Mathieu-Daudé # define ABI_TYPE  DATA_TYPE
47*10f7d4d5SPhilippe Mathieu-Daudé #else
48*10f7d4d5SPhilippe Mathieu-Daudé # define ABI_TYPE  uint32_t
49*10f7d4d5SPhilippe Mathieu-Daudé #endif
50*10f7d4d5SPhilippe Mathieu-Daudé 
51*10f7d4d5SPhilippe Mathieu-Daudé /* Define host-endian atomic operations.  Note that END is used within
52*10f7d4d5SPhilippe Mathieu-Daudé    the ATOMIC_NAME macro, and redefined below.  */
53*10f7d4d5SPhilippe Mathieu-Daudé #if DATA_SIZE == 1
54*10f7d4d5SPhilippe Mathieu-Daudé # define END
55*10f7d4d5SPhilippe Mathieu-Daudé #elif defined(HOST_WORDS_BIGENDIAN)
56*10f7d4d5SPhilippe Mathieu-Daudé # define END  _be
57*10f7d4d5SPhilippe Mathieu-Daudé #else
58*10f7d4d5SPhilippe Mathieu-Daudé # define END  _le
59*10f7d4d5SPhilippe Mathieu-Daudé #endif
60*10f7d4d5SPhilippe Mathieu-Daudé 
61*10f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr,
62*10f7d4d5SPhilippe Mathieu-Daudé                               ABI_TYPE cmpv, ABI_TYPE newv EXTRA_ARGS)
63*10f7d4d5SPhilippe Mathieu-Daudé {
64*10f7d4d5SPhilippe Mathieu-Daudé     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
65*10f7d4d5SPhilippe Mathieu-Daudé     return atomic_cmpxchg__nocheck(haddr, cmpv, newv);
66*10f7d4d5SPhilippe Mathieu-Daudé }
67*10f7d4d5SPhilippe Mathieu-Daudé 
68*10f7d4d5SPhilippe Mathieu-Daudé #if DATA_SIZE >= 16
69*10f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr EXTRA_ARGS)
70*10f7d4d5SPhilippe Mathieu-Daudé {
71*10f7d4d5SPhilippe Mathieu-Daudé     DATA_TYPE val, *haddr = ATOMIC_MMU_LOOKUP;
72*10f7d4d5SPhilippe Mathieu-Daudé     __atomic_load(haddr, &val, __ATOMIC_RELAXED);
73*10f7d4d5SPhilippe Mathieu-Daudé     return val;
74*10f7d4d5SPhilippe Mathieu-Daudé }
75*10f7d4d5SPhilippe Mathieu-Daudé 
76*10f7d4d5SPhilippe Mathieu-Daudé void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr,
77*10f7d4d5SPhilippe Mathieu-Daudé                      ABI_TYPE val EXTRA_ARGS)
78*10f7d4d5SPhilippe Mathieu-Daudé {
79*10f7d4d5SPhilippe Mathieu-Daudé     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
80*10f7d4d5SPhilippe Mathieu-Daudé     __atomic_store(haddr, &val, __ATOMIC_RELAXED);
81*10f7d4d5SPhilippe Mathieu-Daudé }
82*10f7d4d5SPhilippe Mathieu-Daudé #else
83*10f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr,
84*10f7d4d5SPhilippe Mathieu-Daudé                            ABI_TYPE val EXTRA_ARGS)
85*10f7d4d5SPhilippe Mathieu-Daudé {
86*10f7d4d5SPhilippe Mathieu-Daudé     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
87*10f7d4d5SPhilippe Mathieu-Daudé     return atomic_xchg__nocheck(haddr, val);
88*10f7d4d5SPhilippe Mathieu-Daudé }
89*10f7d4d5SPhilippe Mathieu-Daudé 
90*10f7d4d5SPhilippe Mathieu-Daudé #define GEN_ATOMIC_HELPER(X)                                        \
91*10f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr,       \
92*10f7d4d5SPhilippe Mathieu-Daudé                  ABI_TYPE val EXTRA_ARGS)                           \
93*10f7d4d5SPhilippe Mathieu-Daudé {                                                                   \
94*10f7d4d5SPhilippe Mathieu-Daudé     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;                           \
95*10f7d4d5SPhilippe Mathieu-Daudé     return atomic_##X(haddr, val);                                  \
96*10f7d4d5SPhilippe Mathieu-Daudé }                                                                   \
97*10f7d4d5SPhilippe Mathieu-Daudé 
98*10f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_add)
99*10f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_and)
100*10f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_or)
101*10f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_xor)
102*10f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(add_fetch)
103*10f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(and_fetch)
104*10f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(or_fetch)
105*10f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(xor_fetch)
106*10f7d4d5SPhilippe Mathieu-Daudé 
107*10f7d4d5SPhilippe Mathieu-Daudé #undef GEN_ATOMIC_HELPER
108*10f7d4d5SPhilippe Mathieu-Daudé #endif /* DATA SIZE >= 16 */
109*10f7d4d5SPhilippe Mathieu-Daudé 
110*10f7d4d5SPhilippe Mathieu-Daudé #undef END
111*10f7d4d5SPhilippe Mathieu-Daudé 
112*10f7d4d5SPhilippe Mathieu-Daudé #if DATA_SIZE > 1
113*10f7d4d5SPhilippe Mathieu-Daudé 
114*10f7d4d5SPhilippe Mathieu-Daudé /* Define reverse-host-endian atomic operations.  Note that END is used
115*10f7d4d5SPhilippe Mathieu-Daudé    within the ATOMIC_NAME macro.  */
116*10f7d4d5SPhilippe Mathieu-Daudé #ifdef HOST_WORDS_BIGENDIAN
117*10f7d4d5SPhilippe Mathieu-Daudé # define END  _le
118*10f7d4d5SPhilippe Mathieu-Daudé #else
119*10f7d4d5SPhilippe Mathieu-Daudé # define END  _be
120*10f7d4d5SPhilippe Mathieu-Daudé #endif
121*10f7d4d5SPhilippe Mathieu-Daudé 
122*10f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr,
123*10f7d4d5SPhilippe Mathieu-Daudé                               ABI_TYPE cmpv, ABI_TYPE newv EXTRA_ARGS)
124*10f7d4d5SPhilippe Mathieu-Daudé {
125*10f7d4d5SPhilippe Mathieu-Daudé     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
126*10f7d4d5SPhilippe Mathieu-Daudé     return BSWAP(atomic_cmpxchg__nocheck(haddr, BSWAP(cmpv), BSWAP(newv)));
127*10f7d4d5SPhilippe Mathieu-Daudé }
128*10f7d4d5SPhilippe Mathieu-Daudé 
129*10f7d4d5SPhilippe Mathieu-Daudé #if DATA_SIZE >= 16
130*10f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr EXTRA_ARGS)
131*10f7d4d5SPhilippe Mathieu-Daudé {
132*10f7d4d5SPhilippe Mathieu-Daudé     DATA_TYPE val, *haddr = ATOMIC_MMU_LOOKUP;
133*10f7d4d5SPhilippe Mathieu-Daudé     __atomic_load(haddr, &val, __ATOMIC_RELAXED);
134*10f7d4d5SPhilippe Mathieu-Daudé     return BSWAP(val);
135*10f7d4d5SPhilippe Mathieu-Daudé }
136*10f7d4d5SPhilippe Mathieu-Daudé 
137*10f7d4d5SPhilippe Mathieu-Daudé void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr,
138*10f7d4d5SPhilippe Mathieu-Daudé                      ABI_TYPE val EXTRA_ARGS)
139*10f7d4d5SPhilippe Mathieu-Daudé {
140*10f7d4d5SPhilippe Mathieu-Daudé     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
141*10f7d4d5SPhilippe Mathieu-Daudé     val = BSWAP(val);
142*10f7d4d5SPhilippe Mathieu-Daudé     __atomic_store(haddr, &val, __ATOMIC_RELAXED);
143*10f7d4d5SPhilippe Mathieu-Daudé }
144*10f7d4d5SPhilippe Mathieu-Daudé #else
145*10f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr,
146*10f7d4d5SPhilippe Mathieu-Daudé                            ABI_TYPE val EXTRA_ARGS)
147*10f7d4d5SPhilippe Mathieu-Daudé {
148*10f7d4d5SPhilippe Mathieu-Daudé     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
149*10f7d4d5SPhilippe Mathieu-Daudé     return BSWAP(atomic_xchg__nocheck(haddr, BSWAP(val)));
150*10f7d4d5SPhilippe Mathieu-Daudé }
151*10f7d4d5SPhilippe Mathieu-Daudé 
152*10f7d4d5SPhilippe Mathieu-Daudé #define GEN_ATOMIC_HELPER(X)                                        \
153*10f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr,       \
154*10f7d4d5SPhilippe Mathieu-Daudé                  ABI_TYPE val EXTRA_ARGS)                           \
155*10f7d4d5SPhilippe Mathieu-Daudé {                                                                   \
156*10f7d4d5SPhilippe Mathieu-Daudé     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;                           \
157*10f7d4d5SPhilippe Mathieu-Daudé     return BSWAP(atomic_##X(haddr, BSWAP(val)));                    \
158*10f7d4d5SPhilippe Mathieu-Daudé }
159*10f7d4d5SPhilippe Mathieu-Daudé 
160*10f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_and)
161*10f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_or)
162*10f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(fetch_xor)
163*10f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(and_fetch)
164*10f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(or_fetch)
165*10f7d4d5SPhilippe Mathieu-Daudé GEN_ATOMIC_HELPER(xor_fetch)
166*10f7d4d5SPhilippe Mathieu-Daudé 
167*10f7d4d5SPhilippe Mathieu-Daudé #undef GEN_ATOMIC_HELPER
168*10f7d4d5SPhilippe Mathieu-Daudé 
169*10f7d4d5SPhilippe Mathieu-Daudé /* Note that for addition, we need to use a separate cmpxchg loop instead
170*10f7d4d5SPhilippe Mathieu-Daudé    of bswaps for the reverse-host-endian helpers.  */
171*10f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(fetch_add)(CPUArchState *env, target_ulong addr,
172*10f7d4d5SPhilippe Mathieu-Daudé                          ABI_TYPE val EXTRA_ARGS)
173*10f7d4d5SPhilippe Mathieu-Daudé {
174*10f7d4d5SPhilippe Mathieu-Daudé     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
175*10f7d4d5SPhilippe Mathieu-Daudé     DATA_TYPE ldo, ldn, ret, sto;
176*10f7d4d5SPhilippe Mathieu-Daudé 
177*10f7d4d5SPhilippe Mathieu-Daudé     ldo = atomic_read__nocheck(haddr);
178*10f7d4d5SPhilippe Mathieu-Daudé     while (1) {
179*10f7d4d5SPhilippe Mathieu-Daudé         ret = BSWAP(ldo);
180*10f7d4d5SPhilippe Mathieu-Daudé         sto = BSWAP(ret + val);
181*10f7d4d5SPhilippe Mathieu-Daudé         ldn = atomic_cmpxchg__nocheck(haddr, ldo, sto);
182*10f7d4d5SPhilippe Mathieu-Daudé         if (ldn == ldo) {
183*10f7d4d5SPhilippe Mathieu-Daudé             return ret;
184*10f7d4d5SPhilippe Mathieu-Daudé         }
185*10f7d4d5SPhilippe Mathieu-Daudé         ldo = ldn;
186*10f7d4d5SPhilippe Mathieu-Daudé     }
187*10f7d4d5SPhilippe Mathieu-Daudé }
188*10f7d4d5SPhilippe Mathieu-Daudé 
189*10f7d4d5SPhilippe Mathieu-Daudé ABI_TYPE ATOMIC_NAME(add_fetch)(CPUArchState *env, target_ulong addr,
190*10f7d4d5SPhilippe Mathieu-Daudé                          ABI_TYPE val EXTRA_ARGS)
191*10f7d4d5SPhilippe Mathieu-Daudé {
192*10f7d4d5SPhilippe Mathieu-Daudé     DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP;
193*10f7d4d5SPhilippe Mathieu-Daudé     DATA_TYPE ldo, ldn, ret, sto;
194*10f7d4d5SPhilippe Mathieu-Daudé 
195*10f7d4d5SPhilippe Mathieu-Daudé     ldo = atomic_read__nocheck(haddr);
196*10f7d4d5SPhilippe Mathieu-Daudé     while (1) {
197*10f7d4d5SPhilippe Mathieu-Daudé         ret = BSWAP(ldo) + val;
198*10f7d4d5SPhilippe Mathieu-Daudé         sto = BSWAP(ret);
199*10f7d4d5SPhilippe Mathieu-Daudé         ldn = atomic_cmpxchg__nocheck(haddr, ldo, sto);
200*10f7d4d5SPhilippe Mathieu-Daudé         if (ldn == ldo) {
201*10f7d4d5SPhilippe Mathieu-Daudé             return ret;
202*10f7d4d5SPhilippe Mathieu-Daudé         }
203*10f7d4d5SPhilippe Mathieu-Daudé         ldo = ldn;
204*10f7d4d5SPhilippe Mathieu-Daudé     }
205*10f7d4d5SPhilippe Mathieu-Daudé }
206*10f7d4d5SPhilippe Mathieu-Daudé #endif /* DATA_SIZE >= 16 */
207*10f7d4d5SPhilippe Mathieu-Daudé 
208*10f7d4d5SPhilippe Mathieu-Daudé #undef END
209*10f7d4d5SPhilippe Mathieu-Daudé #endif /* DATA_SIZE > 1 */
210*10f7d4d5SPhilippe Mathieu-Daudé 
211*10f7d4d5SPhilippe Mathieu-Daudé #undef BSWAP
212*10f7d4d5SPhilippe Mathieu-Daudé #undef ABI_TYPE
213*10f7d4d5SPhilippe Mathieu-Daudé #undef DATA_TYPE
214*10f7d4d5SPhilippe Mathieu-Daudé #undef SUFFIX
215*10f7d4d5SPhilippe Mathieu-Daudé #undef DATA_SIZE
216