Skip to main content

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}