blob: c7b4bff27948d5cd32764ff4d1d9cbb9127b4bde [file] [log] [blame]
Owen Anderson3c1eaa02009-05-20 18:26:15 +00001//===-- 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"
Owen Anderson3c1eaa02009-05-20 18:26:15 +000015#include "llvm/Config/config.h"
16
17using namespace llvm;
18
19#if defined(_MSC_VER)
20#include <windows.h>
Owen Andersond8cf4032009-06-02 17:35:55 +000021#undef MemoryFence
Owen Anderson3c1eaa02009-05-20 18:26:15 +000022#endif
23
24void sys::MemoryFence() {
25#if LLVM_MULTITHREADED==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
Owen Anderson6f2c64d2009-06-23 20:17:22 +000038sys::cas_flag sys::CompareAndSwap(volatile sys::cas_flag* ptr,
39 sys::cas_flag new_value,
40 sys::cas_flag old_value) {
Owen Anderson3c1eaa02009-05-20 18:26:15 +000041#if LLVM_MULTITHREADED==0
Owen Anderson6f2c64d2009-06-23 20:17:22 +000042 sys::cas_flag result = *ptr;
Owen Anderson41583b92009-05-20 19:01:50 +000043 if (result == old_value)
44 *ptr = new_value;
Owen Anderson3c1eaa02009-05-20 18:26:15 +000045 return result;
46#elif defined(__GNUC__)
47 return __sync_val_compare_and_swap(ptr, old_value, new_value);
48#elif defined(_MSC_VER)
Owen Anderson2aa783b2009-05-20 19:06:49 +000049 return InterlockedCompareExchange(ptr, new_value, old_value);
Owen Anderson3c1eaa02009-05-20 18:26:15 +000050#else
51# error No compare-and-swap implementation for your platform!
52#endif
Duncan Sands05a8c872009-06-03 11:54:28 +000053}
Owen Anderson9a3df672009-06-17 00:13:00 +000054
Owen Anderson6f2c64d2009-06-23 20:17:22 +000055sys::cas_flag sys::AtomicIncrement(volatile sys::cas_flag* ptr) {
Owen Anderson9a3df672009-06-17 00:13:00 +000056#if LLVM_MULTITHREADED==0
57 ++(*ptr);
58 return *ptr;
59#elif defined(__GNUC__)
60 return __sync_add_and_fetch(ptr, 1);
61#elif defined(_MSC_VER)
Owen Andersonb9c2f582009-06-19 18:37:50 +000062 return InterlockedIncrement(ptr);
Owen Anderson9a3df672009-06-17 00:13:00 +000063#else
64# error No atomic increment implementation for your platform!
65#endif
66}
67
Owen Anderson6f2c64d2009-06-23 20:17:22 +000068sys::cas_flag sys::AtomicDecrement(volatile sys::cas_flag* ptr) {
Owen Anderson9a3df672009-06-17 00:13:00 +000069#if LLVM_MULTITHREADED==0
70 --(*ptr);
71 return *ptr;
72#elif defined(__GNUC__)
73 return __sync_sub_and_fetch(ptr, 1);
74#elif defined(_MSC_VER)
Owen Andersonb9c2f582009-06-19 18:37:50 +000075 return InterlockedDecrement(ptr);
Owen Anderson9a3df672009-06-17 00:13:00 +000076#else
77# error No atomic decrement implementation for your platform!
78#endif
79}
80
Owen Anderson6f2c64d2009-06-23 20:17:22 +000081sys::cas_flag sys::AtomicAdd(volatile sys::cas_flag* ptr, sys::cas_flag val) {
Owen Anderson5a9c0ee2009-06-23 17:39:31 +000082#if LLVM_MULTITHREADED==0
83 *ptr += val;
84 return *ptr;
85#elif defined(__GNUC__)
86 return __sync_add_and_fetch(ptr, val);
87#elif defined(_MSC_VER)
Oscar Fuentesbcc2e452009-12-07 05:29:59 +000088 return InterlockedExchangeAdd(ptr, val) + val;
Owen Anderson5a9c0ee2009-06-23 17:39:31 +000089#else
90# error No atomic add implementation for your platform!
91#endif
92}
93
Owen Andersone0fa0b42009-06-23 21:19:04 +000094sys::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);
Owen Anderson9a3df672009-06-17 00:13:00 +0000100
Owen Andersone0fa0b42009-06-23 21:19:04 +0000101 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}