midenc_hir/ir/dialect.rs
1mod info;
2
3use alloc::boxed::Box;
4use core::ptr::{DynMetadata, Pointee};
5
6pub use self::info::DialectInfo;
7use crate::{
8 any::AsAny, interner, AttributeValue, Builder, OperationName, OperationRef, SourceSpan, Type,
9};
10
11pub type DialectRegistrationHook = Box<dyn Fn(&mut DialectInfo, &super::Context)>;
12
13/// A [Dialect] represents a collection of IR entities that are used in conjunction with one
14/// another. Multiple dialects can co-exist _or_ be mutually exclusive. Converting between dialects
15/// is the job of the conversion infrastructure, using a process called _legalization_.
16pub trait Dialect {
17 /// Get metadata about this dialect (it's operations, interfaces, etc.)
18 fn info(&self) -> &DialectInfo;
19
20 /// Get the name(space) of this dialect
21 fn name(&self) -> interner::Symbol {
22 self.info().name()
23 }
24
25 /// Get the set of registered operations associated with this dialect
26 fn registered_ops(&self) -> &[OperationName] {
27 self.info().operations()
28 }
29
30 /// A hook to materialize a single constant operation from a given attribute value and type.
31 ///
32 /// This method should use the provided builder to create the operation without changing the
33 /// insertion point. The generated operation is expected to be constant-like, i.e. single result
34 /// zero operands, no side effects, etc.
35 ///
36 /// Returns `None` if a constant cannot be materialized for the given attribute.
37 #[allow(unused_variables)]
38 #[inline]
39 fn materialize_constant(
40 &self,
41 builder: &mut dyn Builder,
42 attr: Box<dyn AttributeValue>,
43 ty: &Type,
44 span: SourceSpan,
45 ) -> Option<OperationRef> {
46 None
47 }
48}
49
50impl dyn Dialect {
51 /// Get the [OperationName] of the operation type `T`, if registered with this dialect.
52 pub fn registered_name<T>(&self) -> Option<OperationName>
53 where
54 T: crate::OpRegistration,
55 {
56 let opcode = <T as crate::OpRegistration>::name();
57 self.registered_ops().iter().find(|op| op.name() == opcode).cloned()
58 }
59
60 /// Get the [OperationName] of the operation type `T`.
61 ///
62 /// Panics if the operation is not registered with this dialect.
63 pub fn expect_registered_name<T>(&self) -> OperationName
64 where
65 T: crate::OpRegistration,
66 {
67 self.registered_name::<T>().unwrap_or_else(|| {
68 panic!(
69 "{} is not registered with dialect '{}'",
70 core::any::type_name::<T>(),
71 self.name()
72 )
73 })
74 }
75
76 /// Attempt to cast this operation reference to an implementation of `Trait`
77 pub fn as_registered_interface<Trait>(&self) -> Option<&Trait>
78 where
79 Trait: ?Sized + Pointee<Metadata = DynMetadata<Trait>> + 'static,
80 {
81 let this = self as *const dyn Dialect;
82 let (ptr, _) = this.to_raw_parts();
83 let info = self.info();
84 info.upcast(ptr)
85 }
86}
87
88/// A [DialectRegistration] must be implemented for any implementation of [Dialect], to allow the
89/// dialect to be registered with a [crate::Context] and instantiated on demand when building ops
90/// in the IR.
91///
92/// This is not part of the [Dialect] trait itself, as that trait must be object safe, and this
93/// trait is _not_ object safe.
94pub trait DialectRegistration: AsAny + Dialect {
95 /// The namespace of the dialect to register
96 ///
97 /// A dialect namespace serves both as a way to namespace the operations of that dialect, as
98 /// well as a way to uniquely name/identify the dialect itself. Thus, no two dialects can have
99 /// the same namespace at the same time.
100 const NAMESPACE: &'static str;
101
102 /// Initialize an instance of this dialect to be stored (uniqued) in the current
103 /// [crate::Context].
104 ///
105 /// A dialect will only ever be initialized once per context. A dialect must use interior
106 /// mutability to satisfy the requirements of the [Dialect] trait, and to allow the context to
107 /// store the returned instance in a reference-counted smart pointer.
108 fn init(info: DialectInfo) -> Self;
109
110 /// This is called when registering a dialect, to register operations of the dialect.
111 ///
112 /// This is called _before_ [DialectRegistration::init].
113 fn register_operations(info: &mut DialectInfo);
114}