mod boolean_shells;
mod branch_value_folding;
mod carried_locals;
mod close_scopes;
mod closure_self_capture;
mod dead_labels;
mod dead_temps;
pub(super) mod decision;
mod expr_facts;
mod locals;
mod logical_simplify;
mod residuals;
mod table_constructors;
mod temp_inline;
mod temp_touch;
mod traverse;
mod visit;
mod walk;
use crate::generate::GenerateMode;
use crate::hir::common::HirModule;
use crate::hir::promotion::ProtoPromotionFacts;
use crate::readability::ReadabilityOptions;
use crate::scheduler::{run_invalidation_loop, InvalidationTag, PassDescriptor, PassPhase};
use crate::timing::TimingCollector;
const MAX_SIMPLIFY_ITERATIONS: usize = 128;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
enum HirInvalidation {
DecisionShape,
BooleanPattern,
LogicalExpr,
TablePattern,
TempChain,
LocalBinding,
BlockStructure,
LabelGoto,
ClosureCapture,
}
impl InvalidationTag for HirInvalidation {
fn all() -> &'static [Self] {
&[
Self::DecisionShape,
Self::BooleanPattern,
Self::LogicalExpr,
Self::TablePattern,
Self::TempChain,
Self::LocalBinding,
Self::BlockStructure,
Self::LabelGoto,
Self::ClosureCapture,
]
}
}
use HirInvalidation::*;
const PASS_DESCRIPTORS: &[PassDescriptor<HirInvalidation>] = &[
PassDescriptor {
name: "decision",
phase: PassPhase::Normal,
depends_on: &[DecisionShape],
invalidates: &[DecisionShape, LogicalExpr, BooleanPattern],
},
PassDescriptor {
name: "boolean-shells",
phase: PassPhase::Normal,
depends_on: &[BooleanPattern, DecisionShape],
invalidates: &[BooleanPattern, TempChain],
},
PassDescriptor {
name: "logical-simplify",
phase: PassPhase::Normal,
depends_on: &[LogicalExpr, DecisionShape],
invalidates: &[LogicalExpr, DecisionShape],
},
PassDescriptor {
name: "table-constructors",
phase: PassPhase::Normal,
depends_on: &[TablePattern, LocalBinding],
invalidates: &[TablePattern],
},
PassDescriptor {
name: "closure-self-capture",
phase: PassPhase::Normal,
depends_on: &[ClosureCapture],
invalidates: &[ClosureCapture],
},
PassDescriptor {
name: "temp-inline",
phase: PassPhase::Normal,
depends_on: &[TempChain, DecisionShape, BooleanPattern, LogicalExpr],
invalidates: &[TempChain, LocalBinding],
},
PassDescriptor {
name: "locals",
phase: PassPhase::Normal,
depends_on: &[TempChain, LocalBinding, BlockStructure],
invalidates: &[LocalBinding, TempChain],
},
PassDescriptor {
name: "eliminate-decisions",
phase: PassPhase::Deferred,
depends_on: &[DecisionShape],
invalidates: &[DecisionShape],
},
PassDescriptor {
name: "close-scopes",
phase: PassPhase::Deferred,
depends_on: &[BlockStructure],
invalidates: &[BlockStructure, LocalBinding, TempChain],
},
PassDescriptor {
name: "carried-locals",
phase: PassPhase::Deferred,
depends_on: &[LocalBinding],
invalidates: &[LocalBinding],
},
PassDescriptor {
name: "dead-unresolved-temps",
phase: PassPhase::Deferred,
depends_on: &[TempChain],
invalidates: &[TempChain],
},
PassDescriptor {
name: "dead-labels",
phase: PassPhase::Deferred,
depends_on: &[LabelGoto],
invalidates: &[LabelGoto],
},
];
pub(super) fn simplify_hir(
module: &mut HirModule,
readability: ReadabilityOptions,
timings: &TimingCollector,
promotion_facts: &[ProtoPromotionFacts],
generate_mode: GenerateMode,
) {
let empty_facts = ProtoPromotionFacts::default();
run_invalidation_loop(
PASS_DESCRIPTORS,
|index, name| {
timings.record(name, || {
apply_proto_pass(module, |proto| {
let facts = promotion_facts
.get(proto.id.index())
.unwrap_or(&empty_facts);
match index {
0 => decision::simplify_decision_exprs_in_proto(proto),
1 => boolean_shells::remove_boolean_materialization_shells_in_proto(proto),
2 => logical_simplify::simplify_logical_exprs_in_proto(proto),
3 => table_constructors::stabilize_table_constructors_in_proto(proto),
4 => closure_self_capture::resolve_recursive_closure_self_captures_in_proto(proto),
5 => temp_inline::inline_temps_in_proto_with_facts(proto, readability, facts),
6 => locals::promote_temps_to_locals_in_proto_with_facts(proto, facts),
7 => decision::eliminate_remaining_decisions_in_proto(proto),
8 => close_scopes::materialize_tbc_close_scopes_in_proto(proto),
9 => carried_locals::collapse_carried_local_handoffs_in_proto(proto),
10 => dead_temps::remove_dead_temp_materializations_in_proto(proto),
11 => dead_labels::remove_unused_labels_in_proto(proto),
_ => unreachable!("invalid HIR pass index: {index}"),
}
})
})
},
MAX_SIMPLIFY_ITERATIONS,
);
let residuals = residuals::collect_hir_exit_residuals(module);
if residuals.has_soft_residuals() && generate_mode != GenerateMode::Permissive {
residuals::emit_hir_warning(format!(
"HIR exit still contains residual nodes: decision={}, unresolved={}, \
fallback_unstructured={}, other_unstructured={}.",
residuals.decisions,
residuals.unresolved,
residuals.fallback_unstructured,
residuals.other_unstructured
));
}
}
fn apply_proto_pass(
module: &mut HirModule,
mut pass: impl FnMut(&mut crate::hir::common::HirProto) -> bool,
) -> bool {
let mut changed = false;
for proto in &mut module.protos {
changed |= pass(proto);
}
changed
}
pub(crate) use decision::synthesize_readable_pure_logical_expr;