xref: /freebsd/sys/contrib/ck/include/gcc/ck_pr.h (revision 9ff086544d5f85b58349e28ed36a9811b8fe5cf9)
1 /*
2  * Copyright 2010 Samy Al Bahra.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 
27 #ifndef CK_PR_GCC_H
28 #define CK_PR_GCC_H
29 
30 #ifndef CK_PR_H
31 #error Do not include this file directly, use ck_pr.h
32 #endif
33 
34 #include <ck_cc.h>
35 
36 CK_CC_INLINE static void
37 ck_pr_barrier(void)
38 {
39 
40 	__asm__ __volatile__("" ::: "memory");
41 	return;
42 }
43 
44 #ifndef CK_F_PR
45 #define CK_F_PR
46 
47 #include <ck_stdbool.h>
48 #include <ck_stdint.h>
49 
50 /*
51  * The following represent supported atomic operations.
52  * These operations may be emulated.
53  */
54 #include "ck_f_pr.h"
55 
56 #define CK_PR_ACCESS(x) (*(volatile __typeof__(x) *)&(x))
57 
58 #define CK_PR_LOAD(S, M, T)		 			\
59 	CK_CC_INLINE static T					\
60 	ck_pr_md_load_##S(const M *target)			\
61 	{							\
62 		T r;						\
63 		ck_pr_barrier();				\
64 		r = CK_PR_ACCESS(*(const T *)target);		\
65 		ck_pr_barrier();				\
66 		return (r);					\
67 	}							\
68 	CK_CC_INLINE static void				\
69 	ck_pr_md_store_##S(M *target, T v)			\
70 	{							\
71 		ck_pr_barrier();				\
72 		CK_PR_ACCESS(*(T *)target) = v;			\
73 		ck_pr_barrier();				\
74 		return;						\
75 	}
76 
77 CK_CC_INLINE static void *
78 ck_pr_md_load_ptr(const void *target)
79 {
80 	void *r;
81 
82 	ck_pr_barrier();
83 	r = CK_CC_DECONST_PTR(CK_PR_ACCESS(target));
84 	ck_pr_barrier();
85 
86 	return r;
87 }
88 
89 CK_CC_INLINE static void
90 ck_pr_md_store_ptr(void *target, const void *v)
91 {
92 
93 	ck_pr_barrier();
94 	CK_PR_ACCESS(target) = CK_CC_DECONST_PTR(v);
95 	ck_pr_barrier();
96 	return;
97 }
98 
99 #define CK_PR_LOAD_S(S, T) CK_PR_LOAD(S, T, T)
100 
101 CK_PR_LOAD_S(char, char)
102 CK_PR_LOAD_S(uint, unsigned int)
103 CK_PR_LOAD_S(int, int)
104 CK_PR_LOAD_S(double, double)
105 CK_PR_LOAD_S(64, uint64_t)
106 CK_PR_LOAD_S(32, uint32_t)
107 CK_PR_LOAD_S(16, uint16_t)
108 CK_PR_LOAD_S(8,  uint8_t)
109 
110 #undef CK_PR_LOAD_S
111 #undef CK_PR_LOAD
112 
113 CK_CC_INLINE static void
114 ck_pr_stall(void)
115 {
116 
117 	ck_pr_barrier();
118 }
119 
120 /*
121  * Load and store fences are equivalent to full fences in the GCC port.
122  */
123 #define CK_PR_FENCE(T)					\
124 	CK_CC_INLINE static void			\
125 	ck_pr_fence_strict_##T(void)			\
126 	{						\
127 		__sync_synchronize();			\
128 	}
129 
130 CK_PR_FENCE(atomic)
131 CK_PR_FENCE(atomic_atomic)
132 CK_PR_FENCE(atomic_load)
133 CK_PR_FENCE(atomic_store)
134 CK_PR_FENCE(store_atomic)
135 CK_PR_FENCE(load_atomic)
136 CK_PR_FENCE(load)
137 CK_PR_FENCE(load_load)
138 CK_PR_FENCE(load_store)
139 CK_PR_FENCE(store)
140 CK_PR_FENCE(store_store)
141 CK_PR_FENCE(store_load)
142 CK_PR_FENCE(memory)
143 CK_PR_FENCE(acquire)
144 CK_PR_FENCE(release)
145 CK_PR_FENCE(acqrel)
146 CK_PR_FENCE(lock)
147 CK_PR_FENCE(unlock)
148 
149 #undef CK_PR_FENCE
150 
151 /*
152  * Atomic compare and swap.
153  */
154 #define CK_PR_CAS(S, M, T)							\
155 	CK_CC_INLINE static bool						\
156 	ck_pr_cas_##S(M *target, T compare, T set)				\
157 	{									\
158 		bool z;								\
159 		z = __sync_bool_compare_and_swap((T *)target, compare, set);	\
160 		return z;							\
161 	}
162 
163 CK_PR_CAS(ptr, void, void *)
164 
165 #define CK_PR_CAS_S(S, T) CK_PR_CAS(S, T, T)
166 
167 CK_PR_CAS_S(char, char)
168 CK_PR_CAS_S(int, int)
169 CK_PR_CAS_S(uint, unsigned int)
170 CK_PR_CAS_S(64, uint64_t)
171 CK_PR_CAS_S(32, uint32_t)
172 CK_PR_CAS_S(16, uint16_t)
173 CK_PR_CAS_S(8,  uint8_t)
174 
175 #undef CK_PR_CAS_S
176 #undef CK_PR_CAS
177 
178 /*
179  * Compare and swap, set *v to old value of target.
180  */
181 CK_CC_INLINE static bool
182 ck_pr_cas_ptr_value(void *target, void *compare, void *set, void *v)
183 {
184 	set = __sync_val_compare_and_swap((void **)target, compare, set);
185 	*(void **)v = set;
186 	return (set == compare);
187 }
188 
189 #define CK_PR_CAS_O(S, T)						\
190 	CK_CC_INLINE static bool					\
191 	ck_pr_cas_##S##_value(T *target, T compare, T set, T *v)	\
192 	{								\
193 		set = __sync_val_compare_and_swap(target, compare, set);\
194 		*v = set;						\
195 		return (set == compare);				\
196 	}
197 
198 CK_PR_CAS_O(char, char)
199 CK_PR_CAS_O(int, int)
200 CK_PR_CAS_O(uint, unsigned int)
201 CK_PR_CAS_O(64, uint64_t)
202 CK_PR_CAS_O(32, uint32_t)
203 CK_PR_CAS_O(16, uint16_t)
204 CK_PR_CAS_O(8,  uint8_t)
205 
206 #undef CK_PR_CAS_O
207 
208 /*
209  * Atomic fetch-and-add operations.
210  */
211 #define CK_PR_FAA(S, M, T)					\
212 	CK_CC_INLINE static T					\
213 	ck_pr_faa_##S(M *target, T d)				\
214 	{							\
215 		d = __sync_fetch_and_add((T *)target, d);	\
216 		return (d);					\
217 	}
218 
219 CK_PR_FAA(ptr, void, void *)
220 
221 #define CK_PR_FAA_S(S, T) CK_PR_FAA(S, T, T)
222 
223 CK_PR_FAA_S(char, char)
224 CK_PR_FAA_S(uint, unsigned int)
225 CK_PR_FAA_S(int, int)
226 CK_PR_FAA_S(64, uint64_t)
227 CK_PR_FAA_S(32, uint32_t)
228 CK_PR_FAA_S(16, uint16_t)
229 CK_PR_FAA_S(8,  uint8_t)
230 
231 #undef CK_PR_FAA_S
232 #undef CK_PR_FAA
233 
234 /*
235  * Atomic store-only binary operations.
236  */
237 #define CK_PR_BINARY(K, S, M, T)				\
238 	CK_CC_INLINE static void				\
239 	ck_pr_##K##_##S(M *target, T d)				\
240 	{							\
241 		d = __sync_fetch_and_##K((T *)target, d);	\
242 		return;						\
243 	}
244 
245 #define CK_PR_BINARY_S(K, S, T) CK_PR_BINARY(K, S, T, T)
246 
247 #define CK_PR_GENERATE(K)			\
248 	CK_PR_BINARY(K, ptr, void, void *)	\
249 	CK_PR_BINARY_S(K, char, char)		\
250 	CK_PR_BINARY_S(K, int, int)		\
251 	CK_PR_BINARY_S(K, uint, unsigned int)	\
252 	CK_PR_BINARY_S(K, 64, uint64_t)		\
253 	CK_PR_BINARY_S(K, 32, uint32_t)		\
254 	CK_PR_BINARY_S(K, 16, uint16_t)		\
255 	CK_PR_BINARY_S(K, 8, uint8_t)
256 
257 CK_PR_GENERATE(add)
258 CK_PR_GENERATE(sub)
259 CK_PR_GENERATE(and)
260 CK_PR_GENERATE(or)
261 CK_PR_GENERATE(xor)
262 
263 #undef CK_PR_GENERATE
264 #undef CK_PR_BINARY_S
265 #undef CK_PR_BINARY
266 
267 #define CK_PR_UNARY(S, M, T)			\
268 	CK_CC_INLINE static void		\
269 	ck_pr_inc_##S(M *target)		\
270 	{					\
271 		ck_pr_add_##S(target, (T)1);	\
272 		return;				\
273 	}					\
274 	CK_CC_INLINE static void		\
275 	ck_pr_dec_##S(M *target)		\
276 	{					\
277 		ck_pr_sub_##S(target, (T)1);	\
278 		return;				\
279 	}
280 
281 #define CK_PR_UNARY_S(S, M) CK_PR_UNARY(S, M, M)
282 
283 CK_PR_UNARY(ptr, void, void *)
284 CK_PR_UNARY_S(char, char)
285 CK_PR_UNARY_S(int, int)
286 CK_PR_UNARY_S(uint, unsigned int)
287 CK_PR_UNARY_S(64, uint64_t)
288 CK_PR_UNARY_S(32, uint32_t)
289 CK_PR_UNARY_S(16, uint16_t)
290 CK_PR_UNARY_S(8, uint8_t)
291 
292 #undef CK_PR_UNARY_S
293 #undef CK_PR_UNARY
294 #endif /* !CK_F_PR */
295 #endif /* CK_PR_GCC_H */
296