From 490834924cc390cb812713c225b9a8227c66cf1f Mon Sep 17 00:00:00 2001 From: Yong He Date: Fri, 20 Sep 2024 15:11:23 -0700 Subject: Initial `Atomic` type implementation. (#5125) * Initial Atomic type implementation. * Update design doc. * Fix. * Add test. * Fixes and add tests. * Fix WGSL. * Fix glsl. * Fix metal. * experiemnt with github metal. * experiment github metal 2 * github metal experiment 3 * experiment with github metal 4. * experiment with metal 5. * experiment 7. * metal experiment 8. * Fix metal tests. --------- Co-authored-by: Yong He --- docs/proposals/003-atomic-t.md | 86 ++++++++++++++++++++++++++++-------------- 1 file changed, 58 insertions(+), 28 deletions(-) (limited to 'docs') diff --git a/docs/proposals/003-atomic-t.md b/docs/proposals/003-atomic-t.md index 03df9bb5e..d05067714 100644 --- a/docs/proposals/003-atomic-t.md +++ b/docs/proposals/003-atomic-t.md @@ -7,11 +7,11 @@ Status Author: Yong He -Status: Design Discussion. +Status: Implementation in review. -Implementation: N/A +Implementation: [PR 5125](https://github.com/shader-slang/slang/pull/5125) -Reviewed by: N/A +Reviewed by: Theresa Foley, Jay Kwak Background ---------- @@ -31,42 +31,72 @@ Proposed Approach ----------------- We define an `Atomic` type that functions as a wrapper of `T` and provides atomic operations: -``` -[sealed] interface IAtomicable {} -[sealed] interface IArithmeticAtomicable : IAtomicable {} -[sealed] interface IBitAtomicable : IArithmeticAtomicable {} +```csharp +enum MemoryOrder +{ + Relaxed = 0, + Acquire = 1, + Release = 2, + AcquireRelease = 3, + SeqCst = 4, +} -extension int : IArithmeticAtomicable {} -extension uint : IArithmeticAtomicable {} -extension int64_t : IBitAtomicable {} -extension uint64_t : IBitAtomicable {} -extension float : IArithmeticAtomicable {} -extension half : IArithmeticAtomicable {} +[sealed] interface IAtomicable {} +[sealed] interface IArithmeticAtomicable : IAtomicable, IArithmetic {} +[sealed] interface IBitAtomicable : IArithmeticAtomicable, IInteger {} +[require(cuda_glsl_hlsl_metal_spirv_wgsl)] struct Atomic { - T load(); - [ref] void store(T newValue); // Question: do we really need this? - [ref] T exchange(T newValue); // returns old value - [ref] T compareExchange(T compareValue, T newValue); // returns old value. + T load(MemoryOrder order = MemoryOrder.Relaxed); + + [__ref] void store(T newValue, MemoryOrder order = MemoryOrder.Relaxed); + + [__ref] T exchange(T newValue, MemoryOrder order = MemoryOrder.Relaxed); // returns old value + + [__ref] T compareExchange( + T compareValue, + T newValue, + MemoryOrder successOrder = MemoryOrder.Relaxed, + MemoryOrder failOrder = MemoryOrder.Relaxed); } -extension Atomic +extension Atomic { - [ref] T atomicAdd(T value); // returns original value - [ref] T atomicSub(T value); // returns original value - [ref] T atomicMax(T value); // returns original value - [ref] T atomicMin(T value); // returns original value - [ref] T atomicIncrement(); - [ref] T atomicDecrement(); + [__ref] T add(T value, MemoryOrder order = MemoryOrder.Relaxed); // returns original value + [__ref] T sub(T value, MemoryOrder order = MemoryOrder.Relaxed); // returns original value + [__ref] T max(T value, MemoryOrder order = MemoryOrder.Relaxed); // returns original value + [__ref] T min(T value, MemoryOrder order = MemoryOrder.Relaxed); // returns original value } -extension Atomic +extension Atomic { - [ref] T atomicAnd(T value); // returns original value - [ref] T atomicOr(T value); // returns original value - [ref] T atomicXor(T value); // returns original value + [__ref] T and(T value, MemoryOrder order = MemoryOrder.Relaxed); // returns original value + [__ref] T or(T value, MemoryOrder order = MemoryOrder.Relaxed); // returns original value + [__ref] T xor(T value, MemoryOrder order = MemoryOrder.Relaxed); // returns original value + [__ref] T increment(MemoryOrder order = MemoryOrder.Relaxed); // returns original value + [__ref] T decrement(MemoryOrder order = MemoryOrder.Relaxed); // returns original value } + +extension int : IArithmeticAtomicable {} +extension uint : IArithmeticAtomicable {} +extension int64_t : IBitAtomicable {} +extension uint64_t : IBitAtomicable {} +extension double : IArithmeticAtomicable {} +extension float : IArithmeticAtomicable {} +extension half : IArithmeticAtomicable {} + +// Operator overloads: +// All operator overloads are using MemoryOrder.Relaxed semantics. +__prefix T operator++(__ref Atomic v); // returns new value. +__postfix T operator++(__ref Atomic v); // returns original value. +__prefix T operator--(__ref Atomic v); // returns new value. +__postfix T operator--(__ref Atomic v); // returns original value. +T operator+=(__ref Atomic v, T operand); // returns new value. +T operator-=(__ref Atomic v, T operand); // returns new value. +T operator|=(__ref Atomic v, T operand); // returns new value. +T operator&=(__ref Atomic v, T operand); // returns new value. +T operator^=(__ref Atomic v, T operand); // returns new value. ``` We allow `Atomic` to be defined anywhere: as struct fields, as array elements, as elements of `RWStructuredBuffer` types, -- cgit v1.2.3