cpp-d1064d
[cross.git] / i686-linux-gnu-4.7 / usr / include / c++ / 4.7 / parallel / compatibility.h
1 // -*- C++ -*-
2
3 // Copyright (C) 2007, 2008, 2009, 2010, 2012 Free Software Foundation, Inc.
4 //
5 // This file is part of the GNU ISO C++ Library.  This library is free
6 // software; you can redistribute it and/or modify it under the terms
7 // of the GNU General Public License as published by the Free Software
8 // Foundation; either version 3, or (at your option) any later
9 // version.
10
11 // This library is distributed in the hope that it will be useful, but
12 // WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // General Public License for more details.
15
16 // Under Section 7 of GPL version 3, you are granted additional
17 // permissions described in the GCC Runtime Library Exception, version
18 // 3.1, as published by the Free Software Foundation.
19
20 // You should have received a copy of the GNU General Public License and
21 // a copy of the GCC Runtime Library Exception along with this program;
22 // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
23 // <http://www.gnu.org/licenses/>.
24
25 /** @file parallel/compatibility.h
26  *  @brief Compatibility layer, mostly concerned with atomic operations.
27  *  This file is a GNU parallel extension to the Standard C++ Library.
28  */
29
30 // Written by Felix Putze.
31
32 #ifndef _GLIBCXX_PARALLEL_COMPATIBILITY_H
33 #define _GLIBCXX_PARALLEL_COMPATIBILITY_H 1
34
35 #include <parallel/types.h>
36 #include <parallel/base.h>
37
38 #if defined(__SUNPRO_CC) && defined(__sparc)
39 #include <sys/atomic.h>
40 #endif
41
42 #if !defined(_WIN32) || defined (__CYGWIN__)
43 #include <sched.h>
44 #endif
45
46 #if defined(_MSC_VER)
47 #include <Windows.h>
48 #include <intrin.h>
49 #undef max
50 #undef min
51 #endif
52
53 #ifdef __MINGW32__
54 // Including <windows.h> will drag in all the windows32 names.  Since
55 // that can cause user code portability problems, we just declare the
56 // one needed function here.
57 extern "C"
58 __attribute((dllimport)) void __attribute__((stdcall)) Sleep (unsigned long);
59 #endif
60
61 namespace __gnu_parallel
62 {
63 #if defined(__ICC)
64   template<typename _MustBeInt = int>
65   int32_t __faa32(int32_t* __x, int32_t __inc)
66   {
67     asm volatile("lock xadd %0,%1"
68                  : "=__r" (__inc), "=__m" (*__x)
69                  : "0" (__inc)
70                  : "memory");
71     return __inc;
72   }
73 #if defined(__x86_64)
74   template<typename _MustBeInt = int>
75   int64_t __faa64(int64_t* __x, int64_t __inc)
76   {
77     asm volatile("lock xadd %0,%1"
78                  : "=__r" (__inc), "=__m" (*__x)
79                  : "0" (__inc)
80                  : "memory");
81     return __inc;
82   }
83 #endif
84 #endif
85
86   // atomic functions only work on integers
87
88   /** @brief Add a value to a variable, atomically.
89    *
90    *  Implementation is heavily platform-dependent.
91    *  @param __ptr Pointer to a 32-bit signed integer.
92    *  @param __addend Value to add.
93    */
94   inline int32_t
95   __fetch_and_add_32(volatile int32_t* __ptr, int32_t __addend)
96   {
97 #if defined(__ICC)      //x86 version
98     return _InterlockedExchangeAdd((void*)__ptr, __addend);
99 #elif defined(__ECC)    //IA-64 version
100     return _InterlockedExchangeAdd((void*)__ptr, __addend);
101 #elif defined(__ICL) || defined(_MSC_VER)
102     return _InterlockedExchangeAdd(reinterpret_cast<volatile long*>(__ptr),
103                                    __addend);
104 #elif defined(__GNUC__)
105     return __atomic_fetch_add(__ptr, __addend, __ATOMIC_ACQ_REL);
106 #elif defined(__SUNPRO_CC) && defined(__sparc)
107     volatile int32_t __before, __after;
108     do
109       {
110         __before = *__ptr;
111         __after = __before + __addend;
112       } while (atomic_cas_32((volatile unsigned int*)__ptr, __before,
113                              __after) != __before);
114     return __before;
115 #else   //fallback, slow
116 #pragma message("slow __fetch_and_add_32")
117     int32_t __res;
118 #pragma omp critical
119     {
120       __res = *__ptr;
121       *(__ptr) += __addend;
122     }
123     return __res;
124 #endif
125   }
126
127   /** @brief Add a value to a variable, atomically.
128    *
129    *  Implementation is heavily platform-dependent.
130    *  @param __ptr Pointer to a 64-bit signed integer.
131    *  @param __addend Value to add.
132    */
133   inline int64_t
134   __fetch_and_add_64(volatile int64_t* __ptr, int64_t __addend)
135   {
136 #if defined(__ICC) && defined(__x86_64) //x86 version
137     return __faa64<int>((int64_t*)__ptr, __addend);
138 #elif defined(__ECC)    //IA-64 version
139     return _InterlockedExchangeAdd64((void*)__ptr, __addend);
140 #elif defined(__ICL) || defined(_MSC_VER)
141 #ifndef _WIN64
142     _GLIBCXX_PARALLEL_ASSERT(false);    //not available in this case
143     return 0;
144 #else
145     return _InterlockedExchangeAdd64(__ptr, __addend);
146 #endif
147 #elif defined(__GNUC__) && defined(__x86_64)
148     return __atomic_fetch_add(__ptr, __addend, __ATOMIC_ACQ_REL);
149 #elif defined(__GNUC__) && defined(__i386) &&                   \
150   (defined(__i686) || defined(__pentium4) || defined(__athlon)  \
151    || defined(__k8) || defined(__core2))
152     return __atomic_fetch_add(__ptr, __addend, __ATOMIC_ACQ_REL);
153 #elif defined(__SUNPRO_CC) && defined(__sparc)
154     volatile int64_t __before, __after;
155     do
156       {
157         __before = *__ptr;
158         __after = __before + __addend;
159       } while (atomic_cas_64((volatile unsigned long long*)__ptr, __before,
160                              __after) != __before);
161     return __before;
162 #else   //fallback, slow
163 #if defined(__GNUC__) && defined(__i386)
164     // XXX doesn'__t work with -march=native
165     //#warning "please compile with -march=i686 or better"
166 #endif
167 #pragma message("slow __fetch_and_add_64")
168     int64_t __res;
169 #pragma omp critical
170     {
171       __res = *__ptr;
172       *(__ptr) += __addend;
173     }
174     return __res;
175 #endif
176   }
177
178   /** @brief Add a value to a variable, atomically.
179    *
180    *  Implementation is heavily platform-dependent.
181    *  @param __ptr Pointer to a signed integer.
182    *  @param __addend Value to add.
183    */
184   template<typename _Tp>
185   inline _Tp
186   __fetch_and_add(volatile _Tp* __ptr, _Tp __addend)
187   {
188     if (sizeof(_Tp) == sizeof(int32_t))
189       return
190         (_Tp)__fetch_and_add_32((volatile int32_t*) __ptr, (int32_t)__addend);
191     else if (sizeof(_Tp) == sizeof(int64_t))
192       return
193         (_Tp)__fetch_and_add_64((volatile int64_t*) __ptr, (int64_t)__addend);
194     else
195       _GLIBCXX_PARALLEL_ASSERT(false);
196   }
197
198
199 #if defined(__ICC)
200
201   template<typename _MustBeInt = int>
202   inline int32_t
203   __cas32(volatile int32_t* __ptr, int32_t __old, int32_t __nw)
204   {
205     int32_t __before;
206     __asm__ __volatile__("lock; cmpxchgl %1,%2"
207                          : "=a"(__before)
208                          : "q"(__nw), "__m"(*(volatile long long*)(__ptr)),
209                                "0"(__old)
210                          : "memory");
211     return __before;
212   }
213
214 #if defined(__x86_64)
215   template<typename _MustBeInt = int>
216   inline int64_t
217   __cas64(volatile int64_t *__ptr, int64_t __old, int64_t __nw)
218   {
219     int64_t __before;
220     __asm__ __volatile__("lock; cmpxchgq %1,%2"
221                          : "=a"(__before)
222                          : "q"(__nw), "__m"(*(volatile long long*)(__ptr)),
223                                "0"(__old)
224                          : "memory");
225     return __before;
226   }
227 #endif
228
229 #endif
230
231   /** @brief Compare @c *__ptr and @c __comparand. If equal, let @c
232    * *__ptr=__replacement and return @c true, return @c false otherwise.
233    *
234    *  Implementation is heavily platform-dependent.
235    *  @param __ptr Pointer to 32-bit signed integer.
236    *  @param __comparand Compare value.
237    *  @param __replacement Replacement value.
238    */
239   inline bool
240   __compare_and_swap_32(volatile int32_t* __ptr, int32_t __comparand,
241                         int32_t __replacement)
242   {
243 #if defined(__ICC)      //x86 version
244     return _InterlockedCompareExchange((void*)__ptr, __replacement,
245                                        __comparand) == __comparand;
246 #elif defined(__ECC)    //IA-64 version
247     return _InterlockedCompareExchange((void*)__ptr, __replacement,
248                                        __comparand) == __comparand;
249 #elif defined(__ICL) || defined(_MSC_VER)
250     return _InterlockedCompareExchange(
251                reinterpret_cast<volatile long*>(__ptr),
252                __replacement, __comparand)
253              == __comparand;
254 #elif defined(__GNUC__)
255     return __atomic_compare_exchange_n(__ptr, &__comparand, __replacement,
256                                        false, __ATOMIC_ACQ_REL,
257                                        __ATOMIC_RELAXED);
258 #elif defined(__SUNPRO_CC) && defined(__sparc)
259     return atomic_cas_32((volatile unsigned int*)__ptr, __comparand,
260                          __replacement) == __comparand;
261 #else
262 #pragma message("slow __compare_and_swap_32")
263     bool __res = false;
264 #pragma omp critical
265     {
266       if (*__ptr == __comparand)
267         {
268           *__ptr = __replacement;
269           __res = true;
270         }
271     }
272     return __res;
273 #endif
274   }
275
276   /** @brief Compare @c *__ptr and @c __comparand. If equal, let @c
277    * *__ptr=__replacement and return @c true, return @c false otherwise.
278    *
279    *  Implementation is heavily platform-dependent.
280    *  @param __ptr Pointer to 64-bit signed integer.
281    *  @param __comparand Compare value.
282    *  @param __replacement Replacement value.
283    */
284   inline bool
285   __compare_and_swap_64(volatile int64_t* __ptr, int64_t __comparand,
286                         int64_t __replacement)
287   {
288 #if defined(__ICC) && defined(__x86_64) //x86 version
289     return __cas64<int>(__ptr, __comparand, __replacement) == __comparand;
290 #elif defined(__ECC)    //IA-64 version
291     return _InterlockedCompareExchange64((void*)__ptr, __replacement,
292                                          __comparand) == __comparand;
293 #elif defined(__ICL) || defined(_MSC_VER)
294 #ifndef _WIN64
295     _GLIBCXX_PARALLEL_ASSERT(false);    //not available in this case
296     return 0;
297 #else
298     return _InterlockedCompareExchange64(__ptr, __replacement,
299                                          __comparand) == __comparand;
300 #endif
301
302 #elif defined(__GNUC__) && defined(__x86_64)
303     return __atomic_compare_exchange_n(__ptr, &__comparand, __replacement,
304                                        false, __ATOMIC_ACQ_REL,
305                                        __ATOMIC_RELAXED);
306 #elif defined(__GNUC__) && defined(__i386) &&                   \
307   (defined(__i686) || defined(__pentium4) || defined(__athlon)  \
308    || defined(__k8) || defined(__core2))
309     return __atomic_compare_exchange_n(__ptr, &__comparand, __replacement,
310                                        false, __ATOMIC_ACQ_REL,
311                                        __ATOMIC_RELAXED);
312 #elif defined(__SUNPRO_CC) && defined(__sparc)
313     return atomic_cas_64((volatile unsigned long long*)__ptr,
314                          __comparand, __replacement) == __comparand;
315 #else
316 #if defined(__GNUC__) && defined(__i386)
317     // XXX -march=native
318     //#warning "please compile with -march=i686 or better"
319 #endif
320 #pragma message("slow __compare_and_swap_64")
321     bool __res = false;
322 #pragma omp critical
323     {
324       if (*__ptr == __comparand)
325         {
326           *__ptr = __replacement;
327           __res = true;
328         }
329     }
330     return __res;
331 #endif
332   }
333
334   /** @brief Compare @c *__ptr and @c __comparand. If equal, let @c
335    * *__ptr=__replacement and return @c true, return @c false otherwise.
336    *
337    *  Implementation is heavily platform-dependent.
338    *  @param __ptr Pointer to signed integer.
339    *  @param __comparand Compare value.
340    *  @param __replacement Replacement value. */
341   template<typename _Tp>
342   inline bool
343   __compare_and_swap(volatile _Tp* __ptr, _Tp __comparand, _Tp __replacement)
344   {
345     if (sizeof(_Tp) == sizeof(int32_t))
346       return __compare_and_swap_32((volatile int32_t*) __ptr,
347                                    (int32_t)__comparand,
348                                    (int32_t)__replacement);
349     else if (sizeof(_Tp) == sizeof(int64_t))
350       return __compare_and_swap_64((volatile int64_t*) __ptr,
351                                    (int64_t)__comparand,
352                                    (int64_t)__replacement);
353     else
354       _GLIBCXX_PARALLEL_ASSERT(false);
355   }
356
357   /** @brief Yield the control to another thread, without waiting for
358       the end to the time slice. */
359   inline void
360   __yield()
361   {
362 #if defined (_WIN32) && !defined (__CYGWIN__)
363     Sleep(0);
364 #else
365     sched_yield();
366 #endif
367   }
368 } // end namespace
369
370 #endif /* _GLIBCXX_PARALLEL_COMPATIBILITY_H */