1 // Copyright 2020 yuzu Emulator Project
2 // Licensed under GPLv2 or any later version
3 // Refer to the license.txt file included.
4 
5 #include <cstring>
6 
7 #include "common/atomic_ops.h"
8 
9 #if _MSC_VER
10 #include <intrin.h>
11 #endif
12 
13 namespace Common {
14 
15 #if _MSC_VER
16 
AtomicCompareAndSwap(volatile u8 * pointer,u8 value,u8 expected)17 bool AtomicCompareAndSwap(volatile u8* pointer, u8 value, u8 expected) {
18     const u8 result =
19         _InterlockedCompareExchange8(reinterpret_cast<volatile char*>(pointer), value, expected);
20     return result == expected;
21 }
22 
AtomicCompareAndSwap(volatile u16 * pointer,u16 value,u16 expected)23 bool AtomicCompareAndSwap(volatile u16* pointer, u16 value, u16 expected) {
24     const u16 result =
25         _InterlockedCompareExchange16(reinterpret_cast<volatile short*>(pointer), value, expected);
26     return result == expected;
27 }
28 
AtomicCompareAndSwap(volatile u32 * pointer,u32 value,u32 expected)29 bool AtomicCompareAndSwap(volatile u32* pointer, u32 value, u32 expected) {
30     const u32 result =
31         _InterlockedCompareExchange(reinterpret_cast<volatile long*>(pointer), value, expected);
32     return result == expected;
33 }
34 
AtomicCompareAndSwap(volatile u64 * pointer,u64 value,u64 expected)35 bool AtomicCompareAndSwap(volatile u64* pointer, u64 value, u64 expected) {
36     const u64 result = _InterlockedCompareExchange64(reinterpret_cast<volatile __int64*>(pointer),
37                                                      value, expected);
38     return result == expected;
39 }
40 
AtomicCompareAndSwap(volatile u64 * pointer,u128 value,u128 expected)41 bool AtomicCompareAndSwap(volatile u64* pointer, u128 value, u128 expected) {
42     return _InterlockedCompareExchange128(reinterpret_cast<volatile __int64*>(pointer), value[1],
43                                           value[0],
44                                           reinterpret_cast<__int64*>(expected.data())) != 0;
45 }
46 
47 #else
48 
49 bool AtomicCompareAndSwap(volatile u8* pointer, u8 value, u8 expected) {
50     return __sync_bool_compare_and_swap(pointer, expected, value);
51 }
52 
53 bool AtomicCompareAndSwap(volatile u16* pointer, u16 value, u16 expected) {
54     return __sync_bool_compare_and_swap(pointer, expected, value);
55 }
56 
57 bool AtomicCompareAndSwap(volatile u32* pointer, u32 value, u32 expected) {
58     return __sync_bool_compare_and_swap(pointer, expected, value);
59 }
60 
61 bool AtomicCompareAndSwap(volatile u64* pointer, u64 value, u64 expected) {
62     return __sync_bool_compare_and_swap(pointer, expected, value);
63 }
64 
65 bool AtomicCompareAndSwap(volatile u64* pointer, u128 value, u128 expected) {
66     unsigned __int128 value_a;
67     unsigned __int128 expected_a;
68     std::memcpy(&value_a, value.data(), sizeof(u128));
69     std::memcpy(&expected_a, expected.data(), sizeof(u128));
70     return __sync_bool_compare_and_swap((unsigned __int128*)pointer, expected_a, value_a);
71 }
72 
73 #endif
74 
75 } // namespace Common
76