egraphs: a few miscellaneous compile-time optimizations. (#5072)
* egraphs: a few miscellaneous compile-time optimizations. These optimizations together are worth about a 2% compile-time reduction, as measured on one core with spidermonkey.wasm as an input, using `hyperfine` on `wasmtime compile`. The changes included are: - Some better pre-allocation (blockparams and side-effects concatenated list vecs); - Avoiding the indirection of storing list-of-types for every Pure and Inst node, when almost all nodes produce only a single result; instead, store arity and single type if it exists, and allow result projection nodes to fill in types otherwise; - Pack the `MemoryState` enum into one `u32` (this together with the above removal of the type slice allows `Node` to shrink from 48 bytes to 32 bytes); - always-inline an accessor (`entry` on `CtxHash`) that wasn't (`always(inline)` appears to be load-bearing, rather than just `inline`); - Split the update-analysis path into two hotpaths, one for the union case and one for the new-node case (and the former can avoid recomputing for the contained node when replacing a node with node-and-child eclass entry). * Review feedback. * Fix test build. * Fix to lowering when unused output with invalid type is present.
This commit is contained in:
@@ -134,6 +134,7 @@ impl<K, V> CtxHashMap<K, V> {
|
||||
|
||||
/// Return an Entry cursor on a given bucket for a key, allowing
|
||||
/// for fetching the current value or inserting a new one.
|
||||
#[inline(always)]
|
||||
pub fn entry<'a, Ctx: CtxEq<K, K> + CtxHash<K>>(
|
||||
&'a mut self,
|
||||
k: K,
|
||||
|
||||
@@ -530,7 +530,7 @@ where
|
||||
|
||||
// Update analysis.
|
||||
let node_ctx = ctx.node_ctx;
|
||||
self.update_analysis(node_ctx, eclass_id);
|
||||
self.update_analysis_new(node_ctx, eclass_id, key);
|
||||
|
||||
NewOrExisting::New(eclass_id)
|
||||
}
|
||||
@@ -568,7 +568,7 @@ where
|
||||
b
|
||||
);
|
||||
self.classes[a] = EClass::node_and_child(node, b);
|
||||
self.update_analysis(ctx, a);
|
||||
self.update_analysis_union(ctx, a, a, b);
|
||||
return a;
|
||||
}
|
||||
|
||||
@@ -576,7 +576,7 @@ where
|
||||
self.unionfind.add(u);
|
||||
self.unionfind.union(u, b);
|
||||
trace!(" -> union id {} and id {} into id {}", a, b, u);
|
||||
self.update_analysis(ctx, u);
|
||||
self.update_analysis_union(ctx, u, a, b);
|
||||
u
|
||||
}
|
||||
|
||||
@@ -605,26 +605,20 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// Update analysis for a given eclass node.
|
||||
fn update_analysis(&mut self, ctx: &L, eclass: Id) {
|
||||
/// Update analysis for a given eclass node (new-enode case).
|
||||
fn update_analysis_new(&mut self, ctx: &L, eclass: Id, node: NodeKey) {
|
||||
if let Some((analysis, state)) = self.analysis.as_mut() {
|
||||
let eclass_data = self.classes[eclass];
|
||||
let value = if let Some(node_key) = eclass_data.as_node() {
|
||||
let node = node_key.node(&self.nodes);
|
||||
analysis.for_node(ctx, node, state)
|
||||
} else if let Some((node_key, child)) = eclass_data.as_node_and_child() {
|
||||
let node = node_key.node(&self.nodes);
|
||||
let value = analysis.for_node(ctx, node, state);
|
||||
let child_value = &state[child];
|
||||
analysis.meet(ctx, &value, child_value)
|
||||
} else if let Some((c1, c2)) = eclass_data.as_union() {
|
||||
let c1 = &state[c1];
|
||||
let c2 = &state[c2];
|
||||
analysis.meet(ctx, c1, c2)
|
||||
} else {
|
||||
panic!("Invalid eclass node: {:?}", eclass_data);
|
||||
};
|
||||
state[eclass] = value;
|
||||
let node = node.node(&self.nodes);
|
||||
state[eclass] = analysis.for_node(ctx, node, state);
|
||||
}
|
||||
}
|
||||
|
||||
/// Update analysis for a given eclass node (union case).
|
||||
fn update_analysis_union(&mut self, ctx: &L, eclass: Id, a: Id, b: Id) {
|
||||
if let Some((analysis, state)) = self.analysis.as_mut() {
|
||||
let a = &state[a];
|
||||
let b = &state[b];
|
||||
state[eclass] = analysis.meet(ctx, a, b);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -646,6 +640,7 @@ pub struct NodeIter<L: Language, A: Analysis<L = L>> {
|
||||
}
|
||||
|
||||
impl<L: Language, A: Analysis<L = L>> NodeIter<L, A> {
|
||||
#[inline(always)]
|
||||
pub fn next<'a>(&mut self, egraph: &'a EGraph<L, A>) -> Option<&'a L::Node> {
|
||||
while let Some(next) = self.stack.pop() {
|
||||
let eclass = egraph.classes[next];
|
||||
|
||||
Reference in New Issue
Block a user