diff --git a/cranelift/codegen/src/egraph.rs b/cranelift/codegen/src/egraph.rs index 73f98a9b94..1f3f2a8829 100644 --- a/cranelift/codegen/src/egraph.rs +++ b/cranelift/codegen/src/egraph.rs @@ -566,6 +566,10 @@ impl<'a> EgraphPass<'a> { /// only refer to its subset that exists at this stage, to /// maintain acyclicity.) fn remove_pure_and_optimize(&mut self) { + // This pass relies on every value having a unique name, so first + // eliminate any value aliases. + self.func.dfg.resolve_all_aliases(); + let mut cursor = FuncCursor::new(self.func); let mut value_to_opt_value: SecondaryMap = SecondaryMap::with_default(Value::reserved_value()); @@ -661,7 +665,6 @@ impl<'a> EgraphPass<'a> { // Rewrite args of *all* instructions using the // value-to-opt-value map. - cursor.func.dfg.resolve_aliases_in_arguments(inst); cursor.func.dfg.map_inst_values(inst, |arg| { let new_value = value_to_opt_value[arg]; trace!("rewriting arg {} of inst {} to {}", arg, inst, new_value); diff --git a/cranelift/codegen/src/egraph/elaborate.rs b/cranelift/codegen/src/egraph/elaborate.rs index f7aa002b1c..2aca8bf645 100644 --- a/cranelift/codegen/src/egraph/elaborate.rs +++ b/cranelift/codegen/src/egraph/elaborate.rs @@ -416,8 +416,7 @@ impl<'a> Elaborator<'a> { while let Some(entry) = self.elab_stack.pop() { match entry { ElabStackEntry::Start { value, before } => { - debug_assert_ne!(value, Value::reserved_value()); - let value = self.func.dfg.resolve_aliases(value); + debug_assert!(self.func.dfg.value_is_real(value)); self.stats.elaborate_visit_node += 1; diff --git a/cranelift/codegen/src/ir/dfg.rs b/cranelift/codegen/src/ir/dfg.rs index 2ac1152cee..d65f15ed73 100644 --- a/cranelift/codegen/src/ir/dfg.rs +++ b/cranelift/codegen/src/ir/dfg.rs @@ -333,6 +333,13 @@ impl DataFlowGraph { self.values.is_valid(v) } + /// Check whether a value is valid and not an alias. + pub fn value_is_real(&self, value: Value) -> bool { + // Deleted or unused values are also stored as aliases so this excludes + // those as well. + self.value_is_valid(value) && !matches!(self.values[value].into(), ValueData::Alias { .. }) + } + /// Get the type of a value. pub fn value_type(&self, v: Value) -> Type { self.values[v].ty() @@ -419,6 +426,8 @@ impl DataFlowGraph { // Now aliases don't point to other aliases, so we can replace any use // of an alias with the final value in constant time. + + // Rewrite InstructionData in `self.insts`. for inst in self.insts.0.values_mut() { inst.map_values(&mut self.value_lists, &mut self.jump_tables, |arg| { if let ValueData::Alias { original, .. } = self.values[arg].into() { @@ -429,6 +438,50 @@ impl DataFlowGraph { }); } + // - `results` and block-params in `blocks` are not aliases, by + // definition. + // - `dynamic_types` has no values. + // - `value_lists` can only be accessed via references from elsewhere. + // - `values` only has value references in aliases (which we've + // removed), and unions (but the egraph pass ensures there are no + // aliases before creating unions). + + // Merge `facts` from any alias onto the aliased value. Note that if + // there was a chain of aliases, at this point every alias that was in + // the chain points to the same final value, so their facts will all be + // merged together. + for value in self.facts.keys() { + if let ValueData::Alias { original, .. } = self.values[value].into() { + if let Some(new_fact) = self.facts[value].take() { + match &mut self.facts[original] { + Some(old_fact) => *old_fact = Fact::intersect(old_fact, &new_fact), + old_fact => *old_fact = Some(new_fact), + } + } + } + } + + // - `signatures`, `old_signatures`, and `ext_funcs` have no values. + + if let Some(values_labels) = &mut self.values_labels { + // Debug info is best-effort. If any is attached to value aliases, + // just discard it. + values_labels.retain(|&k, _| !matches!(self.values[k].into(), ValueData::Alias { .. })); + + // If debug-info says a value should have the same labels as another + // value, then make sure that target is not a value alias. + for value_label in values_labels.values_mut() { + if let ValueLabelAssignments::Alias { value, .. } = value_label { + if let ValueData::Alias { original, .. } = self.values[*value].into() { + *value = original; + } + } + } + } + + // - `constants` and `immediates` have no values. + // - `jump_tables` is updated together with instruction-data above. + // Delete all aliases now that there are no uses left. for value in self.values.values_mut() { if let ValueData::Alias { .. } = ValueData::from(*value) { @@ -437,16 +490,6 @@ impl DataFlowGraph { } } - /// Resolve all aliases among inst's arguments. - /// - /// For each argument of inst which is defined by an alias, replace the - /// alias with the aliased value. - pub fn resolve_aliases_in_arguments(&mut self, inst: Inst) { - self.insts[inst].map_values(&mut self.value_lists, &mut self.jump_tables, |arg| { - resolve_aliases(&self.values, arg) - }); - } - /// Turn a value into an alias of another. /// /// Change the `dest` value to behave as an alias of `src`. This means that all uses of `dest` diff --git a/cranelift/codegen/src/opts.rs b/cranelift/codegen/src/opts.rs index 2d0819a43a..f6bdcfb381 100644 --- a/cranelift/codegen/src/opts.rs +++ b/cranelift/codegen/src/opts.rs @@ -83,8 +83,7 @@ where fn next(&mut self, ctx: &mut IsleContext<'a, 'b, 'c>) -> Option { while let Some(value) = self.stack.pop() { - debug_assert_ne!(value, Value::reserved_value()); - let value = ctx.ctx.func.dfg.resolve_aliases(value); + debug_assert!(ctx.ctx.func.dfg.value_is_real(value)); trace!("iter: value {:?}", value); match ctx.ctx.func.dfg.value_def(value) { ValueDef::Union(x, y) => { diff --git a/cranelift/filetests/filetests/egraph/licm.clif b/cranelift/filetests/filetests/egraph/licm.clif index 51fdf38a5f..8409f3dc0a 100644 --- a/cranelift/filetests/filetests/egraph/licm.clif +++ b/cranelift/filetests/filetests/egraph/licm.clif @@ -58,7 +58,6 @@ block2(v8: i64x2): ; check: v9 = iconst.i32 1 ; check: v10 = isub v3, v9 ; check: v5 = iadd v2, v4 -; check: v8 -> v5 ; check: brif v10, block1(v5, v10), block2 ; check: block2: ; check: return v5