Skip to main content

vyre_foundation/ir_inner/model/program/
mod.rs

1//! Program model  -  a complete, self-contained GPU compute dispatch.
2//!
3//! A `Program` can be constructed without a GPU, serialized to disk,
4//! transmitted over a network, optimized by transformation passes, and lowered
5//! to any target backend. It is the unit of work in vyre.
6//!
7//! Equality is intentionally **structural**, not allocation-based:
8//! - `Program::structural_eq` performs an O(N) walk of the visible IR.
9//! - [`PartialEq`] delegates to that same structural walk.
10//! - Buffer declaration order is treated as a set, because reordering
11//!   declarations without changing names/bindings/types does not change
12//!   dispatch semantics.
13//!
14//! This keeps arena-local identities and pointer layouts out of the public API.
15
16mod buffer_decl;
17mod builder;
18mod cache_digest;
19mod canonical;
20mod definition;
21#[allow(clippy::expect_used)]
22mod meta;
23mod scope;
24/// Per-node-kind bitset constants for `ProgramStats`.
25pub mod stats;
26
27#[cfg(test)]
28mod stats_test;
29#[cfg(test)]
30mod tests;
31
32#[cfg(test)]
33#[inline]
34fn record_digest_computation() {
35    tests::DIGEST_COMPUTATIONS.with(|count| count.set(count.get() + 1));
36}
37
38#[cfg(not(test))]
39#[inline]
40fn record_digest_computation() {}
41
42pub use self::buffer_decl::{BufferDecl, LinearType, ShapePredicate};
43pub use self::cache_digest::NORMALIZED_PROGRAM_CACHE_DIGEST_VERSION;
44pub use self::definition::Program;
45pub use self::scope::Scope;
46pub use self::stats::ProgramStats;
47pub use self::stats::{
48    NODE_KIND_ALL_GATHER, NODE_KIND_ALL_REDUCE, NODE_KIND_ASSIGN, NODE_KIND_ASYNC_LOAD,
49    NODE_KIND_ASYNC_STORE, NODE_KIND_ASYNC_WAIT, NODE_KIND_BARRIER, NODE_KIND_BLOCK,
50    NODE_KIND_BROADCAST, NODE_KIND_EXPRESSION_BEARING_MASK, NODE_KIND_IF,
51    NODE_KIND_INDIRECT_DISPATCH, NODE_KIND_LET, NODE_KIND_LOOP, NODE_KIND_OPAQUE,
52    NODE_KIND_REDUCE_SCATTER, NODE_KIND_REGION, NODE_KIND_RESUME, NODE_KIND_RETURN,
53    NODE_KIND_STORE, NODE_KIND_TRAP,
54};
55
56/// Memory tier requested for a declared program region.
57#[non_exhaustive]
58#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
59pub enum MemoryKind {
60    /// Large device memory, lowered to storage bindings by GPU backends.
61    Global,
62    /// Workgroup-local shared memory.
63    Shared,
64    /// Cached broadcast memory, lowered to uniform bindings by GPU backends.
65    Uniform,
66    /// Per-invocation function memory.
67    Local,
68    /// Immutable device memory for the dispatch lifetime.
69    Readonly,
70    /// Persistent memory (SSD/NVMe), accessed via `AsyncLoad` into Global memory.
71    Persistent,
72    /// Push constants, root constants, or a uniform-backed fallback.
73    Push,
74}
75
76/// Non-binding cache behavior hint for a memory region.
77#[non_exhaustive]
78#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
79pub enum CacheLocality {
80    /// One-pass streaming access.
81    Streaming,
82    /// Reused temporal access.
83    Temporal,
84    /// Random access with little spatial predictability.
85    Random,
86}
87
88/// Non-binding memory optimization hints.
89#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
90pub struct MemoryHints {
91    /// Preferred coalescing axis for multidimensional access.
92    pub coalesce_axis: Option<u8>,
93    /// Preferred byte alignment. `0` means no explicit preference.
94    pub preferred_alignment: u32,
95    /// Expected cache locality.
96    pub cache_locality: CacheLocality,
97}
98
99impl Default for MemoryHints {
100    fn default() -> Self {
101        Self {
102            coalesce_axis: None,
103            preferred_alignment: 0,
104            cache_locality: CacheLocality::Temporal,
105        }
106    }
107}