cubecl-wgpu 0.11.0-pre.4

WGPU runtime for the CubeCL
Documentation
use cubecl_ir::{
    AddressSpace, CanMaterialize, GlobalState, NoSideEffects, Scope, dialect::memory::*, ident,
    prelude::*,
};
use pliron::attribute::AttrObj;

use crate::compiler::wgsl::{
    AddressOfOp, GlobalVariableOp,
    lower::LowerOp,
    ops::general::attr_to_wgsl,
    to_wgsl::{TypeExtWgsl, wgsl_op, wgsl_op_with_out},
    value::WgslValue,
};

#[cube_op(name = "wgsl.declare_local")]
#[result_ty(argument)]
#[op_traits(NoSideEffects, CanMaterialize)]
pub struct DeclareLocalOp {
    pub value_ty: TypeAttr,
    #[attribute(optional, untyped)]
    pub initializer: AttrObj,
}

wgsl_op!(DeclareLocalOp, |op, ctx| {
    let value_ty = op.value_ty(ctx).get_type(ctx).to_wgsl(ctx);
    let name = op.get_result(ctx).name(ctx);
    let init = op.initializer(ctx).map(|init| attr_to_wgsl(ctx, &**init));
    let init = init.map(|init| format!("= {init}")).unwrap_or_default();
    format!("var<function> {name}_store: {value_ty}{init};\nlet {name} = &{name}_store;\n")
});

#[op_interface_impl]
impl LowerOp for DeclareVariableOp {
    fn lower(&self, scope: &Scope) -> Vec<Value> {
        let ctx = scope.ctx_mut();
        let addr_space = self.addr_space(ctx).0;
        let ty = self.result_type(ctx);
        let value_ty = self.value_ty(ctx).get_type(ctx);
        match addr_space {
            AddressSpace::Global(_) => panic!("Global vars not supported"),
            AddressSpace::Shared => {
                let name = ident(format!("shared_{}", self.get_result(ctx).name(ctx)));
                let var = GlobalVariableOp::new(ctx, value_ty, addr_space, None, None);
                let entry = ctx.aux_ty::<GlobalState>().entry_func.get_operation();
                var.set_symbol_name(ctx, name.clone());
                var.get_operation().insert_before(ctx, entry);
                vec![scope.register_with_result(&AddressOfOp::new(ctx, ty, name))]
            }
            AddressSpace::Local => {
                let init = self.initializer(ctx).map(|it| it.clone());
                let local = DeclareLocalOp::new(ctx, ty, value_ty, init);
                vec![scope.register_with_result(&local)]
            }
        }
    }
}

wgsl_op_with_out!(IndexOp; |op, ctx| {
    format!("&(*{})[{}]", op.base(ctx).name(ctx), op.index(ctx).name(ctx))
});

wgsl_op_with_out!(LoadOp; |op, ctx| format!("*{}", op.ptr(ctx).name(ctx)));
wgsl_op!(StoreOp, |op, ctx| {
    let ptr = op.ptr(ctx).name(ctx);
    format!("*{ptr} = {};\n", op.value(ctx).name(ctx))
});
wgsl_op!(CopyOp, |op, ctx| {
    assert_eq!(op.len(ctx).0, 1, "WGSL doesn't support bulk copy");
    let dest = op.destination(ctx).name(ctx);
    format!("*{dest} = *{};\n", op.source(ctx).name(ctx))
});