19#ifndef COMPAT_ATOMICS_WIN32_STDATOMIC_IMPL_H
20#define COMPAT_ATOMICS_WIN32_STDATOMIC_IMPL_H
26#define FF_ATOMIC_LOCK_FREE 2
32#define FF_ATOMIC_ALIGN64 __declspec(align(8))
34#define FF_ATOMIC_ALIGN64
54#if defined(_M_ARM64) || defined(_M_ARM64EC)
63#define WIN32_ATOMIC_LOAD_STORE(name, type, W) \
64static av_always_inline type \
65ff_atomic_load_##name(const volatile void *object, memory_order order) \
67 if (order != memory_order_relaxed) \
68 return (type)__ldar##W((unsigned __int##W volatile *)object); \
69 return (type)__iso_volatile_load##W((const volatile __int##W *)object); \
72static av_always_inline void ff_atomic_store_##name(volatile void *object, \
76 if (order == memory_order_relaxed) \
77 __iso_volatile_store##W((volatile __int##W *)object, \
80 __stlr##W((unsigned __int##W volatile *)object, \
81 (unsigned __int##W)desired); \
84#define WIN32_ATOMIC_ORDERED(Intrinsic, suffix) Intrinsic##suffix
85#define WIN32_ATOMIC_XCHG_REL _rel
90 __dmb(_ARM64_BARRIER_ISHLD);
92 __dmb(_ARM64_BARRIER_ISH);
104#define WIN32_ATOMIC_LOAD_STORE(name, type, W) \
105static av_always_inline type \
106ff_atomic_load_##name(const volatile void *object, memory_order order) \
109 (type)__iso_volatile_load##W((const volatile __int##W *)object); \
110 if (order != memory_order_relaxed) \
111 __dmb(_ARM_BARRIER_ISH); \
115static av_always_inline void ff_atomic_store_##name(volatile void *object, \
117 memory_order order) \
119 if (order != memory_order_relaxed) \
120 __dmb(_ARM_BARRIER_ISH); \
121 __iso_volatile_store##W((volatile __int##W *)object, (__int##W)desired); \
122 if (order == memory_order_seq_cst) \
123 __dmb(_ARM_BARRIER_ISH); \
126#define WIN32_ATOMIC_ORDERED(Intrinsic, suffix) Intrinsic##suffix
127#define WIN32_ATOMIC_XCHG_REL
132 __dmb(_ARM_BARRIER_ISH);
148 _InterlockedOr(&barrier, 0);
152#define WIN32_ATOMIC_LOAD_STORE(name, type, W) \
153static av_always_inline type \
154ff_atomic_load_##name(const volatile void *object, memory_order order) \
157 (type)__iso_volatile_load##W((const volatile __int##W *)object); \
158 if (order != memory_order_relaxed) \
159 _ReadWriteBarrier(); \
163static av_always_inline void ff_atomic_store_##name(volatile void *object, \
165 memory_order order) \
167 if (order != memory_order_relaxed) \
168 _ReadWriteBarrier(); \
169 __iso_volatile_store##W((volatile __int##W *)object, (__int##W)desired); \
170 if (order == memory_order_seq_cst) \
171 win32_atomic_full_fence(); \
174#define WIN32_ATOMIC_ORDERED(Intrinsic, suffix) Intrinsic
175#define WIN32_ATOMIC_XCHG_REL
187#define WIN32_ATOMIC_CALL(Intrinsic, rel, order, ...) \
188 ((order) == memory_order_relaxed \
189 ? WIN32_ATOMIC_ORDERED(Intrinsic, _nf)(__VA_ARGS__) \
190 : (order) == memory_order_release \
191 ? WIN32_ATOMIC_ORDERED(Intrinsic, rel)(__VA_ARGS__) \
192 : (order) == memory_order_acquire || (order) == memory_order_consume \
193 ? WIN32_ATOMIC_ORDERED(Intrinsic, _acq)(__VA_ARGS__) \
194 : Intrinsic(__VA_ARGS__))
203#define WIN32_ATOMIC_CAS_LOOP64(name, expr) \
204static av_always_inline long long \
205win32_Interlocked##name##64(volatile long long *object, long long operand) \
207 long long old = __iso_volatile_load64(object), prev; \
208 while ((prev = _InterlockedCompareExchange64(object, (long long)(expr), \
213WIN32_ATOMIC_CAS_LOOP64(Exchange, operand)
214WIN32_ATOMIC_CAS_LOOP64(ExchangeAdd, (uint64_t)old + (uint64_t)operand)
215WIN32_ATOMIC_CAS_LOOP64(Or, old | operand)
216WIN32_ATOMIC_CAS_LOOP64(Xor, old ^ operand)
217WIN32_ATOMIC_CAS_LOOP64(And, old & operand)
218#undef WIN32_ATOMIC_CAS_LOOP64
219#define win32_InterlockedCompareExchange64 _InterlockedCompareExchange64
222#define WIN32_ATOMIC_OP(op, Intrinsic, rel, expr, name, type) \
223static av_always_inline type ff_atomic_##op##name(volatile void *object, \
225 memory_order order) \
227 return WIN32_ATOMIC_CALL(Intrinsic, rel, order, object, expr); \
233#define WIN32_ATOMIC_RMW(name, type, P, S) \
234static av_always_inline bool ff_atomic_cas_##name(volatile void *object, \
237 memory_order order) \
240 memcpy(&old, expected, sizeof(old)); \
241 prev = WIN32_ATOMIC_CALL(P##CompareExchange##S, _rel, order, \
242 object, desired, old); \
245 memcpy(expected, &prev, sizeof(prev)); \
249WIN32_ATOMIC_OP(exchange, P##Exchange##S, WIN32_ATOMIC_XCHG_REL, \
250 operand, _##name, type) \
251WIN32_ATOMIC_OP(fetch_add, P##ExchangeAdd##S, _rel, operand, _##name, type) \
252WIN32_ATOMIC_OP(fetch_sub, P##ExchangeAdd##S, _rel, \
253 (type)(0 - (uint64_t)operand), _##name, type) \
254WIN32_ATOMIC_OP(fetch_or, P##Or##S, _rel, operand, _##name, type) \
255WIN32_ATOMIC_OP(fetch_xor, P##Xor##S, _rel, operand, _##name, type) \
256WIN32_ATOMIC_OP(fetch_and, P##And##S, _rel, operand, _##name, type)
267ff_atomic_load_64(
const volatile void *
object,
memory_order order)
269 unsigned long long value = __ldrexd((
const volatile __int64 *)
object);
271 __dmb(_ARM_BARRIER_ISH);
276 unsigned long long desired,
280 _InterlockedExchange64_nf((
volatile long long *)
object, desired);
282 _InterlockedExchange64((
volatile long long *)
object, desired);
296#undef WIN32_ATOMIC_LOAD_STORE
297#undef WIN32_ATOMIC_RMW
298#undef WIN32_ATOMIC_OP
299#undef WIN32_ATOMIC_CALL
300#undef WIN32_ATOMIC_ORDERED
301#undef WIN32_ATOMIC_XCHG_REL
302#undef win32_InterlockedCompareExchange64
#define ff_atomic_thread_fence(order)
#define ff_atomic_signal_fence(order)
static av_always_inline void win32_atomic_full_fence(void)
#define WIN32_ATOMIC_RMW(name, type, P, S)
#define WIN32_ATOMIC_LOAD_STORE(name, type, W)