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 header file implements atomic operations.
     11 //
     12 //===----------------------------------------------------------------------===//
     13 
     14 #include "llvm/Support/Atomic.h"
     15 #include "llvm/Config/llvm-config.h"
     16 #if defined(ANDROID_TARGET_BUILD)
     17 #include "cutils/atomic.h"
     18 #endif
     19 
     20 using namespace llvm;
     21 
     22 #if defined(_MSC_VER)
     23 #include <windows.h>
     24 #undef MemoryFence
     25 #endif
     26 
     27 #if defined(__GNUC__) || (defined(__IBMCPP__) && __IBMCPP__ >= 1210)
     28 #define GNU_ATOMICS
     29 #endif
     30 
     31 void sys::MemoryFence() {
     32 #if LLVM_HAS_ATOMICS == 0
     33   return;
     34 #else
     35 #  if defined(GNU_ATOMICS)
     36   __sync_synchronize();
     37 #  elif defined(_MSC_VER)
     38   MemoryBarrier();
     39 #  else
     40 # error No memory fence implementation for your platform!
     41 #  endif
     42 #endif
     43 }
     44 
     45 sys::cas_flag sys::CompareAndSwap(volatile sys::cas_flag* ptr,
     46                                   sys::cas_flag new_value,
     47                                   sys::cas_flag old_value) {
     48 #if LLVM_HAS_ATOMICS == 0
     49   sys::cas_flag result = *ptr;
     50   if (result == old_value)
     51     *ptr = new_value;
     52   return result;
     53 #elif defined(ANDROID_TARGET_BUILD)
     54   return android_atomic_cmpxchg((int32_t)old_value, (int32_t)new_value,
     55                                 (volatile int*)ptr);
     56 #elif defined(GNU_ATOMICS)
     57   return __sync_val_compare_and_swap(ptr, old_value, new_value);
     58 #elif defined(_MSC_VER)
     59   return InterlockedCompareExchange(ptr, new_value, old_value);
     60 #else
     61 #  error No compare-and-swap implementation for your platform!
     62 #endif
     63 }
     64 
     65 sys::cas_flag sys::AtomicIncrement(volatile sys::cas_flag* ptr) {
     66 #if LLVM_HAS_ATOMICS == 0
     67   ++(*ptr);
     68   return *ptr;
     69 #elif defined(ANDROID_TARGET_BUILD)
     70   return android_atomic_inc((volatile int*)ptr);
     71 #elif defined(GNU_ATOMICS)
     72   return __sync_add_and_fetch(ptr, 1);
     73 #elif defined(_MSC_VER)
     74   return InterlockedIncrement(ptr);
     75 #else
     76 #  error No atomic increment implementation for your platform!
     77 #endif
     78 }
     79 
     80 sys::cas_flag sys::AtomicDecrement(volatile sys::cas_flag* ptr) {
     81 #if LLVM_HAS_ATOMICS == 0
     82   --(*ptr);
     83   return *ptr;
     84 #elif defined(ANDROID_TARGET_BUILD)
     85   return android_atomic_dec((volatile int*)ptr);
     86 #elif defined(GNU_ATOMICS)
     87   return __sync_sub_and_fetch(ptr, 1);
     88 #elif defined(_MSC_VER)
     89   return InterlockedDecrement(ptr);
     90 #else
     91 #  error No atomic decrement implementation for your platform!
     92 #endif
     93 }
     94 
     95 sys::cas_flag sys::AtomicAdd(volatile sys::cas_flag* ptr, sys::cas_flag val) {
     96 #if LLVM_HAS_ATOMICS == 0
     97   *ptr += val;
     98   return *ptr;
     99 #elif defined(ANDROID_TARGET_BUILD)
    100   return android_atomic_add((int32_t)val, (volatile int*)ptr);
    101 #elif defined(GNU_ATOMICS)
    102   return __sync_add_and_fetch(ptr, val);
    103 #elif defined(_MSC_VER)
    104   return InterlockedExchangeAdd(ptr, val) + val;
    105 #else
    106 #  error No atomic add implementation for your platform!
    107 #endif
    108 }
    109 
    110 sys::cas_flag sys::AtomicMul(volatile sys::cas_flag* ptr, sys::cas_flag val) {
    111   sys::cas_flag original, result;
    112   do {
    113     original = *ptr;
    114     result = original * val;
    115   } while (sys::CompareAndSwap(ptr, result, original) != original);
    116 
    117   return result;
    118 }
    119 
    120 sys::cas_flag sys::AtomicDiv(volatile sys::cas_flag* ptr, sys::cas_flag val) {
    121   sys::cas_flag original, result;
    122   do {
    123     original = *ptr;
    124     result = original / val;
    125   } while (sys::CompareAndSwap(ptr, result, original) != original);
    126 
    127   return result;
    128 }
    129