use std::sync::Arc;
use onnx_runtime_ir::{Graph, WeightRef};
use crate::error::{OptimizerError, Result};
pub trait InitializerResolver: Send + Sync {
fn bytes<'a>(&'a self, weight: &'a WeightRef) -> Option<&'a [u8]>;
}
#[derive(Clone, Default)]
#[non_exhaustive]
pub struct PassContext {
initializer_resolver: Option<Arc<dyn InitializerResolver>>,
}
impl std::fmt::Debug for PassContext {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("PassContext")
.field(
"initializer_resolver",
&self.initializer_resolver.as_ref().map(|_| "<resolver>"),
)
.finish()
}
}
impl PassContext {
pub fn new() -> Self {
Self::default()
}
pub fn with_initializer_resolver(
mut self,
resolver: Arc<dyn InitializerResolver>,
) -> Self {
self.initializer_resolver = Some(resolver);
self
}
pub fn initializer_bytes<'b>(&'b self, weight: &'b WeightRef) -> Option<&'b [u8]> {
match weight {
WeightRef::Inline(tensor) => Some(&tensor.data),
WeightRef::External { .. } => self.initializer_resolver.as_deref()?.bytes(weight),
}
}
}
pub trait OptimizationPass: Send + Sync {
fn name(&self) -> &str;
fn run(&self, graph: &mut Graph, ctx: &PassContext) -> Result<()>;
fn postconditions(&self, graph: &Graph) -> Result<()> {
graph
.validate()
.map_err(|errors| OptimizerError::PostconditionFailed {
pass: self.name().to_string(),
errors,
})
}
}
pub fn run_passes(
graph: &mut Graph,
passes: &[Box<dyn OptimizationPass>],
ctx: &PassContext,
) -> Result<()> {
for pass in passes {
pass.run(graph, ctx)?;
#[cfg(debug_assertions)]
pass.postconditions(graph)?;
}
Ok(())
}