Home | History | Annotate | Download | only in Support
      1 //===-- 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 file implements atomic operations.
     11 //
     12 //===----------------------------------------------------------------------===//
     13 
     14 #include "llvm/Support/Atomic.h"
     15 #include "llvm/Config/llvm-config.h"
     16 
     17 using namespace llvm;
     18 
     19 #if defined(_MSC_VER)
     20 #include <Intrin.h>
     21 #include <windows.h>
     22 #undef MemoryFence
     23 #endif
     24 
     25 #if defined(__GNUC__) || (defined(__IBMCPP__) && __IBMCPP__ >= 1210)
     26 #define GNU_ATOMICS
     27 #endif
     28 
     29 void sys::MemoryFence() {
     30 #if LLVM_HAS_ATOMICS == 0
     31   return;
     32 #else
     33 #  if defined(GNU_ATOMICS)
     34   __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 
     43 sys::cas_flag sys::CompareAndSwap(volatile sys::cas_flag* ptr,
     44                                   sys::cas_flag new_value,
     45                                   sys::cas_flag old_value) {
     46 #if LLVM_HAS_ATOMICS == 0
     47   sys::cas_flag result = *ptr;
     48   if (result == old_value)
     49     *ptr = new_value;
     50   return result;
     51 #elif defined(GNU_ATOMICS)
     52   return __sync_val_compare_and_swap(ptr, old_value, new_value);
     53 #elif defined(_MSC_VER)
     54   return InterlockedCompareExchange(ptr, new_value, old_value);
     55 #else
     56 #  error No compare-and-swap implementation for your platform!
     57 #endif
     58 }
     59 
     60 sys::cas_flag sys::AtomicIncrement(volatile sys::cas_flag* ptr) {
     61 #if LLVM_HAS_ATOMICS == 0
     62   ++(*ptr);
     63   return *ptr;
     64 #elif defined(GNU_ATOMICS)
     65   return __sync_add_and_fetch(ptr, 1);
     66 #elif defined(_MSC_VER)
     67   return InterlockedIncrement(ptr);
     68 #else
     69 #  error No atomic increment implementation for your platform!
     70 #endif
     71 }
     72 
     73 sys::cas_flag sys::AtomicDecrement(volatile sys::cas_flag* ptr) {
     74 #if LLVM_HAS_ATOMICS == 0
     75   --(*ptr);
     76   return *ptr;
     77 #elif defined(GNU_ATOMICS)
     78   return __sync_sub_and_fetch(ptr, 1);
     79 #elif defined(_MSC_VER)
     80   return InterlockedDecrement(ptr);
     81 #else
     82 #  error No atomic decrement implementation for your platform!
     83 #endif
     84 }
     85 
     86 sys::cas_flag sys::AtomicAdd(volatile sys::cas_flag* ptr, sys::cas_flag val) {
     87 #if LLVM_HAS_ATOMICS == 0
     88   *ptr += val;
     89   return *ptr;
     90 #elif defined(GNU_ATOMICS)
     91   return __sync_add_and_fetch(ptr, val);
     92 #elif defined(_MSC_VER)
     93   return InterlockedExchangeAdd(ptr, val) + val;
     94 #else
     95 #  error No atomic add implementation for your platform!
     96 #endif
     97 }
     98 
     99 sys::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);
    105 
    106   return result;
    107 }
    108 
    109 sys::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 }
    118