blob: 58497b98c812567f6f8776dbd7feddd229c4eb6a [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
27void sys::MemoryFence() {
Eric Christopher627445f2011-09-19 20:43:23 +000028#if LLVM_HAS_ATOMICS == 0
Shih-wei Liaoe264f622010-02-10 11:10:31 -080029 return;
30#else
31# if defined(__GNUC__)
32 __sync_synchronize();
33# elif defined(_MSC_VER)
34 MemoryBarrier();
35# else
36# error No memory fence implementation for your platform!
37# endif
38#endif
39}
40
41sys::cas_flag sys::CompareAndSwap(volatile sys::cas_flag* ptr,
42 sys::cas_flag new_value,
43 sys::cas_flag old_value) {
Eric Christopher627445f2011-09-19 20:43:23 +000044#if LLVM_HAS_ATOMICS == 0
Shih-wei Liaoe264f622010-02-10 11:10:31 -080045 sys::cas_flag result = *ptr;
46 if (result == old_value)
47 *ptr = new_value;
48 return result;
Shih-wei Liao845de582012-05-10 09:12:44 -070049#elif defined(ANDROID_TARGET_BUILD)
Shih-wei Liao30ce65e2012-05-10 11:19:22 -070050 return android_atomic_cmpxchg((int32_t)old_value, (int32_t)new_value,
51 (volatile int*)ptr);
Shih-wei Liaoe264f622010-02-10 11:10:31 -080052#elif defined(__GNUC__)
53 return __sync_val_compare_and_swap(ptr, old_value, new_value);
54#elif defined(_MSC_VER)
55 return InterlockedCompareExchange(ptr, new_value, old_value);
56#else
57# error No compare-and-swap implementation for your platform!
58#endif
59}
60
61sys::cas_flag sys::AtomicIncrement(volatile sys::cas_flag* ptr) {
Eric Christopher627445f2011-09-19 20:43:23 +000062#if LLVM_HAS_ATOMICS == 0
Shih-wei Liaoe264f622010-02-10 11:10:31 -080063 ++(*ptr);
64 return *ptr;
Shih-wei Liao845de582012-05-10 09:12:44 -070065#elif defined(ANDROID_TARGET_BUILD)
Shih-wei Liao30ce65e2012-05-10 11:19:22 -070066 return android_atomic_inc((volatile int*)ptr);
Shih-wei Liaoe264f622010-02-10 11:10:31 -080067#elif defined(__GNUC__)
68 return __sync_add_and_fetch(ptr, 1);
69#elif defined(_MSC_VER)
70 return InterlockedIncrement(ptr);
71#else
72# error No atomic increment implementation for your platform!
73#endif
74}
75
76sys::cas_flag sys::AtomicDecrement(volatile sys::cas_flag* ptr) {
Eric Christopher627445f2011-09-19 20:43:23 +000077#if LLVM_HAS_ATOMICS == 0
Shih-wei Liaoe264f622010-02-10 11:10:31 -080078 --(*ptr);
79 return *ptr;
Shih-wei Liao845de582012-05-10 09:12:44 -070080#elif defined(ANDROID_TARGET_BUILD)
Shih-wei Liao30ce65e2012-05-10 11:19:22 -070081 return android_atomic_dec((volatile int*)ptr);
Shih-wei Liaoe264f622010-02-10 11:10:31 -080082#elif defined(__GNUC__)
83 return __sync_sub_and_fetch(ptr, 1);
84#elif defined(_MSC_VER)
85 return InterlockedDecrement(ptr);
86#else
87# error No atomic decrement implementation for your platform!
88#endif
89}
90
91sys::cas_flag sys::AtomicAdd(volatile sys::cas_flag* ptr, sys::cas_flag val) {
Eric Christopher627445f2011-09-19 20:43:23 +000092#if LLVM_HAS_ATOMICS == 0
Shih-wei Liaoe264f622010-02-10 11:10:31 -080093 *ptr += val;
94 return *ptr;
Shih-wei Liao845de582012-05-10 09:12:44 -070095#elif defined(ANDROID_TARGET_BUILD)
Shih-wei Liao30ce65e2012-05-10 11:19:22 -070096 return android_atomic_add((int32_t)val, (volatile int*)ptr);
Shih-wei Liaoe264f622010-02-10 11:10:31 -080097#elif defined(__GNUC__)
98 return __sync_add_and_fetch(ptr, val);
99#elif defined(_MSC_VER)
100 return InterlockedExchangeAdd(ptr, val) + val;
101#else
102# error No atomic add implementation for your platform!
103#endif
104}
105
106sys::cas_flag sys::AtomicMul(volatile sys::cas_flag* ptr, sys::cas_flag val) {
107 sys::cas_flag original, result;
108 do {
109 original = *ptr;
110 result = original * val;
111 } while (sys::CompareAndSwap(ptr, result, original) != original);
112
113 return result;
114}
115
116sys::cas_flag sys::AtomicDiv(volatile sys::cas_flag* ptr, sys::cas_flag val) {
117 sys::cas_flag original, result;
118 do {
119 original = *ptr;
120 result = original / val;
121 } while (sys::CompareAndSwap(ptr, result, original) != original);
122
123 return result;
124}