]>
Commit | Line | Data |
---|---|---|
11fdf7f2 TL |
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) 2018 Andrey Semashev | |
7 | */ | |
8 | /*! | |
9 | * \file atomic/detail/extra_fp_ops_generic.hpp | |
10 | * | |
11 | * This header contains generic implementation of the extra floating point atomic operations. | |
12 | */ | |
13 | ||
14 | #ifndef BOOST_ATOMIC_DETAIL_EXTRA_FP_OPS_GENERIC_HPP_INCLUDED_ | |
15 | #define BOOST_ATOMIC_DETAIL_EXTRA_FP_OPS_GENERIC_HPP_INCLUDED_ | |
16 | ||
17 | #include <cstddef> | |
18 | #include <boost/memory_order.hpp> | |
19 | #include <boost/atomic/detail/config.hpp> | |
20 | #include <boost/atomic/detail/bitwise_fp_cast.hpp> | |
f67539c2 | 21 | #include <boost/atomic/detail/storage_traits.hpp> |
11fdf7f2 TL |
22 | #include <boost/atomic/detail/extra_fp_operations_fwd.hpp> |
23 | #include <boost/atomic/detail/type_traits/is_iec559.hpp> | |
24 | #include <boost/atomic/detail/type_traits/is_integral.hpp> | |
20effc67 | 25 | #include <boost/atomic/detail/header.hpp> |
11fdf7f2 TL |
26 | |
27 | #ifdef BOOST_HAS_PRAGMA_ONCE | |
28 | #pragma once | |
29 | #endif | |
30 | ||
20effc67 | 31 | #if defined(BOOST_GCC) && BOOST_GCC >= 60000 |
11fdf7f2 TL |
32 | #pragma GCC diagnostic push |
33 | // ignoring attributes on template argument X - this warning is because we need to pass storage_type as a template argument; no problem in this case | |
34 | #pragma GCC diagnostic ignored "-Wignored-attributes" | |
35 | #endif | |
36 | ||
37 | namespace boost { | |
38 | namespace atomics { | |
39 | namespace detail { | |
40 | ||
41 | //! Negate implementation | |
42 | template< | |
43 | typename Base, | |
44 | typename Value, | |
45 | std::size_t Size | |
46 | #if defined(BOOST_ATOMIC_DETAIL_INT_FP_ENDIAN_MATCH) | |
47 | , bool = atomics::detail::is_iec559< Value >::value && atomics::detail::is_integral< typename Base::storage_type >::value | |
48 | #endif | |
49 | > | |
20effc67 | 50 | struct extra_fp_negate_generic : |
11fdf7f2 TL |
51 | public Base |
52 | { | |
53 | typedef Base base_type; | |
54 | typedef typename base_type::storage_type storage_type; | |
55 | typedef Value value_type; | |
56 | ||
57 | static BOOST_FORCEINLINE value_type fetch_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT | |
58 | { | |
59 | storage_type old_storage, new_storage; | |
60 | value_type old_val, new_val; | |
61 | atomics::detail::non_atomic_load(storage, old_storage); | |
62 | do | |
63 | { | |
64 | old_val = atomics::detail::bitwise_fp_cast< value_type >(old_storage); | |
65 | new_val = -old_val; | |
66 | new_storage = atomics::detail::bitwise_fp_cast< storage_type >(new_val); | |
67 | } | |
68 | while (!base_type::compare_exchange_weak(storage, old_storage, new_storage, order, memory_order_relaxed)); | |
69 | return old_val; | |
70 | } | |
71 | ||
72 | static BOOST_FORCEINLINE value_type negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT | |
73 | { | |
74 | storage_type old_storage, new_storage; | |
75 | value_type old_val, new_val; | |
76 | atomics::detail::non_atomic_load(storage, old_storage); | |
77 | do | |
78 | { | |
79 | old_val = atomics::detail::bitwise_fp_cast< value_type >(old_storage); | |
80 | new_val = -old_val; | |
81 | new_storage = atomics::detail::bitwise_fp_cast< storage_type >(new_val); | |
82 | } | |
83 | while (!base_type::compare_exchange_weak(storage, old_storage, new_storage, order, memory_order_relaxed)); | |
84 | return new_val; | |
85 | } | |
86 | ||
87 | static BOOST_FORCEINLINE void opaque_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT | |
88 | { | |
89 | fetch_negate(storage, order); | |
90 | } | |
91 | }; | |
92 | ||
93 | #if defined(BOOST_ATOMIC_DETAIL_INT_FP_ENDIAN_MATCH) | |
94 | ||
95 | //! Negate implementation for IEEE 754 / IEC 559 floating point types. We leverage the fact that the sign bit is the most significant bit in the value. | |
96 | template< typename Base, typename Value, std::size_t Size > | |
20effc67 | 97 | struct extra_fp_negate_generic< Base, Value, Size, true > : |
11fdf7f2 TL |
98 | public Base |
99 | { | |
100 | typedef Base base_type; | |
101 | typedef typename base_type::storage_type storage_type; | |
102 | typedef Value value_type; | |
103 | ||
104 | //! The mask with only one sign bit set to 1 | |
105 | static BOOST_CONSTEXPR_OR_CONST storage_type sign_mask = static_cast< storage_type >(1u) << (atomics::detail::value_sizeof< value_type >::value * 8u - 1u); | |
106 | ||
107 | static BOOST_FORCEINLINE value_type fetch_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT | |
108 | { | |
109 | return atomics::detail::bitwise_fp_cast< value_type >(base_type::fetch_xor(storage, sign_mask, order)); | |
110 | } | |
111 | ||
112 | static BOOST_FORCEINLINE value_type negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT | |
113 | { | |
114 | return atomics::detail::bitwise_fp_cast< value_type >(base_type::bitwise_xor(storage, sign_mask, order)); | |
115 | } | |
116 | ||
117 | static BOOST_FORCEINLINE void opaque_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT | |
118 | { | |
119 | base_type::opaque_xor(storage, sign_mask, order); | |
120 | } | |
121 | }; | |
122 | ||
123 | #endif // defined(BOOST_ATOMIC_DETAIL_INT_FP_ENDIAN_MATCH) | |
124 | ||
125 | //! Generic implementation of floating point operations | |
126 | template< typename Base, typename Value, std::size_t Size > | |
20effc67 TL |
127 | struct extra_fp_operations_generic : |
128 | public extra_fp_negate_generic< Base, Value, Size > | |
11fdf7f2 | 129 | { |
20effc67 | 130 | typedef extra_fp_negate_generic< Base, Value, Size > base_type; |
11fdf7f2 TL |
131 | typedef typename base_type::storage_type storage_type; |
132 | typedef Value value_type; | |
133 | ||
134 | static BOOST_FORCEINLINE value_type add(storage_type volatile& storage, value_type v, memory_order order) BOOST_NOEXCEPT | |
135 | { | |
136 | storage_type old_storage, new_storage; | |
137 | value_type old_val, new_val; | |
138 | atomics::detail::non_atomic_load(storage, old_storage); | |
139 | do | |
140 | { | |
141 | old_val = atomics::detail::bitwise_fp_cast< value_type >(old_storage); | |
142 | new_val = old_val + v; | |
143 | new_storage = atomics::detail::bitwise_fp_cast< storage_type >(new_val); | |
144 | } | |
145 | while (!base_type::compare_exchange_weak(storage, old_storage, new_storage, order, memory_order_relaxed)); | |
146 | return new_val; | |
147 | } | |
148 | ||
149 | static BOOST_FORCEINLINE value_type sub(storage_type volatile& storage, value_type v, memory_order order) BOOST_NOEXCEPT | |
150 | { | |
151 | storage_type old_storage, new_storage; | |
152 | value_type old_val, new_val; | |
153 | atomics::detail::non_atomic_load(storage, old_storage); | |
154 | do | |
155 | { | |
156 | old_val = atomics::detail::bitwise_fp_cast< value_type >(old_storage); | |
157 | new_val = old_val - v; | |
158 | new_storage = atomics::detail::bitwise_fp_cast< storage_type >(new_val); | |
159 | } | |
160 | while (!base_type::compare_exchange_weak(storage, old_storage, new_storage, order, memory_order_relaxed)); | |
161 | return new_val; | |
162 | } | |
163 | ||
164 | static BOOST_FORCEINLINE void opaque_add(storage_type volatile& storage, value_type v, memory_order order) BOOST_NOEXCEPT | |
165 | { | |
166 | base_type::fetch_add(storage, v, order); | |
167 | } | |
168 | ||
169 | static BOOST_FORCEINLINE void opaque_sub(storage_type volatile& storage, value_type v, memory_order order) BOOST_NOEXCEPT | |
170 | { | |
171 | base_type::fetch_sub(storage, v, order); | |
172 | } | |
173 | }; | |
174 | ||
175 | // Default extra_fp_operations template definition will be used unless specialized for a specific platform | |
176 | template< typename Base, typename Value, std::size_t Size > | |
177 | struct extra_fp_operations< Base, Value, Size, true > : | |
20effc67 | 178 | public extra_fp_operations_generic< Base, Value, Size > |
11fdf7f2 TL |
179 | { |
180 | }; | |
181 | ||
182 | } // namespace detail | |
183 | } // namespace atomics | |
184 | } // namespace boost | |
185 | ||
20effc67 | 186 | #if defined(BOOST_GCC) && BOOST_GCC >= 60000 |
11fdf7f2 TL |
187 | #pragma GCC diagnostic pop |
188 | #endif | |
189 | ||
20effc67 TL |
190 | #include <boost/atomic/detail/footer.hpp> |
191 | ||
11fdf7f2 | 192 | #endif // BOOST_ATOMIC_DETAIL_FP_OPS_GENERIC_HPP_INCLUDED_ |