12754fe60SDimitry Andric //===-- Atomic.cpp - Atomic Operations --------------------------*- C++ -*-===//
22754fe60SDimitry Andric //
32754fe60SDimitry Andric //                     The LLVM Compiler Infrastructure
42754fe60SDimitry Andric //
52754fe60SDimitry Andric // This file is distributed under the University of Illinois Open Source
62754fe60SDimitry Andric // License. See LICENSE.TXT for details.
72754fe60SDimitry Andric //
82754fe60SDimitry Andric //===----------------------------------------------------------------------===//
92754fe60SDimitry Andric //
102754fe60SDimitry Andric //  This file implements atomic operations.
112754fe60SDimitry Andric //
122754fe60SDimitry Andric //===----------------------------------------------------------------------===//
132754fe60SDimitry Andric 
142754fe60SDimitry Andric #include "llvm/Support/Atomic.h"
152754fe60SDimitry Andric #include "llvm/Config/llvm-config.h"
162754fe60SDimitry Andric 
172754fe60SDimitry Andric using namespace llvm;
182754fe60SDimitry Andric 
192754fe60SDimitry Andric #if defined(_MSC_VER)
202754fe60SDimitry Andric #include <intrin.h>
212754fe60SDimitry Andric 
222754fe60SDimitry Andric // We must include windows.h after intrin.h.
232754fe60SDimitry Andric #include <windows.h>
242754fe60SDimitry Andric #undef MemoryFence
25*86b360adSDimitry Andric #endif
262754fe60SDimitry Andric 
272754fe60SDimitry Andric #if defined(__GNUC__) || (defined(__IBMCPP__) && __IBMCPP__ >= 1210)
282754fe60SDimitry Andric #define GNU_ATOMICS
292754fe60SDimitry Andric #endif
302754fe60SDimitry Andric 
MemoryFence()312754fe60SDimitry Andric void sys::MemoryFence() {
322754fe60SDimitry Andric #if LLVM_HAS_ATOMICS == 0
332754fe60SDimitry Andric   return;
342754fe60SDimitry Andric #else
352754fe60SDimitry Andric #  if defined(GNU_ATOMICS)
362754fe60SDimitry Andric   __sync_synchronize();
372754fe60SDimitry Andric #  elif defined(_MSC_VER)
382754fe60SDimitry Andric   MemoryBarrier();
392754fe60SDimitry Andric #  else
402754fe60SDimitry Andric # error No memory fence implementation for your platform!
41*86b360adSDimitry Andric #  endif
422754fe60SDimitry Andric #endif
432754fe60SDimitry Andric }
442754fe60SDimitry Andric 
CompareAndSwap(volatile sys::cas_flag * ptr,sys::cas_flag new_value,sys::cas_flag old_value)452754fe60SDimitry Andric sys::cas_flag sys::CompareAndSwap(volatile sys::cas_flag* ptr,
462754fe60SDimitry Andric                                   sys::cas_flag new_value,
472754fe60SDimitry Andric                                   sys::cas_flag old_value) {
482754fe60SDimitry Andric #if LLVM_HAS_ATOMICS == 0
492754fe60SDimitry Andric   sys::cas_flag result = *ptr;
502754fe60SDimitry Andric   if (result == old_value)
512754fe60SDimitry Andric     *ptr = new_value;
522754fe60SDimitry Andric   return result;
532754fe60SDimitry Andric #elif defined(GNU_ATOMICS)
542754fe60SDimitry Andric   return __sync_val_compare_and_swap(ptr, old_value, new_value);
552754fe60SDimitry Andric #elif defined(_MSC_VER)
56*86b360adSDimitry Andric   return InterlockedCompareExchange(ptr, new_value, old_value);
572754fe60SDimitry Andric #else
582754fe60SDimitry Andric #  error No compare-and-swap implementation for your platform!
592754fe60SDimitry Andric #endif
602754fe60SDimitry Andric }
612754fe60SDimitry Andric