egraph-based midend: draw the rest of the owl (productionized). (#4953)
* egraph-based midend: draw the rest of the owl. * Rename `egg` submodule of cranelift-codegen to `egraph`. * Apply some feedback from @jsharp during code walkthrough. * Remove recursion from find_best_node by doing a single pass. Rather than recursively computing the lowest-cost node for a given eclass and memoizing the answer at each eclass node, we can do a single forward pass; because every eclass node refers only to earlier nodes, this is sufficient. The behavior may slightly differ from the earlier behavior because we cannot short-circuit costs to zero once a node is elaborated; but in practice this should not matter. * Make elaboration non-recursive. Use an explicit stack instead (with `ElabStackEntry` entries, alongside a result stack). * Make elaboration traversal of the domtree non-recursive/stack-safe. * Work analysis logic in Cranelift-side egraph glue into a general analysis framework in cranelift-egraph. * Apply static recursion limit to rule application. * Fix aarch64 wrt dynamic-vector support -- broken rebase. * Topo-sort cranelift-egraph before cranelift-codegen in publish script, like the comment instructs me to! * Fix multi-result call testcase. * Include `cranelift-egraph` in `PUBLISHED_CRATES`. * Fix atomic_rmw: not really a load. * Remove now-unnecessary PartialOrd/Ord derivations. * Address some code-review comments. * Review feedback. * Review feedback. * No overlap in mid-end rules, because we are defining a multi-constructor. * rustfmt * Review feedback. * Review feedback. * Review feedback. * Review feedback. * Remove redundant `mut`. * Add comment noting what rules can do. * Review feedback. * Clarify comment wording. * Update `has_memory_fence_semantics`. * Apply @jameysharp's improved loop-level computation. Co-authored-by: Jamey Sharp <jamey@minilop.net> * Fix suggestion commit. * Fix off-by-one in new loop-nest analysis. * Review feedback. * Review feedback. * Review feedback. * Use `Default`, not `std::default::Default`, as per @fitzgen Co-authored-by: Nick Fitzgerald <fitzgen@gmail.com> * Apply @fitzgen's comment elaboration to a doc-comment. Co-authored-by: Nick Fitzgerald <fitzgen@gmail.com> * Add stat for hitting the rewrite-depth limit. * Some code motion in split prelude to make the diff a little clearer wrt `main`. * Take @jameysharp's suggested `try_into()` usage for blockparam indices. Co-authored-by: Jamey Sharp <jamey@minilop.net> * Take @jameysharp's suggestion to avoid double-match on load op. Co-authored-by: Jamey Sharp <jamey@minilop.net> * Fix suggestion (add import). * Review feedback. * Fix stack_load handling. * Remove redundant can_store case. * Take @jameysharp's suggested improvement to FuncEGraph::build() logic Co-authored-by: Jamey Sharp <jamey@minilop.net> * Tweaks to FuncEGraph::build() on top of suggestion. * Take @jameysharp's suggested clarified condition Co-authored-by: Jamey Sharp <jamey@minilop.net> * Clean up after suggestion (unused variable). * Fix loop analysis. * loop level asserts * Revert constant-space loop analysis -- edge cases were incorrect, so let's go with the simple thing for now. * Take @jameysharp's suggestion re: result_tys Co-authored-by: Jamey Sharp <jamey@minilop.net> * Fix up after suggestion * Take @jameysharp's suggestion to use fold rather than reduce Co-authored-by: Jamey Sharp <jamey@minilop.net> * Fixup after suggestion * Take @jameysharp's suggestion to remove elaborate_eclass_use's return value. * Clarifying comment in terminator insts. Co-authored-by: Jamey Sharp <jamey@minilop.net> Co-authored-by: Nick Fitzgerald <fitzgen@gmail.com>
This commit is contained in:
@@ -12,6 +12,7 @@
|
||||
use crate::alias_analysis::AliasAnalysis;
|
||||
use crate::dce::do_dce;
|
||||
use crate::dominator_tree::DominatorTree;
|
||||
use crate::egraph::FuncEGraph;
|
||||
use crate::flowgraph::ControlFlowGraph;
|
||||
use crate::ir::Function;
|
||||
use crate::isa::TargetIsa;
|
||||
@@ -104,15 +105,20 @@ impl Context {
|
||||
|
||||
/// Compile the function, and emit machine code into a `Vec<u8>`.
|
||||
///
|
||||
/// Run the function through all the passes necessary to generate code for the target ISA
|
||||
/// represented by `isa`, as well as the final step of emitting machine code into a
|
||||
/// `Vec<u8>`. The machine code is not relocated. Instead, any relocations can be obtained
|
||||
/// from `compiled_code()`.
|
||||
/// Run the function through all the passes necessary to generate
|
||||
/// code for the target ISA represented by `isa`, as well as the
|
||||
/// final step of emitting machine code into a `Vec<u8>`. The
|
||||
/// machine code is not relocated. Instead, any relocations can be
|
||||
/// obtained from `compiled_code()`.
|
||||
///
|
||||
/// Performs any optimizations that are enabled, unless
|
||||
/// `optimize()` was already invoked.
|
||||
///
|
||||
/// This function calls `compile`, taking care to resize `mem` as
|
||||
/// needed, so it provides a safe interface.
|
||||
/// needed.
|
||||
///
|
||||
/// Returns information about the function's code and read-only data.
|
||||
/// Returns information about the function's code and read-only
|
||||
/// data.
|
||||
pub fn compile_and_emit(
|
||||
&mut self,
|
||||
isa: &dyn TargetIsa,
|
||||
@@ -131,15 +137,26 @@ impl Context {
|
||||
|
||||
self.verify_if(isa)?;
|
||||
|
||||
self.optimize(isa)?;
|
||||
|
||||
isa.compile_function(&self.func, self.want_disasm)
|
||||
}
|
||||
|
||||
/// Optimize the function, performing all compilation steps up to
|
||||
/// but not including machine-code lowering and register
|
||||
/// allocation.
|
||||
///
|
||||
/// Public only for testing purposes.
|
||||
pub fn optimize(&mut self, isa: &dyn TargetIsa) -> CodegenResult<()> {
|
||||
let opt_level = isa.flags().opt_level();
|
||||
log::trace!(
|
||||
"Compiling (opt level {:?}):\n{}",
|
||||
"Optimizing (opt level {:?}):\n{}",
|
||||
opt_level,
|
||||
self.func.display()
|
||||
);
|
||||
|
||||
self.compute_cfg();
|
||||
if opt_level != OptLevel::None {
|
||||
if !isa.flags().use_egraphs() && opt_level != OptLevel::None {
|
||||
self.preopt(isa)?;
|
||||
}
|
||||
if isa.flags().enable_nan_canonicalization() {
|
||||
@@ -147,7 +164,8 @@ impl Context {
|
||||
}
|
||||
|
||||
self.legalize(isa)?;
|
||||
if opt_level != OptLevel::None {
|
||||
|
||||
if !isa.flags().use_egraphs() && opt_level != OptLevel::None {
|
||||
self.compute_domtree();
|
||||
self.compute_loop_analysis();
|
||||
self.licm(isa)?;
|
||||
@@ -156,18 +174,29 @@ impl Context {
|
||||
|
||||
self.compute_domtree();
|
||||
self.eliminate_unreachable_code(isa)?;
|
||||
if opt_level != OptLevel::None {
|
||||
|
||||
if isa.flags().use_egraphs() || opt_level != OptLevel::None {
|
||||
self.dce(isa)?;
|
||||
}
|
||||
|
||||
self.remove_constant_phis(isa)?;
|
||||
|
||||
if opt_level != OptLevel::None && isa.flags().enable_alias_analysis() {
|
||||
if isa.flags().use_egraphs() {
|
||||
log::debug!(
|
||||
"About to optimize with egraph phase:\n{}",
|
||||
self.func.display()
|
||||
);
|
||||
self.compute_loop_analysis();
|
||||
let mut eg = FuncEGraph::new(&self.func, &self.domtree, &self.loop_analysis, &self.cfg);
|
||||
eg.elaborate(&mut self.func);
|
||||
log::debug!("After egraph optimization:\n{}", self.func.display());
|
||||
log::info!("egraph stats: {:?}", eg.stats);
|
||||
} else if opt_level != OptLevel::None && isa.flags().enable_alias_analysis() {
|
||||
self.replace_redundant_loads()?;
|
||||
self.simple_gvn(isa)?;
|
||||
}
|
||||
|
||||
isa.compile_function(&self.func, self.want_disasm)
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Compile the function.
|
||||
|
||||
Reference in New Issue
Block a user