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