vyre 0.4.0

GPU compute intermediate representation with a standard operation library
Documentation
use crate::ir::model::program::BufferDecl;
use crate::ir::model::types::{BufferAccess, DataType};
use crate::lower::wgsl::emit::wgsl_element_type;
use crate::lower::wgsl::Error;
use std::fmt::Write as _;

#[inline]
pub(crate) fn emit_buffer_decl(
    out: &mut String,
    buf: &BufferDecl,
    uses_atomics: bool,
) -> Result<(), Error> {
    // L.2.4: use `write!` into the caller-owned String instead of
    // `out.push_str(&format!(...))`. The prior code allocated one
    // 1000-node / 10-buffer program, added ~1020 small heap allocations
    // to lowering — this path is invoked fresh per dispatch in the
    // internet-scale JIT case.
    let wgsl_type = wgsl_element_type(buf.element.clone())?;
    match &buf.access {
        BufferAccess::ReadOnly => {
            write!(
                out,
                "struct _vyre_buf_{name} {{ data: array<{wgsl_type}>, }};\n\
                 @group(0) @binding({binding})\n\
                 var<storage, read> {name}: _vyre_buf_{name};\n\n",
                name = buf.name,
                binding = buf.binding,
            )
            .expect("write into String never fails");
        }
        BufferAccess::ReadWrite => {
            if uses_atomics {
                if buf.element != DataType::U32 {
                    return Err(Error::lowering(format!(
                        "atomic buffer `{}` has element type `{:?}` but WGSL atomics require u32. Fix: use DataType::U32 for atomic buffers or remove atomic operations from this buffer.",
                        buf.name, buf.element,
                    )));
                }
                write!(
                    out,
                    "struct _vyre_buf_{name} {{ data: array<atomic<u32>>, }};\n\
                     @group(0) @binding({binding})\n\
                     var<storage, read_write> {name}: _vyre_buf_{name};\n\n",
                    name = buf.name,
                    binding = buf.binding,
                )
                .expect("write into String never fails");
            } else {
                write!(
                    out,
                    "struct _vyre_buf_{name} {{ data: array<{wgsl_type}>, }};\n\
                     @group(0) @binding({binding})\n\
                     var<storage, read_write> {name}: _vyre_buf_{name};\n\n",
                    name = buf.name,
                    binding = buf.binding,
                )
                .expect("write into String never fails");
            }
        }
        BufferAccess::Uniform => {
            write!(
                out,
                "struct _vyre_buf_{name} {{ data: array<{wgsl_type}>, }};\n\
                 @group(0) @binding({binding})\n\
                 var<uniform> {name}: _vyre_buf_{name};\n\n",
                name = buf.name,
                binding = buf.binding,
            )
            .expect("write into String never fails");
        }
        BufferAccess::Workgroup => {
            write!(
                out,
                "var<workgroup> {name}: array<{wgsl_type}, {count}>;\n\n",
                name = buf.name,
                wgsl_type = wgsl_element_type(buf.element.clone())?,
                count = buf.count,
            )
            .expect("write into String never fails");
        }
    }
    Ok(())
}