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