119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman//===-- Atomic.cpp - Atomic Operations --------------------------*- C++ -*-===//
219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman//
319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman//                     The LLVM Compiler Infrastructure
419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman//
519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman// This file is distributed under the University of Illinois Open Source
619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman// License. See LICENSE.TXT for details.
719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman//
819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman//===----------------------------------------------------------------------===//
919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman//
1019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman//  This header file implements atomic operations.
1119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman//
1219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman//===----------------------------------------------------------------------===//
1319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
1419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman#include "llvm/Support/Atomic.h"
1519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman#include "llvm/Config/config.h"
1619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
1719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Baumanusing namespace llvm;
1819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
1919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman#if defined(_MSC_VER)
20e23e5b4205911946e24dfaa4d7a69e44a4c0160fAlexis Hetu#include <intrin.h>
2119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman#include <windows.h>
2219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman#undef MemoryFence
2319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman#endif
2419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
2519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Baumanvoid sys::MemoryFence() {
2619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman#if LLVM_HAS_ATOMICS == 0
2719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  return;
2819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman#else
2919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman#  if defined(__GNUC__)
3019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  __sync_synchronize();
3119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman#  elif defined(_MSC_VER)
3219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  MemoryBarrier();
3319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman#  else
3419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman# error No memory fence implementation for your platform!
3519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman#  endif
3619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman#endif
3719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman}
3819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
3919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Baumansys::cas_flag sys::CompareAndSwap(volatile sys::cas_flag* ptr,
4019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman                                  sys::cas_flag new_value,
4119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman                                  sys::cas_flag old_value) {
4219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman#if LLVM_HAS_ATOMICS == 0
4319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  sys::cas_flag result = *ptr;
4419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  if (result == old_value)
4519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    *ptr = new_value;
4619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  return result;
4719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman#elif defined(__GNUC__)
4819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  return __sync_val_compare_and_swap(ptr, old_value, new_value);
4919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman#elif defined(_MSC_VER)
5019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  return InterlockedCompareExchange(ptr, new_value, old_value);
5119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman#else
5219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman#  error No compare-and-swap implementation for your platform!
5319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman#endif
5419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman}
5519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
5619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Baumansys::cas_flag sys::AtomicIncrement(volatile sys::cas_flag* ptr) {
5719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman#if LLVM_HAS_ATOMICS == 0
5819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  ++(*ptr);
5919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  return *ptr;
6019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman#elif defined(__GNUC__)
6119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  return __sync_add_and_fetch(ptr, 1);
6219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman#elif defined(_MSC_VER)
6319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  return InterlockedIncrement(ptr);
6419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman#else
6519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman#  error No atomic increment implementation for your platform!
6619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman#endif
6719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman}
6819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
6919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Baumansys::cas_flag sys::AtomicDecrement(volatile sys::cas_flag* ptr) {
7019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman#if LLVM_HAS_ATOMICS == 0
7119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  --(*ptr);
7219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  return *ptr;
7319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman#elif defined(__GNUC__)
7419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  return __sync_sub_and_fetch(ptr, 1);
7519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman#elif defined(_MSC_VER)
7619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  return InterlockedDecrement(ptr);
7719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman#else
7819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman#  error No atomic decrement implementation for your platform!
7919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman#endif
8019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman}
8119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
8219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Baumansys::cas_flag sys::AtomicAdd(volatile sys::cas_flag* ptr, sys::cas_flag val) {
8319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman#if LLVM_HAS_ATOMICS == 0
8419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  *ptr += val;
8519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  return *ptr;
8619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman#elif defined(__GNUC__)
8719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  return __sync_add_and_fetch(ptr, val);
8819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman#elif defined(_MSC_VER)
8919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  return InterlockedExchangeAdd(ptr, val) + val;
9019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman#else
9119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman#  error No atomic add implementation for your platform!
9219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman#endif
9319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman}
9419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
9519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Baumansys::cas_flag sys::AtomicMul(volatile sys::cas_flag* ptr, sys::cas_flag val) {
9619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  sys::cas_flag original, result;
9719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  do {
9819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    original = *ptr;
9919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    result = original * val;
10019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  } while (sys::CompareAndSwap(ptr, result, original) != original);
10119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
10219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  return result;
10319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman}
10419bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
10519bac1e08be200c31efd26f0f5fd144c9b3eefd3John Baumansys::cas_flag sys::AtomicDiv(volatile sys::cas_flag* ptr, sys::cas_flag val) {
10619bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  sys::cas_flag original, result;
10719bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  do {
10819bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    original = *ptr;
10919bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman    result = original / val;
11019bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  } while (sys::CompareAndSwap(ptr, result, original) != original);
11119bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman
11219bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman  return result;
11319bac1e08be200c31efd26f0f5fd144c9b3eefd3John Bauman}
114