use crate::{
error::Result,
ir::{function::SsaFunction, variable::SsaVarId},
passes,
scheduling::{ModificationScope, SsaPass, SsaPassHost},
target::Target,
};
const DEFAULT_MAX_ITERATIONS: usize = 10;
#[derive(Debug, Default, Clone, Copy)]
pub struct AlgebraicSimplificationPass;
impl AlgebraicSimplificationPass {
#[must_use]
pub fn new() -> Self {
Self
}
}
impl<T, H> SsaPass<T, H> for AlgebraicSimplificationPass
where
T: Target,
T::MethodRef: Send + Sync,
H: SsaPassHost<T>,
{
fn name(&self) -> &'static str {
"algebraic-simplification"
}
fn description(&self) -> &'static str {
"Simplify algebraic identities (x xor x = 0, x + 0 = x, etc.)"
}
fn modification_scope(&self) -> ModificationScope {
ModificationScope::InstructionsOnly
}
fn run_on_method(
&self,
ssa: &mut SsaFunction<T>,
method: &T::MethodRef,
host: &H,
) -> Result<bool> {
Ok(passes::algebraic::run(ssa, method, host.events()))
}
}
#[derive(Debug, Clone, Copy)]
pub struct BlockMergingPass {
pub max_iterations: usize,
}
impl Default for BlockMergingPass {
fn default() -> Self {
Self {
max_iterations: DEFAULT_MAX_ITERATIONS,
}
}
}
impl BlockMergingPass {
#[must_use]
pub fn new(max_iterations: usize) -> Self {
Self { max_iterations }
}
}
impl<T, H> SsaPass<T, H> for BlockMergingPass
where
T: Target,
T::MethodRef: Send + Sync,
H: SsaPassHost<T>,
{
fn name(&self) -> &'static str {
"block-merging"
}
fn description(&self) -> &'static str {
"Eliminate trampoline (single-jump) blocks"
}
fn run_on_method(
&self,
ssa: &mut SsaFunction<T>,
method: &T::MethodRef,
host: &H,
) -> Result<bool> {
Ok(passes::blockmerge::run(
ssa,
method,
host.events(),
self.max_iterations,
))
}
}
#[derive(Debug, Clone, Copy)]
pub struct ControlFlowSimplificationPass {
pub max_iterations: usize,
}
impl Default for ControlFlowSimplificationPass {
fn default() -> Self {
Self {
max_iterations: DEFAULT_MAX_ITERATIONS,
}
}
}
impl ControlFlowSimplificationPass {
#[must_use]
pub fn new(max_iterations: usize) -> Self {
Self { max_iterations }
}
}
impl<T, H> SsaPass<T, H> for ControlFlowSimplificationPass
where
T: Target,
T::MethodRef: Send + Sync,
H: SsaPassHost<T>,
{
fn name(&self) -> &'static str {
"control-flow-simplification"
}
fn description(&self) -> &'static str {
"Simplify branches, eliminate unreachable code, fold constant predicates"
}
fn run_on_method(
&self,
ssa: &mut SsaFunction<T>,
method: &T::MethodRef,
host: &H,
) -> Result<bool> {
Ok(passes::controlflow::run(
ssa,
method,
host.events(),
self.max_iterations,
))
}
}
#[derive(Debug, Clone, Copy)]
pub struct CopyPropagationPass {
pub max_iterations: usize,
}
impl Default for CopyPropagationPass {
fn default() -> Self {
Self {
max_iterations: DEFAULT_MAX_ITERATIONS,
}
}
}
impl CopyPropagationPass {
#[must_use]
pub fn new(max_iterations: usize) -> Self {
Self { max_iterations }
}
}
impl<T, H> SsaPass<T, H> for CopyPropagationPass
where
T: Target,
T::MethodRef: Send + Sync,
H: SsaPassHost<T>,
{
fn name(&self) -> &'static str {
"copy-propagation"
}
fn description(&self) -> &'static str {
"Eliminate redundant copy operations and trivial phi nodes"
}
fn modification_scope(&self) -> ModificationScope {
ModificationScope::InstructionsOnly
}
fn run_on_method(
&self,
ssa: &mut SsaFunction<T>,
method: &T::MethodRef,
host: &H,
) -> Result<bool> {
Ok(passes::copying::run(
ssa,
method,
host.events(),
self.max_iterations,
))
}
}
#[derive(Debug, Clone, Copy)]
pub struct DeadCodeEliminationPass {
pub max_iterations: usize,
}
impl Default for DeadCodeEliminationPass {
fn default() -> Self {
Self {
max_iterations: DEFAULT_MAX_ITERATIONS,
}
}
}
impl DeadCodeEliminationPass {
#[must_use]
pub fn new(max_iterations: usize) -> Self {
Self { max_iterations }
}
}
impl<T, H> SsaPass<T, H> for DeadCodeEliminationPass
where
T: Target,
T::MethodRef: Send + Sync,
H: SsaPassHost<T>,
{
fn name(&self) -> &'static str {
"dead-code-elimination"
}
fn description(&self) -> &'static str {
"Remove unreachable blocks, unused definitions, and op-less instructions"
}
fn modification_scope(&self) -> ModificationScope {
ModificationScope::InstructionsOnly
}
fn run_on_method(
&self,
ssa: &mut SsaFunction<T>,
method: &T::MethodRef,
host: &H,
) -> Result<bool> {
Ok(passes::deadcode::run(
ssa,
method,
host.events(),
self.max_iterations,
))
}
}
#[derive(Debug, Default, Clone, Copy)]
pub struct DeadMethodEliminationPass;
impl<T, H> SsaPass<T, H> for DeadMethodEliminationPass
where
T: Target,
T::MethodRef: Send + Sync,
H: SsaPassHost<T>,
{
fn name(&self) -> &'static str {
"dead-method-elimination"
}
fn description(&self) -> &'static str {
"Mark methods that have no live callers and aren't entry points"
}
fn is_global(&self) -> bool {
true
}
fn run_on_method(
&self,
_ssa: &mut SsaFunction<T>,
_method: &T::MethodRef,
_host: &H,
) -> Result<bool> {
Ok(false)
}
fn run_global(&self, host: &H) -> Result<bool> {
Ok(passes::deadcode::run_global::<T, _, _>(host, host.events()))
}
}
#[derive(Debug, Default, Clone, Copy)]
pub struct GlobalValueNumberingPass;
impl GlobalValueNumberingPass {
#[must_use]
pub fn new() -> Self {
Self
}
}
impl<T, H> SsaPass<T, H> for GlobalValueNumberingPass
where
T: Target,
T::MethodRef: Send + Sync,
H: SsaPassHost<T>,
{
fn name(&self) -> &'static str {
"global-value-numbering"
}
fn description(&self) -> &'static str {
"Eliminate redundant computations via value numbering"
}
fn modification_scope(&self) -> ModificationScope {
ModificationScope::UsesOnly
}
fn run_on_method(
&self,
ssa: &mut SsaFunction<T>,
method: &T::MethodRef,
host: &H,
) -> Result<bool> {
Ok(passes::gvn::run(ssa, method, host.events()))
}
}
#[derive(Debug, Default, Clone, Copy)]
pub struct LicmPass;
impl LicmPass {
#[must_use]
pub fn new() -> Self {
Self
}
}
impl<T, H> SsaPass<T, H> for LicmPass
where
T: Target,
T::MethodRef: Send + Sync,
H: SsaPassHost<T>,
{
fn name(&self) -> &'static str {
"licm"
}
fn description(&self) -> &'static str {
"Hoist loop-invariant computations out of loops"
}
fn run_on_method(
&self,
ssa: &mut SsaFunction<T>,
method: &T::MethodRef,
host: &H,
) -> Result<bool> {
Ok(passes::licm::run(ssa, method, host.events()))
}
}
#[derive(Debug, Default, Clone, Copy)]
pub struct LoopCanonicalizationPass;
impl LoopCanonicalizationPass {
#[must_use]
pub fn new() -> Self {
Self
}
}
impl<T, H> SsaPass<T, H> for LoopCanonicalizationPass
where
T: Target,
T::MethodRef: Send + Sync,
H: SsaPassHost<T>,
{
fn name(&self) -> &'static str {
"loop-canonicalization"
}
fn description(&self) -> &'static str {
"Ensure each loop has a single preheader and latch"
}
fn run_on_method(
&self,
ssa: &mut SsaFunction<T>,
method: &T::MethodRef,
host: &H,
) -> Result<bool> {
Ok(passes::loopcanon::run(ssa, method, host.events()))
}
}
pub use crate::passes::predicates::OpaquePredicatePass;
impl<T, H> SsaPass<T, H> for OpaquePredicatePass<T>
where
T: Target + Send + Sync,
T::MethodRef: Send + Sync,
H: SsaPassHost<T>,
{
fn name(&self) -> &'static str {
"opaque-predicate"
}
fn description(&self) -> &'static str {
"Remove always-true/false conditions, simplify trivial comparisons"
}
fn run_on_method(
&self,
ssa: &mut SsaFunction<T>,
method: &T::MethodRef,
host: &H,
) -> Result<bool> {
Ok(passes::predicates::run(
ssa,
method,
host.events(),
host.ptr_size(),
))
}
}
#[derive(Debug, Clone, Copy)]
pub struct ValueRangePropagationPass {
pub max_iterations: usize,
}
impl Default for ValueRangePropagationPass {
fn default() -> Self {
Self {
max_iterations: DEFAULT_MAX_ITERATIONS,
}
}
}
impl ValueRangePropagationPass {
#[must_use]
pub fn new(max_iterations: usize) -> Self {
Self { max_iterations }
}
}
impl<T, H> SsaPass<T, H> for ValueRangePropagationPass
where
T: Target,
T::MethodRef: Send + Sync,
H: SsaPassHost<T>,
{
fn name(&self) -> &'static str {
"value-range-propagation"
}
fn description(&self) -> &'static str {
"Propagate value-range information across the SSA graph"
}
fn modification_scope(&self) -> ModificationScope {
ModificationScope::InstructionsOnly
}
fn run_on_method(
&self,
ssa: &mut SsaFunction<T>,
method: &T::MethodRef,
host: &H,
) -> Result<bool> {
Ok(passes::ranges::run(
ssa,
method,
host.events(),
self.max_iterations,
))
}
}
#[derive(Debug, Default, Clone, Copy)]
pub struct ReassociationPass;
impl ReassociationPass {
#[must_use]
pub fn new() -> Self {
Self
}
}
impl<T, H> SsaPass<T, H> for ReassociationPass
where
T: Target,
T::MethodRef: Send + Sync,
H: SsaPassHost<T>,
{
fn name(&self) -> &'static str {
"reassociation"
}
fn description(&self) -> &'static str {
"Reorder associative operations to expose simplification opportunities"
}
fn modification_scope(&self) -> ModificationScope {
ModificationScope::InstructionsOnly
}
fn run_on_method(
&self,
ssa: &mut SsaFunction<T>,
method: &T::MethodRef,
host: &H,
) -> Result<bool> {
Ok(passes::reassociate::run(
ssa,
method,
host.events(),
host.ptr_size(),
))
}
}
#[derive(Debug, Default, Clone, Copy)]
pub struct StrengthReductionPass;
impl<T, H> SsaPass<T, H> for StrengthReductionPass
where
T: Target,
T::MethodRef: Send + Sync,
H: SsaPassHost<T>,
{
fn name(&self) -> &'static str {
"strength-reduction"
}
fn description(&self) -> &'static str {
"Replace expensive operations with cheaper equivalents"
}
fn modification_scope(&self) -> ModificationScope {
ModificationScope::InstructionsOnly
}
fn run_on_method(
&self,
ssa: &mut SsaFunction<T>,
method: &T::MethodRef,
host: &H,
) -> Result<bool> {
let is_non_negative = |_: SsaVarId| false;
Ok(passes::strength::run(
ssa,
method,
host.events(),
&is_non_negative,
))
}
}
#[derive(Debug, Default, Clone, Copy)]
pub struct JumpThreadingPass;
impl JumpThreadingPass {
#[must_use]
pub fn new() -> Self {
Self
}
}
impl<T, H> SsaPass<T, H> for JumpThreadingPass
where
T: Target,
T::MethodRef: Send + Sync,
H: SsaPassHost<T>,
{
fn name(&self) -> &'static str {
"jump-threading"
}
fn description(&self) -> &'static str {
"Thread jumps through empty or predictable blocks"
}
fn run_on_method(
&self,
ssa: &mut SsaFunction<T>,
method: &T::MethodRef,
host: &H,
) -> Result<bool> {
Ok(passes::threading::run(
ssa,
method,
host.events(),
host.ptr_size(),
))
}
}