blob: 13d16d4fdad6b720295dfa7f6463e25b4de5d2cf [file] [log] [blame]
Shih-wei Liaoe264f622010-02-10 11:10:31 -08001//===-- 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
Michael J. Spencer1f6efa32010-11-29 18:16:10 +000014#include "llvm/Support/Atomic.h"
Dylan Noblesmith94214062011-12-22 23:04:07 +000015#include "llvm/Config/llvm-config.h"
Shih-wei Liao845de582012-05-10 09:12:44 -070016#if defined(ANDROID_TARGET_BUILD)
17#include "cutils/atomic.h"
18#endif
Shih-wei Liaoe264f622010-02-10 11:10:31 -080019
20using namespace llvm;
21
22#if defined(_MSC_VER)
23#include <windows.h>
24#undef MemoryFence
25#endif
26
Rafael Espindola986f29c2012-11-02 20:54:45 +000027#if defined(__GNUC__) || (defined(__IBMCPP__) && __IBMCPP__ >= 1210)
28#define GNU_ATOMICS
29#endif
30
Shih-wei Liaoe264f622010-02-10 11:10:31 -080031void sys::MemoryFence() {
Eric Christopher627445f2011-09-19 20:43:23 +000032#if LLVM_HAS_ATOMICS == 0
Shih-wei Liaoe264f622010-02-10 11:10:31 -080033 return;
34#else
Rafael Espindola986f29c2012-11-02 20:54:45 +000035# if defined(GNU_ATOMICS)
Shih-wei Liaoe264f622010-02-10 11:10:31 -080036 __sync_synchronize();
37# elif defined(_MSC_VER)
38 MemoryBarrier();
39# else
40# error No memory fence implementation for your platform!
41# endif
42#endif
43}
44
45sys::cas_flag sys::CompareAndSwap(volatile sys::cas_flag* ptr,
46 sys::cas_flag new_value,
47 sys::cas_flag old_value) {
Eric Christopher627445f2011-09-19 20:43:23 +000048#if LLVM_HAS_ATOMICS == 0
Shih-wei Liaoe264f622010-02-10 11:10:31 -080049 sys::cas_flag result = *ptr;
50 if (result == old_value)
51 *ptr = new_value;
52 return result;
Shih-wei Liao845de582012-05-10 09:12:44 -070053#elif defined(ANDROID_TARGET_BUILD)
Shih-wei Liao30ce65e2012-05-10 11:19:22 -070054 return android_atomic_cmpxchg((int32_t)old_value, (int32_t)new_value,
55 (volatile int*)ptr);
Rafael Espindola986f29c2012-11-02 20:54:45 +000056#elif defined(GNU_ATOMICS)
Shih-wei Liaoe264f622010-02-10 11:10:31 -080057 return __sync_val_compare_and_swap(ptr, old_value, new_value);
58#elif defined(_MSC_VER)
59 return InterlockedCompareExchange(ptr, new_value, old_value);
60#else
61# error No compare-and-swap implementation for your platform!
62#endif
63}
64
65sys::cas_flag sys::AtomicIncrement(volatile sys::cas_flag* ptr) {
Eric Christopher627445f2011-09-19 20:43:23 +000066#if LLVM_HAS_ATOMICS == 0
Shih-wei Liaoe264f622010-02-10 11:10:31 -080067 ++(*ptr);
68 return *ptr;
Shih-wei Liao845de582012-05-10 09:12:44 -070069#elif defined(ANDROID_TARGET_BUILD)
Shih-wei Liao30ce65e2012-05-10 11:19:22 -070070 return android_atomic_inc((volatile int*)ptr);
Rafael Espindola986f29c2012-11-02 20:54:45 +000071#elif defined(GNU_ATOMICS)
Shih-wei Liaoe264f622010-02-10 11:10:31 -080072 return __sync_add_and_fetch(ptr, 1);
73#elif defined(_MSC_VER)
74 return InterlockedIncrement(ptr);
75#else
76# error No atomic increment implementation for your platform!
77#endif
78}
79
80sys::cas_flag sys::AtomicDecrement(volatile sys::cas_flag* ptr) {
Eric Christopher627445f2011-09-19 20:43:23 +000081#if LLVM_HAS_ATOMICS == 0
Shih-wei Liaoe264f622010-02-10 11:10:31 -080082 --(*ptr);
83 return *ptr;
Shih-wei Liao845de582012-05-10 09:12:44 -070084#elif defined(ANDROID_TARGET_BUILD)
Shih-wei Liao30ce65e2012-05-10 11:19:22 -070085 return android_atomic_dec((volatile int*)ptr);
Rafael Espindola986f29c2012-11-02 20:54:45 +000086#elif defined(GNU_ATOMICS)
Shih-wei Liaoe264f622010-02-10 11:10:31 -080087 return __sync_sub_and_fetch(ptr, 1);
88#elif defined(_MSC_VER)
89 return InterlockedDecrement(ptr);
90#else
91# error No atomic decrement implementation for your platform!
92#endif
93}
94
95sys::cas_flag sys::AtomicAdd(volatile sys::cas_flag* ptr, sys::cas_flag val) {
Eric Christopher627445f2011-09-19 20:43:23 +000096#if LLVM_HAS_ATOMICS == 0
Shih-wei Liaoe264f622010-02-10 11:10:31 -080097 *ptr += val;
98 return *ptr;
Shih-wei Liao845de582012-05-10 09:12:44 -070099#elif defined(ANDROID_TARGET_BUILD)
Shih-wei Liao30ce65e2012-05-10 11:19:22 -0700100 return android_atomic_add((int32_t)val, (volatile int*)ptr);
Rafael Espindola986f29c2012-11-02 20:54:45 +0000101#elif defined(GNU_ATOMICS)
Shih-wei Liaoe264f622010-02-10 11:10:31 -0800102 return __sync_add_and_fetch(ptr, val);
103#elif defined(_MSC_VER)
104 return InterlockedExchangeAdd(ptr, val) + val;
105#else
106# error No atomic add implementation for your platform!
107#endif
108}
109
110sys::cas_flag sys::AtomicMul(volatile sys::cas_flag* ptr, sys::cas_flag val) {
111 sys::cas_flag original, result;
112 do {
113 original = *ptr;
114 result = original * val;
115 } while (sys::CompareAndSwap(ptr, result, original) != original);
116
117 return result;
118}
119
120sys::cas_flag sys::AtomicDiv(volatile sys::cas_flag* ptr, sys::cas_flag val) {
121 sys::cas_flag original, result;
122 do {
123 original = *ptr;
124 result = original / val;
125 } while (sys::CompareAndSwap(ptr, result, original) != original);
126
127 return result;
128}