.. _program_listing_file_include_embers_atomic.h: Program Listing for File atomic.h ================================= |exhale_lsh| :ref:`Return to documentation for file ` (``include/embers/atomic.h``) .. |exhale_lsh| unicode:: U+021B0 .. UPWARDS ARROW WITH TIP LEFTWARDS .. code-block:: cpp /* Copyright © 2020 Advanced Micro Devices, Inc. All rights reserved */ #ifndef _EMBERS__ATOMIC_H_ #define _EMBERS__ATOMIC_H_ #include #include #include #include "embers/memory/memory_model.h" namespace embers { // must be trivially copyable // must be copy constructible // must be move constructible // must be copy assignable // must be move assignable template class atomic { private: T val_; __host__ void _store(T desired, std::memory_order order) noexcept; __device__ void _store(T desired, std::memory_order order) noexcept; __host__ T _load(std::memory_order order) const noexcept; __device__ T _load(std::memory_order order) const noexcept; __host__ T _exchange(T desired, std::memory_order order) noexcept; __device__ T _exchange(T desired, std::memory_order order) noexcept; __host__ T _fetch_add(T arg, std::memory_order order) noexcept; __device__ T _fetch_add(T arg, std::memory_order order) noexcept; __host__ T _fetch_sub(T arg, std::memory_order order) noexcept; __device__ T _fetch_sub(T arg, std::memory_order order) noexcept; __host__ T _fetch_and(T arg, std::memory_order order) noexcept; __device__ T _fetch_and(T arg, std::memory_order order) noexcept; __host__ T _fetch_or(T arg, std::memory_order order) noexcept; __device__ T _fetch_or(T arg, std::memory_order order) noexcept; __host__ T _fetch_xor(T arg, std::memory_order order) noexcept; __device__ T _fetch_xor(T arg, std::memory_order order) noexcept; __host__ bool _compare_exchange_strong(T &expected, T desired, std::memory_order success, std::memory_order failure) noexcept; __device__ bool _compare_exchange_strong(T &expected, T desired, std::memory_order success, std::memory_order failure) noexcept; __host__ bool _compare_exchange_weak(T &expected, T desired, std::memory_order success, std::memory_order failure) noexcept; __device__ bool _compare_exchange_weak(T &expected, T desired, std::memory_order success, std::memory_order failure) noexcept; template ::value || std::is_pointer::value> > __host__ T _post_increment(std::memory_order order) noexcept; template ::value || std::is_pointer::value> > __device__ T _post_increment(std::memory_order order) noexcept; public: __host__ __device__ atomic() noexcept = default; ; __host__ __device__ constexpr atomic(T desired) noexcept; __host__ __device__ atomic(const atomic &) = delete; __host__ __device__ T operator=(T desired) noexcept; __host__ __device__ void store(T desired, std::memory_order = std::memory_order_seq_cst) noexcept; __host__ __device__ T load(std::memory_order = std::memory_order_seq_cst) const noexcept; __host__ __device__ operator T() const noexcept; __host__ __device__ T exchange(T desired, std::memory_order = std::memory_order_seq_cst) noexcept; __host__ __device__ bool compare_exchange_strong( T &expected, T desired, std::memory_order success = std::memory_order_seq_cst, std::memory_order failure = std::memory_order_seq_cst) noexcept; __host__ __device__ bool compare_exchange_weak( T &expected, T desired, std::memory_order success = std::memory_order_seq_cst, std::memory_order failure = std::memory_order_seq_cst) noexcept; __host__ __device__ T fetch_add(T arg, std::memory_order = std::memory_order_seq_cst) noexcept; template ::value || std::is_pointer::value> > __host__ __device__ T fetch_inc(std::memory_order = std::memory_order_seq_cst) noexcept; __host__ __device__ T fetch_sub(T arg, std::memory_order = std::memory_order_seq_cst) noexcept; __host__ __device__ T fetch_and(T arg, std::memory_order = std::memory_order_seq_cst) noexcept; __host__ __device__ T fetch_or(T arg, std::memory_order = std::memory_order_seq_cst) noexcept; __host__ __device__ T fetch_xor(T arg, std::memory_order = std::memory_order_seq_cst) noexcept; __host__ __device__ T operator+=(T arg) noexcept; __host__ __device__ T operator-=(T arg) noexcept; __host__ __device__ T operator&=(T arg) noexcept; __host__ __device__ T operator|=(T arg) noexcept; __host__ __device__ T operator^=(T arg) noexcept; template ::value || std::is_pointer::value> > __host__ __device__ T operator++() noexcept; template ::value || std::is_pointer::value> > __host__ __device__ T operator++(int) noexcept; template ::value || std::is_pointer::value> > __host__ __device__ T operator--() noexcept; template ::value || std::is_pointer::value> > __host__ __device__ T operator--(int) noexcept; }; template __host__ __device__ constexpr atomic::atomic(T desired) noexcept : val_(desired) { } template __host__ __device__ atomic::operator T() const noexcept { return load(); } template __host__ __device__ T atomic::operator=(T desired) noexcept { store(desired); return desired; } template template __host__ T atomic::_post_increment(std::memory_order order) noexcept { return fetch_add(1, order); } template template __device__ T atomic::_post_increment(std::memory_order order) noexcept { return fetch_add(1, order); } template template __host__ __device__ T atomic::operator++() noexcept { return _post_increment(std::memory_order_seq_cst) + 1; } template template __host__ __device__ T atomic::operator++(int) noexcept { return _post_increment(std::memory_order_seq_cst); } template template __host__ __device__ T atomic::operator--() noexcept { return fetch_sub(1) - 1; } template template __host__ __device__ T atomic::operator--(int) noexcept { return fetch_sub(1); } template __host__ __device__ void atomic::store(T desired, std::memory_order order) noexcept { _store(desired, order); } template __host__ __device__ T atomic::load(std::memory_order order) const noexcept { return _load(order); } template __host__ __device__ T atomic::exchange(T desired, std::memory_order order) noexcept { return _exchange(desired, order); } template __host__ __device__ bool atomic::compare_exchange_strong( T &expected, T desired, std::memory_order success, std::memory_order failure) noexcept { return _compare_exchange_strong(expected, desired, success, failure); } template __host__ __device__ bool atomic::compare_exchange_weak(T &expected, T desired, std::memory_order success, std::memory_order failure) noexcept { return _compare_exchange_weak(expected, desired, success, failure); } template __host__ __device__ T atomic::fetch_add(T arg, std::memory_order order) noexcept { return _fetch_add(arg, order); } template __host__ __device__ T atomic::fetch_sub(T arg, std::memory_order order) noexcept { return _fetch_sub(arg, order); } template __host__ __device__ T atomic::fetch_and(T arg, std::memory_order order) noexcept { return _fetch_and(arg, order); } template __host__ __device__ T atomic::fetch_or(T arg, std::memory_order order) noexcept { return _fetch_or(arg, order); } template __host__ __device__ T atomic::fetch_xor(T arg, std::memory_order order) noexcept { return _fetch_xor(arg, order); } template template __host__ __device__ T atomic::fetch_inc(std::memory_order order) noexcept { return _post_increment(order); } template __host__ __device__ T atomic::operator+=(T arg) noexcept { return fetch_add(arg); } template __host__ __device__ T atomic::operator-=(T arg) noexcept { return fetch_sub(arg); } template __host__ __device__ T atomic::operator&=(T arg) noexcept { return fetch_and(arg); } template __host__ __device__ T atomic::operator|=(T arg) noexcept { return fetch_or(arg); } template __host__ __device__ T atomic::operator^=(T arg) noexcept { return fetch_xor(arg); } // device template __device__ void atomic::_store(T desired, std::memory_order order) noexcept { __hip_atomic_store(&val_, desired, std_memory_order_to_int(order), static_cast::type>(scope)); }; template __device__ T atomic::_load(std::memory_order order) const noexcept { return __hip_atomic_load(&val_, std_memory_order_to_int(order), static_cast::type>(scope)); } template __device__ T atomic::_exchange(T desired, std::memory_order order) noexcept { return __hip_atomic_exchange(&val_, desired, std_memory_order_to_int(order), static_cast::type>(scope)); }; template __device__ bool atomic::_compare_exchange_strong(T &expected, T desired, std::memory_order success, std::memory_order failure) noexcept { return __hip_atomic_compare_exchange_strong(&val_, &expected, desired, std_memory_order_to_int(success), std_memory_order_to_int(failure), static_cast::type>( scope)); } template __device__ bool atomic::_compare_exchange_weak(T &expected, T desired, std::memory_order success, std::memory_order failure) noexcept { return __hip_atomic_compare_exchange_weak(&val_, &expected, desired, std_memory_order_to_int(success), std_memory_order_to_int(failure), static_cast::type>( scope)); } template __device__ T atomic::_fetch_add(T arg, std::memory_order order) noexcept { return __hip_atomic_fetch_add(&val_, arg, std_memory_order_to_int(order), static_cast::type>(scope)); } template __device__ T atomic::_fetch_sub(T arg, std::memory_order order) noexcept { return _fetch_add(-arg, order); } template __device__ T atomic::_fetch_and(T arg, std::memory_order order) noexcept { return __hip_atomic_fetch_and(&val_, arg, std_memory_order_to_int(order), static_cast::type>(scope)); } template __device__ T atomic::_fetch_or(T arg, std::memory_order order) noexcept { return __hip_atomic_fetch_or(&val_, arg, std_memory_order_to_int(order), static_cast::type>(scope)); } template __device__ T atomic::_fetch_xor(T arg, std::memory_order order) noexcept { return __hip_atomic_fetch_xor(&val_, arg, std_memory_order_to_int(order), static_cast::type>(scope)); } // host template __host__ void atomic::_store(T desired, std::memory_order order) noexcept { return __atomic_store_n(&val_, desired, std_memory_order_to_int(order)); } template __host__ T atomic::_load(std::memory_order order) const noexcept { return __atomic_load_n(&val_, std_memory_order_to_int(order)); } template __host__ T atomic::_exchange(T desired, std::memory_order order) noexcept { return __atomic_exchange_n(&val_, desired, std_memory_order_to_int(order)); } template __host__ bool atomic::_compare_exchange_strong(T &expected, T desired, std::memory_order success, std::memory_order failure) noexcept { return __atomic_compare_exchange_n(&val_, &expected, desired, true /*strong*/, std_memory_order_to_int(success), std_memory_order_to_int(failure)); } template __host__ bool atomic::_compare_exchange_weak(T &expected, T desired, std::memory_order success, std::memory_order failure) noexcept { return __atomic_compare_exchange_n(&val_, &expected, desired, false /*weak*/, std_memory_order_to_int(success), std_memory_order_to_int(failure)); } template __host__ T atomic::_fetch_add(T arg, std::memory_order order) noexcept { return __atomic_fetch_add(&val_, arg, std_memory_order_to_int(order)); } template __host__ T atomic::_fetch_sub(T arg, std::memory_order order) noexcept { return __atomic_fetch_sub(&val_, arg, std_memory_order_to_int(order)); } template __host__ T atomic::_fetch_and(T arg, std::memory_order order) noexcept { return __atomic_fetch_and(&val_, arg, std_memory_order_to_int(order)); } template __host__ T atomic::_fetch_or(T arg, std::memory_order order) noexcept { return __atomic_fetch_or(&val_, arg, std_memory_order_to_int(order)); } template __host__ T atomic::_fetch_xor(T arg, std::memory_order order) noexcept { return __atomic_fetch_xor(&val_, arg, std_memory_order_to_int(order)); } } // namespace embers #endif // _EMBERS__ATOMIC_H_