1 /*
2  * Distributed under the Boost Software License, Version 1.0.
3  * (See accompanying file LICENSE_1_0.txt or copy at
4  * http://www.boost.org/LICENSE_1_0.txt)
5  *
6  * Copyright (c) 2020 Andrey Semashev
7  */
8 /*!
9  * \file   atomic/detail/gcc_atomic_memory_order_utils.hpp
10  *
11  * This header contains utilities for working with gcc atomic memory order constants.
12  */
13 
14 #ifndef BOOST_ATOMIC_DETAIL_GCC_ATOMIC_MEMORY_ORDER_UTILS_HPP_INCLUDED_
15 #define BOOST_ATOMIC_DETAIL_GCC_ATOMIC_MEMORY_ORDER_UTILS_HPP_INCLUDED_
16 
17 #include <boost/memory_order.hpp>
18 #include <boost/atomic/detail/config.hpp>
19 #include <boost/atomic/detail/header.hpp>
20 
21 #ifdef BOOST_HAS_PRAGMA_ONCE
22 #pragma once
23 #endif
24 
25 namespace boost {
26 namespace atomics {
27 namespace detail {
28 
29 /*!
30  * The function converts \c boost::memory_order values to the compiler-specific constants.
31  *
32  * NOTE: The intention is that the function is optimized away by the compiler, and the
33  *       compiler-specific constants are passed to the intrinsics. Unfortunately, constexpr doesn't
34  *       work in this case because the standard atomics interface require memory ordering
35  *       constants to be passed as function arguments, at which point they stop being constexpr.
36  *       However, it is crucial that the compiler sees constants and not runtime values,
37  *       because otherwise it just ignores the ordering value and always uses seq_cst.
38  *       This is the case with Intel C++ Compiler 14.0.3 (Composer XE 2013 SP1, update 3) and
39  *       gcc 4.8.2. Intel Compiler issues a warning in this case:
40  *
41  *       warning #32013: Invalid memory order specified. Defaulting to seq_cst memory order.
42  *
43  *       while gcc acts silently.
44  *
45  *       To mitigate the problem ALL functions, including the atomic<> members must be
46  *       declared with BOOST_FORCEINLINE. In this case the compilers are able to see that
47  *       all functions are called with constant orderings and call intrinstcts properly.
48  *
49  *       Unfortunately, this still doesn't work in debug mode as the compiler doesn't
50  *       propagate constants even when functions are marked with BOOST_FORCEINLINE. In this case
51  *       all atomic operaions will be executed with seq_cst semantics.
52  */
convert_memory_order_to_gcc(memory_order order)53 BOOST_FORCEINLINE BOOST_CONSTEXPR int convert_memory_order_to_gcc(memory_order order) BOOST_NOEXCEPT
54 {
55     return (order == memory_order_relaxed ? __ATOMIC_RELAXED : (order == memory_order_consume ? __ATOMIC_CONSUME :
56         (order == memory_order_acquire ? __ATOMIC_ACQUIRE : (order == memory_order_release ? __ATOMIC_RELEASE :
57         (order == memory_order_acq_rel ? __ATOMIC_ACQ_REL : __ATOMIC_SEQ_CST)))));
58 }
59 
60 } // namespace detail
61 } // namespace atomics
62 } // namespace boost
63 
64 #include <boost/atomic/detail/footer.hpp>
65 
66 #endif // BOOST_ATOMIC_DETAIL_GCC_ATOMIC_MEMORY_ORDER_UTILS_HPP_INCLUDED_
67