diff --git a/cranelift/codegen/src/ir/dfg.rs b/cranelift/codegen/src/ir/dfg.rs index b7c8e161a602..2ac1152cee24 100644 --- a/cranelift/codegen/src/ir/dfg.rs +++ b/cranelift/codegen/src/ir/dfg.rs @@ -378,6 +378,65 @@ impl DataFlowGraph { resolve_aliases(&self.values, value) } + /// Replace all uses of value aliases with their resolved values, and delete + /// the aliases. + pub fn resolve_all_aliases(&mut self) { + let invalid_value = ValueDataPacked::from(ValueData::Alias { + ty: types::INVALID, + original: Value::reserved_value(), + }); + + // Rewrite each chain of aliases. Update every alias along the chain + // into an alias directly to the final value. Due to updating every + // alias that it looks at, this loop runs in time linear in the number + // of values. + for mut src in self.values.keys() { + let value_data = self.values[src]; + if value_data == invalid_value { + continue; + } + if let ValueData::Alias { mut original, .. } = value_data.into() { + // We don't use the type after this, we just need some place to + // store the resolved aliases temporarily. + let resolved = ValueDataPacked::from(ValueData::Alias { + ty: types::INVALID, + original: resolve_aliases(&self.values, original), + }); + // Walk the chain again, splatting the new alias everywhere. + // resolve_aliases panics if there's an alias cycle, so we don't + // need to guard against cycles here. + loop { + self.values[src] = resolved; + src = original; + if let ValueData::Alias { original: next, .. } = self.values[src].into() { + original = next; + } else { + break; + } + } + } + } + + // Now aliases don't point to other aliases, so we can replace any use + // of an alias with the final value in constant time. + 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() { + original + } else { + arg + } + }); + } + + // Delete all aliases now that there are no uses left. + for value in self.values.values_mut() { + if let ValueData::Alias { .. } = ValueData::from(*value) { + *value = invalid_value; + } + } + } + /// Resolve all aliases among inst's arguments. /// /// For each argument of inst which is defined by an alias, replace the diff --git a/cranelift/src/bugpoint.rs b/cranelift/src/bugpoint.rs index 63fa16f3e096..862664b11d3d 100644 --- a/cranelift/src/bugpoint.rs +++ b/cranelift/src/bugpoint.rs @@ -822,18 +822,10 @@ fn inst_count(func: &Function) -> usize { .sum() } -fn resolve_aliases(func: &mut Function) { - for block in func.stencil.layout.blocks() { - for inst in func.stencil.layout.block_insts(block) { - func.stencil.dfg.resolve_aliases_in_arguments(inst); - } - } -} - /// Resolve aliases only if function still crashes after this. fn try_resolve_aliases(context: &mut CrashCheckContext, func: &mut Function) { let mut func_with_resolved_aliases = func.clone(); - resolve_aliases(&mut func_with_resolved_aliases); + func_with_resolved_aliases.dfg.resolve_all_aliases(); if let CheckResult::Crash(_) = context.check_for_crash(&func_with_resolved_aliases) { *func = func_with_resolved_aliases; } diff --git a/cranelift/tests/bugpoint_test_expected.clif b/cranelift/tests/bugpoint_test_expected.clif index 982fcb001188..cc83b54bf151 100644 --- a/cranelift/tests/bugpoint_test_expected.clif +++ b/cranelift/tests/bugpoint_test_expected.clif @@ -6,30 +6,11 @@ block0: v0 = iconst.i64 0 v105 = iconst.i64 0 v829 = iconst.i64 0 - v935 -> v829 - v962 -> v829 - v992 -> v829 - v1036 -> v829 - v1049 -> v829 v842 = iconst.i64 0 - v976 -> v842 - v989 -> v842 - v1038 -> v842 - v1061 -> v842 v883 = iconst.i64 0 - v934 -> v883 - v961 -> v883 - v991 -> v883 - v1005 -> v883 - v1048 -> v883 v951 = iconst.i64 0 - v988 -> v951 v987 = iconst.i64 0 v1052 = iconst.i16 0 - v960 -> v1052 - v990 -> v1052 - v1051 -> v1052 - v1055 -> v1052 call fn0(v0, v105, v1052, v883, v829, v987, v951, v842) ; v0 = 0, v105 = 0, v1052 = 0, v883 = 0, v829 = 0, v987 = 0, v951 = 0, v842 = 0 trap user0 }