diff --git a/hercules_opt/src/pass.rs b/hercules_opt/src/pass.rs index d24b6563f6e330df89a5206349ff1103a04e607b..1e7104ce6461b94d2404fb8f59c29b2b7c75a67e 100644 --- a/hercules_opt/src/pass.rs +++ b/hercules_opt/src/pass.rs @@ -25,6 +25,7 @@ pub enum Pass { PhiElim, Forkify, ForkGuardElim, + SLF, WritePredication, Predication, SROA, @@ -470,6 +471,38 @@ impl PassManager { } self.clear_analyses(); } + Pass::SLF => { + self.make_def_uses(); + self.make_reverse_postorders(); + self.make_typing(); + let def_uses = self.def_uses.as_ref().unwrap(); + let reverse_postorders = self.reverse_postorders.as_ref().unwrap(); + let typing = self.typing.as_ref().unwrap(); + for idx in 0..self.module.functions.len() { + let constants_ref = + RefCell::new(std::mem::take(&mut self.module.constants)); + let dynamic_constants_ref = + RefCell::new(std::mem::take(&mut self.module.dynamic_constants)); + let types_ref = RefCell::new(std::mem::take(&mut self.module.types)); + let mut editor = FunctionEditor::new( + &mut self.module.functions[idx], + FunctionID::new(idx), + &constants_ref, + &dynamic_constants_ref, + &types_ref, + &def_uses[idx], + ); + slf(&mut editor, &reverse_postorders[idx], &typing[idx]); + + self.module.constants = constants_ref.take(); + self.module.dynamic_constants = dynamic_constants_ref.take(); + self.module.types = types_ref.take(); + + println!("{}", self.module.functions[idx].name); + self.module.functions[idx].delete_gravestones(); + } + self.clear_analyses(); + } Pass::WritePredication => { self.make_def_uses(); let def_uses = self.def_uses.as_ref().unwrap(); diff --git a/hercules_opt/src/slf.rs b/hercules_opt/src/slf.rs index efbeae8147daafd1f4c9d4a53ae41c9e0c888903..981a0cce2d4dd1ba72ba3525aa9e31467cd6ecc7 100644 --- a/hercules_opt/src/slf.rs +++ b/hercules_opt/src/slf.rs @@ -54,7 +54,10 @@ impl Semilattice for SLFLattice { } fn bottom() -> Self { - panic!() + let mut subvalues = BTreeMap::new(); + // The empty indices set overlaps with all possible indices sets. + subvalues.insert(Box::new([]) as Box<[Index]>, None); + SLFLattice { subvalues } } } @@ -63,7 +66,7 @@ impl Semilattice for SLFLattice { * known values inside collections and replaces reads of those values with the * values directly. */ -pub fn slf(editor: &mut FunctionEditor, reverse_postorder: &Vec<NodeID>) { +pub fn slf(editor: &mut FunctionEditor, reverse_postorder: &Vec<NodeID>, typing: &Vec<TypeID>) { // First, run a dataflow analysis that looks at known values inside // collections. Thanks to the value semantics of Hercules IR, this analysis // is relatively simple and straightforward. @@ -95,9 +98,63 @@ pub fn slf(editor: &mut FunctionEditor, reverse_postorder: &Vec<NodeID>) { // Start with the indices of the `collect` input. let mut value = inputs[0].clone(); + // Any indices sets that overlap with `indices` become `None`, + // since we no longer know what's stored there. + for (other_indices, subvalue) in value.subvalues.iter_mut() { + if indices_may_overlap(other_indices, indices) { + *subvalue = None; + } + } + + // Track `data` at `indices`. + value.subvalues.insert(indices.clone(), Some(data)); + value } - _ => SLFLattice::top(), + _ => SLFLattice::bottom(), } }); + + // Second, look for reads where the indices set either: + // 1. Equal the indices of a known sub-value. Then, the read can be replaced + // by the known sub-value. + // 2. Otherwise, if the indices set doesn't overlap with any known or + // unknown sub-value, then the read can be replaced by a zero constant. + // 3. Otherwise, the read can't be replaced. + // Keep track of which nodes we've already replaced, since a sub-value we + // knew previously may be the ID of an old node replaced previously. + let mut replacements = BTreeMap::new(); + for id in editor.node_ids() { + let Node::Read { + collect, + ref indices, + } = editor.func().nodes[id.idx()] + else { + continue; + }; + let subvalues = &lattice[collect.idx()].subvalues; + + if let Some(sub_value) = subvalues.get(indices) + && let Some(mut known) = *sub_value + { + while let Some(replacement) = replacements.get(&known) { + known = *replacement; + } + editor.edit(|mut edit| { + edit = edit.replace_all_uses(id, known)?; + edit.delete_node(id) + }); + replacements.insert(id, known); + } else if !subvalues + .keys() + .any(|other_indices| indices_may_overlap(other_indices, indices)) + { + editor.edit(|mut edit| { + let zero = edit.add_zero_constant(typing[id.idx()]); + let zero = edit.add_node(Node::Constant { id: zero }); + edit = edit.replace_all_uses(id, zero)?; + edit.delete_node(id) + }); + } + } } diff --git a/juno_frontend/src/lib.rs b/juno_frontend/src/lib.rs index cfaf7a2687d062d2c4da3b2504a9097f753ca319..46d3489156d34f5152388d08e6e66a600600b4f8 100644 --- a/juno_frontend/src/lib.rs +++ b/juno_frontend/src/lib.rs @@ -182,6 +182,8 @@ pub fn compile_ir( add_pass!(pm, verify, WritePredication); add_pass!(pm, verify, PhiElim); add_pass!(pm, verify, DCE); + add_pass!(pm, verify, SLF); + add_pass!(pm, verify, DCE); add_pass!(pm, verify, Predication); add_pass!(pm, verify, DCE); add_pass!(pm, verify, CCP);