Skip to content

Commit f3dfad2

Browse files
authored
egraphs: disable GVN of effectful idempotent ops (temporarily). (#5809)
This is a short-term fix to the same bug that #5800 is addressing (#5796), but with less risk: it simply turns off GVN'ing of effectful but idempotent ops. Because we have an upcoming release, and this is a miscompile (albeit to do with trapping behavior), we would like to make the simplest possible fix that avoids the bug, and backport it. I will then rebase #5800 on top of a revert of this followed by the more complete fix.
1 parent 473a366 commit f3dfad2

File tree

3 files changed

+5
-147
lines changed

3 files changed

+5
-147
lines changed

cranelift/codegen/src/egraph.rs

Lines changed: 5 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use crate::dominator_tree::DominatorTree;
77
use crate::egraph::domtree::DomTreeWithChildren;
88
use crate::egraph::elaborate::Elaborator;
99
use crate::fx::FxHashSet;
10-
use crate::inst_predicates::{is_mergeable_for_egraph, is_pure_for_egraph};
10+
use crate::inst_predicates::is_pure_for_egraph;
1111
use crate::ir::{
1212
DataFlowGraph, Function, Inst, InstructionData, Type, Value, ValueDef, ValueListPool,
1313
};
@@ -285,41 +285,10 @@ where
285285
fn optimize_skeleton_inst(&mut self, inst: Inst) -> bool {
286286
self.stats.skeleton_inst += 1;
287287

288-
// First, can we try to deduplicate? We need to keep some copy
289-
// of the instruction around because it's side-effecting, but
290-
// we may be able to reuse an earlier instance of it.
291-
if is_mergeable_for_egraph(self.func, inst) {
292-
let result = self.func.dfg.inst_results(inst)[0];
293-
trace!(" -> mergeable side-effecting op {}", inst);
294-
let inst = NewOrExistingInst::Existing(inst);
295-
let gvn_context = GVNContext {
296-
union_find: self.eclasses,
297-
value_lists: &self.func.dfg.value_lists,
298-
};
299-
300-
// Does this instruction already exist? If so, add entries to
301-
// the value-map to rewrite uses of its results to the results
302-
// of the original (existing) instruction. If not, optimize
303-
// the new instruction.
304-
let key = inst.get_inst_key(&self.func.dfg);
305-
if let Some(&orig_result) = self.gvn_map.get(&key, &gvn_context) {
306-
// Hit in GVN map -- reuse value.
307-
self.value_to_opt_value[result] = orig_result;
308-
self.eclasses.union(orig_result, result);
309-
trace!(" -> merges result {} to {}", result, orig_result);
310-
true
311-
} else {
312-
// Otherwise, insert it into the value-map.
313-
self.value_to_opt_value[result] = result;
314-
self.gvn_map.insert(key, result, &gvn_context);
315-
trace!(" -> inserts as new (no GVN)");
316-
false
317-
}
318-
}
319-
// Otherwise, if a load or store, process it with the alias
320-
// analysis to see if we can optimize it (rewrite in terms of
321-
// an earlier load or stored value).
322-
else if let Some(new_result) =
288+
// If a load or store, process it with the alias analysis to see
289+
// if we can optimize it (rewrite in terms of an earlier load or
290+
// stored value).
291+
if let Some(new_result) =
323292
self.alias_analysis
324293
.process_inst(self.func, self.alias_analysis_state, inst)
325294
{

cranelift/codegen/src/inst_predicates.rs

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -74,25 +74,6 @@ pub fn is_pure_for_egraph(func: &Function, inst: Inst) -> bool {
7474
has_one_result && (is_readonly_load || (!op.can_load() && !trivially_has_side_effects(op)))
7575
}
7676

77-
/// Can the given instruction be merged into another copy of itself?
78-
/// These instructions may have side-effects, but as long as we retain
79-
/// the first instance of the instruction, the second and further
80-
/// instances are redundant if they would produce the same trap or
81-
/// result.
82-
pub fn is_mergeable_for_egraph(func: &Function, inst: Inst) -> bool {
83-
let op = func.dfg.insts[inst].opcode();
84-
// We can only merge one-result operators due to the way that GVN
85-
// is structured in the egraph implementation.
86-
let has_one_result = func.dfg.inst_results(inst).len() == 1;
87-
has_one_result
88-
// Loads/stores are handled by alias analysis and not
89-
// otherwise mergeable.
90-
&& !op.can_load()
91-
&& !op.can_store()
92-
// Can only have idempotent side-effects.
93-
&& (!has_side_effect(func, inst) || op.side_effects_idempotent())
94-
}
95-
9677
/// Does the given instruction have any side-effect as per [has_side_effect], or else is a load,
9778
/// but not the get_pinned_reg opcode?
9879
pub fn has_lowering_side_effect(func: &Function, inst: Inst) -> bool {

cranelift/filetests/filetests/wasm/duplicate-loads-dynamic-memory-egraph.wat

Lines changed: 0 additions & 92 deletions
This file was deleted.

0 commit comments

Comments
 (0)