pub mod budget;
pub mod dump;
pub mod remark;
pub mod timing;
pub use crate::pass::observer::dump::DumpObserver;
pub use budget::BudgetObserver;
pub use remark::{
NoRemarks, PassRemarks, RecordedArg, RecordedRemark, Remark, RemarkArg, RemarkArgValue,
RemarkCollector, RemarkCounter, RemarkKind, RemarkSink, RemarkValue,
};
pub use timing::WalkTiming;
use super::{Fusability, FusionGroup, PassDesc, PassKind, Pipeline, Preserved};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct PassEvent<'a> {
pub pipeline: &'a Pipeline,
pub group_index: usize,
pub group: FusionGroup,
pub pass_index: usize,
}
impl<'a> PassEvent<'a> {
#[inline]
#[must_use]
pub fn desc(&self) -> PassDesc {
const UNKNOWN: PassDesc = PassDesc {
name: "",
kind: PassKind::MandatoryLowering,
fusability: Fusability::Barrier,
preserved: Preserved::NONE,
};
self.pipeline
.passes
.get(self.pass_index)
.copied()
.unwrap_or(UNKNOWN)
}
#[inline]
#[must_use]
pub const fn is_group_entry(&self) -> bool {
self.pass_index == self.group.start
}
#[inline]
#[must_use]
pub const fn is_group_exit(&self) -> bool {
self.pass_index + 1 == self.group.end()
}
#[inline]
#[must_use]
pub fn group_members(&self) -> &'a [PassDesc] {
self.pipeline
.passes
.get(self.group.start..self.group.end())
.unwrap_or_default()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct AnalysisEvent<'a> {
pub pipeline: &'a Pipeline,
pub name: &'static str,
pub required_by: Option<usize>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct FailEvent<'a> {
pub pipeline: &'a Pipeline,
pub pass_index: Option<usize>,
pub reason: &'static str,
}
pub trait PassObserver {
const REMARKS: bool = false;
fn before_pipeline(&mut self, _pipeline: &Pipeline) {}
fn after_pipeline(&mut self, _pipeline: &Pipeline) {}
fn before_pass(&mut self, _event: &PassEvent<'_>) {}
fn after_pass(&mut self, _event: &PassEvent<'_>) {}
fn before_analysis(&mut self, _event: &AnalysisEvent<'_>) {}
fn after_analysis(&mut self, _event: &AnalysisEvent<'_>) {}
fn on_fail(&mut self, _event: &FailEvent<'_>) {}
fn on_remark(&mut self, _event: &PassEvent<'_>, _remark: &Remark<'_>) {}
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct NoObserver;
impl PassObserver for NoObserver {}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct Pair<A, B>(pub A, pub B);
impl<A: PassObserver, B: PassObserver> PassObserver for Pair<A, B> {
const REMARKS: bool = A::REMARKS || B::REMARKS;
fn before_pipeline(&mut self, pipeline: &Pipeline) {
self.0.before_pipeline(pipeline);
self.1.before_pipeline(pipeline);
}
fn after_pipeline(&mut self, pipeline: &Pipeline) {
self.0.after_pipeline(pipeline);
self.1.after_pipeline(pipeline);
}
fn before_pass(&mut self, event: &PassEvent<'_>) {
self.0.before_pass(event);
self.1.before_pass(event);
}
fn after_pass(&mut self, event: &PassEvent<'_>) {
self.0.after_pass(event);
self.1.after_pass(event);
}
fn before_analysis(&mut self, event: &AnalysisEvent<'_>) {
self.0.before_analysis(event);
self.1.before_analysis(event);
}
fn after_analysis(&mut self, event: &AnalysisEvent<'_>) {
self.0.after_analysis(event);
self.1.after_analysis(event);
}
fn on_fail(&mut self, event: &FailEvent<'_>) {
self.0.on_fail(event);
self.1.on_fail(event);
}
fn on_remark(&mut self, event: &PassEvent<'_>, remark: &Remark<'_>) {
if A::REMARKS {
self.0.on_remark(event, remark);
}
if B::REMARKS {
self.1.on_remark(event, remark);
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct PassFailure {
pub reason: &'static str,
}
impl PassFailure {
#[inline]
#[must_use]
pub const fn new(reason: &'static str) -> Self {
Self { reason }
}
}
pub fn run_pipeline<O, F>(
pipeline: &Pipeline,
observer: &mut O,
mut step: F,
) -> Result<(), PassFailure>
where
O: PassObserver,
F: FnMut(&PassEvent<'_>) -> Result<(), PassFailure>,
{
run_pipeline_remarked(pipeline, observer, |event, _remarks| step(event))
}
pub fn run_pipeline_remarked<O, F>(
pipeline: &Pipeline,
observer: &mut O,
mut step: F,
) -> Result<(), PassFailure>
where
O: PassObserver,
F: FnMut(&PassEvent<'_>, &mut PassRemarks<'_, '_, O>) -> Result<(), PassFailure>,
{
observer.before_pipeline(pipeline);
let group_count = pipeline.group_count();
let mut group_index = 0;
while group_index < group_count {
let Some(group) = pipeline.group(group_index) else {
break;
};
let mut pass_index = group.start;
while pass_index < group.end() {
let event = PassEvent {
pipeline,
group_index,
group,
pass_index,
};
observer.before_pass(&event);
let outcome = step(&event, &mut PassRemarks::new(observer, event));
match outcome {
Ok(()) => observer.after_pass(&event),
Err(failure) => {
observer.on_fail(&FailEvent {
pipeline,
pass_index: Some(pass_index),
reason: failure.reason,
});
return Err(failure);
}
}
pass_index += 1;
}
group_index += 1;
}
observer.after_pipeline(pipeline);
Ok(())
}