From 68b81db90f250d39964aabe542819bc996a4ae52 Mon Sep 17 00:00:00 2001 From: Jasper Bekkers Date: Fri, 11 Sep 2020 18:10:11 +0100 Subject: [PATCH 1/2] LDS access proposal --- rfcs/000-safe-lds-access.md | 100 ++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 rfcs/000-safe-lds-access.md diff --git a/rfcs/000-safe-lds-access.md b/rfcs/000-safe-lds-access.md new file mode 100644 index 0000000000..7224749316 --- /dev/null +++ b/rfcs/000-safe-lds-access.md @@ -0,0 +1,100 @@ + +# Summary + +Provide safe access to a (limited) set of LDS memory without race conditions and without violating SPIR-V rules. + +# Explanation + + +``` + +struct LdsWriter; + +impl LdsWriter { + fn write_thread_idx(&mut self, value: T); + fn barrier(self) -> LdsReader; +} + +struct LdsReader; + +impl LdsReader { + fn read(&self, idx: usize) -> T; + fn barrier(self) -> LdsWriter; +} +``` +## Barriers in non-uniform control flow + +``` +// sample 1: +let lds = LdsWriter::::new(); + +lds.write_thread_idx(0); + +// barrier should be in uniform control flow +let value = if something { + lds.barrier().read(12) +} else { + lds.barrier().read(23) +}; +``` + +## Multiple barriers with write in one branch +``` +// sample 2: + +let lds = LdsWriter::::new(); + +lds.write_thread_idx(0); + +let value = if something { + lds.barrier().read(12) +} else { + let rdr = lds.barrier(); + let value = rdr.read(23); + + rdr.barrier().write_thread_idx(12); + value +}; +``` + +## Multiple consecutive writes to same location +``` +// sample 3: +let lds = LdsWriter::::new(); + +lds.write_thread_idx(0); +lds.write_thread_idx(666); // race? +``` + +## Multiple writes to same memory location after a read +``` +// sample 4: +let lds = LdsWriter::::new(); + +lds.write_thread_idx(0); + +let (value, rdr) = if something { + let rdr = lds.barrier(); + let value = rdr.read(12) + (value, rdr) +} else { + let rdr = lds.barrier(); + let value = rdr.read(12) + (value, rdr) +}; + +let wrt = rdr.barrier(); +wrt.write_thread_idx(12234); +``` + +# Drawbacks + + * Limited amount of indexing for write operations + +# Alternatives + + * No known alternatives + +# Prior art + + * Regular shading languages only provide unsafe/unsound access \ No newline at end of file From dbfa0ac35792313f07ae09b0ae0b19f7152149fa Mon Sep 17 00:00:00 2001 From: Jasper Bekkers Date: Fri, 11 Sep 2020 18:36:09 +0100 Subject: [PATCH 2/2] Tobias's proposal and ThreadIdx --- rfcs/000-safe-lds-access.md | 50 +++++++++++++++++++++++++++++++------ 1 file changed, 43 insertions(+), 7 deletions(-) diff --git a/rfcs/000-safe-lds-access.md b/rfcs/000-safe-lds-access.md index 7224749316..11bb6dce42 100644 --- a/rfcs/000-safe-lds-access.md +++ b/rfcs/000-safe-lds-access.md @@ -6,8 +6,7 @@ Provide safe access to a (limited) set of LDS memory without race conditions and # Explanation -``` - +```rust struct LdsWriter; impl LdsWriter { @@ -24,7 +23,7 @@ impl LdsReader { ``` ## Barriers in non-uniform control flow -``` +```rust // sample 1: let lds = LdsWriter::::new(); @@ -39,7 +38,7 @@ let value = if something { ``` ## Multiple barriers with write in one branch -``` +```rust // sample 2: let lds = LdsWriter::::new(); @@ -58,7 +57,7 @@ let value = if something { ``` ## Multiple consecutive writes to same location -``` +```rust // sample 3: let lds = LdsWriter::::new(); @@ -67,7 +66,7 @@ lds.write_thread_idx(666); // race? ``` ## Multiple writes to same memory location after a read -``` +```rust // sample 4: let lds = LdsWriter::::new(); @@ -93,7 +92,44 @@ wrt.write_thread_idx(12234); # Alternatives - * No known alternatives +@Tobski proposed making join operations explict and potentially passing in ranges in, to partition the data +```rust +struct BufferWriter; + +impl BufferWriter { + fn write_thread_idx(&mut self, value: T); +} + +struct BufferReader; + + +impl BufferReader { + fn read(&self, idx: usize) -> T; + fn partition_readers(self, ranges: [(usize, usize)]) -> [BufferReader]; + fn partition_writers(self, ranges: [(usize, usize)]) -> [BufferWriter]; +} + +fn join_writers(a: BufferWriter, b: BufferWriter) -> BufferReader; +fn join_readers(a: BufferReader, b: BufferReader) -> BufferReader; +``` + +@Jasper-Bekkers proposed making thread index a type with limited safe operations to extend the writer types with some more flexibilty. One concern here is also that this should be done in uniform controlflow most likely. + +```rust +struct ThreadIdx; + +impl ThreadIdx { + /// XOR shuffle with a constant + fn butterfly_shuffle(&self, i: u32) -> ThreadIdx; + + /// Shuffle all lanes up / down by a constant + fn up(&self, i: u32) -> ThreadIdx; + fn down(&self, i: u32) -> ThreadIdx; + + /// Selecting arbitrary threads is unsafe + unsafe fn new(idx: u32) -> ThreadIdx; +} +``` # Prior art