annotate DEPENDENCIES/generic/include/boost/atomic/detail/ops_msvc_x86.hpp @ 125:34e428693f5d vext

Vext -> Repoint
author Chris Cannam
date Thu, 14 Jun 2018 11:15:39 +0100
parents f46d142149f5
children
rev   line source
Chris@102 1 /*
Chris@102 2 * Distributed under the Boost Software License, Version 1.0.
Chris@102 3 * (See accompanying file LICENSE_1_0.txt or copy at
Chris@102 4 * http://www.boost.org/LICENSE_1_0.txt)
Chris@102 5 *
Chris@102 6 * Copyright (c) 2009 Helge Bahmann
Chris@102 7 * Copyright (c) 2012 Tim Blechmann
Chris@102 8 * Copyright (c) 2014 Andrey Semashev
Chris@102 9 */
Chris@102 10 /*!
Chris@102 11 * \file atomic/detail/ops_msvc_x86.hpp
Chris@102 12 *
Chris@102 13 * This header contains implementation of the \c operations template.
Chris@102 14 */
Chris@102 15
Chris@102 16 #ifndef BOOST_ATOMIC_DETAIL_OPS_MSVC_X86_HPP_INCLUDED_
Chris@102 17 #define BOOST_ATOMIC_DETAIL_OPS_MSVC_X86_HPP_INCLUDED_
Chris@102 18
Chris@102 19 #include <boost/memory_order.hpp>
Chris@102 20 #include <boost/type_traits/make_signed.hpp>
Chris@102 21 #include <boost/atomic/detail/config.hpp>
Chris@102 22 #include <boost/atomic/detail/interlocked.hpp>
Chris@102 23 #include <boost/atomic/detail/storage_type.hpp>
Chris@102 24 #include <boost/atomic/detail/operations_fwd.hpp>
Chris@102 25 #include <boost/atomic/capabilities.hpp>
Chris@102 26 #if defined(BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG8B) || defined(BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG16B)
Chris@102 27 #include <boost/cstdint.hpp>
Chris@102 28 #include <boost/atomic/detail/ops_cas_based.hpp>
Chris@102 29 #endif
Chris@102 30 #include <boost/atomic/detail/ops_msvc_common.hpp>
Chris@102 31 #if !defined(_M_IX86) && !(defined(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE8) && defined(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE16))
Chris@102 32 #include <boost/atomic/detail/ops_extending_cas_based.hpp>
Chris@102 33 #endif
Chris@102 34
Chris@102 35 #ifdef BOOST_HAS_PRAGMA_ONCE
Chris@102 36 #pragma once
Chris@102 37 #endif
Chris@102 38
Chris@102 39 #if defined(BOOST_MSVC)
Chris@102 40 #pragma warning(push)
Chris@102 41 // frame pointer register 'ebx' modified by inline assembly code. See the note below.
Chris@102 42 #pragma warning(disable: 4731)
Chris@102 43 #endif
Chris@102 44
Chris@102 45 #if defined(_MSC_VER) && (defined(_M_AMD64) || (defined(_M_IX86) && defined(_M_IX86_FP) && _M_IX86_FP >= 2))
Chris@102 46 extern "C" void _mm_mfence(void);
Chris@102 47 #if defined(BOOST_MSVC)
Chris@102 48 #pragma intrinsic(_mm_mfence)
Chris@102 49 #endif
Chris@102 50 #endif
Chris@102 51
Chris@102 52 namespace boost {
Chris@102 53 namespace atomics {
Chris@102 54 namespace detail {
Chris@102 55
Chris@102 56 /*
Chris@102 57 * Implementation note for asm blocks.
Chris@102 58 *
Chris@102 59 * http://msdn.microsoft.com/en-us/data/k1a8ss06%28v=vs.105%29
Chris@102 60 *
Chris@102 61 * Some SSE types require eight-byte stack alignment, forcing the compiler to emit dynamic stack-alignment code.
Chris@102 62 * To be able to access both the local variables and the function parameters after the alignment, the compiler
Chris@102 63 * maintains two frame pointers. If the compiler performs frame pointer omission (FPO), it will use EBP and ESP.
Chris@102 64 * If the compiler does not perform FPO, it will use EBX and EBP. To ensure code runs correctly, do not modify EBX
Chris@102 65 * in asm code if the function requires dynamic stack alignment as it could modify the frame pointer.
Chris@102 66 * Either move the eight-byte aligned types out of the function, or avoid using EBX.
Chris@102 67 *
Chris@102 68 * Since we have no way of knowing that the compiler uses FPO, we have to always save and restore ebx
Chris@102 69 * whenever we have to clobber it. Additionally, we disable warning C4731 above so that the compiler
Chris@102 70 * doesn't spam about ebx use.
Chris@102 71 */
Chris@102 72
Chris@102 73 struct msvc_x86_operations_base
Chris@102 74 {
Chris@102 75 static BOOST_FORCEINLINE void hardware_full_fence() BOOST_NOEXCEPT
Chris@102 76 {
Chris@102 77 #if defined(_MSC_VER) && (defined(_M_AMD64) || (defined(_M_IX86) && defined(_M_IX86_FP) && _M_IX86_FP >= 2))
Chris@102 78 // Use mfence only if SSE2 is available
Chris@102 79 _mm_mfence();
Chris@102 80 #else
Chris@102 81 long tmp;
Chris@102 82 BOOST_ATOMIC_INTERLOCKED_EXCHANGE(&tmp, 0);
Chris@102 83 #endif
Chris@102 84 }
Chris@102 85
Chris@102 86 static BOOST_FORCEINLINE void fence_before(memory_order) BOOST_NOEXCEPT
Chris@102 87 {
Chris@102 88 BOOST_ATOMIC_DETAIL_COMPILER_BARRIER();
Chris@102 89 }
Chris@102 90
Chris@102 91 static BOOST_FORCEINLINE void fence_after(memory_order) BOOST_NOEXCEPT
Chris@102 92 {
Chris@102 93 BOOST_ATOMIC_DETAIL_COMPILER_BARRIER();
Chris@102 94 }
Chris@102 95
Chris@102 96 static BOOST_FORCEINLINE void fence_after_load(memory_order) BOOST_NOEXCEPT
Chris@102 97 {
Chris@102 98 BOOST_ATOMIC_DETAIL_COMPILER_BARRIER();
Chris@102 99
Chris@102 100 // On x86 and x86_64 there is no need for a hardware barrier,
Chris@102 101 // even if seq_cst memory order is requested, because all
Chris@102 102 // seq_cst writes are implemented with lock-prefixed operations
Chris@102 103 // or xchg which has implied lock prefix. Therefore normal loads
Chris@102 104 // are already ordered with seq_cst stores on these architectures.
Chris@102 105 }
Chris@102 106 };
Chris@102 107
Chris@102 108 template< typename T, typename Derived >
Chris@102 109 struct msvc_x86_operations :
Chris@102 110 public msvc_x86_operations_base
Chris@102 111 {
Chris@102 112 typedef T storage_type;
Chris@102 113
Chris@102 114 static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
Chris@102 115 {
Chris@102 116 if (order != memory_order_seq_cst)
Chris@102 117 {
Chris@102 118 fence_before(order);
Chris@102 119 storage = v;
Chris@102 120 fence_after(order);
Chris@102 121 }
Chris@102 122 else
Chris@102 123 {
Chris@102 124 Derived::exchange(storage, v, order);
Chris@102 125 }
Chris@102 126 }
Chris@102 127
Chris@102 128 static BOOST_FORCEINLINE storage_type load(storage_type const volatile& storage, memory_order order) BOOST_NOEXCEPT
Chris@102 129 {
Chris@102 130 storage_type v = storage;
Chris@102 131 fence_after_load(order);
Chris@102 132 return v;
Chris@102 133 }
Chris@102 134
Chris@102 135 static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
Chris@102 136 {
Chris@102 137 typedef typename make_signed< storage_type >::type signed_storage_type;
Chris@102 138 return Derived::fetch_add(storage, static_cast< storage_type >(-static_cast< signed_storage_type >(v)), order);
Chris@102 139 }
Chris@102 140
Chris@102 141 static BOOST_FORCEINLINE bool compare_exchange_weak(
Chris@102 142 storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT
Chris@102 143 {
Chris@102 144 return Derived::compare_exchange_strong(storage, expected, desired, success_order, failure_order);
Chris@102 145 }
Chris@102 146
Chris@102 147 static BOOST_FORCEINLINE bool test_and_set(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT
Chris@102 148 {
Chris@102 149 return !!Derived::exchange(storage, (storage_type)1, order);
Chris@102 150 }
Chris@102 151
Chris@102 152 static BOOST_FORCEINLINE void clear(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT
Chris@102 153 {
Chris@102 154 store(storage, (storage_type)0, order);
Chris@102 155 }
Chris@102 156
Chris@102 157 static BOOST_FORCEINLINE bool is_lock_free(storage_type const volatile&) BOOST_NOEXCEPT
Chris@102 158 {
Chris@102 159 return true;
Chris@102 160 }
Chris@102 161 };
Chris@102 162
Chris@102 163 template< bool Signed >
Chris@102 164 struct operations< 4u, Signed > :
Chris@102 165 public msvc_x86_operations< typename make_storage_type< 4u, Signed >::type, operations< 4u, Signed > >
Chris@102 166 {
Chris@102 167 typedef msvc_x86_operations< typename make_storage_type< 4u, Signed >::type, operations< 4u, Signed > > base_type;
Chris@102 168 typedef typename base_type::storage_type storage_type;
Chris@102 169
Chris@102 170 static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT
Chris@102 171 {
Chris@102 172 return static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD(&storage, v));
Chris@102 173 }
Chris@102 174
Chris@102 175 static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT
Chris@102 176 {
Chris@102 177 return static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE(&storage, v));
Chris@102 178 }
Chris@102 179
Chris@102 180 static BOOST_FORCEINLINE bool compare_exchange_strong(
Chris@102 181 storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order, memory_order) BOOST_NOEXCEPT
Chris@102 182 {
Chris@102 183 storage_type previous = expected;
Chris@102 184 storage_type old_val = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE(&storage, desired, previous));
Chris@102 185 expected = old_val;
Chris@102 186 return (previous == old_val);
Chris@102 187 }
Chris@102 188
Chris@102 189 #if defined(BOOST_ATOMIC_INTERLOCKED_AND)
Chris@102 190 static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT
Chris@102 191 {
Chris@102 192 return static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_AND(&storage, v));
Chris@102 193 }
Chris@102 194 #else
Chris@102 195 static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
Chris@102 196 {
Chris@102 197 storage_type res = storage;
Chris@102 198 while (!compare_exchange_strong(storage, res, res & v, order, memory_order_relaxed)) {}
Chris@102 199 return res;
Chris@102 200 }
Chris@102 201 #endif
Chris@102 202
Chris@102 203 #if defined(BOOST_ATOMIC_INTERLOCKED_OR)
Chris@102 204 static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT
Chris@102 205 {
Chris@102 206 return static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_OR(&storage, v));
Chris@102 207 }
Chris@102 208 #else
Chris@102 209 static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
Chris@102 210 {
Chris@102 211 storage_type res = storage;
Chris@102 212 while (!compare_exchange_strong(storage, res, res | v, order, memory_order_relaxed)) {}
Chris@102 213 return res;
Chris@102 214 }
Chris@102 215 #endif
Chris@102 216
Chris@102 217 #if defined(BOOST_ATOMIC_INTERLOCKED_XOR)
Chris@102 218 static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT
Chris@102 219 {
Chris@102 220 return static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_XOR(&storage, v));
Chris@102 221 }
Chris@102 222 #else
Chris@102 223 static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
Chris@102 224 {
Chris@102 225 storage_type res = storage;
Chris@102 226 while (!compare_exchange_strong(storage, res, res ^ v, order, memory_order_relaxed)) {}
Chris@102 227 return res;
Chris@102 228 }
Chris@102 229 #endif
Chris@102 230 };
Chris@102 231
Chris@102 232 #if defined(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE8)
Chris@102 233
Chris@102 234 template< bool Signed >
Chris@102 235 struct operations< 1u, Signed > :
Chris@102 236 public msvc_x86_operations< typename make_storage_type< 1u, Signed >::type, operations< 1u, Signed > >
Chris@102 237 {
Chris@102 238 typedef msvc_x86_operations< typename make_storage_type< 1u, Signed >::type, operations< 1u, Signed > > base_type;
Chris@102 239 typedef typename base_type::storage_type storage_type;
Chris@102 240
Chris@102 241 static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT
Chris@102 242 {
Chris@102 243 return static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD8(&storage, v));
Chris@102 244 }
Chris@102 245
Chris@102 246 static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT
Chris@102 247 {
Chris@102 248 return static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE8(&storage, v));
Chris@102 249 }
Chris@102 250
Chris@102 251 static BOOST_FORCEINLINE bool compare_exchange_strong(
Chris@102 252 storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order, memory_order) BOOST_NOEXCEPT
Chris@102 253 {
Chris@102 254 storage_type previous = expected;
Chris@102 255 storage_type old_val = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE8(&storage, desired, previous));
Chris@102 256 expected = old_val;
Chris@102 257 return (previous == old_val);
Chris@102 258 }
Chris@102 259
Chris@102 260 static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT
Chris@102 261 {
Chris@102 262 return static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_AND8(&storage, v));
Chris@102 263 }
Chris@102 264
Chris@102 265 static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT
Chris@102 266 {
Chris@102 267 return static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_OR8(&storage, v));
Chris@102 268 }
Chris@102 269
Chris@102 270 static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT
Chris@102 271 {
Chris@102 272 return static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_XOR8(&storage, v));
Chris@102 273 }
Chris@102 274 };
Chris@102 275
Chris@102 276 #elif defined(_M_IX86)
Chris@102 277
Chris@102 278 template< bool Signed >
Chris@102 279 struct operations< 1u, Signed > :
Chris@102 280 public msvc_x86_operations< typename make_storage_type< 1u, Signed >::type, operations< 1u, Signed > >
Chris@102 281 {
Chris@102 282 typedef msvc_x86_operations< typename make_storage_type< 1u, Signed >::type, operations< 1u, Signed > > base_type;
Chris@102 283 typedef typename base_type::storage_type storage_type;
Chris@102 284
Chris@102 285 static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
Chris@102 286 {
Chris@102 287 base_type::fence_before(order);
Chris@102 288 __asm
Chris@102 289 {
Chris@102 290 mov edx, storage
Chris@102 291 movzx eax, v
Chris@102 292 lock xadd byte ptr [edx], al
Chris@102 293 mov v, al
Chris@102 294 };
Chris@102 295 base_type::fence_after(order);
Chris@102 296 return v;
Chris@102 297 }
Chris@102 298
Chris@102 299 static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
Chris@102 300 {
Chris@102 301 base_type::fence_before(order);
Chris@102 302 __asm
Chris@102 303 {
Chris@102 304 mov edx, storage
Chris@102 305 movzx eax, v
Chris@102 306 xchg byte ptr [edx], al
Chris@102 307 mov v, al
Chris@102 308 };
Chris@102 309 base_type::fence_after(order);
Chris@102 310 return v;
Chris@102 311 }
Chris@102 312
Chris@102 313 static BOOST_FORCEINLINE bool compare_exchange_strong(
Chris@102 314 storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order) BOOST_NOEXCEPT
Chris@102 315 {
Chris@102 316 base_type::fence_before(success_order);
Chris@102 317 bool success;
Chris@102 318 __asm
Chris@102 319 {
Chris@102 320 mov esi, expected
Chris@102 321 mov edi, storage
Chris@102 322 movzx eax, byte ptr [esi]
Chris@102 323 movzx edx, desired
Chris@102 324 lock cmpxchg byte ptr [edi], dl
Chris@102 325 mov byte ptr [esi], al
Chris@102 326 sete success
Chris@102 327 };
Chris@102 328 // The success and failure fences are equivalent anyway
Chris@102 329 base_type::fence_after(success_order);
Chris@102 330 return success;
Chris@102 331 }
Chris@102 332
Chris@102 333 static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
Chris@102 334 {
Chris@102 335 base_type::fence_before(order);
Chris@102 336 int backup;
Chris@102 337 __asm
Chris@102 338 {
Chris@102 339 mov backup, ebx
Chris@102 340 xor edx, edx
Chris@102 341 mov edi, storage
Chris@102 342 movzx ebx, v
Chris@102 343 movzx eax, byte ptr [edi]
Chris@102 344 align 16
Chris@102 345 again:
Chris@102 346 mov dl, al
Chris@102 347 and dl, bl
Chris@102 348 lock cmpxchg byte ptr [edi], dl
Chris@102 349 jne again
Chris@102 350 mov v, al
Chris@102 351 mov ebx, backup
Chris@102 352 };
Chris@102 353 base_type::fence_after(order);
Chris@102 354 return v;
Chris@102 355 }
Chris@102 356
Chris@102 357 static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
Chris@102 358 {
Chris@102 359 base_type::fence_before(order);
Chris@102 360 int backup;
Chris@102 361 __asm
Chris@102 362 {
Chris@102 363 mov backup, ebx
Chris@102 364 xor edx, edx
Chris@102 365 mov edi, storage
Chris@102 366 movzx ebx, v
Chris@102 367 movzx eax, byte ptr [edi]
Chris@102 368 align 16
Chris@102 369 again:
Chris@102 370 mov dl, al
Chris@102 371 or dl, bl
Chris@102 372 lock cmpxchg byte ptr [edi], dl
Chris@102 373 jne again
Chris@102 374 mov v, al
Chris@102 375 mov ebx, backup
Chris@102 376 };
Chris@102 377 base_type::fence_after(order);
Chris@102 378 return v;
Chris@102 379 }
Chris@102 380
Chris@102 381 static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
Chris@102 382 {
Chris@102 383 base_type::fence_before(order);
Chris@102 384 int backup;
Chris@102 385 __asm
Chris@102 386 {
Chris@102 387 mov backup, ebx
Chris@102 388 xor edx, edx
Chris@102 389 mov edi, storage
Chris@102 390 movzx ebx, v
Chris@102 391 movzx eax, byte ptr [edi]
Chris@102 392 align 16
Chris@102 393 again:
Chris@102 394 mov dl, al
Chris@102 395 xor dl, bl
Chris@102 396 lock cmpxchg byte ptr [edi], dl
Chris@102 397 jne again
Chris@102 398 mov v, al
Chris@102 399 mov ebx, backup
Chris@102 400 };
Chris@102 401 base_type::fence_after(order);
Chris@102 402 return v;
Chris@102 403 }
Chris@102 404 };
Chris@102 405
Chris@102 406 #else
Chris@102 407
Chris@102 408 template< bool Signed >
Chris@102 409 struct operations< 1u, Signed > :
Chris@102 410 public extending_cas_based_operations< operations< 4u, Signed >, 1u, Signed >
Chris@102 411 {
Chris@102 412 };
Chris@102 413
Chris@102 414 #endif
Chris@102 415
Chris@102 416 #if defined(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE16)
Chris@102 417
Chris@102 418 template< bool Signed >
Chris@102 419 struct operations< 2u, Signed > :
Chris@102 420 public msvc_x86_operations< typename make_storage_type< 2u, Signed >::type, operations< 2u, Signed > >
Chris@102 421 {
Chris@102 422 typedef msvc_x86_operations< typename make_storage_type< 2u, Signed >::type, operations< 2u, Signed > > base_type;
Chris@102 423 typedef typename base_type::storage_type storage_type;
Chris@102 424
Chris@102 425 static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT
Chris@102 426 {
Chris@102 427 return static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD16(&storage, v));
Chris@102 428 }
Chris@102 429
Chris@102 430 static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT
Chris@102 431 {
Chris@102 432 return static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE16(&storage, v));
Chris@102 433 }
Chris@102 434
Chris@102 435 static BOOST_FORCEINLINE bool compare_exchange_strong(
Chris@102 436 storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order, memory_order) BOOST_NOEXCEPT
Chris@102 437 {
Chris@102 438 storage_type previous = expected;
Chris@102 439 storage_type old_val = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE16(&storage, desired, previous));
Chris@102 440 expected = old_val;
Chris@102 441 return (previous == old_val);
Chris@102 442 }
Chris@102 443
Chris@102 444 static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT
Chris@102 445 {
Chris@102 446 return static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_AND16(&storage, v));
Chris@102 447 }
Chris@102 448
Chris@102 449 static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT
Chris@102 450 {
Chris@102 451 return static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_OR16(&storage, v));
Chris@102 452 }
Chris@102 453
Chris@102 454 static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT
Chris@102 455 {
Chris@102 456 return static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_XOR16(&storage, v));
Chris@102 457 }
Chris@102 458 };
Chris@102 459
Chris@102 460 #elif defined(_M_IX86)
Chris@102 461
Chris@102 462 template< bool Signed >
Chris@102 463 struct operations< 2u, Signed > :
Chris@102 464 public msvc_x86_operations< typename make_storage_type< 2u, Signed >::type, operations< 2u, Signed > >
Chris@102 465 {
Chris@102 466 typedef msvc_x86_operations< typename make_storage_type< 2u, Signed >::type, operations< 2u, Signed > > base_type;
Chris@102 467 typedef typename base_type::storage_type storage_type;
Chris@102 468
Chris@102 469 static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
Chris@102 470 {
Chris@102 471 base_type::fence_before(order);
Chris@102 472 __asm
Chris@102 473 {
Chris@102 474 mov edx, storage
Chris@102 475 movzx eax, v
Chris@102 476 lock xadd word ptr [edx], ax
Chris@102 477 mov v, ax
Chris@102 478 };
Chris@102 479 base_type::fence_after(order);
Chris@102 480 return v;
Chris@102 481 }
Chris@102 482
Chris@102 483 static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
Chris@102 484 {
Chris@102 485 base_type::fence_before(order);
Chris@102 486 __asm
Chris@102 487 {
Chris@102 488 mov edx, storage
Chris@102 489 movzx eax, v
Chris@102 490 xchg word ptr [edx], ax
Chris@102 491 mov v, ax
Chris@102 492 };
Chris@102 493 base_type::fence_after(order);
Chris@102 494 return v;
Chris@102 495 }
Chris@102 496
Chris@102 497 static BOOST_FORCEINLINE bool compare_exchange_strong(
Chris@102 498 storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order) BOOST_NOEXCEPT
Chris@102 499 {
Chris@102 500 base_type::fence_before(success_order);
Chris@102 501 bool success;
Chris@102 502 __asm
Chris@102 503 {
Chris@102 504 mov esi, expected
Chris@102 505 mov edi, storage
Chris@102 506 movzx eax, word ptr [esi]
Chris@102 507 movzx edx, desired
Chris@102 508 lock cmpxchg word ptr [edi], dx
Chris@102 509 mov word ptr [esi], ax
Chris@102 510 sete success
Chris@102 511 };
Chris@102 512 // The success and failure fences are equivalent anyway
Chris@102 513 base_type::fence_after(success_order);
Chris@102 514 return success;
Chris@102 515 }
Chris@102 516
Chris@102 517 static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
Chris@102 518 {
Chris@102 519 base_type::fence_before(order);
Chris@102 520 int backup;
Chris@102 521 __asm
Chris@102 522 {
Chris@102 523 mov backup, ebx
Chris@102 524 xor edx, edx
Chris@102 525 mov edi, storage
Chris@102 526 movzx ebx, v
Chris@102 527 movzx eax, word ptr [edi]
Chris@102 528 align 16
Chris@102 529 again:
Chris@102 530 mov dx, ax
Chris@102 531 and dx, bx
Chris@102 532 lock cmpxchg word ptr [edi], dx
Chris@102 533 jne again
Chris@102 534 mov v, ax
Chris@102 535 mov ebx, backup
Chris@102 536 };
Chris@102 537 base_type::fence_after(order);
Chris@102 538 return v;
Chris@102 539 }
Chris@102 540
Chris@102 541 static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
Chris@102 542 {
Chris@102 543 base_type::fence_before(order);
Chris@102 544 int backup;
Chris@102 545 __asm
Chris@102 546 {
Chris@102 547 mov backup, ebx
Chris@102 548 xor edx, edx
Chris@102 549 mov edi, storage
Chris@102 550 movzx ebx, v
Chris@102 551 movzx eax, word ptr [edi]
Chris@102 552 align 16
Chris@102 553 again:
Chris@102 554 mov dx, ax
Chris@102 555 or dx, bx
Chris@102 556 lock cmpxchg word ptr [edi], dx
Chris@102 557 jne again
Chris@102 558 mov v, ax
Chris@102 559 mov ebx, backup
Chris@102 560 };
Chris@102 561 base_type::fence_after(order);
Chris@102 562 return v;
Chris@102 563 }
Chris@102 564
Chris@102 565 static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT
Chris@102 566 {
Chris@102 567 base_type::fence_before(order);
Chris@102 568 int backup;
Chris@102 569 __asm
Chris@102 570 {
Chris@102 571 mov backup, ebx
Chris@102 572 xor edx, edx
Chris@102 573 mov edi, storage
Chris@102 574 movzx ebx, v
Chris@102 575 movzx eax, word ptr [edi]
Chris@102 576 align 16
Chris@102 577 again:
Chris@102 578 mov dx, ax
Chris@102 579 xor dx, bx
Chris@102 580 lock cmpxchg word ptr [edi], dx
Chris@102 581 jne again
Chris@102 582 mov v, ax
Chris@102 583 mov ebx, backup
Chris@102 584 };
Chris@102 585 base_type::fence_after(order);
Chris@102 586 return v;
Chris@102 587 }
Chris@102 588 };
Chris@102 589
Chris@102 590 #else
Chris@102 591
Chris@102 592 template< bool Signed >
Chris@102 593 struct operations< 2u, Signed > :
Chris@102 594 public extending_cas_based_operations< operations< 4u, Signed >, 2u, Signed >
Chris@102 595 {
Chris@102 596 };
Chris@102 597
Chris@102 598 #endif
Chris@102 599
Chris@102 600
Chris@102 601 #if defined(BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG8B)
Chris@102 602
Chris@102 603 template< bool Signed >
Chris@102 604 struct msvc_dcas_x86
Chris@102 605 {
Chris@102 606 typedef typename make_storage_type< 8u, Signed >::type storage_type;
Chris@102 607
Chris@102 608 // Intel 64 and IA-32 Architectures Software Developer's Manual, Volume 3A, 8.1.1. Guaranteed Atomic Operations:
Chris@102 609 //
Chris@102 610 // The Pentium processor (and newer processors since) guarantees that the following additional memory operations will always be carried out atomically:
Chris@102 611 // * Reading or writing a quadword aligned on a 64-bit boundary
Chris@102 612 //
Chris@102 613 // Luckily, the memory is almost always 8-byte aligned in our case because atomic<> uses 64 bit native types for storage and dynamic memory allocations
Chris@102 614 // have at least 8 byte alignment. The only unfortunate case is when atomic is placeod on the stack and it is not 8-byte aligned (like on 32 bit Windows).
Chris@102 615
Chris@102 616 static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT
Chris@102 617 {
Chris@102 618 storage_type volatile* p = &storage;
Chris@102 619 if (((uint32_t)p & 0x00000007) == 0)
Chris@102 620 {
Chris@102 621 #if defined(_M_IX86_FP) && _M_IX86_FP >= 2
Chris@102 622 #if defined(__AVX__)
Chris@102 623 __asm
Chris@102 624 {
Chris@102 625 mov edx, p
Chris@102 626 vmovq xmm4, v
Chris@102 627 vmovq qword ptr [edx], xmm4
Chris@102 628 };
Chris@102 629 #else
Chris@102 630 __asm
Chris@102 631 {
Chris@102 632 mov edx, p
Chris@102 633 movq xmm4, v
Chris@102 634 movq qword ptr [edx], xmm4
Chris@102 635 };
Chris@102 636 #endif
Chris@102 637 #else
Chris@102 638 __asm
Chris@102 639 {
Chris@102 640 mov edx, p
Chris@102 641 fild v
Chris@102 642 fistp qword ptr [edx]
Chris@102 643 };
Chris@102 644 #endif
Chris@102 645 }
Chris@102 646 else
Chris@102 647 {
Chris@102 648 int backup;
Chris@102 649 __asm
Chris@102 650 {
Chris@102 651 mov backup, ebx
Chris@102 652 mov edi, p
Chris@102 653 mov ebx, dword ptr [v]
Chris@102 654 mov ecx, dword ptr [v + 4]
Chris@102 655 mov eax, dword ptr [edi]
Chris@102 656 mov edx, dword ptr [edi + 4]
Chris@102 657 align 16
Chris@102 658 again:
Chris@102 659 lock cmpxchg8b qword ptr [edi]
Chris@102 660 jne again
Chris@102 661 mov ebx, backup
Chris@102 662 };
Chris@102 663 }
Chris@102 664 }
Chris@102 665
Chris@102 666 static BOOST_FORCEINLINE storage_type load(storage_type const volatile& storage, memory_order) BOOST_NOEXCEPT
Chris@102 667 {
Chris@102 668 storage_type const volatile* p = &storage;
Chris@102 669 storage_type value;
Chris@102 670
Chris@102 671 if (((uint32_t)p & 0x00000007) == 0)
Chris@102 672 {
Chris@102 673 #if defined(_M_IX86_FP) && _M_IX86_FP >= 2
Chris@102 674 #if defined(__AVX__)
Chris@102 675 __asm
Chris@102 676 {
Chris@102 677 mov edx, p
Chris@102 678 vmovq xmm4, qword ptr [edx]
Chris@102 679 vmovq value, xmm4
Chris@102 680 };
Chris@102 681 #else
Chris@102 682 __asm
Chris@102 683 {
Chris@102 684 mov edx, p
Chris@102 685 movq xmm4, qword ptr [edx]
Chris@102 686 movq value, xmm4
Chris@102 687 };
Chris@102 688 #endif
Chris@102 689 #else
Chris@102 690 __asm
Chris@102 691 {
Chris@102 692 mov edx, p
Chris@102 693 fild qword ptr [edx]
Chris@102 694 fistp value
Chris@102 695 };
Chris@102 696 #endif
Chris@102 697 }
Chris@102 698 else
Chris@102 699 {
Chris@102 700 // We don't care for comparison result here; the previous value will be stored into value anyway.
Chris@102 701 // Also we don't care for ebx and ecx values, they just have to be equal to eax and edx before cmpxchg8b.
Chris@102 702 __asm
Chris@102 703 {
Chris@102 704 mov edi, p
Chris@102 705 mov eax, ebx
Chris@102 706 mov edx, ecx
Chris@102 707 lock cmpxchg8b qword ptr [edi]
Chris@102 708 mov dword ptr [value], eax
Chris@102 709 mov dword ptr [value + 4], edx
Chris@102 710 };
Chris@102 711 }
Chris@102 712
Chris@102 713 return value;
Chris@102 714 }
Chris@102 715
Chris@102 716 static BOOST_FORCEINLINE bool compare_exchange_strong(
Chris@102 717 storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order, memory_order) BOOST_NOEXCEPT
Chris@102 718 {
Chris@102 719 storage_type volatile* p = &storage;
Chris@102 720 #if defined(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE64)
Chris@102 721 const storage_type old_val = (storage_type)BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE64(p, desired, expected);
Chris@102 722 const bool result = (old_val == expected);
Chris@102 723 expected = old_val;
Chris@102 724 return result;
Chris@102 725 #else
Chris@102 726 bool result;
Chris@102 727 int backup;
Chris@102 728 __asm
Chris@102 729 {
Chris@102 730 mov backup, ebx
Chris@102 731 mov edi, p
Chris@102 732 mov esi, expected
Chris@102 733 mov ebx, dword ptr [desired]
Chris@102 734 mov ecx, dword ptr [desired + 4]
Chris@102 735 mov eax, dword ptr [esi]
Chris@102 736 mov edx, dword ptr [esi + 4]
Chris@102 737 lock cmpxchg8b qword ptr [edi]
Chris@102 738 mov dword ptr [esi], eax
Chris@102 739 mov dword ptr [esi + 4], edx
Chris@102 740 mov ebx, backup
Chris@102 741 sete result
Chris@102 742 };
Chris@102 743 return result;
Chris@102 744 #endif
Chris@102 745 }
Chris@102 746
Chris@102 747 static BOOST_FORCEINLINE bool compare_exchange_weak(
Chris@102 748 storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT
Chris@102 749 {
Chris@102 750 return compare_exchange_strong(storage, expected, desired, success_order, failure_order);
Chris@102 751 }
Chris@102 752
Chris@102 753 static BOOST_FORCEINLINE bool is_lock_free(storage_type const volatile&) BOOST_NOEXCEPT
Chris@102 754 {
Chris@102 755 return true;
Chris@102 756 }
Chris@102 757 };
Chris@102 758
Chris@102 759 template< bool Signed >
Chris@102 760 struct operations< 8u, Signed > :
Chris@102 761 public cas_based_operations< msvc_dcas_x86< Signed > >
Chris@102 762 {
Chris@102 763 };
Chris@102 764
Chris@102 765 #elif defined(_M_AMD64)
Chris@102 766
Chris@102 767 template< bool Signed >
Chris@102 768 struct operations< 8u, Signed > :
Chris@102 769 public msvc_x86_operations< typename make_storage_type< 8u, Signed >::type, operations< 8u, Signed > >
Chris@102 770 {
Chris@102 771 typedef msvc_x86_operations< typename make_storage_type< 8u, Signed >::type, operations< 8u, Signed > > base_type;
Chris@102 772 typedef typename base_type::storage_type storage_type;
Chris@102 773
Chris@102 774 static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT
Chris@102 775 {
Chris@102 776 return static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD64(&storage, v));
Chris@102 777 }
Chris@102 778
Chris@102 779 static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT
Chris@102 780 {
Chris@102 781 return static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE64(&storage, v));
Chris@102 782 }
Chris@102 783
Chris@102 784 static BOOST_FORCEINLINE bool compare_exchange_strong(
Chris@102 785 storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order, memory_order) BOOST_NOEXCEPT
Chris@102 786 {
Chris@102 787 storage_type previous = expected;
Chris@102 788 storage_type old_val = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE64(&storage, desired, previous));
Chris@102 789 expected = old_val;
Chris@102 790 return (previous == old_val);
Chris@102 791 }
Chris@102 792
Chris@102 793 static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT
Chris@102 794 {
Chris@102 795 return static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_AND64(&storage, v));
Chris@102 796 }
Chris@102 797
Chris@102 798 static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT
Chris@102 799 {
Chris@102 800 return static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_OR64(&storage, v));
Chris@102 801 }
Chris@102 802
Chris@102 803 static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT
Chris@102 804 {
Chris@102 805 return static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_XOR64(&storage, v));
Chris@102 806 }
Chris@102 807 };
Chris@102 808
Chris@102 809 #endif
Chris@102 810
Chris@102 811 #if defined(BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG16B)
Chris@102 812
Chris@102 813 template< bool Signed >
Chris@102 814 struct msvc_dcas_x86_64
Chris@102 815 {
Chris@102 816 typedef typename make_storage_type< 16u, Signed >::type storage_type;
Chris@102 817
Chris@102 818 static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT
Chris@102 819 {
Chris@102 820 storage_type value = const_cast< storage_type& >(storage);
Chris@102 821 while (!BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE128(&storage, v, &value)) {}
Chris@102 822 }
Chris@102 823
Chris@102 824 static BOOST_FORCEINLINE storage_type load(storage_type const volatile& storage, memory_order) BOOST_NOEXCEPT
Chris@102 825 {
Chris@102 826 storage_type value = storage_type();
Chris@102 827 BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE128(&storage, value, &value);
Chris@102 828 return value;
Chris@102 829 }
Chris@102 830
Chris@102 831 static BOOST_FORCEINLINE bool compare_exchange_strong(
Chris@102 832 storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order, memory_order) BOOST_NOEXCEPT
Chris@102 833 {
Chris@102 834 return !!BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE128(&storage, desired, &expected);
Chris@102 835 }
Chris@102 836
Chris@102 837 static BOOST_FORCEINLINE bool compare_exchange_weak(
Chris@102 838 storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT
Chris@102 839 {
Chris@102 840 return compare_exchange_strong(storage, expected, desired, success_order, failure_order);
Chris@102 841 }
Chris@102 842
Chris@102 843 static BOOST_FORCEINLINE bool is_lock_free(storage_type const volatile&) BOOST_NOEXCEPT
Chris@102 844 {
Chris@102 845 return true;
Chris@102 846 }
Chris@102 847 };
Chris@102 848
Chris@102 849 template< bool Signed >
Chris@102 850 struct operations< 16u, Signed > :
Chris@102 851 public cas_based_operations< msvc_dcas_x86_64< Signed > >
Chris@102 852 {
Chris@102 853 };
Chris@102 854
Chris@102 855 #endif // defined(BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG16B)
Chris@102 856
Chris@102 857 BOOST_FORCEINLINE void thread_fence(memory_order order) BOOST_NOEXCEPT
Chris@102 858 {
Chris@102 859 BOOST_ATOMIC_DETAIL_COMPILER_BARRIER();
Chris@102 860 if (order == memory_order_seq_cst)
Chris@102 861 msvc_x86_operations_base::hardware_full_fence();
Chris@102 862 BOOST_ATOMIC_DETAIL_COMPILER_BARRIER();
Chris@102 863 }
Chris@102 864
Chris@102 865 BOOST_FORCEINLINE void signal_fence(memory_order order) BOOST_NOEXCEPT
Chris@102 866 {
Chris@102 867 if (order != memory_order_relaxed)
Chris@102 868 BOOST_ATOMIC_DETAIL_COMPILER_BARRIER();
Chris@102 869 }
Chris@102 870
Chris@102 871 } // namespace detail
Chris@102 872 } // namespace atomics
Chris@102 873 } // namespace boost
Chris@102 874
Chris@102 875 #if defined(BOOST_MSVC)
Chris@102 876 #pragma warning(pop)
Chris@102 877 #endif
Chris@102 878
Chris@102 879 #endif // BOOST_ATOMIC_DETAIL_OPS_MSVC_X86_HPP_INCLUDED_