atomic_ops.h 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #pragma once
  4. #include "common/common_types.h"
  5. #if _MSC_VER
  6. #include <intrin.h>
  7. #else
  8. #include <cstring>
  9. #endif
  10. namespace Common {
  11. #if _MSC_VER
  12. [[nodiscard]] inline bool AtomicCompareAndSwap(volatile u8* pointer, u8 value, u8 expected) {
  13. const u8 result =
  14. _InterlockedCompareExchange8(reinterpret_cast<volatile char*>(pointer), value, expected);
  15. return result == expected;
  16. }
  17. [[nodiscard]] inline bool AtomicCompareAndSwap(volatile u16* pointer, u16 value, u16 expected) {
  18. const u16 result =
  19. _InterlockedCompareExchange16(reinterpret_cast<volatile short*>(pointer), value, expected);
  20. return result == expected;
  21. }
  22. [[nodiscard]] inline bool AtomicCompareAndSwap(volatile u32* pointer, u32 value, u32 expected) {
  23. const u32 result =
  24. _InterlockedCompareExchange(reinterpret_cast<volatile long*>(pointer), value, expected);
  25. return result == expected;
  26. }
  27. [[nodiscard]] inline bool AtomicCompareAndSwap(volatile u64* pointer, u64 value, u64 expected) {
  28. const u64 result = _InterlockedCompareExchange64(reinterpret_cast<volatile __int64*>(pointer),
  29. value, expected);
  30. return result == expected;
  31. }
  32. [[nodiscard]] inline bool AtomicCompareAndSwap(volatile u64* pointer, u128 value, u128 expected) {
  33. return _InterlockedCompareExchange128(reinterpret_cast<volatile __int64*>(pointer), value[1],
  34. value[0],
  35. reinterpret_cast<__int64*>(expected.data())) != 0;
  36. }
  37. [[nodiscard]] inline bool AtomicCompareAndSwap(volatile u8* pointer, u8 value, u8 expected,
  38. u8& actual) {
  39. actual =
  40. _InterlockedCompareExchange8(reinterpret_cast<volatile char*>(pointer), value, expected);
  41. return actual == expected;
  42. }
  43. [[nodiscard]] inline bool AtomicCompareAndSwap(volatile u16* pointer, u16 value, u16 expected,
  44. u16& actual) {
  45. actual =
  46. _InterlockedCompareExchange16(reinterpret_cast<volatile short*>(pointer), value, expected);
  47. return actual == expected;
  48. }
  49. [[nodiscard]] inline bool AtomicCompareAndSwap(volatile u32* pointer, u32 value, u32 expected,
  50. u32& actual) {
  51. actual =
  52. _InterlockedCompareExchange(reinterpret_cast<volatile long*>(pointer), value, expected);
  53. return actual == expected;
  54. }
  55. [[nodiscard]] inline bool AtomicCompareAndSwap(volatile u64* pointer, u64 value, u64 expected,
  56. u64& actual) {
  57. actual = _InterlockedCompareExchange64(reinterpret_cast<volatile __int64*>(pointer), value,
  58. expected);
  59. return actual == expected;
  60. }
  61. [[nodiscard]] inline bool AtomicCompareAndSwap(volatile u64* pointer, u128 value, u128 expected,
  62. u128& actual) {
  63. const bool result =
  64. _InterlockedCompareExchange128(reinterpret_cast<volatile __int64*>(pointer), value[1],
  65. value[0], reinterpret_cast<__int64*>(expected.data())) != 0;
  66. actual = expected;
  67. return result;
  68. }
  69. [[nodiscard]] inline u128 AtomicLoad128(volatile u64* pointer) {
  70. u128 result{};
  71. _InterlockedCompareExchange128(reinterpret_cast<volatile __int64*>(pointer), result[1],
  72. result[0], reinterpret_cast<__int64*>(result.data()));
  73. return result;
  74. }
  75. #else
  76. [[nodiscard]] inline bool AtomicCompareAndSwap(volatile u8* pointer, u8 value, u8 expected) {
  77. return __sync_bool_compare_and_swap(pointer, expected, value);
  78. }
  79. [[nodiscard]] inline bool AtomicCompareAndSwap(volatile u16* pointer, u16 value, u16 expected) {
  80. return __sync_bool_compare_and_swap(pointer, expected, value);
  81. }
  82. [[nodiscard]] inline bool AtomicCompareAndSwap(volatile u32* pointer, u32 value, u32 expected) {
  83. return __sync_bool_compare_and_swap(pointer, expected, value);
  84. }
  85. [[nodiscard]] inline bool AtomicCompareAndSwap(volatile u64* pointer, u64 value, u64 expected) {
  86. return __sync_bool_compare_and_swap(pointer, expected, value);
  87. }
  88. [[nodiscard]] inline bool AtomicCompareAndSwap(volatile u64* pointer, u128 value, u128 expected) {
  89. unsigned __int128 value_a;
  90. unsigned __int128 expected_a;
  91. std::memcpy(&value_a, value.data(), sizeof(u128));
  92. std::memcpy(&expected_a, expected.data(), sizeof(u128));
  93. return __sync_bool_compare_and_swap((unsigned __int128*)pointer, expected_a, value_a);
  94. }
  95. [[nodiscard]] inline bool AtomicCompareAndSwap(volatile u8* pointer, u8 value, u8 expected,
  96. u8& actual) {
  97. actual = __sync_val_compare_and_swap(pointer, expected, value);
  98. return actual == expected;
  99. }
  100. [[nodiscard]] inline bool AtomicCompareAndSwap(volatile u16* pointer, u16 value, u16 expected,
  101. u16& actual) {
  102. actual = __sync_val_compare_and_swap(pointer, expected, value);
  103. return actual == expected;
  104. }
  105. [[nodiscard]] inline bool AtomicCompareAndSwap(volatile u32* pointer, u32 value, u32 expected,
  106. u32& actual) {
  107. actual = __sync_val_compare_and_swap(pointer, expected, value);
  108. return actual == expected;
  109. }
  110. [[nodiscard]] inline bool AtomicCompareAndSwap(volatile u64* pointer, u64 value, u64 expected,
  111. u64& actual) {
  112. actual = __sync_val_compare_and_swap(pointer, expected, value);
  113. return actual == expected;
  114. }
  115. [[nodiscard]] inline bool AtomicCompareAndSwap(volatile u64* pointer, u128 value, u128 expected,
  116. u128& actual) {
  117. unsigned __int128 value_a;
  118. unsigned __int128 expected_a;
  119. unsigned __int128 actual_a;
  120. std::memcpy(&value_a, value.data(), sizeof(u128));
  121. std::memcpy(&expected_a, expected.data(), sizeof(u128));
  122. actual_a = __sync_val_compare_and_swap((unsigned __int128*)pointer, expected_a, value_a);
  123. std::memcpy(actual.data(), &actual_a, sizeof(u128));
  124. return actual_a == expected_a;
  125. }
  126. [[nodiscard]] inline u128 AtomicLoad128(volatile u64* pointer) {
  127. unsigned __int128 zeros_a = 0;
  128. unsigned __int128 result_a =
  129. __sync_val_compare_and_swap((unsigned __int128*)pointer, zeros_a, zeros_a);
  130. u128 result;
  131. std::memcpy(result.data(), &result_a, sizeof(u128));
  132. return result;
  133. }
  134. #endif
  135. } // namespace Common