warp_types/fence.rs
1//! Fence-divergence interaction types (§5.6).
2//!
3//! Global memory writes from diverged warps must be carefully tracked.
4//! A fence is only valid after ALL lanes have written — which requires
5//! the same complement proof used for merge.
6//!
7//! # Type-state protocol
8//!
9//! ```text
10//! GlobalRegion<Unwritten>
11//! → Warp<S1>.global_store() → GlobalRegion<PartialWrite<S1>>
12//! → merge_writes(PartialWrite<S1>, PartialWrite<S2>) → GlobalRegion<FullWrite>
13//! (requires S1: ComplementOf<S2>)
14//! → threadfence(FullWrite) → GlobalRegion<Fenced>
15//! ```
16//!
17//! This turns a memory ordering bug into a type error.
18
19use crate::active_set::{ActiveSet, ComplementOf, ComplementWithin};
20use crate::warp::Warp;
21use core::marker::PhantomData;
22
23// ============================================================================
24// Write state markers
25// ============================================================================
26
27/// Marker trait for global region write states.
28///
29/// Sealed — external crates cannot implement this trait, preventing
30/// forgery of write-state transitions.
31pub trait WriteState: crate::active_set::sealed::Sealed {}
32
33/// No writes have occurred.
34#[derive(Debug, Clone, Copy)]
35pub struct Unwritten;
36#[allow(private_interfaces)]
37impl crate::active_set::sealed::Sealed for Unwritten {
38 fn _sealed() -> crate::active_set::sealed::SealToken {
39 crate::active_set::sealed::SealToken
40 }
41}
42impl WriteState for Unwritten {}
43
44/// Partial write: only lanes in `S` have written.
45#[derive(Debug, Clone, Copy)]
46pub struct PartialWrite<S: ActiveSet> {
47 _phantom: PhantomData<S>,
48}
49#[allow(private_interfaces)]
50impl<S: ActiveSet> crate::active_set::sealed::Sealed for PartialWrite<S> {
51 fn _sealed() -> crate::active_set::sealed::SealToken {
52 crate::active_set::sealed::SealToken
53 }
54}
55impl<S: ActiveSet> WriteState for PartialWrite<S> {}
56
57/// All lanes have written (complement-verified).
58#[derive(Debug, Clone, Copy)]
59pub struct FullWrite;
60#[allow(private_interfaces)]
61impl crate::active_set::sealed::Sealed for FullWrite {
62 fn _sealed() -> crate::active_set::sealed::SealToken {
63 crate::active_set::sealed::SealToken
64 }
65}
66impl WriteState for FullWrite {}
67
68/// Fence has been issued after full write.
69#[derive(Debug, Clone, Copy)]
70pub struct Fenced;
71#[allow(private_interfaces)]
72impl crate::active_set::sealed::Sealed for Fenced {
73 fn _sealed() -> crate::active_set::sealed::SealToken {
74 crate::active_set::sealed::SealToken
75 }
76}
77impl WriteState for Fenced {}
78
79// ============================================================================
80// Global region with write tracking
81// ============================================================================
82
83/// A global memory region with type-state tracked write progress.
84///
85/// The type parameter `S` tracks which write state the region is in.
86/// Operations are only available in the correct state:
87/// - `global_store()` requires a warp (any active set)
88/// - `merge_writes()` requires complementary partial writes
89/// - `threadfence()` requires full write
90/// - Reading requires fenced state
91#[must_use = "GlobalRegion tracks write progress — dropping it loses the write-state proof"]
92pub struct GlobalRegion<S: WriteState> {
93 _phantom: PhantomData<S>,
94}
95
96impl GlobalRegion<Unwritten> {
97 /// Create a new unwritten global region.
98 pub fn new() -> Self {
99 GlobalRegion {
100 _phantom: PhantomData,
101 }
102 }
103}
104
105impl Default for GlobalRegion<Unwritten> {
106 fn default() -> Self {
107 Self::new()
108 }
109}
110
111/// Warp writes to a global region, producing a partial write.
112impl<S: ActiveSet> Warp<S> {
113 /// Store values to global memory.
114 ///
115 /// Returns the warp (unchanged) and a partially-written region
116 /// that tracks which lanes have written.
117 ///
118 /// **Note:** Even `Warp<All>` produces `PartialWrite<All>`, not `FullWrite`.
119 /// Use `global_store_complement` with the complement's partial write to
120 /// advance to `FullWrite`, or call this then `merge_writes` with a
121 /// `PartialWrite<Empty>` (which `Empty: ComplementOf<All>` satisfies).
122 pub fn global_store(
123 self,
124 _region: GlobalRegion<Unwritten>,
125 ) -> (Self, GlobalRegion<PartialWrite<S>>) {
126 (
127 self,
128 GlobalRegion {
129 _phantom: PhantomData,
130 },
131 )
132 }
133
134 /// Store values to a region that already has a partial write from
135 /// complementary lanes, producing a full write.
136 ///
137 /// Returns the warp (unchanged) so it can still be merged.
138 pub fn global_store_complement<S2: ActiveSet>(
139 self,
140 _region: GlobalRegion<PartialWrite<S2>>,
141 ) -> (Self, GlobalRegion<FullWrite>)
142 where
143 S: ComplementOf<S2>,
144 {
145 (
146 self,
147 GlobalRegion {
148 _phantom: PhantomData,
149 },
150 )
151 }
152}
153
154/// Merge writes from complementary partial writes (top-level: covers All).
155///
156/// Requires the same `ComplementOf` proof as warp merge.
157///
158/// Writing with wrong complement type fails:
159///
160/// ```compile_fail
161/// use warp_types::prelude::*;
162/// use warp_types::fence::*;
163/// let warp1 = Warp::kernel_entry();
164/// let (evens, _odds) = warp1.diverge_even_odd();
165/// let warp2 = Warp::kernel_entry();
166/// let (low, _high) = warp2.diverge_halves();
167/// let region1 = GlobalRegion::new();
168/// let region2 = GlobalRegion::new();
169/// let (_evens, partial_even) = evens.global_store(region1);
170/// let (_low, partial_low) = low.global_store(region2);
171/// // Even and LowHalf are not complements (they overlap) — compile error
172/// let _full = merge_writes(partial_even, partial_low);
173/// ```
174pub fn merge_writes<S1, S2>(
175 _a: GlobalRegion<PartialWrite<S1>>,
176 _b: GlobalRegion<PartialWrite<S2>>,
177) -> GlobalRegion<FullWrite>
178where
179 S1: ComplementOf<S2>,
180 S2: ActiveSet,
181{
182 GlobalRegion {
183 _phantom: PhantomData,
184 }
185}
186
187/// Merge writes from partial writes that are complements within a parent set.
188///
189/// For nested divergence: e.g., EvenLow + EvenHigh within Even.
190/// Returns a partial write for the parent set, not a full write.
191pub fn merge_writes_within<S1, S2, P>(
192 _a: GlobalRegion<PartialWrite<S1>>,
193 _b: GlobalRegion<PartialWrite<S2>>,
194) -> GlobalRegion<PartialWrite<P>>
195where
196 S1: ComplementWithin<S2, P>,
197 S2: ActiveSet,
198 P: ActiveSet,
199{
200 GlobalRegion {
201 _phantom: PhantomData,
202 }
203}
204
205/// Issue a thread fence after all writes are complete.
206///
207/// Only callable on `GlobalRegion<FullWrite>` — the type system ensures
208/// all lanes have written before the fence.
209pub fn threadfence(_proof: GlobalRegion<FullWrite>) -> GlobalRegion<Fenced> {
210 // In real implementation: __threadfence()
211 GlobalRegion {
212 _phantom: PhantomData,
213 }
214}
215
216impl GlobalRegion<Fenced> {
217 /// Read from a fenced global region. Safe because:
218 /// 1. All lanes have written (FullWrite)
219 /// 2. Fence ensures visibility (Fenced)
220 pub fn read<T: Default>(&self) -> T {
221 T::default() // placeholder
222 }
223}
224
225#[cfg(test)]
226mod tests {
227 use super::*;
228 use crate::active_set::*;
229
230 #[test]
231 fn test_full_fence_protocol() {
232 let warp: Warp<All> = Warp::new();
233 let (evens, odds) = warp.diverge_even_odd();
234
235 // Each half writes to global memory
236 let region = GlobalRegion::new();
237 let (evens, partial_even) = evens.global_store(region);
238 // evens still usable — global_store returns the warp
239
240 // Second half completes the write — warp returned for merge
241 let (odds, full) = odds.global_store_complement(partial_even);
242
243 // Warps can still be merged after fence operations
244 let _merged: Warp<All> = crate::merge(evens, odds);
245
246 // Fence after full write
247 let fenced = threadfence(full);
248 let _val: i32 = fenced.read();
249 }
250
251 #[test]
252 fn test_merge_writes() {
253 let region1 = GlobalRegion::<PartialWrite<Even>> {
254 _phantom: PhantomData,
255 };
256 let region2 = GlobalRegion::<PartialWrite<Odd>> {
257 _phantom: PhantomData,
258 };
259
260 let full = merge_writes(region1, region2);
261 let _fenced = threadfence(full);
262 }
263
264 #[test]
265 fn test_nested_fence_protocol() {
266 // Nested divergence: EvenLow + EvenHigh are complements within Even (not All).
267 // merge_writes_within returns PartialWrite<Even>, which can then be merged
268 // with PartialWrite<Odd> to get FullWrite.
269 let el = GlobalRegion::<PartialWrite<EvenLow>> {
270 _phantom: PhantomData,
271 };
272 let eh = GlobalRegion::<PartialWrite<EvenHigh>> {
273 _phantom: PhantomData,
274 };
275
276 // Nested merge: EvenLow + EvenHigh → Even (partial)
277 let even_partial: GlobalRegion<PartialWrite<Even>> = merge_writes_within(el, eh);
278
279 // Top-level merge: Even + Odd → FullWrite
280 let odd = GlobalRegion::<PartialWrite<Odd>> {
281 _phantom: PhantomData,
282 };
283 let full = merge_writes(even_partial, odd);
284 let _fenced = threadfence(full);
285 }
286}