blob: 5a62c7f31cf3040132448dc2a204b6bc1c4b4b10 [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)
50 return android_atomic_cas(old_value, new_value, (volatile int32_t*)ptr);
Shih-wei Liaoe264f622010-02-10 11:10:31 -080051#elif defined(__GNUC__)
52 return __sync_val_compare_and_swap(ptr, old_value, new_value);
53#elif defined(_MSC_VER)
54 return InterlockedCompareExchange(ptr, new_value, old_value);
55#else
56# error No compare-and-swap implementation for your platform!
57#endif
58}
59
60sys::cas_flag sys::AtomicIncrement(volatile sys::cas_flag* ptr) {
Eric Christopher627445f2011-09-19 20:43:23 +000061#if LLVM_HAS_ATOMICS == 0
Shih-wei Liaoe264f622010-02-10 11:10:31 -080062 ++(*ptr);
63 return *ptr;
Shih-wei Liao845de582012-05-10 09:12:44 -070064#elif defined(ANDROID_TARGET_BUILD)
65 return android_atomic_inc((volatile int32_t*)ptr);
Shih-wei Liaoe264f622010-02-10 11:10:31 -080066#elif defined(__GNUC__)
67 return __sync_add_and_fetch(ptr, 1);
68#elif defined(_MSC_VER)
69 return InterlockedIncrement(ptr);
70#else
71# error No atomic increment implementation for your platform!
72#endif
73}
74
75sys::cas_flag sys::AtomicDecrement(volatile sys::cas_flag* ptr) {
Eric Christopher627445f2011-09-19 20:43:23 +000076#if LLVM_HAS_ATOMICS == 0
Shih-wei Liaoe264f622010-02-10 11:10:31 -080077 --(*ptr);
78 return *ptr;
Shih-wei Liao845de582012-05-10 09:12:44 -070079#elif defined(ANDROID_TARGET_BUILD)
80 return android_atomic_dec((volatile int32_t*)ptr);
Shih-wei Liaoe264f622010-02-10 11:10:31 -080081#elif defined(__GNUC__)
82 return __sync_sub_and_fetch(ptr, 1);
83#elif defined(_MSC_VER)
84 return InterlockedDecrement(ptr);
85#else
86# error No atomic decrement implementation for your platform!
87#endif
88}
89
90sys::cas_flag sys::AtomicAdd(volatile sys::cas_flag* ptr, sys::cas_flag val) {
Eric Christopher627445f2011-09-19 20:43:23 +000091#if LLVM_HAS_ATOMICS == 0
Shih-wei Liaoe264f622010-02-10 11:10:31 -080092 *ptr += val;
93 return *ptr;
Shih-wei Liao845de582012-05-10 09:12:44 -070094#elif defined(ANDROID_TARGET_BUILD)
95 return android_atomic_add((int32_t)val, (volatile int32_t*)ptr);
Shih-wei Liaoe264f622010-02-10 11:10:31 -080096#elif defined(__GNUC__)
97 return __sync_add_and_fetch(ptr, val);
98#elif defined(_MSC_VER)
99 return InterlockedExchangeAdd(ptr, val) + val;
100#else
101# error No atomic add implementation for your platform!
102#endif
103}
104
105sys::cas_flag sys::AtomicMul(volatile sys::cas_flag* ptr, sys::cas_flag val) {
106 sys::cas_flag original, result;
107 do {
108 original = *ptr;
109 result = original * val;
110 } while (sys::CompareAndSwap(ptr, result, original) != original);
111
112 return result;
113}
114
115sys::cas_flag sys::AtomicDiv(volatile sys::cas_flag* ptr, sys::cas_flag val) {
116 sys::cas_flag original, result;
117 do {
118 original = *ptr;
119 result = original / val;
120 } while (sys::CompareAndSwap(ptr, result, original) != original);
121
122 return result;
123}