845e517a42fb31df4da1e2d3ad5fbc71f46e4e89
[blender.git] / intern / atomic / atomic_ops.h
1 /*
2  * Adopted from jemalloc with this license:
3  *
4  * Copyright (C) 2002-2013 Jason Evans <jasone@canonware.com>.
5  * All rights reserved.
6  * Copyright (C) 2007-2012 Mozilla Foundation.  All rights reserved.
7  * Copyright (C) 2009-2013 Facebook, Inc.  All rights reserved.
8
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions are met:
11  * 1. Redistributions of source code must retain the above copyright notice(s),
12  *    this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright notice(s),
14  *    this list of conditions and the following disclaimer in the documentation
15  *    and/or other materials provided with the distribution.
16
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY EXPRESS
18  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO
20  * EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
26  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #ifndef ATOMIC_OPS_H__
30 #define ATOMIC_OPS_H__
31
32 /* needed for int types */
33 #include "../../source/blender/blenlib/BLI_sys_types.h"
34
35 /* little macro so inline keyword works */
36 #if defined(_MSC_VER)
37 #  define ATOMIC_INLINE static __forceinline
38 #else
39 #  if (defined(__APPLE__) && defined(__ppc__))
40 /* static inline __attribute__ here breaks osx ppc gcc42 build */
41 #    define ATOMIC_INLINE static __attribute__((always_inline))
42 #  else
43 #    define ATOMIC_INLINE static inline __attribute__((always_inline))
44 #  endif
45 #endif
46
47 #if defined(_M_X64) || defined(__amd64__) || defined(__x86_64__)
48 #  define LG_SIZEOF_PTR 3
49 #  define LG_SIZEOF_INT 3
50 #else
51 #  define LG_SIZEOF_PTR 2
52 #  define LG_SIZEOF_INT 2
53 #endif
54
55 /******************************************************************************/
56 /* 64-bit operations. */
57 #if (LG_SIZEOF_PTR == 3 || LG_SIZEOF_INT == 3)
58 #  ifdef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8
59 ATOMIC_INLINE uint64_t
60 atomic_add_uint64(uint64_t *p, uint64_t x)
61 {
62         return (__sync_add_and_fetch(p, x));
63 }
64
65 ATOMIC_INLINE uint64_t
66 atomic_sub_uint64(uint64_t *p, uint64_t x)
67 {
68         return (__sync_sub_and_fetch(p, x));
69 }
70 #elif (defined(_MSC_VER))
71 ATOMIC_INLINE uint64_t
72 atomic_add_uint64(uint64_t *p, uint64_t x)
73 {
74         return (InterlockedExchangeAdd64(p, x));
75 }
76
77 ATOMIC_INLINE uint64_t
78 atomic_sub_uint64(uint64_t *p, uint64_t x)
79 {
80         return (InterlockedExchangeAdd64(p, -((int64_t)x)));
81 }
82 #elif (defined(JEMALLOC_OSATOMIC))
83 ATOMIC_INLINE uint64_t
84 atomic_add_uint64(uint64_t *p, uint64_t x)
85 {
86         return (OSAtomicAdd64((int64_t)x, (int64_t *)p));
87 }
88
89 ATOMIC_INLINE uint64_t
90 atomic_sub_uint64(uint64_t *p, uint64_t x)
91 {
92         return (OSAtomicAdd64(-((int64_t)x), (int64_t *)p));
93 }
94 #  elif (defined(__amd64__) || defined(__x86_64__))
95 ATOMIC_INLINE uint64_t
96 atomic_add_uint64(uint64_t *p, uint64_t x)
97 {
98         asm volatile (
99             "lock; xaddq %0, %1;"
100             : "+r" (x), "=m" (*p) /* Outputs. */
101             : "m" (*p) /* Inputs. */
102             );
103         return (x);
104 }
105
106 ATOMIC_INLINE uint64_t
107 atomic_sub_uint64(uint64_t *p, uint64_t x)
108 {
109         x = (uint64_t)(-(int64_t)x);
110         asm volatile (
111             "lock; xaddq %0, %1;"
112             : "+r" (x), "=m" (*p) /* Outputs. */
113             : "m" (*p) /* Inputs. */
114             );
115         return (x);
116 }
117 #  elif (defined(JEMALLOC_ATOMIC9))
118 ATOMIC_INLINE uint64_t
119 atomic_add_uint64(uint64_t *p, uint64_t x)
120 {
121         /*
122          * atomic_fetchadd_64() doesn't exist, but we only ever use this
123          * function on LP64 systems, so atomic_fetchadd_long() will do.
124          */
125         assert(sizeof(uint64_t) == sizeof(unsigned long));
126
127         return (atomic_fetchadd_long(p, (unsigned long)x) + x);
128 }
129
130 ATOMIC_INLINE uint64_t
131 atomic_sub_uint64(uint64_t *p, uint64_t x)
132 {
133         assert(sizeof(uint64_t) == sizeof(unsigned long));
134
135         return (atomic_fetchadd_long(p, (unsigned long)(-(long)x)) - x);
136 }
137 #  elif (defined(JE_FORCE_SYNC_COMPARE_AND_SWAP_8))
138 ATOMIC_INLINE uint64_t
139 atomic_add_uint64(uint64_t *p, uint64_t x)
140 {
141         return (__sync_add_and_fetch(p, x));
142 }
143
144 ATOMIC_INLINE uint64_t
145 atomic_sub_uint64(uint64_t *p, uint64_t x)
146 {
147         return (__sync_sub_and_fetch(p, x));
148 }
149 #  else
150 #    error "Missing implementation for 64-bit atomic operations"
151 #  endif
152 #endif
153
154 /******************************************************************************/
155 /* 32-bit operations. */
156 #ifdef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4
157 ATOMIC_INLINE uint32_t
158 atomic_add_uint32(uint32_t *p, uint32_t x)
159 {
160         return (__sync_add_and_fetch(p, x));
161 }
162
163 ATOMIC_INLINE uint32_t
164 atomic_sub_uint32(uint32_t *p, uint32_t x)
165 {
166         return (__sync_sub_and_fetch(p, x));
167 }
168 #elif (defined(_MSC_VER))
169 ATOMIC_INLINE uint32_t
170 atomic_add_uint32(uint32_t *p, uint32_t x)
171 {
172         return (InterlockedExchangeAdd(p, x));
173 }
174
175 ATOMIC_INLINE uint32_t
176 atomic_sub_uint32(uint32_t *p, uint32_t x)
177 {
178         return (InterlockedExchangeAdd(p, -((int32_t)x)));
179 }
180 #elif (defined(JEMALLOC_OSATOMIC))
181 ATOMIC_INLINE uint32_t
182 atomic_add_uint32(uint32_t *p, uint32_t x)
183 {
184         return (OSAtomicAdd32((int32_t)x, (int32_t *)p));
185 }
186
187 ATOMIC_INLINE uint32_t
188 atomic_sub_uint32(uint32_t *p, uint32_t x)
189 {
190         return (OSAtomicAdd32(-((int32_t)x), (int32_t *)p));
191 }
192 #elif (defined(__i386__) || defined(__amd64__) || defined(__x86_64__))
193 ATOMIC_INLINE uint32_t
194 atomic_add_uint32(uint32_t *p, uint32_t x)
195 {
196         asm volatile (
197             "lock; xaddl %0, %1;"
198             : "+r" (x), "=m" (*p) /* Outputs. */
199             : "m" (*p) /* Inputs. */
200             );
201         return (x);
202 }
203
204 ATOMIC_INLINE uint32_t
205 atomic_sub_uint32(uint32_t *p, uint32_t x)
206 {
207         x = (uint32_t)(-(int32_t)x);
208         asm volatile (
209             "lock; xaddl %0, %1;"
210             : "+r" (x), "=m" (*p) /* Outputs. */
211             : "m" (*p) /* Inputs. */
212             );
213         return (x);
214 }
215 #elif (defined(JEMALLOC_ATOMIC9))
216 ATOMIC_INLINE uint32_t
217 atomic_add_uint32(uint32_t *p, uint32_t x)
218 {
219         return (atomic_fetchadd_32(p, x) + x);
220 }
221
222 ATOMIC_INLINE uint32_t
223 atomic_sub_uint32(uint32_t *p, uint32_t x)
224 {
225         return (atomic_fetchadd_32(p, (uint32_t)(-(int32_t)x)) - x);
226 }
227 #elif (defined(JE_FORCE_SYNC_COMPARE_AND_SWAP_4))
228 ATOMIC_INLINE uint32_t
229 atomic_add_uint32(uint32_t *p, uint32_t x)
230 {
231         return (__sync_add_and_fetch(p, x));
232 }
233
234 ATOMIC_INLINE uint32_t
235 atomic_sub_uint32(uint32_t *p, uint32_t x)
236 {
237         return (__sync_sub_and_fetch(p, x));
238 }
239 #else
240 #  error "Missing implementation for 32-bit atomic operations"
241 #endif
242
243 /******************************************************************************/
244 /* size_t operations. */
245 ATOMIC_INLINE size_t
246 atomic_add_z(size_t *p, size_t x)
247 {
248 #if (LG_SIZEOF_PTR == 3)
249         return ((size_t)atomic_add_uint64((uint64_t *)p, (uint64_t)x));
250 #elif (LG_SIZEOF_PTR == 2)
251         return ((size_t)atomic_add_uint32((uint32_t *)p, (uint32_t)x));
252 #endif
253 }
254
255 ATOMIC_INLINE size_t
256 atomic_sub_z(size_t *p, size_t x)
257 {
258 #if (LG_SIZEOF_PTR == 3)
259         return ((size_t)atomic_add_uint64((uint64_t *)p,
260             (uint64_t)-((int64_t)x)));
261 #elif (LG_SIZEOF_PTR == 2)
262         return ((size_t)atomic_add_uint32((uint32_t *)p,
263             (uint32_t)-((int32_t)x)));
264 #endif
265 }
266
267 /******************************************************************************/
268 /* unsigned operations. */
269 ATOMIC_INLINE unsigned
270 atomic_add_u(unsigned *p, unsigned x)
271 {
272 #if (LG_SIZEOF_INT == 3)
273         return ((unsigned)atomic_add_uint64((uint64_t *)p, (uint64_t)x));
274 #elif (LG_SIZEOF_INT == 2)
275         return ((unsigned)atomic_add_uint32((uint32_t *)p, (uint32_t)x));
276 #endif
277 }
278
279 ATOMIC_INLINE unsigned
280 atomic_sub_u(unsigned *p, unsigned x)
281 {
282 #if (LG_SIZEOF_INT == 3)
283         return ((unsigned)atomic_add_uint64((uint64_t *)p,
284             (uint64_t)-((int64_t)x)));
285 #elif (LG_SIZEOF_INT == 2)
286         return ((unsigned)atomic_add_uint32((uint32_t *)p,
287             (uint32_t)-((int32_t)x)));
288 #endif
289 }
290
291 #endif /* ATOMIC_OPS_H__ */