midenc_hir/ir/
op.rs

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