Skip to main content

midenc_hir/ir/
op.rs

1use alloc::{boxed::Box, format, rc::Rc};
2
3use super::*;
4use crate::{AttributeRef, any::AsAny, interner, traits::TraitInfo};
5
6pub trait OpRegistration: Op {
7    type Dialect: DialectRegistration;
8
9    /// The name of the dialect this op is declared part of
10    fn dialect_name() -> interner::Symbol {
11        interner::Symbol::intern(<Self as OpRegistration>::Dialect::NAMESPACE)
12    }
13    /// The name of the operation (i.e. its opcode)
14    fn name() -> interner::Symbol;
15    /// The fully-qualified name of the operation (i.e. `<dialect>.<opcode>`)
16    fn full_name() -> interner::Symbol {
17        interner::Symbol::intern(format!(
18            "{}.{}",
19            Self::dialect_name(),
20            <Self as OpRegistration>::name()
21        ))
22    }
23    /// The set of statically known traits for this op
24    fn traits() -> Box<[TraitInfo]>;
25    /// The set of statically known attributes for this op
26    fn attrs() -> Box<[AttrInfo]>;
27    /// Allocate a new, default-initialized instance of this op in `context`
28    fn alloc_uninit(context: Rc<Context>) -> OperationRef;
29}
30
31pub trait BuildableOp<Args: core::marker::Tuple>: Op {
32    type Builder<'a, T>: FnOnce<Args, Output = Result<UnsafeIntrusiveEntityRef<Self>, crate::Report>>
33        + 'a
34    where
35        T: ?Sized + Builder + 'a;
36    fn builder<'b, B>(builder: &'b mut B, span: SourceSpan) -> Self::Builder<'b, B>
37    where
38        B: ?Sized + Builder + 'b;
39}
40
41pub trait Op: AsAny + OpVerifier {
42    /// The name of this operation's opcode
43    ///
44    /// The opcode must be distinct from all other opcodes in the same dialect
45    fn name(&self) -> OperationName;
46    fn as_operation(&self) -> &Operation;
47    fn as_operation_mut(&mut self) -> &mut Operation;
48
49    fn print(&self, flags: &OpPrintingFlags) -> crate::formatter::Document {
50        use print::OpPrinter;
51
52        let op = self.as_operation();
53        let context = op.context_rc();
54        let mut printer = print::AsmPrinter::new(context, flags);
55        op.print(&mut printer);
56        printer.finish()
57    }
58
59    #[inline]
60    fn as_operation_ref(&self) -> OperationRef {
61        self.as_operation().as_operation_ref()
62    }
63    fn set_span(&mut self, span: SourceSpan) {
64        self.as_operation_mut().set_span(span);
65    }
66    fn parent(&self) -> Option<BlockRef> {
67        self.as_operation().parent()
68    }
69    fn parent_region(&self) -> Option<RegionRef> {
70        self.as_operation().parent_region()
71    }
72    fn parent_op(&self) -> Option<OperationRef> {
73        self.as_operation().parent_op()
74    }
75    fn num_regions(&self) -> usize {
76        self.as_operation().num_regions()
77    }
78    fn regions(&self) -> &RegionList {
79        self.as_operation().regions()
80    }
81    fn regions_mut(&mut self) -> &mut RegionList {
82        self.as_operation_mut().regions_mut()
83    }
84    fn region(&self, index: usize) -> EntityRef<'_, Region> {
85        self.as_operation().region(index)
86    }
87    fn region_mut(&mut self, index: usize) -> EntityMut<'_, Region> {
88        self.as_operation_mut().region_mut(index)
89    }
90    fn has_successors(&self) -> bool {
91        self.as_operation().has_successors()
92    }
93    fn num_successors(&self) -> usize {
94        self.as_operation().num_successors()
95    }
96    fn has_operands(&self) -> bool {
97        self.as_operation().has_operands()
98    }
99    fn num_operands(&self) -> usize {
100        self.as_operation().num_operands()
101    }
102    fn operands(&self) -> &OpOperandStorage {
103        self.as_operation().operands()
104    }
105    fn operands_mut(&mut self) -> &mut OpOperandStorage {
106        self.as_operation_mut().operands_mut()
107    }
108    fn has_results(&self) -> bool {
109        self.as_operation().has_results()
110    }
111    fn num_results(&self) -> usize {
112        self.as_operation().num_results()
113    }
114    fn results(&self) -> &OpResultStorage {
115        self.as_operation().results()
116    }
117    fn results_mut(&mut self) -> &mut OpResultStorage {
118        self.as_operation_mut().results_mut()
119    }
120    fn successors(&self) -> &OpSuccessorStorage {
121        self.as_operation().successors()
122    }
123    fn successors_mut(&mut self) -> &mut OpSuccessorStorage {
124        self.as_operation_mut().successors_mut()
125    }
126}
127
128impl Spanned for dyn Op {
129    fn span(&self) -> SourceSpan {
130        self.as_operation().span
131    }
132}
133
134pub trait OpExt {
135    /// Return the attribute named `name` for this operation
136    fn get_attribute(&self, name: impl Into<interner::Symbol>) -> Option<AttributeRef>;
137
138    /// Return true if this function has an attribute named `name`
139    fn has_attribute(&self, name: impl Into<interner::Symbol>) -> bool;
140
141    /// Set the attribute `name` with `value` for this operation.
142    fn set_attribute(&mut self, name: impl Into<interner::Symbol>, value: AttributeRef);
143
144    /// Remove any attribute with the given name from this function
145    fn remove_attribute(&mut self, name: impl Into<interner::Symbol>);
146
147    /// Returns a handle to the nearest containing [Operation] of type `T` for this operation, if it
148    /// is attached to one
149    fn nearest_parent_op<T: Op>(&self) -> Option<UnsafeIntrusiveEntityRef<T>>;
150}
151
152impl<T: ?Sized + Op> OpExt for T {
153    #[inline]
154    fn get_attribute(&self, name: impl Into<interner::Symbol>) -> Option<AttributeRef> {
155        self.as_operation().get_attribute(name)
156    }
157
158    #[inline]
159    fn has_attribute(&self, name: impl Into<interner::Symbol>) -> bool {
160        self.as_operation().has_attribute(name)
161    }
162
163    #[inline]
164    fn set_attribute(&mut self, name: impl Into<interner::Symbol>, value: AttributeRef) {
165        self.as_operation_mut().set_attribute(name, value);
166    }
167
168    #[inline]
169    fn remove_attribute(&mut self, name: impl Into<interner::Symbol>) {
170        self.as_operation_mut().remove_attribute(name);
171    }
172
173    #[inline]
174    fn nearest_parent_op<U: Op>(&self) -> Option<UnsafeIntrusiveEntityRef<U>> {
175        self.as_operation().nearest_parent_op()
176    }
177}