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 file implements atomic operations.
11//
12//===----------------------------------------------------------------------===//
13
14#include "llvm/Support/Atomic.h"
15#include "llvm/Config/llvm-config.h"
16
17using namespace llvm;
18
19#if defined(_MSC_VER)
20#include <Intrin.h>
21#include <windows.h>
22#undef MemoryFence
23#endif
24
25#if defined(__GNUC__) || (defined(__IBMCPP__) && __IBMCPP__ >= 1210)
26#define GNU_ATOMICS
27#endif
28
29void sys::MemoryFence() {
30#if LLVM_HAS_ATOMICS == 0
31  return;
32#else
33#  if defined(GNU_ATOMICS)
34  __sync_synchronize();
35#  elif defined(_MSC_VER)
36  MemoryBarrier();
37#  else
38# error No memory fence implementation for your platform!
39#  endif
40#endif
41}
42
43sys::cas_flag sys::CompareAndSwap(volatile sys::cas_flag* ptr,
44                                  sys::cas_flag new_value,
45                                  sys::cas_flag old_value) {
46#if LLVM_HAS_ATOMICS == 0
47  sys::cas_flag result = *ptr;
48  if (result == old_value)
49    *ptr = new_value;
50  return result;
51#elif defined(GNU_ATOMICS)
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(GNU_ATOMICS)
65  return __sync_add_and_fetch(ptr, 1);
66#elif defined(_MSC_VER)
67  return InterlockedIncrement(ptr);
68#else
69#  error No atomic increment implementation for your platform!
70#endif
71}
72
73sys::cas_flag sys::AtomicDecrement(volatile sys::cas_flag* ptr) {
74#if LLVM_HAS_ATOMICS == 0
75  --(*ptr);
76  return *ptr;
77#elif defined(GNU_ATOMICS)
78  return __sync_sub_and_fetch(ptr, 1);
79#elif defined(_MSC_VER)
80  return InterlockedDecrement(ptr);
81#else
82#  error No atomic decrement implementation for your platform!
83#endif
84}
85
86sys::cas_flag sys::AtomicAdd(volatile sys::cas_flag* ptr, sys::cas_flag val) {
87#if LLVM_HAS_ATOMICS == 0
88  *ptr += val;
89  return *ptr;
90#elif defined(GNU_ATOMICS)
91  return __sync_add_and_fetch(ptr, val);
92#elif defined(_MSC_VER)
93  return InterlockedExchangeAdd(ptr, val) + val;
94#else
95#  error No atomic add implementation for your platform!
96#endif
97}
98
99sys::cas_flag sys::AtomicMul(volatile sys::cas_flag* ptr, sys::cas_flag val) {
100  sys::cas_flag original, result;
101  do {
102    original = *ptr;
103    result = original * val;
104  } while (sys::CompareAndSwap(ptr, result, original) != original);
105
106  return result;
107}
108
109sys::cas_flag sys::AtomicDiv(volatile sys::cas_flag* ptr, sys::cas_flag val) {
110  sys::cas_flag original, result;
111  do {
112    original = *ptr;
113    result = original / val;
114  } while (sys::CompareAndSwap(ptr, result, original) != original);
115
116  return result;
117}
118