vyre 0.4.0

GPU compute intermediate representation with a standard operation library
Documentation
use crate::ir::Program;
use crate::ops::cpu_op::CpuFn;

/// Backend identity used when checking Category C intrinsic availability.
///
/// The enum is intentionally small: most operations are Category A and
/// therefore backend-agnostic. Category C ops use this type only to
/// declare which silicon features they require.
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Backend {
    /// The reference WGSL backend.
    Wgsl,
    /// A CUDA backend.
    Cuda,
    /// A SPIR-V backend.
    SpirV,
    /// A Metal backend.
    Metal,
}

/// Operation category: compositional (A) or hardware intrinsic (C).
///
/// The category system is the moat that keeps vyre from becoming an
/// unbounded framework. Category A guarantees zero-overhead abstraction;
/// Category C guarantees an honest performance model with no silent
/// software fallback.
#[non_exhaustive]
#[derive(Debug, Clone, Copy)]
pub enum Category {
    /// A composition expressible entirely as vyre IR.
    ///
    /// Category A ops must lower to exactly the primitives a hand-optimizer
    /// would write. The conform gate enforces this with byte-identicality
    /// checks against the reference composition.
    A,
    /// A hardware intrinsic with declared per-backend availability.
    ///
    /// The predicate returns `true` only when the backend actually supports
    /// the required hardware feature. If it returns `false`, the op is
    /// unavailable on that backend; there is no silent fallback.
    C {
        /// Predicate that returns `true` when the backend supports this op.
        backend_availability: fn(&Backend) -> bool,
    },
}

/// Descriptor for a Category C hardware intrinsic.
///
/// Intrinsics bind a stable name, a required hardware unit, and a CPU
/// reference function. Backends that claim support must produce output
/// that matches the CPU reference exactly on every witnessed input.
#[non_exhaustive]
#[derive(Debug, Clone, Copy)]
pub struct IntrinsicDescriptor {
    name: &'static str,
    hardware: &'static str,
    cpu_fn: CpuFn,
}

impl IntrinsicDescriptor {
    /// Create an intrinsic descriptor with an explicit CPU reference function.
    ///
    /// The `cpu_fn` is the oracle against which GPU backends are judged.
    /// It must be deterministic and free of side effects.
    #[must_use]
    pub const fn new(name: &'static str, hardware: &'static str, cpu_fn: CpuFn) -> Self {
        Self {
            name,
            hardware,
            cpu_fn,
        }
    }

    /// Stable intrinsic name.
    ///
    /// This identifier appears in conform certificates and backend
    /// capability reports.
    #[must_use]
    pub const fn name(&self) -> &'static str {
        self.name
    }

    /// Required hardware unit or backend feature.
    ///
    /// Examples include `"subgroup_ops"`, `"tensor_core"`, or
    /// `"texture_sample"`. The string is opaque to vyre core; backends
    /// interpret it as part of their capability model.
    #[must_use]
    pub const fn hardware(&self) -> &'static str {
        self.hardware
    }

    /// CPU reference implementation for this intrinsic.
    ///
    /// The conform gate executes this function to compute the expected
    /// output for every witness input.
    #[must_use]
    pub const fn cpu_fn(&self) -> CpuFn {
        self.cpu_fn
    }
}

/// Operation implementation declaration.
///
/// Every operation is either a `Composition` (Category A IR body) or an
/// `Intrinsic` (Category C hardware descriptor). The enum separates the
/// two universes so that the lowering path can dispatch statically.
#[non_exhaustive]
#[derive(Debug, Clone, Copy)]
pub enum Compose {
    /// Build the canonical IR program for this operation.
    ///
    /// The returned `Program` is the reference implementation. Backends
    /// must produce byte-identical output when they lower this IR.
    Composition(fn() -> Program),
    /// Require a hardware intrinsic. No software fallback exists.
    ///
    /// If the backend does not support the required hardware, the op is
    /// simply unavailable.
    Intrinsic(IntrinsicDescriptor),
}