1use alloc::rc::Rc;
2use core::{
3 any::{Any, TypeId},
4 cell::RefCell,
5};
6
7use smallvec::SmallVec;
8
9use super::{PassInstrumentor, PassTarget};
10use crate::{FxHashMap, Op, Operation, OperationRef, Report};
11
12pub trait Analysis: Default + Any {
27 type Target: ?Sized + PassTarget;
31
32 #[inline]
38 fn analysis_id(&self) -> TypeId {
39 TypeId::of::<Self>()
40 }
41
42 #[inline(always)]
48 fn as_any(&self) -> &dyn Any {
49 self as &dyn Any
50 }
51
52 #[inline(always)]
55 fn as_any_rc(self: Rc<Self>) -> Rc<dyn Any> {
56 self as Rc<dyn Any>
57 }
58
59 fn name(&self) -> &'static str {
63 core::any::type_name::<Self>()
64 }
65
66 fn analyze(
68 &mut self,
69 op: &Self::Target,
70 analysis_manager: AnalysisManager,
71 ) -> Result<(), Report>;
72
73 fn invalidate(&self, preserved_analyses: &mut PreservedAnalyses) -> bool;
80}
81
82pub trait OperationAnalysis {
91 fn analysis_id(&self) -> TypeId;
93
94 fn as_any(&self) -> &dyn Any;
96
97 fn as_any_rc(self: Rc<Self>) -> Rc<dyn Any>;
99
100 fn name(&self) -> &'static str;
102
103 fn analyze(&mut self, op: &OperationRef, am: AnalysisManager) -> Result<(), Report>;
109
110 fn invalidate(&self, preserved_analyses: &mut PreservedAnalyses) -> bool;
119}
120
121impl dyn OperationAnalysis {
122 #[inline]
126 pub fn downcast<T: 'static>(self: Rc<Self>) -> Option<Rc<T>> {
127 self.as_any_rc().downcast::<T>().ok()
128 }
129}
130
131impl<A> OperationAnalysis for A
132where
133 A: Analysis,
134{
135 #[inline]
136 fn analysis_id(&self) -> TypeId {
137 <A as Analysis>::analysis_id(self)
138 }
139
140 #[inline]
141 fn as_any(&self) -> &dyn Any {
142 <A as Analysis>::as_any(self)
143 }
144
145 #[inline]
146 fn as_any_rc(self: Rc<Self>) -> Rc<dyn Any> {
147 <A as Analysis>::as_any_rc(self)
148 }
149
150 #[inline]
151 fn name(&self) -> &'static str {
152 <A as Analysis>::name(self)
153 }
154
155 #[inline]
156 fn analyze(&mut self, op: &OperationRef, am: AnalysisManager) -> Result<(), Report> {
157 let op = <<A as Analysis>::Target as PassTarget>::into_target(op);
158 <A as Analysis>::analyze(self, &op, am)
159 }
160
161 #[inline]
162 fn invalidate(&self, preserved_analyses: &mut PreservedAnalyses) -> bool {
163 <A as Analysis>::invalidate(self, preserved_analyses)
164 }
165}
166
167#[derive(Default)]
169pub struct PreservedAnalyses {
170 preserved: SmallVec<[TypeId; 8]>,
172}
173impl PreservedAnalyses {
174 pub fn preserve_all(&mut self) {
178 self.insert(AllAnalyses::TYPE_ID);
179 }
180
181 pub fn preserve<A: 'static>(&mut self) {
183 self.insert(TypeId::of::<A>());
184 }
185
186 pub fn preserve_raw(&mut self, id: TypeId) {
191 self.insert(id);
192 }
193
194 pub fn is_preserved<A: 'static>(&self) -> bool {
199 self.preserved.contains(&TypeId::of::<A>()) || self.is_all()
200 }
201
202 pub fn is_preserved_raw(&self, ty: &TypeId) -> bool {
207 self.preserved.contains(ty) || self.is_all()
208 }
209
210 pub fn unpreserve<A: 'static>(&mut self) {
214 self.remove(&AllAnalyses::TYPE_ID);
216 self.remove(&TypeId::of::<A>());
217 }
218
219 pub fn unpreserve_raw(&mut self, ty: &TypeId) {
223 self.remove(&AllAnalyses::TYPE_ID);
225 self.remove(ty)
226 }
227
228 pub fn is_all(&self) -> bool {
230 self.preserved.contains(&AllAnalyses::TYPE_ID)
231 }
232
233 pub fn is_none(&self) -> bool {
235 self.preserved.is_empty()
236 }
237
238 fn insert(&mut self, id: TypeId) {
239 match self.preserved.binary_search_by_key(&id, |probe| *probe) {
240 Ok(index) => self.preserved.insert(index, id),
241 Err(index) => self.preserved.insert(index, id),
242 }
243 }
244
245 fn remove(&mut self, id: &TypeId) {
246 if let Ok(index) = self.preserved.binary_search_by_key(&id, |probe| probe) {
247 self.preserved.remove(index);
248 }
249 }
250}
251
252pub struct AllAnalyses;
254impl AllAnalyses {
255 const TYPE_ID: TypeId = TypeId::of::<AllAnalyses>();
256}
257
258#[repr(transparent)]
266struct AnalysisWrapper<A> {
267 analysis: A,
268}
269impl<A: Analysis> AnalysisWrapper<A> {
270 fn new(op: &<A as Analysis>::Target, am: AnalysisManager) -> Result<Self, Report> {
271 let mut analysis = A::default();
272 analysis.analyze(op, am)?;
273
274 Ok(Self { analysis })
275 }
276}
277impl<A: Default> Default for AnalysisWrapper<A> {
278 fn default() -> Self {
279 Self {
280 analysis: Default::default(),
281 }
282 }
283}
284impl<A: Analysis> Analysis for AnalysisWrapper<A> {
285 type Target = <A as Analysis>::Target;
286
287 #[inline]
288 fn analysis_id(&self) -> TypeId {
289 self.analysis.analysis_id()
290 }
291
292 #[inline]
293 fn as_any(&self) -> &dyn Any {
294 self.analysis.as_any()
295 }
296
297 #[inline]
298 fn as_any_rc(self: Rc<Self>) -> Rc<dyn Any> {
299 let ptr = Rc::into_raw(self);
302 unsafe { Rc::<A>::from_raw(ptr.cast()) as Rc<dyn Any> }
303 }
304
305 #[inline]
306 fn name(&self) -> &'static str {
307 self.analysis.name()
308 }
309
310 #[inline]
311 fn analyze(&mut self, op: &Self::Target, am: AnalysisManager) -> Result<(), Report> {
312 self.analysis.analyze(op, am)
313 }
314
315 fn invalidate(&self, preserved_analyses: &mut PreservedAnalyses) -> bool {
316 let invalidated = self.analysis.invalidate(preserved_analyses);
317 if invalidated {
318 preserved_analyses.unpreserve::<A>();
319 }
320 invalidated
321 }
322}
323
324#[derive(Clone)]
333#[repr(transparent)]
334pub struct AnalysisManager {
335 analyses: Rc<NestedAnalysisMap>,
336}
337impl AnalysisManager {
338 pub fn new(op: OperationRef, instrumentor: Option<Rc<PassInstrumentor>>) -> Self {
340 Self {
341 analyses: Rc::new(NestedAnalysisMap::new(op, instrumentor)),
342 }
343 }
344
345 pub fn get_cached_parent_analysis<A>(&self, parent: OperationRef) -> Option<Rc<A>>
348 where
349 A: Analysis,
350 {
351 let mut current_parent = self.analyses.parent();
352 while let Some(parent_am) = current_parent.take() {
353 if parent_am.get_operation() == parent {
354 return parent_am.analyses().get_cached::<A>();
355 }
356 current_parent = parent_am.parent();
357 }
358 None
359 }
360
361 pub fn get_analysis<A>(&self) -> Result<Rc<A>, Report>
363 where
364 A: Analysis<Target = Operation>,
365 {
366 self.get_analysis_for::<A, Operation>()
367 }
368
369 pub fn get_analysis_for<A, O>(&self) -> Result<Rc<A>, Report>
373 where
374 A: Analysis<Target = O>,
375 O: 'static,
376 {
377 let op = {
378 let analysis_map = self.analyses.analyses.borrow();
379 let cached = analysis_map.get_cached_for::<A, O>();
380 if let Some(cached) = cached {
381 return Ok(cached);
382 }
383 analysis_map.ir
384 };
385
386 let pi = self.pass_instrumentor();
389 let am = self.clone();
390 let ir = <O as PassTarget>::into_target(&op);
391 let analysis = AnalysisMap::compute_analysis_for::<A, O>(pi, &*ir, &op, am)?;
392
393 self.analyses
395 .analyses
396 .borrow_mut()
397 .analyses
398 .insert(TypeId::of::<A>(), Rc::clone(&analysis) as Rc<dyn OperationAnalysis>);
399
400 Ok(analysis)
401 }
402
403 pub fn get_cached_analysis<A>(&self) -> Option<Rc<A>>
405 where
406 A: Analysis,
407 {
408 self.analyses.analyses().get_cached::<A>()
409 }
410
411 pub fn get_child_analysis<A>(&self, op: OperationRef) -> Result<Rc<A>, Report>
413 where
414 A: Analysis<Target = Operation>,
415 {
416 self.clone().nest(op).get_analysis::<A>()
417 }
418
419 pub fn get_child_analysis_for<A, O>(&self, op: &O) -> Result<Rc<A>, Report>
424 where
425 A: Analysis<Target = O>,
426 O: Op,
427 {
428 self.clone().nest(op.as_operation_ref()).get_analysis_for::<A, O>()
429 }
430
431 pub fn get_cached_child_analysis<A>(&self, child: &OperationRef) -> Option<Rc<A>>
433 where
434 A: Analysis,
435 {
436 assert!(child.borrow().parent_op().unwrap() == self.analyses.get_operation());
437 let child_analyses = self.analyses.child_analyses.borrow();
438 let child_analyses = child_analyses.get(child)?;
439 let child_analyses = child_analyses.analyses.borrow();
440 child_analyses.get_cached::<A>()
441 }
442
443 pub fn nest(&self, op: OperationRef) -> AnalysisManager {
446 let current_op = self.analyses.get_operation();
447 assert!(
448 current_op.borrow().is_proper_ancestor_of(&op.borrow()),
449 "expected valid descendant op"
450 );
451
452 if current_op == op.borrow().parent_op().expect("expected `op` to have a parent") {
454 return self.nest_immediate(op);
455 }
456
457 let mut ancestors = SmallVec::<[OperationRef; 4]>::default();
459 let mut next_op = op;
460 while next_op != current_op {
461 ancestors.push(next_op);
462 next_op = next_op.borrow().parent_op().unwrap();
463 }
464
465 let mut manager = self.clone();
466 while let Some(op) = ancestors.pop() {
467 manager = manager.nest_immediate(op);
468 }
469 manager
470 }
471
472 fn nest_immediate(&self, op: OperationRef) -> AnalysisManager {
473 use hashbrown::hash_map::Entry;
474
475 assert!(
476 Some(self.analyses.get_operation()) == op.borrow().parent_op(),
477 "expected immediate child operation"
478 );
479 let parent = self.analyses.clone();
480 let mut child_analyses = self.analyses.child_analyses.borrow_mut();
481 match child_analyses.entry(op) {
482 Entry::Vacant(entry) => {
483 let analyses = entry.insert(Rc::new(parent.nest(op)));
484 AnalysisManager {
485 analyses: Rc::clone(analyses),
486 }
487 }
488 Entry::Occupied(entry) => AnalysisManager {
489 analyses: Rc::clone(entry.get()),
490 },
491 }
492 }
493
494 #[inline]
496 pub fn invalidate(&self, preserved_analyses: &mut PreservedAnalyses) {
497 Rc::clone(&self.analyses).invalidate(preserved_analyses)
498 }
499
500 #[inline]
502 pub fn clear(&mut self) {
503 self.analyses.clear();
504 }
505
506 #[inline]
508 pub fn defer_clear(&self) -> ResetAnalysesOnDrop {
509 ResetAnalysesOnDrop {
510 analyses: self.analyses.clone(),
511 }
512 }
513
514 #[inline]
516 pub fn pass_instrumentor(&self) -> Option<Rc<PassInstrumentor>> {
517 self.analyses.pass_instrumentor()
518 }
519}
520
521#[must_use]
522#[doc(hidden)]
523pub struct ResetAnalysesOnDrop {
524 analyses: Rc<NestedAnalysisMap>,
525}
526impl Drop for ResetAnalysesOnDrop {
527 fn drop(&mut self) {
528 self.analyses.clear()
529 }
530}
531
532struct NestedAnalysisMap {
535 parent: Option<Rc<NestedAnalysisMap>>,
536 instrumentor: Option<Rc<PassInstrumentor>>,
537 analyses: RefCell<AnalysisMap>,
538 child_analyses: RefCell<FxHashMap<OperationRef, Rc<NestedAnalysisMap>>>,
539}
540impl NestedAnalysisMap {
541 pub fn new(op: OperationRef, instrumentor: Option<Rc<PassInstrumentor>>) -> Self {
544 Self {
545 parent: None,
546 instrumentor,
547 analyses: RefCell::new(AnalysisMap::new(op)),
548 child_analyses: Default::default(),
549 }
550 }
551
552 pub fn nest(self: Rc<Self>, op: OperationRef) -> Self {
554 let instrumentor = self.instrumentor.clone();
555 Self {
556 parent: Some(self),
557 instrumentor,
558 analyses: RefCell::new(AnalysisMap::new(op)),
559 child_analyses: Default::default(),
560 }
561 }
562
563 pub fn parent(&self) -> Option<Rc<NestedAnalysisMap>> {
565 self.parent.clone()
566 }
567
568 pub fn pass_instrumentor(&self) -> Option<Rc<PassInstrumentor>> {
570 self.instrumentor.clone()
571 }
572
573 #[inline]
575 pub fn get_operation(&self) -> OperationRef {
576 self.analyses.borrow().get_operation()
577 }
578
579 fn analyses(&self) -> core::cell::Ref<'_, AnalysisMap> {
580 self.analyses.borrow()
581 }
582
583 pub fn invalidate(self: Rc<Self>, preserved_analyses: &mut PreservedAnalyses) {
585 if preserved_analyses.is_all() {
587 return;
588 }
589
590 self.analyses.borrow_mut().invalidate(preserved_analyses);
592
593 if preserved_analyses.is_none() {
595 self.child_analyses.borrow_mut().clear();
596 }
597
598 let mut to_invalidate = SmallVec::<[Rc<NestedAnalysisMap>; 8]>::from_iter([self]);
600 while let Some(map) = to_invalidate.pop() {
601 map.child_analyses.borrow_mut().retain(|_op, nested_analysis_map| {
602 Rc::clone(nested_analysis_map).invalidate(preserved_analyses);
603 if nested_analysis_map.child_analyses.borrow().is_empty() {
604 false
605 } else {
606 to_invalidate.push(Rc::clone(nested_analysis_map));
607 true
608 }
609 });
610 }
611 }
612
613 pub fn clear(&self) {
614 self.child_analyses.borrow_mut().clear();
615 self.analyses.borrow_mut().clear();
616 }
617}
618
619struct AnalysisMap {
623 analyses: FxHashMap<TypeId, Rc<dyn OperationAnalysis>>,
624 ir: OperationRef,
625}
626impl AnalysisMap {
627 pub fn new(ir: OperationRef) -> Self {
628 Self {
629 analyses: Default::default(),
630 ir,
631 }
632 }
633
634 pub fn get_cached<A>(&self) -> Option<Rc<A>>
636 where
637 A: Analysis,
638 {
639 self.analyses.get(&TypeId::of::<A>()).cloned().and_then(|a| a.downcast::<A>())
640 }
641
642 pub fn get_cached_for<A, O>(&self) -> Option<Rc<A>>
644 where
645 A: Analysis<Target = O>,
646 O: 'static,
647 {
648 self.analyses.get(&TypeId::of::<A>()).cloned().and_then(|a| a.downcast::<A>())
649 }
650
651 fn compute_analysis_for<A, O>(
652 pi: Option<Rc<PassInstrumentor>>,
653 ir: &O,
654 op: &OperationRef,
655 am: AnalysisManager,
656 ) -> Result<Rc<A>, Report>
657 where
658 A: Analysis<Target = O>,
659 {
660 let id = TypeId::of::<A>();
661
662 if let Some(pi) = pi.as_deref() {
665 pi.run_before_analysis(core::any::type_name::<A>(), &id, op);
666 }
667
668 let analysis = Self::construct_analysis::<A, O>(am, ir)?;
669
670 if let Some(pi) = pi.as_deref() {
671 pi.run_after_analysis(core::any::type_name::<A>(), &id, op);
672 }
673
674 Ok(analysis.downcast::<A>().unwrap())
675 }
676
677 fn construct_analysis<A, O>(
678 am: AnalysisManager,
679 op: &O,
680 ) -> Result<Rc<dyn OperationAnalysis>, Report>
681 where
682 A: Analysis<Target = O>,
683 {
684 AnalysisWrapper::<A>::new(op, am)
685 .map(|analysis| Rc::new(analysis) as Rc<dyn OperationAnalysis>)
686 }
687
688 pub fn get_operation(&self) -> OperationRef {
690 self.ir
691 }
692
693 pub fn clear(&mut self) {
695 self.analyses.clear();
696 }
697
698 pub fn invalidate(&mut self, preserved_analyses: &mut PreservedAnalyses) {
700 self.analyses.retain(|_, a| !a.invalidate(preserved_analyses));
705 }
706}