]> CyberLeo.Net >> Repos - FreeBSD/releng/9.0.git/blob - contrib/llvm/lib/Support/Atomic.cpp
Copy stable/9 to releng/9.0 as part of the FreeBSD 9.0-RELEASE release
[FreeBSD/releng/9.0.git] / contrib / llvm / lib / Support / Atomic.cpp
1 //===-- Atomic.cpp - Atomic Operations --------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 //  This header file implements atomic operations.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #include "llvm/Support/Atomic.h"
15 #include "llvm/Config/config.h"
16
17 using namespace llvm;
18
19 #if defined(_MSC_VER)
20 #include <windows.h>
21 #undef MemoryFence
22 #endif
23
24 void sys::MemoryFence() {
25 #if LLVM_HAS_ATOMICS == 0
26   return;
27 #else
28 #  if defined(__GNUC__)
29   __sync_synchronize();
30 #  elif defined(_MSC_VER)
31   MemoryBarrier();
32 #  else
33 # error No memory fence implementation for your platform!
34 #  endif
35 #endif
36 }
37
38 sys::cas_flag sys::CompareAndSwap(volatile sys::cas_flag* ptr,
39                                   sys::cas_flag new_value,
40                                   sys::cas_flag old_value) {
41 #if LLVM_HAS_ATOMICS == 0
42   sys::cas_flag result = *ptr;
43   if (result == old_value)
44     *ptr = new_value;
45   return result;
46 #elif defined(__GNUC__)
47   return __sync_val_compare_and_swap(ptr, old_value, new_value);
48 #elif defined(_MSC_VER)
49   return InterlockedCompareExchange(ptr, new_value, old_value);
50 #else
51 #  error No compare-and-swap implementation for your platform!
52 #endif
53 }
54
55 sys::cas_flag sys::AtomicIncrement(volatile sys::cas_flag* ptr) {
56 #if LLVM_HAS_ATOMICS == 0
57   ++(*ptr);
58   return *ptr;
59 #elif defined(__GNUC__)
60   return __sync_add_and_fetch(ptr, 1);
61 #elif defined(_MSC_VER)
62   return InterlockedIncrement(ptr);
63 #else
64 #  error No atomic increment implementation for your platform!
65 #endif
66 }
67
68 sys::cas_flag sys::AtomicDecrement(volatile sys::cas_flag* ptr) {
69 #if LLVM_HAS_ATOMICS == 0
70   --(*ptr);
71   return *ptr;
72 #elif defined(__GNUC__)
73   return __sync_sub_and_fetch(ptr, 1);
74 #elif defined(_MSC_VER)
75   return InterlockedDecrement(ptr);
76 #else
77 #  error No atomic decrement implementation for your platform!
78 #endif
79 }
80
81 sys::cas_flag sys::AtomicAdd(volatile sys::cas_flag* ptr, sys::cas_flag val) {
82 #if LLVM_HAS_ATOMICS == 0
83   *ptr += val;
84   return *ptr;
85 #elif defined(__GNUC__)
86   return __sync_add_and_fetch(ptr, val);
87 #elif defined(_MSC_VER)
88   return InterlockedExchangeAdd(ptr, val) + val;
89 #else
90 #  error No atomic add implementation for your platform!
91 #endif
92 }
93
94 sys::cas_flag sys::AtomicMul(volatile sys::cas_flag* ptr, sys::cas_flag val) {
95   sys::cas_flag original, result;
96   do {
97     original = *ptr;
98     result = original * val;
99   } while (sys::CompareAndSwap(ptr, result, original) != original);
100
101   return result;
102 }
103
104 sys::cas_flag sys::AtomicDiv(volatile sys::cas_flag* ptr, sys::cas_flag val) {
105   sys::cas_flag original, result;
106   do {
107     original = *ptr;
108     result = original / val;
109   } while (sys::CompareAndSwap(ptr, result, original) != original);
110
111   return result;
112 }