blob: 9559ad729570d5c6814a43f825df4d17a5878d39 [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"
Dylan Noblesmith94214062011-12-22 23:04:07 +000015#include "llvm/Config/llvm-config.h"
Owen Anderson3c1eaa02009-05-20 18:26:15 +000016
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
Rafael Espindola986f29c2012-11-02 20:54:45 +000024#if defined(__GNUC__) || (defined(__IBMCPP__) && __IBMCPP__ >= 1210)
25#define GNU_ATOMICS
26#endif
27
Owen Anderson3c1eaa02009-05-20 18:26:15 +000028void sys::MemoryFence() {
Eric Christopher627445f2011-09-19 20:43:23 +000029#if LLVM_HAS_ATOMICS == 0
Owen Anderson3c1eaa02009-05-20 18:26:15 +000030 return;
31#else
Rafael Espindola986f29c2012-11-02 20:54:45 +000032# if defined(GNU_ATOMICS)
Owen Anderson3c1eaa02009-05-20 18:26:15 +000033 __sync_synchronize();
34# elif defined(_MSC_VER)
35 MemoryBarrier();
36# else
37# error No memory fence implementation for your platform!
38# endif
39#endif
40}
41
Owen Anderson6f2c64d2009-06-23 20:17:22 +000042sys::cas_flag sys::CompareAndSwap(volatile sys::cas_flag* ptr,
43 sys::cas_flag new_value,
44 sys::cas_flag old_value) {
Eric Christopher627445f2011-09-19 20:43:23 +000045#if LLVM_HAS_ATOMICS == 0
Owen Anderson6f2c64d2009-06-23 20:17:22 +000046 sys::cas_flag result = *ptr;
Owen Anderson41583b92009-05-20 19:01:50 +000047 if (result == old_value)
48 *ptr = new_value;
Owen Anderson3c1eaa02009-05-20 18:26:15 +000049 return result;
Rafael Espindola986f29c2012-11-02 20:54:45 +000050#elif defined(GNU_ATOMICS)
Owen Anderson3c1eaa02009-05-20 18:26:15 +000051 return __sync_val_compare_and_swap(ptr, old_value, new_value);
52#elif defined(_MSC_VER)
Owen Anderson2aa783b2009-05-20 19:06:49 +000053 return InterlockedCompareExchange(ptr, new_value, old_value);
Owen Anderson3c1eaa02009-05-20 18:26:15 +000054#else
55# error No compare-and-swap implementation for your platform!
56#endif
Duncan Sands05a8c872009-06-03 11:54:28 +000057}
Owen Anderson9a3df672009-06-17 00:13:00 +000058
Owen Anderson6f2c64d2009-06-23 20:17:22 +000059sys::cas_flag sys::AtomicIncrement(volatile sys::cas_flag* ptr) {
Eric Christopher627445f2011-09-19 20:43:23 +000060#if LLVM_HAS_ATOMICS == 0
Owen Anderson9a3df672009-06-17 00:13:00 +000061 ++(*ptr);
62 return *ptr;
Rafael Espindola986f29c2012-11-02 20:54:45 +000063#elif defined(GNU_ATOMICS)
Owen Anderson9a3df672009-06-17 00:13:00 +000064 return __sync_add_and_fetch(ptr, 1);
65#elif defined(_MSC_VER)
Owen Andersonb9c2f582009-06-19 18:37:50 +000066 return InterlockedIncrement(ptr);
Owen Anderson9a3df672009-06-17 00:13:00 +000067#else
68# error No atomic increment implementation for your platform!
69#endif
70}
71
Owen Anderson6f2c64d2009-06-23 20:17:22 +000072sys::cas_flag sys::AtomicDecrement(volatile sys::cas_flag* ptr) {
Eric Christopher627445f2011-09-19 20:43:23 +000073#if LLVM_HAS_ATOMICS == 0
Owen Anderson9a3df672009-06-17 00:13:00 +000074 --(*ptr);
75 return *ptr;
Rafael Espindola986f29c2012-11-02 20:54:45 +000076#elif defined(GNU_ATOMICS)
Owen Anderson9a3df672009-06-17 00:13:00 +000077 return __sync_sub_and_fetch(ptr, 1);
78#elif defined(_MSC_VER)
Owen Andersonb9c2f582009-06-19 18:37:50 +000079 return InterlockedDecrement(ptr);
Owen Anderson9a3df672009-06-17 00:13:00 +000080#else
81# error No atomic decrement implementation for your platform!
82#endif
83}
84
Owen Anderson6f2c64d2009-06-23 20:17:22 +000085sys::cas_flag sys::AtomicAdd(volatile sys::cas_flag* ptr, sys::cas_flag val) {
Eric Christopher627445f2011-09-19 20:43:23 +000086#if LLVM_HAS_ATOMICS == 0
Owen Anderson5a9c0ee2009-06-23 17:39:31 +000087 *ptr += val;
88 return *ptr;
Rafael Espindola986f29c2012-11-02 20:54:45 +000089#elif defined(GNU_ATOMICS)
Owen Anderson5a9c0ee2009-06-23 17:39:31 +000090 return __sync_add_and_fetch(ptr, val);
91#elif defined(_MSC_VER)
Oscar Fuentesbcc2e452009-12-07 05:29:59 +000092 return InterlockedExchangeAdd(ptr, val) + val;
Owen Anderson5a9c0ee2009-06-23 17:39:31 +000093#else
94# error No atomic add implementation for your platform!
95#endif
96}
97
Owen Andersone0fa0b42009-06-23 21:19:04 +000098sys::cas_flag sys::AtomicMul(volatile sys::cas_flag* ptr, sys::cas_flag val) {
99 sys::cas_flag original, result;
100 do {
101 original = *ptr;
102 result = original * val;
103 } while (sys::CompareAndSwap(ptr, result, original) != original);
Owen Anderson9a3df672009-06-17 00:13:00 +0000104
Owen Andersone0fa0b42009-06-23 21:19:04 +0000105 return result;
106}
107
108sys::cas_flag sys::AtomicDiv(volatile sys::cas_flag* ptr, sys::cas_flag val) {
109 sys::cas_flag original, result;
110 do {
111 original = *ptr;
112 result = original / val;
113 } while (sys::CompareAndSwap(ptr, result, original) != original);
114
115 return result;
116}