1use core::{
7 any::Any,
8 cell::{Cell, Ref, RefCell, RefMut},
9 fmt::Display,
10 hash::Hash,
11 marker::PhantomData,
12};
13
14use crate::{
15 arg_error_noloc,
16 basic_block::BasicBlock,
17 common_traits::Verify,
18 dialect::{Dialect, DialectName},
19 identifier::Identifier,
20 operation::Operation,
21 printable::{self, Printable},
22 region::Region,
23 result::Result,
24 std_deps::sync::LazyLock,
25 storage_uniquer::UniqueStore,
26 r#type::TypeObj,
27 uniqued_any::UniquedAny,
28 utils::table::{HMap, HSet, IMap},
29 verify_err_noloc,
30};
31use alloc::{boxed::Box, format, string::ToString, vec, vec::Vec};
32use slotmap::{SlotMap, new_key_type};
33
34new_key_type! {
35 pub struct ArenaIndex;
37}
38
39new_key_type! {
40 pub struct AuxDataIndex;
42}
43
44impl Display for ArenaIndex {
45 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
46 write!(f, "{:?}", self.0)
47 }
48}
49
50pub type Arena<T> = SlotMap<ArenaIndex, RefCell<T>>;
52
53pub struct Context {
55 pub(crate) value_counter: Cell<u64>,
58 pub(crate) use_counter: Cell<u64>,
61 pub(crate) operations: Arena<Operation>,
63 pub(crate) basic_blocks: Arena<BasicBlock>,
65 pub(crate) regions: Arena<Region>,
67 pub(crate) dialects: HMap<DialectName, Dialect>,
69 pub(crate) type_store: UniqueStore<TypeObj>,
71 pub(crate) uniqued_any_store: UniqueStore<UniquedAny>,
73 pub aux_data: SlotMap<AuxDataIndex, Box<dyn Any + Send>>,
75 pub aux_data_map: HMap<Identifier, AuxDataIndex>,
77}
78
79impl Context {
80 pub fn new() -> Context {
81 Self::default()
82 }
83
84 pub fn is_ir_empty(&self) -> bool {
88 self.operations.is_empty() && self.basic_blocks.is_empty() && self.regions.is_empty()
89 }
90
91 pub(crate) fn get_new_value_uid(&self) -> u64 {
93 let uid = self.value_counter.get();
94 self.value_counter.set(uid + 1);
95 uid
96 }
97
98 pub(crate) fn get_new_use_uid(&self) -> u64 {
100 let uid = self.use_counter.get();
101 self.use_counter.set(uid + 1);
102 uid
103 }
104}
105
106impl Default for Context {
107 fn default() -> Self {
108 let mut ctx = Context {
109 value_counter: Cell::new(0),
110 use_counter: Cell::new(0),
111 operations: Arena::default(),
112 basic_blocks: Arena::default(),
113 regions: Arena::default(),
114 dialects: HMap::default(),
115 type_store: UniqueStore::default(),
116 uniqued_any_store: UniqueStore::default(),
117 aux_data: SlotMap::with_key(),
118 aux_data_map: HMap::default(),
119 };
120
121 if let Err(err) = &*DICT_KEYS_VERIFIER {
123 panic!("{}", err.err);
124 }
125
126 for registration in get_context_registrations() {
128 registration(&mut ctx);
129 }
130
131 ctx
132 }
133}
134
135const _: () = {
137 const fn assert_send<T: Send>() {}
138 assert_send::<Context>();
139};
140
141pub(crate) mod private {
142 use super::*;
143
144 pub trait ArenaObj
146 where
147 Self: Sized,
148 {
149 fn get_arena(ctx: &Context) -> &Arena<Self>;
151 fn get_arena_mut(ctx: &mut Context) -> &mut Arena<Self>;
153 fn get_self_ptr(&self, ctx: &Context) -> Ptr<Self>;
155 fn dealloc_sub_objects(ptr: Ptr<Self>, ctx: &mut Context);
158
159 fn alloc<T: FnOnce(Ptr<Self>) -> Self>(ctx: &mut Context, f: T) -> Ptr<Self> {
161 let creator = |idx: ArenaIndex| {
162 let t = f(Ptr::<Self> {
163 idx,
164 _dummy: PhantomData::<Self>,
165 });
166 RefCell::new(t)
167 };
168 Ptr::<Self> {
169 idx: Self::get_arena_mut(ctx).insert_with_key(creator),
170 _dummy: PhantomData,
171 }
172 }
173
174 fn dealloc(ptr: Ptr<Self>, ctx: &mut Context) {
176 Self::dealloc_sub_objects(ptr, ctx);
177 Self::get_arena_mut(ctx).remove(ptr.idx);
178 }
179 }
180}
181
182use private::ArenaObj;
183
184pub struct Ptr<T: ArenaObj> {
186 pub(crate) idx: ArenaIndex,
187 pub(crate) _dummy: PhantomData<T>,
188}
189
190impl<T: ArenaObj> core::fmt::Debug for Ptr<T> {
191 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
192 write!(f, "Ptr<{}>[{}]", core::any::type_name::<T>(), self.idx)
193 }
194}
195
196#[derive(Debug, thiserror::Error)]
197#[error("Attempt to dereference a dangling Ptr")]
198pub struct DanglingPtrDerefError;
199
200impl<'a, T: ArenaObj> Ptr<T> {
201 #[track_caller]
207 pub fn deref(&self, ctx: &'a Context) -> Ref<'a, T> {
208 T::get_arena(ctx)
209 .get(self.idx)
210 .expect("Dangling Ptr deref")
211 .borrow()
212 }
213
214 #[track_caller]
220 pub fn deref_mut(&self, ctx: &'a Context) -> RefMut<'a, T> {
221 T::get_arena(ctx)
222 .get(self.idx)
223 .expect("Dangling Ptr deref_mut")
224 .borrow_mut()
225 }
226
227 pub fn try_deref(&self, ctx: &'a Context) -> Result<Ref<'a, T>> {
232 T::get_arena(ctx)
233 .get(self.idx)
234 .ok_or_else(|| arg_error_noloc!(DanglingPtrDerefError))?
235 .try_borrow()
236 .map_err(|err| arg_error_noloc!(err))
237 }
238
239 pub fn try_deref_mut(&self, ctx: &'a Context) -> Result<RefMut<'a, T>> {
244 T::get_arena(ctx)
245 .get(self.idx)
246 .ok_or_else(|| arg_error_noloc!(DanglingPtrDerefError))?
247 .try_borrow_mut()
248 .map_err(|err| arg_error_noloc!(err))
249 }
250
251 pub(crate) fn make_name(&self, name_base: &str) -> Identifier {
253 let idx = format!("{}", self.idx);
254 (name_base.to_string() + &idx).try_into().unwrap()
255 }
256}
257
258impl<T: ArenaObj> Clone for Ptr<T> {
259 fn clone(&self) -> Ptr<T> {
260 *self
261 }
262}
263
264impl<T: ArenaObj> Copy for Ptr<T> {}
265
266impl<T: ArenaObj> PartialEq for Ptr<T> {
267 fn eq(&self, other: &Self) -> bool {
268 self.idx == other.idx
269 }
270}
271
272impl<T: ArenaObj> Eq for Ptr<T> {}
273
274impl<T: ArenaObj + 'static> Hash for Ptr<T> {
275 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
276 self.idx.hash(state);
277 }
278}
279
280impl<T: ArenaObj + Printable> Printable for Ptr<T> {
281 fn fmt(
282 &self,
283 ctx: &Context,
284 state: &printable::State,
285 f: &mut core::fmt::Formatter<'_>,
286 ) -> core::fmt::Result {
287 self.deref(ctx).fmt(ctx, state, f)
288 }
289}
290
291impl<T: ArenaObj + Verify> Verify for Ptr<T> {
292 fn verify(&self, ctx: &Context) -> Result<()> {
293 self.deref(ctx).verify(ctx)
294 }
295}
296
297#[doc(hidden)]
298#[derive(Eq, PartialEq, Debug, Clone)]
300pub struct DictKeyId {
301 pub id: Identifier,
303 pub file: &'static str,
305 pub line: u32,
307 pub column: u32,
309}
310
311pub type ContextRegistration = fn(&mut Context);
315
316#[doc(hidden)]
317#[cfg(not(target_family = "wasm"))]
324pub mod statics {
325 use super::*;
326
327 #[::pliron::linkme::distributed_slice]
328 #[linkme(crate = ::pliron::linkme)]
329 pub static DICT_KEY_IDS: [DictKeyId];
330
331 pub fn get_dict_key_ids() -> impl Iterator<Item = &'static DictKeyId> {
332 DICT_KEY_IDS.iter()
333 }
334
335 #[::pliron::linkme::distributed_slice]
336 #[linkme(crate = ::pliron::linkme)]
337 pub static CONTEXT_REGISTRATIONS: [ContextRegistration];
338
339 pub fn get_context_registrations() -> impl Iterator<Item = &'static ContextRegistration> {
340 CONTEXT_REGISTRATIONS.iter()
341 }
342}
343
344#[cfg(target_family = "wasm")]
345pub mod statics {
346 use super::*;
347 use crate::InventoryWrapper;
348
349 ::pliron::inventory::collect!(InventoryWrapper<DictKeyId>);
350
351 pub fn get_dict_key_ids() -> impl Iterator<Item = &'static DictKeyId> {
352 ::pliron::inventory::iter::<InventoryWrapper<DictKeyId>>().map(|llw| llw.0)
353 }
354
355 ::pliron::inventory::collect!(InventoryWrapper<ContextRegistration>);
356
357 pub fn get_context_registrations() -> impl Iterator<Item = &'static ContextRegistration> {
358 ::pliron::inventory::iter::<InventoryWrapper<ContextRegistration>>().map(|llw| llw.0)
359 }
360}
361
362pub use statics::*;
363
364#[doc(hidden)]
365pub static DICT_KEYS_VERIFIER: LazyLock<Result<()>> = LazyLock::new(verify_dict_keys);
366
367#[doc(hidden)]
368pub(crate) fn collect_deduped_interface_verifiers<Id, AllVerifiers, Verifier>(
374 interface_verifiers: impl Iterator<Item = &'static &'static [(Id, AllVerifiers)]>,
375) -> HMap<Id, Vec<Verifier>>
376where
377 Id: Eq + Hash + Clone + 'static,
378 AllVerifiers: Fn() -> Vec<Verifier> + Clone + 'static,
379 Verifier: Eq + Hash + Clone,
380{
381 let mut grouped = IMap::default();
382 for entry in interface_verifiers.flat_map(|it| it.iter()) {
383 let (id, all_verifiers_for_interface) = entry;
384 grouped
385 .entry(id.clone())
386 .and_modify(|verifiers: &mut Vec<AllVerifiers>| {
387 verifiers.push(all_verifiers_for_interface.clone())
388 })
389 .or_insert(vec![all_verifiers_for_interface.clone()]);
390 }
391
392 grouped
396 .into_iter()
397 .map(|(id, verifiers)| {
398 let mut dedupd_verifiers = Vec::new();
399 let mut seen = HSet::default();
400 for verifier_fn_list in verifiers {
401 for verifier in verifier_fn_list() {
402 if seen.insert(verifier.clone()) {
403 dedupd_verifiers.push(verifier);
404 }
405 }
406 }
407 (id, dedupd_verifiers)
408 })
409 .collect()
410}
411
412#[doc(hidden)]
413pub fn verify_dict_keys() -> Result<()> {
417 let mut seen: HMap<Identifier, (&'static str, u32, u32)> = HMap::default();
418 for key in get_dict_key_ids() {
419 if let Some((file, line, column)) = seen.get(&key.id) {
420 return verify_err_noloc!(
421 "Duplicate dictionary key \"{}\" declared in {}:{}:{} and {}:{}:{}",
422 key.id,
423 file,
424 line,
425 column,
426 key.file,
427 key.line,
428 key.column
429 );
430 }
431 seen.insert(key.id.clone(), (key.file, key.line, key.column));
432 }
433 Ok(())
434}
435
436#[macro_export]
452macro_rules! dict_key {
453 ( $(#[$outer:meta])*
454 $decl:ident, $name:literal
455 ) => {
456 const _: () = {
460 #[cfg_attr(not(target_family = "wasm"),
461 ::pliron::linkme::distributed_slice(::pliron::context::DICT_KEY_IDS), linkme(crate = ::pliron::linkme))]
462 pub static $decl: ::pliron::context::DictKeyId = ::pliron::context::DictKeyId {
463 id: $crate::ident!($name),
464 file: file!(),
465 line: line!(),
466 column: column!(),
467 };
468
469 #[cfg(target_family = "wasm")]
470 ::pliron::inventory::submit! {
471 ::pliron::InventoryWrapper(&$decl)
472 }
473 };
474 $(#[$outer])*
475 pub static $decl: ::pliron::identifier::Identifier = $crate::ident!($name);
477 };
478}
479
480#[macro_export]
492macro_rules! context_registration {
493 ( $(#[$outer:meta])*
494 $registration:expr
495 ) => {
496 const _: () = {
497 $(#[$outer])*
498 #[cfg_attr(not(target_family = "wasm"),
499 ::pliron::linkme::distributed_slice(::pliron::context::CONTEXT_REGISTRATIONS), linkme(crate = ::pliron::linkme))]
500 static CONTEXT_REGISTRATION: ::pliron::context::ContextRegistration = $registration;
501
502 #[cfg(target_family = "wasm")]
503 ::pliron::inventory::submit! {
504 ::pliron::InventoryWrapper(&CONTEXT_REGISTRATION)
505 }
506 };
507 };
508}