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#if defined(ANDROID_TARGET_BUILD)
17#  include "sys/atomics.h"
18#endif
19
20using namespace llvm;
21
22#if defined(_MSC_VER)
23#include <windows.h>
24#undef MemoryFence
25#endif
26
27void sys::MemoryFence() {
28#if LLVM_HAS_ATOMICS == 0
29  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) {
44#if LLVM_HAS_ATOMICS == 0
45  sys::cas_flag result = *ptr;
46  if (result == old_value)
47    *ptr = new_value;
48  return result;
49#elif defined(ANDROID_TARGET_BUILD)
50  return __atomic_cmpxchg(old_value, new_value, (volatile int*)ptr);
51#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) {
61#if LLVM_HAS_ATOMICS == 0
62  ++(*ptr);
63  return *ptr;
64#elif defined(ANDROID_TARGET_BUILD)
65  return __atomic_inc((volatile int*)ptr);
66#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) {
76#if LLVM_HAS_ATOMICS == 0
77  --(*ptr);
78  return *ptr;
79#elif defined(ANDROID_TARGET_BUILD)
80  return __atomic_dec((volatile int*)ptr);
81#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) {
91#if LLVM_HAS_ATOMICS == 0
92  *ptr += val;
93  return *ptr;
94#elif defined(ANDROID_TARGET_BUILD)
95  sys::cas_flag original, result;
96  do {
97    original = *ptr;
98    result = original + val;
99  } while (__atomic_cmpxchg(original, result, (volatile int*)ptr) != original);
100  return result;
101#elif defined(__GNUC__)
102  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}
129