Skip to main content

cubecl_core/frontend/
asm.rs

1use alloc::{string::String, vec::Vec};
2
3use cubecl_ir::{
4    Scope,
5    dialect::{InlineAsmOp, OperationPtrExt},
6    interfaces::TypeExt,
7};
8use pliron::{op::Op, r#type::Typed, value::Value};
9
10use crate::frontend::{HasValue, assign};
11
12#[derive(Default)]
13pub struct BuildAsmExpand {
14    asm: String,
15    out_values: Vec<Value>,
16    in_values: Vec<Value>,
17    pure: bool,
18    nomem: bool,
19    readonly: bool,
20}
21
22impl BuildAsmExpand {
23    pub fn new(asm: String) -> Self {
24        BuildAsmExpand {
25            asm,
26            ..Default::default()
27        }
28    }
29
30    // Takes by reference because of syntax reasons, since normal Rust allows immutables that are
31    // uninitialized and only assigned once (i.e. as the output for an assembly macro).
32    // We also only assign once, so reference gives the correct semantics.
33    pub fn push_output<T: HasValue>(mut self, scope: &Scope, output: &T) -> Self {
34        let value = output.value(scope);
35        self.out_values.push(value);
36        self
37    }
38
39    pub fn push_input<T: HasValue>(mut self, scope: &Scope, input: T) -> Self {
40        let value = input.value(scope);
41        self.in_values.push(value);
42        self
43    }
44
45    pub fn pure(mut self) -> Self {
46        self.pure = true;
47        self
48    }
49
50    pub fn nomem(mut self) -> Self {
51        self.nomem = true;
52        self
53    }
54
55    pub fn readonly(mut self) -> Self {
56        self.readonly = true;
57        self
58    }
59
60    pub fn register(self, scope: &Scope) {
61        let ctx = scope.ctx_mut();
62        let result_types = self
63            .out_values
64            .iter()
65            .map(|it| it.get_type(ctx).as_ptr(ctx).inner)
66            .collect();
67        let op = InlineAsmOp::new(ctx, result_types, self.asm, self.in_values);
68        if self.pure {
69            op.set_pure(ctx);
70        }
71        if self.nomem {
72            op.set_nomem(ctx);
73        }
74        if self.readonly {
75            op.set_readonly(ctx);
76        }
77        scope.register(&op);
78        // Store results back to out expand values
79        for (&out_ptr, result) in self.out_values.iter().zip(op.get_operation().results(ctx)) {
80            assign::expand_element(scope, result.into(), out_ptr.into());
81        }
82    }
83}