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