vyre 0.4.0

GPU compute intermediate representation with a standard operation library
Documentation
//! Expression encoder for the stable IR wire format.

use crate::ir::serial::wire::framing::{put_len_u32, put_string, put_u32, put_u8};
use crate::ir::serial::wire::tags::{atomic_op_tag, bin_op_tag, put_data_type, un_op_tag};
use crate::ir::serial::wire::Expr;

/// Append the tag and payload for one expression.
///
/// # Errors
///
/// Returns an actionable error when a nested string, type tag, or operation tag
/// cannot be represented by the current wire schema.
#[inline]
pub fn put_expr(out: &mut Vec<u8>, expr: &Expr) -> Result<(), String> {
    match expr {
        Expr::LitU32(value) => {
            put_u8(out, 0);
            put_u32(out, *value);
        }
        Expr::LitI32(value) => {
            put_u8(out, 1);
            put_u32(out, u32::from_le_bytes(value.to_le_bytes()));
        }
        Expr::LitBool(value) => {
            put_u8(out, 2);
            put_u8(out, u8::from(*value));
        }
        Expr::LitF32(value) => {
            put_u8(out, 15);
            put_u32(out, value.to_bits());
        }
        Expr::Var(name) => {
            put_u8(out, 3);
            put_string(out, name)?;
        }
        Expr::Load { buffer, index } => {
            put_u8(out, 4);
            put_string(out, buffer)?;
            put_expr(out, index)?;
        }
        Expr::BufLen { buffer } => {
            put_u8(out, 5);
            put_string(out, buffer)?;
        }
        Expr::InvocationId { axis } => {
            put_u8(out, 6);
            put_u8(out, *axis);
        }
        Expr::WorkgroupId { axis } => {
            put_u8(out, 7);
            put_u8(out, *axis);
        }
        Expr::LocalId { axis } => {
            put_u8(out, 8);
            put_u8(out, *axis);
        }
        Expr::BinOp { op, left, right } => {
            put_u8(out, 9);
            put_u8(out, bin_op_tag(op.clone())?);
            put_expr(out, left)?;
            put_expr(out, right)?;
        }
        Expr::UnOp { op, operand } => {
            put_u8(out, 10);
            put_u8(out, un_op_tag(op.clone())?);
            put_expr(out, operand)?;
        }
        Expr::Call { op_id, args } => {
            put_u8(out, 11);
            put_string(out, op_id)?;
            put_len_u32(out, args.len(), "call argument count")?;
            for arg in args {
                put_expr(out, arg)?;
            }
        }
        Expr::Select {
            cond,
            true_val,
            false_val,
        } => {
            put_u8(out, 12);
            put_expr(out, cond)?;
            put_expr(out, true_val)?;
            put_expr(out, false_val)?;
        }
        Expr::Cast { target, value } => {
            put_u8(out, 13);
            put_data_type(out, target)?;
            put_expr(out, value)?;
        }
        Expr::Fma { a, b, c } => {
            put_u8(out, 16);
            put_expr(out, a)?;
            put_expr(out, b)?;
            put_expr(out, c)?;
        }
        Expr::Atomic {
            op,
            buffer,
            index,
            expected,
            value,
        } => {
            put_u8(out, 14);
            put_u8(out, atomic_op_tag(op.clone())?);
            put_string(out, buffer)?;
            put_expr(out, index)?;
            match expected {
                Some(expected) => {
                    put_u8(out, 1);
                    put_expr(out, expected)?;
                }
                None => put_u8(out, 0),
            }
            put_expr(out, value)?;
        }
    }
    Ok(())
}