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