Attempt to fix compilation error on OSX and Windows
[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 #if defined (__APPLE__)
33 #  include <libkern/OSAtomic.h>
34 #elif defined(_MSC_VER)
35 #  include <windows.h>
36 #endif
37
38 /* needed for int types */
39 #include "../../source/blender/blenlib/BLI_sys_types.h"
40
41 /* little macro so inline keyword works */
42 #if defined(_MSC_VER)
43 #  define ATOMIC_INLINE static __forceinline
44 #else
45 #  if (defined(__APPLE__) && defined(__ppc__))
46 /* static inline __attribute__ here breaks osx ppc gcc42 build */
47 #    define ATOMIC_INLINE static __attribute__((always_inline))
48 #  else
49 #    define ATOMIC_INLINE static inline __attribute__((always_inline))
50 #  endif
51 #endif
52
53 #if defined(_M_X64) || defined(__amd64__) || defined(__x86_64__)
54 #  define LG_SIZEOF_PTR 3
55 #  define LG_SIZEOF_INT 3
56 #else
57 #  define LG_SIZEOF_PTR 2
58 #  define LG_SIZEOF_INT 2
59 #endif
60
61 /******************************************************************************/
62 /* 64-bit operations. */
63 #if (LG_SIZEOF_PTR == 3 || LG_SIZEOF_INT == 3)
64 #  ifdef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8
65 ATOMIC_INLINE uint64_t
66 atomic_add_uint64(uint64_t *p, uint64_t x)
67 {
68         return (__sync_add_and_fetch(p, x));
69 }
70
71 ATOMIC_INLINE uint64_t
72 atomic_sub_uint64(uint64_t *p, uint64_t x)
73 {
74         return (__sync_sub_and_fetch(p, x));
75 }
76 #elif (defined(_MSC_VER))
77 ATOMIC_INLINE uint64_t
78 atomic_add_uint64(uint64_t *p, uint64_t x)
79 {
80         return (InterlockedExchangeAdd64(p, x));
81 }
82
83 ATOMIC_INLINE uint64_t
84 atomic_sub_uint64(uint64_t *p, uint64_t x)
85 {
86         return (InterlockedExchangeAdd64(p, -((int64_t)x)));
87 }
88 #elif (defined(__APPLE__))
89 ATOMIC_INLINE uint64_t
90 atomic_add_uint64(uint64_t *p, uint64_t x)
91 {
92         return (OSAtomicAdd64((int64_t)x, (int64_t *)p));
93 }
94
95 ATOMIC_INLINE uint64_t
96 atomic_sub_uint64(uint64_t *p, uint64_t x)
97 {
98         return (OSAtomicAdd64(-((int64_t)x), (int64_t *)p));
99 }
100 #  elif (defined(__amd64__) || defined(__x86_64__))
101 ATOMIC_INLINE uint64_t
102 atomic_add_uint64(uint64_t *p, uint64_t x)
103 {
104         asm volatile (
105             "lock; xaddq %0, %1;"
106             : "+r" (x), "=m" (*p) /* Outputs. */
107             : "m" (*p) /* Inputs. */
108             );
109         return (x);
110 }
111
112 ATOMIC_INLINE uint64_t
113 atomic_sub_uint64(uint64_t *p, uint64_t x)
114 {
115         x = (uint64_t)(-(int64_t)x);
116         asm volatile (
117             "lock; xaddq %0, %1;"
118             : "+r" (x), "=m" (*p) /* Outputs. */
119             : "m" (*p) /* Inputs. */
120             );
121         return (x);
122 }
123 #  elif (defined(JEMALLOC_ATOMIC9))
124 ATOMIC_INLINE uint64_t
125 atomic_add_uint64(uint64_t *p, uint64_t x)
126 {
127         /*
128          * atomic_fetchadd_64() doesn't exist, but we only ever use this
129          * function on LP64 systems, so atomic_fetchadd_long() will do.
130          */
131         assert(sizeof(uint64_t) == sizeof(unsigned long));
132
133         return (atomic_fetchadd_long(p, (unsigned long)x) + x);
134 }
135
136 ATOMIC_INLINE uint64_t
137 atomic_sub_uint64(uint64_t *p, uint64_t x)
138 {
139         assert(sizeof(uint64_t) == sizeof(unsigned long));
140
141         return (atomic_fetchadd_long(p, (unsigned long)(-(long)x)) - x);
142 }
143 #  elif (defined(JE_FORCE_SYNC_COMPARE_AND_SWAP_8))
144 ATOMIC_INLINE uint64_t
145 atomic_add_uint64(uint64_t *p, uint64_t x)
146 {
147         return (__sync_add_and_fetch(p, x));
148 }
149
150 ATOMIC_INLINE uint64_t
151 atomic_sub_uint64(uint64_t *p, uint64_t x)
152 {
153         return (__sync_sub_and_fetch(p, x));
154 }
155 #  else
156 #    error "Missing implementation for 64-bit atomic operations"
157 #  endif
158 #endif
159
160 /******************************************************************************/
161 /* 32-bit operations. */
162 #ifdef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4
163 ATOMIC_INLINE uint32_t
164 atomic_add_uint32(uint32_t *p, uint32_t x)
165 {
166         return (__sync_add_and_fetch(p, x));
167 }
168
169 ATOMIC_INLINE uint32_t
170 atomic_sub_uint32(uint32_t *p, uint32_t x)
171 {
172         return (__sync_sub_and_fetch(p, x));
173 }
174 #elif (defined(_MSC_VER))
175 ATOMIC_INLINE uint32_t
176 atomic_add_uint32(uint32_t *p, uint32_t x)
177 {
178         return (InterlockedExchangeAdd(p, x));
179 }
180
181 ATOMIC_INLINE uint32_t
182 atomic_sub_uint32(uint32_t *p, uint32_t x)
183 {
184         return (InterlockedExchangeAdd(p, -((int32_t)x)));
185 }
186 #elif (defined(__APPLE__))
187 ATOMIC_INLINE uint32_t
188 atomic_add_uint32(uint32_t *p, uint32_t x)
189 {
190         return (OSAtomicAdd32((int32_t)x, (int32_t *)p));
191 }
192
193 ATOMIC_INLINE uint32_t
194 atomic_sub_uint32(uint32_t *p, uint32_t x)
195 {
196         return (OSAtomicAdd32(-((int32_t)x), (int32_t *)p));
197 }
198 #elif (defined(__i386__) || defined(__amd64__) || defined(__x86_64__))
199 ATOMIC_INLINE uint32_t
200 atomic_add_uint32(uint32_t *p, uint32_t x)
201 {
202         asm volatile (
203             "lock; xaddl %0, %1;"
204             : "+r" (x), "=m" (*p) /* Outputs. */
205             : "m" (*p) /* Inputs. */
206             );
207         return (x);
208 }
209
210 ATOMIC_INLINE uint32_t
211 atomic_sub_uint32(uint32_t *p, uint32_t x)
212 {
213         x = (uint32_t)(-(int32_t)x);
214         asm volatile (
215             "lock; xaddl %0, %1;"
216             : "+r" (x), "=m" (*p) /* Outputs. */
217             : "m" (*p) /* Inputs. */
218             );
219         return (x);
220 }
221 #elif (defined(JEMALLOC_ATOMIC9))
222 ATOMIC_INLINE uint32_t
223 atomic_add_uint32(uint32_t *p, uint32_t x)
224 {
225         return (atomic_fetchadd_32(p, x) + x);
226 }
227
228 ATOMIC_INLINE uint32_t
229 atomic_sub_uint32(uint32_t *p, uint32_t x)
230 {
231         return (atomic_fetchadd_32(p, (uint32_t)(-(int32_t)x)) - x);
232 }
233 #elif (defined(JE_FORCE_SYNC_COMPARE_AND_SWAP_4))
234 ATOMIC_INLINE uint32_t
235 atomic_add_uint32(uint32_t *p, uint32_t x)
236 {
237         return (__sync_add_and_fetch(p, x));
238 }
239
240 ATOMIC_INLINE uint32_t
241 atomic_sub_uint32(uint32_t *p, uint32_t x)
242 {
243         return (__sync_sub_and_fetch(p, x));
244 }
245 #else
246 #  error "Missing implementation for 32-bit atomic operations"
247 #endif
248
249 /******************************************************************************/
250 /* size_t operations. */
251 ATOMIC_INLINE size_t
252 atomic_add_z(size_t *p, size_t x)
253 {
254 #if (LG_SIZEOF_PTR == 3)
255         return ((size_t)atomic_add_uint64((uint64_t *)p, (uint64_t)x));
256 #elif (LG_SIZEOF_PTR == 2)
257         return ((size_t)atomic_add_uint32((uint32_t *)p, (uint32_t)x));
258 #endif
259 }
260
261 ATOMIC_INLINE size_t
262 atomic_sub_z(size_t *p, size_t x)
263 {
264 #if (LG_SIZEOF_PTR == 3)
265         return ((size_t)atomic_add_uint64((uint64_t *)p,
266             (uint64_t)-((int64_t)x)));
267 #elif (LG_SIZEOF_PTR == 2)
268         return ((size_t)atomic_add_uint32((uint32_t *)p,
269             (uint32_t)-((int32_t)x)));
270 #endif
271 }
272
273 /******************************************************************************/
274 /* unsigned operations. */
275 ATOMIC_INLINE unsigned
276 atomic_add_u(unsigned *p, unsigned x)
277 {
278 #if (LG_SIZEOF_INT == 3)
279         return ((unsigned)atomic_add_uint64((uint64_t *)p, (uint64_t)x));
280 #elif (LG_SIZEOF_INT == 2)
281         return ((unsigned)atomic_add_uint32((uint32_t *)p, (uint32_t)x));
282 #endif
283 }
284
285 ATOMIC_INLINE unsigned
286 atomic_sub_u(unsigned *p, unsigned x)
287 {
288 #if (LG_SIZEOF_INT == 3)
289         return ((unsigned)atomic_add_uint64((uint64_t *)p,
290             (uint64_t)-((int64_t)x)));
291 #elif (LG_SIZEOF_INT == 2)
292         return ((unsigned)atomic_add_uint32((uint32_t *)p,
293             (uint32_t)-((int32_t)x)));
294 #endif
295 }
296
297 #endif /* ATOMIC_OPS_H__ */