blob: ac4ff3eb5c6650e47c94d3e81a6e5de3248f956d [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//
Hans Wennborgcfe341f2014-06-20 01:36:00 +000010// This file implements atomic operations.
Owen Andersone5370f42009-05-20 18:26:15 +000011//
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)
Reid Kleckner64c75a52014-05-06 00:57:33 +000020#include <Intrin.h>
Owen Andersone5370f42009-05-20 18:26:15 +000021#include <windows.h>
Owen Anderson5bd914d2009-06-02 17:35:55 +000022#undef MemoryFence
Owen Andersone5370f42009-05-20 18:26:15 +000023#endif
24
Rafael Espindola2f92f612012-11-02 20:54:45 +000025#if defined(__GNUC__) || (defined(__IBMCPP__) && __IBMCPP__ >= 1210)
26#define GNU_ATOMICS
27#endif
28
Owen Andersone5370f42009-05-20 18:26:15 +000029void sys::MemoryFence() {
Eric Christopher4418a602011-09-19 20:43:23 +000030#if LLVM_HAS_ATOMICS == 0
Owen Andersone5370f42009-05-20 18:26:15 +000031 return;
32#else
Rafael Espindola2f92f612012-11-02 20:54:45 +000033# if defined(GNU_ATOMICS)
Owen Andersone5370f42009-05-20 18:26:15 +000034 __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
Owen Anderson5cc41312009-06-23 20:17:22 +000043sys::cas_flag sys::CompareAndSwap(volatile sys::cas_flag* ptr,
44 sys::cas_flag new_value,
45 sys::cas_flag old_value) {
Eric Christopher4418a602011-09-19 20:43:23 +000046#if LLVM_HAS_ATOMICS == 0
Owen Anderson5cc41312009-06-23 20:17:22 +000047 sys::cas_flag result = *ptr;
Owen Anderson5b9400d2009-05-20 19:01:50 +000048 if (result == old_value)
49 *ptr = new_value;
Owen Andersone5370f42009-05-20 18:26:15 +000050 return result;
Rafael Espindola2f92f612012-11-02 20:54:45 +000051#elif defined(GNU_ATOMICS)
Owen Andersone5370f42009-05-20 18:26:15 +000052 return __sync_val_compare_and_swap(ptr, old_value, new_value);
53#elif defined(_MSC_VER)
Owen Anderson76ae5dd2009-05-20 19:06:49 +000054 return InterlockedCompareExchange(ptr, new_value, old_value);
Owen Andersone5370f42009-05-20 18:26:15 +000055#else
56# error No compare-and-swap implementation for your platform!
57#endif
Duncan Sands06b61a22009-06-03 11:54:28 +000058}
Owen Anderson8d0fe6f2009-06-17 00:13:00 +000059
Owen Anderson5cc41312009-06-23 20:17:22 +000060sys::cas_flag sys::AtomicIncrement(volatile sys::cas_flag* ptr) {
Eric Christopher4418a602011-09-19 20:43:23 +000061#if LLVM_HAS_ATOMICS == 0
Owen Anderson8d0fe6f2009-06-17 00:13:00 +000062 ++(*ptr);
63 return *ptr;
Rafael Espindola2f92f612012-11-02 20:54:45 +000064#elif defined(GNU_ATOMICS)
Owen Anderson8d0fe6f2009-06-17 00:13:00 +000065 return __sync_add_and_fetch(ptr, 1);
66#elif defined(_MSC_VER)
Owen Andersonff5f14c2009-06-19 18:37:50 +000067 return InterlockedIncrement(ptr);
Owen Anderson8d0fe6f2009-06-17 00:13:00 +000068#else
69# error No atomic increment implementation for your platform!
70#endif
71}
72
Owen Anderson5cc41312009-06-23 20:17:22 +000073sys::cas_flag sys::AtomicDecrement(volatile sys::cas_flag* ptr) {
Eric Christopher4418a602011-09-19 20:43:23 +000074#if LLVM_HAS_ATOMICS == 0
Owen Anderson8d0fe6f2009-06-17 00:13:00 +000075 --(*ptr);
76 return *ptr;
Rafael Espindola2f92f612012-11-02 20:54:45 +000077#elif defined(GNU_ATOMICS)
Owen Anderson8d0fe6f2009-06-17 00:13:00 +000078 return __sync_sub_and_fetch(ptr, 1);
79#elif defined(_MSC_VER)
Owen Andersonff5f14c2009-06-19 18:37:50 +000080 return InterlockedDecrement(ptr);
Owen Anderson8d0fe6f2009-06-17 00:13:00 +000081#else
82# error No atomic decrement implementation for your platform!
83#endif
84}
85
Owen Anderson5cc41312009-06-23 20:17:22 +000086sys::cas_flag sys::AtomicAdd(volatile sys::cas_flag* ptr, sys::cas_flag val) {
Eric Christopher4418a602011-09-19 20:43:23 +000087#if LLVM_HAS_ATOMICS == 0
Owen Andersoncdf2b2d2009-06-23 17:39:31 +000088 *ptr += val;
89 return *ptr;
Rafael Espindola2f92f612012-11-02 20:54:45 +000090#elif defined(GNU_ATOMICS)
Owen Andersoncdf2b2d2009-06-23 17:39:31 +000091 return __sync_add_and_fetch(ptr, val);
92#elif defined(_MSC_VER)
Oscar Fuentes8b6d88d22009-12-07 05:29:59 +000093 return InterlockedExchangeAdd(ptr, val) + val;
Owen Andersoncdf2b2d2009-06-23 17:39:31 +000094#else
95# error No atomic add implementation for your platform!
96#endif
97}
98
Owen Anderson1fdf0102009-06-23 21:19:04 +000099sys::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);
Owen Anderson8d0fe6f2009-06-17 00:13:00 +0000105
Owen Anderson1fdf0102009-06-23 21:19:04 +0000106 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}