blob: 9559ad729570d5c6814a43f825df4d17a5878d39 [file] [log] [blame]
Owen Andersone5370f42009-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. Spencer447762d2010-11-29 18:16:10 +000014#include "llvm/Support/Atomic.h"
Dylan Noblesmith9e5b1782011-12-22 23:04:07 +000015#include "llvm/Config/llvm-config.h"
Owen Andersone5370f42009-05-20 18:26:15 +000016
17using namespace llvm;
18
19#if defined(_MSC_VER)
20#include <windows.h>
Owen Anderson5bd914d2009-06-02 17:35:55 +000021#undef MemoryFence
Owen Andersone5370f42009-05-20 18:26:15 +000022#endif
23
Rafael Espindola2f92f612012-11-02 20:54:45 +000024#if defined(__GNUC__) || (defined(__IBMCPP__) && __IBMCPP__ >= 1210)
25#define GNU_ATOMICS
26#endif
27
Owen Andersone5370f42009-05-20 18:26:15 +000028void sys::MemoryFence() {
Eric Christopher4418a602011-09-19 20:43:23 +000029#if LLVM_HAS_ATOMICS == 0
Owen Andersone5370f42009-05-20 18:26:15 +000030 return;
31#else
Rafael Espindola2f92f612012-11-02 20:54:45 +000032# if defined(GNU_ATOMICS)
Owen Andersone5370f42009-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 Anderson5cc41312009-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 Christopher4418a602011-09-19 20:43:23 +000045#if LLVM_HAS_ATOMICS == 0
Owen Anderson5cc41312009-06-23 20:17:22 +000046 sys::cas_flag result = *ptr;
Owen Anderson5b9400d2009-05-20 19:01:50 +000047 if (result == old_value)
48 *ptr = new_value;
Owen Andersone5370f42009-05-20 18:26:15 +000049 return result;
Rafael Espindola2f92f612012-11-02 20:54:45 +000050#elif defined(GNU_ATOMICS)
Owen Andersone5370f42009-05-20 18:26:15 +000051 return __sync_val_compare_and_swap(ptr, old_value, new_value);
52#elif defined(_MSC_VER)
Owen Anderson76ae5dd2009-05-20 19:06:49 +000053 return InterlockedCompareExchange(ptr, new_value, old_value);
Owen Andersone5370f42009-05-20 18:26:15 +000054#else
55# error No compare-and-swap implementation for your platform!
56#endif
Duncan Sands06b61a22009-06-03 11:54:28 +000057}
Owen Anderson8d0fe6f2009-06-17 00:13:00 +000058
Owen Anderson5cc41312009-06-23 20:17:22 +000059sys::cas_flag sys::AtomicIncrement(volatile sys::cas_flag* ptr) {
Eric Christopher4418a602011-09-19 20:43:23 +000060#if LLVM_HAS_ATOMICS == 0
Owen Anderson8d0fe6f2009-06-17 00:13:00 +000061 ++(*ptr);
62 return *ptr;
Rafael Espindola2f92f612012-11-02 20:54:45 +000063#elif defined(GNU_ATOMICS)
Owen Anderson8d0fe6f2009-06-17 00:13:00 +000064 return __sync_add_and_fetch(ptr, 1);
65#elif defined(_MSC_VER)
Owen Andersonff5f14c2009-06-19 18:37:50 +000066 return InterlockedIncrement(ptr);
Owen Anderson8d0fe6f2009-06-17 00:13:00 +000067#else
68# error No atomic increment implementation for your platform!
69#endif
70}
71
Owen Anderson5cc41312009-06-23 20:17:22 +000072sys::cas_flag sys::AtomicDecrement(volatile sys::cas_flag* ptr) {
Eric Christopher4418a602011-09-19 20:43:23 +000073#if LLVM_HAS_ATOMICS == 0
Owen Anderson8d0fe6f2009-06-17 00:13:00 +000074 --(*ptr);
75 return *ptr;
Rafael Espindola2f92f612012-11-02 20:54:45 +000076#elif defined(GNU_ATOMICS)
Owen Anderson8d0fe6f2009-06-17 00:13:00 +000077 return __sync_sub_and_fetch(ptr, 1);
78#elif defined(_MSC_VER)
Owen Andersonff5f14c2009-06-19 18:37:50 +000079 return InterlockedDecrement(ptr);
Owen Anderson8d0fe6f2009-06-17 00:13:00 +000080#else
81# error No atomic decrement implementation for your platform!
82#endif
83}
84
Owen Anderson5cc41312009-06-23 20:17:22 +000085sys::cas_flag sys::AtomicAdd(volatile sys::cas_flag* ptr, sys::cas_flag val) {
Eric Christopher4418a602011-09-19 20:43:23 +000086#if LLVM_HAS_ATOMICS == 0
Owen Andersoncdf2b2d2009-06-23 17:39:31 +000087 *ptr += val;
88 return *ptr;
Rafael Espindola2f92f612012-11-02 20:54:45 +000089#elif defined(GNU_ATOMICS)
Owen Andersoncdf2b2d2009-06-23 17:39:31 +000090 return __sync_add_and_fetch(ptr, val);
91#elif defined(_MSC_VER)
Oscar Fuentes8b6d88d22009-12-07 05:29:59 +000092 return InterlockedExchangeAdd(ptr, val) + val;
Owen Andersoncdf2b2d2009-06-23 17:39:31 +000093#else
94# error No atomic add implementation for your platform!
95#endif
96}
97
Owen Anderson1fdf0102009-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 Anderson8d0fe6f2009-06-17 00:13:00 +0000104
Owen Anderson1fdf0102009-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}