vyre 0.4.0

GPU compute intermediate representation with a standard operation library
Documentation
// Clamp a value to a packed unsigned range.
//
// The bounds operand packs lo (bits 0..15) and hi is derived as
// (bounds >> 16) | lo, guaranteeing hi >= lo. Returns value.clamp(lo, hi).

use crate::ir::{Expr, Program};
use crate::ops::primitive;
use crate::ops::{AlgebraicLaw, OpSpec, U32_OUTPUTS, U32_U32_INPUTS};


pub const LAWS: &[AlgebraicLaw] = &[AlgebraicLaw::Bounded {
    lo: 0,
    hi: u32::MAX,
}];

/// Clamp operation.
#[derive(Debug, Clone, Copy, Default)]
pub struct Clamp;

impl Clamp {
    /// Declarative operation specification.
    ///
    /// Laws are declared as explicit `AlgebraicLaw` values on `SPEC`.
    pub const SPEC: OpSpec = OpSpec::composition_inlinable(
        "primitive.math.clamp",
        U32_U32_INPUTS,
        U32_OUTPUTS,
        LAWS,
        Self::program,
    );

    /// Build the canonical IR program.
    ///
    /// # Examples
    ///
    /// ```
    /// use vyre::ir::Expr;
    /// use vyre::ops::primitive::clamp::Clamp;
    ///
    /// let _expr = Expr::select(Expr::le(Expr::u32(5), Expr::u32(9)), Expr::u32(5), Expr::u32(9));
    /// let program = Clamp::program();
    /// assert!(!program.entry().is_empty());
    /// ```
    #[must_use]
    pub fn program() -> Program {
        primitive::binary_u32_program(|value, bounds| {
            let lo = Expr::bitand(bounds.clone(), Expr::u32(0xFFFF));
            let hi = Expr::bitor(Expr::shr(bounds, Expr::u32(16)), lo.clone());
            // clamp = max(lo, min(hi, value))
            let clamped_hi = Expr::select(Expr::le(value.clone(), hi.clone()), value, hi);
            Expr::select(Expr::ge(clamped_hi.clone(), lo.clone()), clamped_hi, lo)
        })
    }
}