10b57cec5SDimitry Andric //===-- sanitizer_atomic_msvc.h ---------------------------------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file is a part of ThreadSanitizer/AddressSanitizer runtime.
100b57cec5SDimitry Andric // Not intended for direct inclusion. Include sanitizer_atomic.h.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric
140b57cec5SDimitry Andric #ifndef SANITIZER_ATOMIC_MSVC_H
150b57cec5SDimitry Andric #define SANITIZER_ATOMIC_MSVC_H
160b57cec5SDimitry Andric
170b57cec5SDimitry Andric extern "C" void _ReadWriteBarrier();
180b57cec5SDimitry Andric #pragma intrinsic(_ReadWriteBarrier)
190b57cec5SDimitry Andric extern "C" void _mm_mfence();
200b57cec5SDimitry Andric #pragma intrinsic(_mm_mfence)
210b57cec5SDimitry Andric extern "C" void _mm_pause();
220b57cec5SDimitry Andric #pragma intrinsic(_mm_pause)
2368d75effSDimitry Andric extern "C" char _InterlockedExchange8(char volatile *Addend, char Value);
240b57cec5SDimitry Andric #pragma intrinsic(_InterlockedExchange8)
2568d75effSDimitry Andric extern "C" short _InterlockedExchange16(short volatile *Addend, short Value);
260b57cec5SDimitry Andric #pragma intrinsic(_InterlockedExchange16)
2768d75effSDimitry Andric extern "C" long _InterlockedExchange(long volatile *Addend, long Value);
280b57cec5SDimitry Andric #pragma intrinsic(_InterlockedExchange)
2968d75effSDimitry Andric extern "C" long _InterlockedExchangeAdd(long volatile *Addend, long Value);
300b57cec5SDimitry Andric #pragma intrinsic(_InterlockedExchangeAdd)
3168d75effSDimitry Andric extern "C" char _InterlockedCompareExchange8(char volatile *Destination,
3268d75effSDimitry Andric char Exchange, char Comparand);
330b57cec5SDimitry Andric #pragma intrinsic(_InterlockedCompareExchange8)
3468d75effSDimitry Andric extern "C" short _InterlockedCompareExchange16(short volatile *Destination,
3568d75effSDimitry Andric short Exchange, short Comparand);
360b57cec5SDimitry Andric #pragma intrinsic(_InterlockedCompareExchange16)
3768d75effSDimitry Andric extern "C" long long _InterlockedCompareExchange64(
3868d75effSDimitry Andric long long volatile *Destination, long long Exchange, long long Comparand);
390b57cec5SDimitry Andric #pragma intrinsic(_InterlockedCompareExchange64)
400b57cec5SDimitry Andric extern "C" void *_InterlockedCompareExchangePointer(
410b57cec5SDimitry Andric void *volatile *Destination,
420b57cec5SDimitry Andric void *Exchange, void *Comparand);
430b57cec5SDimitry Andric #pragma intrinsic(_InterlockedCompareExchangePointer)
4468d75effSDimitry Andric extern "C" long __cdecl _InterlockedCompareExchange(long volatile *Destination,
4568d75effSDimitry Andric long Exchange,
4668d75effSDimitry Andric long Comparand);
470b57cec5SDimitry Andric #pragma intrinsic(_InterlockedCompareExchange)
480b57cec5SDimitry Andric
490b57cec5SDimitry Andric #ifdef _WIN64
5068d75effSDimitry Andric extern "C" long long _InterlockedExchangeAdd64(long long volatile *Addend,
5168d75effSDimitry Andric long long Value);
520b57cec5SDimitry Andric #pragma intrinsic(_InterlockedExchangeAdd64)
530b57cec5SDimitry Andric #endif
540b57cec5SDimitry Andric
550b57cec5SDimitry Andric namespace __sanitizer {
560b57cec5SDimitry Andric
atomic_signal_fence(memory_order)57e8d8bef9SDimitry Andric inline void atomic_signal_fence(memory_order) {
580b57cec5SDimitry Andric _ReadWriteBarrier();
590b57cec5SDimitry Andric }
600b57cec5SDimitry Andric
atomic_thread_fence(memory_order)61e8d8bef9SDimitry Andric inline void atomic_thread_fence(memory_order) {
620b57cec5SDimitry Andric _mm_mfence();
630b57cec5SDimitry Andric }
640b57cec5SDimitry Andric
proc_yield(int cnt)65e8d8bef9SDimitry Andric inline void proc_yield(int cnt) {
660b57cec5SDimitry Andric for (int i = 0; i < cnt; i++)
670b57cec5SDimitry Andric _mm_pause();
680b57cec5SDimitry Andric }
690b57cec5SDimitry Andric
700b57cec5SDimitry Andric template<typename T>
atomic_load(const volatile T * a,memory_order mo)71e8d8bef9SDimitry Andric inline typename T::Type atomic_load(
720b57cec5SDimitry Andric const volatile T *a, memory_order mo) {
73*0fca6ea1SDimitry Andric DCHECK(mo == memory_order_relaxed || mo == memory_order_consume ||
74*0fca6ea1SDimitry Andric mo == memory_order_acquire || mo == memory_order_seq_cst);
750b57cec5SDimitry Andric DCHECK(!((uptr)a % sizeof(*a)));
760b57cec5SDimitry Andric typename T::Type v;
770b57cec5SDimitry Andric // FIXME(dvyukov): 64-bit load is not atomic on 32-bits.
780b57cec5SDimitry Andric if (mo == memory_order_relaxed) {
790b57cec5SDimitry Andric v = a->val_dont_use;
800b57cec5SDimitry Andric } else {
810b57cec5SDimitry Andric atomic_signal_fence(memory_order_seq_cst);
820b57cec5SDimitry Andric v = a->val_dont_use;
830b57cec5SDimitry Andric atomic_signal_fence(memory_order_seq_cst);
840b57cec5SDimitry Andric }
850b57cec5SDimitry Andric return v;
860b57cec5SDimitry Andric }
870b57cec5SDimitry Andric
880b57cec5SDimitry Andric template<typename T>
atomic_store(volatile T * a,typename T::Type v,memory_order mo)89e8d8bef9SDimitry Andric inline void atomic_store(volatile T *a, typename T::Type v, memory_order mo) {
90*0fca6ea1SDimitry Andric DCHECK(mo == memory_order_relaxed || mo == memory_order_release ||
91*0fca6ea1SDimitry Andric mo == memory_order_seq_cst);
920b57cec5SDimitry Andric DCHECK(!((uptr)a % sizeof(*a)));
930b57cec5SDimitry Andric // FIXME(dvyukov): 64-bit store is not atomic on 32-bits.
940b57cec5SDimitry Andric if (mo == memory_order_relaxed) {
950b57cec5SDimitry Andric a->val_dont_use = v;
960b57cec5SDimitry Andric } else {
970b57cec5SDimitry Andric atomic_signal_fence(memory_order_seq_cst);
980b57cec5SDimitry Andric a->val_dont_use = v;
990b57cec5SDimitry Andric atomic_signal_fence(memory_order_seq_cst);
1000b57cec5SDimitry Andric }
1010b57cec5SDimitry Andric if (mo == memory_order_seq_cst)
1020b57cec5SDimitry Andric atomic_thread_fence(memory_order_seq_cst);
1030b57cec5SDimitry Andric }
1040b57cec5SDimitry Andric
atomic_fetch_add(volatile atomic_uint32_t * a,u32 v,memory_order mo)105e8d8bef9SDimitry Andric inline u32 atomic_fetch_add(volatile atomic_uint32_t *a,
1060b57cec5SDimitry Andric u32 v, memory_order mo) {
1070b57cec5SDimitry Andric (void)mo;
1080b57cec5SDimitry Andric DCHECK(!((uptr)a % sizeof(*a)));
10968d75effSDimitry Andric return (u32)_InterlockedExchangeAdd((volatile long *)&a->val_dont_use,
11068d75effSDimitry Andric (long)v);
1110b57cec5SDimitry Andric }
1120b57cec5SDimitry Andric
atomic_fetch_add(volatile atomic_uintptr_t * a,uptr v,memory_order mo)113e8d8bef9SDimitry Andric inline uptr atomic_fetch_add(volatile atomic_uintptr_t *a,
1140b57cec5SDimitry Andric uptr v, memory_order mo) {
1150b57cec5SDimitry Andric (void)mo;
1160b57cec5SDimitry Andric DCHECK(!((uptr)a % sizeof(*a)));
1170b57cec5SDimitry Andric #ifdef _WIN64
11868d75effSDimitry Andric return (uptr)_InterlockedExchangeAdd64((volatile long long *)&a->val_dont_use,
11968d75effSDimitry Andric (long long)v);
1200b57cec5SDimitry Andric #else
12168d75effSDimitry Andric return (uptr)_InterlockedExchangeAdd((volatile long *)&a->val_dont_use,
12268d75effSDimitry Andric (long)v);
1230b57cec5SDimitry Andric #endif
1240b57cec5SDimitry Andric }
1250b57cec5SDimitry Andric
atomic_fetch_sub(volatile atomic_uint32_t * a,u32 v,memory_order mo)126e8d8bef9SDimitry Andric inline u32 atomic_fetch_sub(volatile atomic_uint32_t *a,
1270b57cec5SDimitry Andric u32 v, memory_order mo) {
1280b57cec5SDimitry Andric (void)mo;
1290b57cec5SDimitry Andric DCHECK(!((uptr)a % sizeof(*a)));
13068d75effSDimitry Andric return (u32)_InterlockedExchangeAdd((volatile long *)&a->val_dont_use,
13168d75effSDimitry Andric -(long)v);
1320b57cec5SDimitry Andric }
1330b57cec5SDimitry Andric
atomic_fetch_sub(volatile atomic_uintptr_t * a,uptr v,memory_order mo)134e8d8bef9SDimitry Andric inline uptr atomic_fetch_sub(volatile atomic_uintptr_t *a,
1350b57cec5SDimitry Andric uptr v, memory_order mo) {
1360b57cec5SDimitry Andric (void)mo;
1370b57cec5SDimitry Andric DCHECK(!((uptr)a % sizeof(*a)));
1380b57cec5SDimitry Andric #ifdef _WIN64
13968d75effSDimitry Andric return (uptr)_InterlockedExchangeAdd64((volatile long long *)&a->val_dont_use,
14068d75effSDimitry Andric -(long long)v);
1410b57cec5SDimitry Andric #else
14268d75effSDimitry Andric return (uptr)_InterlockedExchangeAdd((volatile long *)&a->val_dont_use,
14368d75effSDimitry Andric -(long)v);
1440b57cec5SDimitry Andric #endif
1450b57cec5SDimitry Andric }
1460b57cec5SDimitry Andric
atomic_exchange(volatile atomic_uint8_t * a,u8 v,memory_order mo)147e8d8bef9SDimitry Andric inline u8 atomic_exchange(volatile atomic_uint8_t *a,
1480b57cec5SDimitry Andric u8 v, memory_order mo) {
1490b57cec5SDimitry Andric (void)mo;
1500b57cec5SDimitry Andric DCHECK(!((uptr)a % sizeof(*a)));
1510b57cec5SDimitry Andric return (u8)_InterlockedExchange8((volatile char*)&a->val_dont_use, v);
1520b57cec5SDimitry Andric }
1530b57cec5SDimitry Andric
atomic_exchange(volatile atomic_uint16_t * a,u16 v,memory_order mo)154e8d8bef9SDimitry Andric inline u16 atomic_exchange(volatile atomic_uint16_t *a,
1550b57cec5SDimitry Andric u16 v, memory_order mo) {
1560b57cec5SDimitry Andric (void)mo;
1570b57cec5SDimitry Andric DCHECK(!((uptr)a % sizeof(*a)));
1580b57cec5SDimitry Andric return (u16)_InterlockedExchange16((volatile short*)&a->val_dont_use, v);
1590b57cec5SDimitry Andric }
1600b57cec5SDimitry Andric
atomic_exchange(volatile atomic_uint32_t * a,u32 v,memory_order mo)161e8d8bef9SDimitry Andric inline u32 atomic_exchange(volatile atomic_uint32_t *a,
1620b57cec5SDimitry Andric u32 v, memory_order mo) {
1630b57cec5SDimitry Andric (void)mo;
1640b57cec5SDimitry Andric DCHECK(!((uptr)a % sizeof(*a)));
1650b57cec5SDimitry Andric return (u32)_InterlockedExchange((volatile long*)&a->val_dont_use, v);
1660b57cec5SDimitry Andric }
1670b57cec5SDimitry Andric
atomic_compare_exchange_strong(volatile atomic_uint8_t * a,u8 * cmp,u8 xchgv,memory_order mo)168e8d8bef9SDimitry Andric inline bool atomic_compare_exchange_strong(volatile atomic_uint8_t *a,
1690b57cec5SDimitry Andric u8 *cmp,
1700b57cec5SDimitry Andric u8 xchgv,
1710b57cec5SDimitry Andric memory_order mo) {
1720b57cec5SDimitry Andric (void)mo;
1730b57cec5SDimitry Andric DCHECK(!((uptr)a % sizeof(*a)));
1740b57cec5SDimitry Andric u8 cmpv = *cmp;
1750b57cec5SDimitry Andric #ifdef _WIN64
1760b57cec5SDimitry Andric u8 prev = (u8)_InterlockedCompareExchange8(
1770b57cec5SDimitry Andric (volatile char*)&a->val_dont_use, (char)xchgv, (char)cmpv);
1780b57cec5SDimitry Andric #else
1790b57cec5SDimitry Andric u8 prev;
1800b57cec5SDimitry Andric __asm {
1810b57cec5SDimitry Andric mov al, cmpv
1820b57cec5SDimitry Andric mov ecx, a
1830b57cec5SDimitry Andric mov dl, xchgv
1840b57cec5SDimitry Andric lock cmpxchg [ecx], dl
1850b57cec5SDimitry Andric mov prev, al
1860b57cec5SDimitry Andric }
1870b57cec5SDimitry Andric #endif
1880b57cec5SDimitry Andric if (prev == cmpv)
1890b57cec5SDimitry Andric return true;
1900b57cec5SDimitry Andric *cmp = prev;
1910b57cec5SDimitry Andric return false;
1920b57cec5SDimitry Andric }
1930b57cec5SDimitry Andric
atomic_compare_exchange_strong(volatile atomic_uintptr_t * a,uptr * cmp,uptr xchg,memory_order mo)194e8d8bef9SDimitry Andric inline bool atomic_compare_exchange_strong(volatile atomic_uintptr_t *a,
1950b57cec5SDimitry Andric uptr *cmp,
1960b57cec5SDimitry Andric uptr xchg,
1970b57cec5SDimitry Andric memory_order mo) {
1980b57cec5SDimitry Andric uptr cmpv = *cmp;
1990b57cec5SDimitry Andric uptr prev = (uptr)_InterlockedCompareExchangePointer(
2000b57cec5SDimitry Andric (void*volatile*)&a->val_dont_use, (void*)xchg, (void*)cmpv);
2010b57cec5SDimitry Andric if (prev == cmpv)
2020b57cec5SDimitry Andric return true;
2030b57cec5SDimitry Andric *cmp = prev;
2040b57cec5SDimitry Andric return false;
2050b57cec5SDimitry Andric }
2060b57cec5SDimitry Andric
atomic_compare_exchange_strong(volatile atomic_uint16_t * a,u16 * cmp,u16 xchg,memory_order mo)207e8d8bef9SDimitry Andric inline bool atomic_compare_exchange_strong(volatile atomic_uint16_t *a,
2080b57cec5SDimitry Andric u16 *cmp,
2090b57cec5SDimitry Andric u16 xchg,
2100b57cec5SDimitry Andric memory_order mo) {
2110b57cec5SDimitry Andric u16 cmpv = *cmp;
2120b57cec5SDimitry Andric u16 prev = (u16)_InterlockedCompareExchange16(
2130b57cec5SDimitry Andric (volatile short*)&a->val_dont_use, (short)xchg, (short)cmpv);
2140b57cec5SDimitry Andric if (prev == cmpv)
2150b57cec5SDimitry Andric return true;
2160b57cec5SDimitry Andric *cmp = prev;
2170b57cec5SDimitry Andric return false;
2180b57cec5SDimitry Andric }
2190b57cec5SDimitry Andric
atomic_compare_exchange_strong(volatile atomic_uint32_t * a,u32 * cmp,u32 xchg,memory_order mo)220e8d8bef9SDimitry Andric inline bool atomic_compare_exchange_strong(volatile atomic_uint32_t *a,
2210b57cec5SDimitry Andric u32 *cmp,
2220b57cec5SDimitry Andric u32 xchg,
2230b57cec5SDimitry Andric memory_order mo) {
2240b57cec5SDimitry Andric u32 cmpv = *cmp;
2250b57cec5SDimitry Andric u32 prev = (u32)_InterlockedCompareExchange(
2260b57cec5SDimitry Andric (volatile long*)&a->val_dont_use, (long)xchg, (long)cmpv);
2270b57cec5SDimitry Andric if (prev == cmpv)
2280b57cec5SDimitry Andric return true;
2290b57cec5SDimitry Andric *cmp = prev;
2300b57cec5SDimitry Andric return false;
2310b57cec5SDimitry Andric }
2320b57cec5SDimitry Andric
atomic_compare_exchange_strong(volatile atomic_uint64_t * a,u64 * cmp,u64 xchg,memory_order mo)233e8d8bef9SDimitry Andric inline bool atomic_compare_exchange_strong(volatile atomic_uint64_t *a,
2340b57cec5SDimitry Andric u64 *cmp,
2350b57cec5SDimitry Andric u64 xchg,
2360b57cec5SDimitry Andric memory_order mo) {
2370b57cec5SDimitry Andric u64 cmpv = *cmp;
2380b57cec5SDimitry Andric u64 prev = (u64)_InterlockedCompareExchange64(
2390b57cec5SDimitry Andric (volatile long long*)&a->val_dont_use, (long long)xchg, (long long)cmpv);
2400b57cec5SDimitry Andric if (prev == cmpv)
2410b57cec5SDimitry Andric return true;
2420b57cec5SDimitry Andric *cmp = prev;
2430b57cec5SDimitry Andric return false;
2440b57cec5SDimitry Andric }
2450b57cec5SDimitry Andric
2460b57cec5SDimitry Andric template<typename T>
atomic_compare_exchange_weak(volatile T * a,typename T::Type * cmp,typename T::Type xchg,memory_order mo)247e8d8bef9SDimitry Andric inline bool atomic_compare_exchange_weak(volatile T *a,
2480b57cec5SDimitry Andric typename T::Type *cmp,
2490b57cec5SDimitry Andric typename T::Type xchg,
2500b57cec5SDimitry Andric memory_order mo) {
2510b57cec5SDimitry Andric return atomic_compare_exchange_strong(a, cmp, xchg, mo);
2520b57cec5SDimitry Andric }
2530b57cec5SDimitry Andric
2540b57cec5SDimitry Andric } // namespace __sanitizer
2550b57cec5SDimitry Andric
2560b57cec5SDimitry Andric #endif // SANITIZER_ATOMIC_CLANG_H
257