Skip to content
Snippets Groups Projects
Commit 8fbc8990 authored by Russel Arbore's avatar Russel Arbore
Browse files

More fixes to outline

parent 0012148d
No related branches found
No related tags found
1 merge request!79More fixes to outline
Pipeline #200654 passed
...@@ -228,27 +228,27 @@ pub fn outline( ...@@ -228,27 +228,27 @@ pub fn outline(
outlined.nodes.push(Node::Parameter { index }); outlined.nodes.push(Node::Parameter { index });
} }
let convert_id = |old| {
if let Some(new) = old_to_new_id.get(&old) {
// Map a use inside the partition to its new ID in the
// outlined function.
*new
} else if let Some(idx) = outside_id_to_param_idx.get(&old) {
// Map a data use outside the partition to the ID of the
// corresponding parameter node.
NodeID::new(idx + 1)
} else {
// Map a control use outside the partition to the start
// node. This corresponds to the outside predecessors of the
// top node and the use of the old start by constant,
// dynamic constant, parameter, and undef nodes.
NodeID::new(0)
}
};
// Add the nodes from the partition. // Add the nodes from the partition.
let mut select_top_phi_inputs = vec![]; let mut select_top_phi_inputs = vec![];
for id in partition.iter() { for id in partition.iter() {
let convert_id = |old| {
if let Some(new) = old_to_new_id.get(&old) {
// Map a use inside the partition to its new ID in the
// outlined function.
*new
} else if let Some(idx) = outside_id_to_param_idx.get(&old) {
// Map a data use outside the partition to the ID of the
// corresponding parameter node.
NodeID::new(idx + 1)
} else {
// Map a control use outside the partition to the start
// node. This corresponds to the outside predecessors of the
// top node and the use of the old start by constant,
// dynamic constant, parameter, and undef nodes.
NodeID::new(0)
}
};
let mut node = edit.get_node(*id).clone(); let mut node = edit.get_node(*id).clone();
if let Node::Phi { control, data } = &mut node if let Node::Phi { control, data } = &mut node
&& *control == top_node && *control == top_node
...@@ -372,7 +372,7 @@ pub fn outline( ...@@ -372,7 +372,7 @@ pub fn outline(
if dom_return_values.contains(inside_id) { if dom_return_values.contains(inside_id) {
// If this outside used value dominates this return, // If this outside used value dominates this return,
// then return the value itself. // then return the value itself.
*inside_id convert_id(*inside_id)
} else { } else {
// If not, then return an Undef. Since this value // If not, then return an Undef. Since this value
// doesn't dominate this return, it can't be used on // doesn't dominate this return, it can't be used on
...@@ -408,7 +408,7 @@ pub fn outline( ...@@ -408,7 +408,7 @@ pub fn outline(
// Return the return product. // Return the return product.
outlined.nodes.push(Node::Return { outlined.nodes.push(Node::Return {
control: *exit, control: convert_id(*exit),
data: construct_id, data: construct_id,
}); });
} }
...@@ -558,7 +558,7 @@ pub fn outline( ...@@ -558,7 +558,7 @@ pub fn outline(
} }
/* /*
* Just outlines all of a function accept the entry and return. Minimum work * Just outlines all of a function except the entry and return. Minimum work
* needed to cause runtime Rust code to be generated as necessary. * needed to cause runtime Rust code to be generated as necessary.
*/ */
pub fn dumb_outline( pub fn dumb_outline(
...@@ -568,7 +568,9 @@ pub fn dumb_outline( ...@@ -568,7 +568,9 @@ pub fn dumb_outline(
dom: &DomTree, dom: &DomTree,
to_be_function_id: FunctionID, to_be_function_id: FunctionID,
) -> Option<Function> { ) -> Option<Function> {
collapse_returns(editor); if !contains_between_control_flow(editor.func()) {
return None;
}
let partition = editor let partition = editor
.node_ids() .node_ids()
.filter(|id| { .filter(|id| {
......
...@@ -659,6 +659,39 @@ impl PassManager { ...@@ -659,6 +659,39 @@ impl PassManager {
self.clear_analyses(); self.clear_analyses();
} }
Pass::Outline => { Pass::Outline => {
self.make_def_uses();
let def_uses = self.def_uses.as_ref().unwrap();
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 old_num_funcs = self.module.functions.len();
let mut editors: Vec<_> =
zip(self.module.functions.iter_mut(), def_uses.iter())
.map(|(func, def_use)| {
FunctionEditor::new(
func,
&constants_ref,
&dynamic_constants_ref,
&types_ref,
def_use,
)
})
.collect();
for editor in editors.iter_mut() {
collapse_returns(editor);
ensure_between_control_flow(editor);
}
let mut edits: Vec<_> = editors
.into_iter()
.enumerate()
.map(|(idx, editor)| (idx, editor.edits()))
.collect();
self.module.constants = constants_ref.take();
self.module.dynamic_constants = dynamic_constants_ref.take();
self.module.types = types_ref.take();
self.clear_analyses();
self.make_def_uses(); self.make_def_uses();
self.make_typing(); self.make_typing();
self.make_control_subgraphs(); self.make_control_subgraphs();
...@@ -671,7 +704,6 @@ impl PassManager { ...@@ -671,7 +704,6 @@ impl PassManager {
let dynamic_constants_ref = let dynamic_constants_ref =
RefCell::new(std::mem::take(&mut self.module.dynamic_constants)); RefCell::new(std::mem::take(&mut self.module.dynamic_constants));
let types_ref = RefCell::new(std::mem::take(&mut self.module.types)); let types_ref = RefCell::new(std::mem::take(&mut self.module.types));
let old_num_funcs = self.module.functions.len();
let mut editors: Vec<_> = let mut editors: Vec<_> =
zip(self.module.functions.iter_mut(), def_uses.iter()) zip(self.module.functions.iter_mut(), def_uses.iter())
.map(|(func, def_use)| { .map(|(func, def_use)| {
...@@ -701,11 +733,23 @@ impl PassManager { ...@@ -701,11 +733,23 @@ impl PassManager {
self.module.constants = constants_ref.take(); self.module.constants = constants_ref.take();
self.module.dynamic_constants = dynamic_constants_ref.take(); self.module.dynamic_constants = dynamic_constants_ref.take();
self.module.types = types_ref.take(); self.module.types = types_ref.take();
let edits: Vec<_> = editors.into_iter().map(|editor| editor.edits()).collect(); edits.extend(
for idx in 0..edits.len() { editors
.into_iter()
.enumerate()
.map(|(idx, editor)| (idx, editor.edits())),
);
for (func_idx, edit) in edits {
if let Some(plans) = self.plans.as_mut() { if let Some(plans) = self.plans.as_mut() {
repair_plan(&mut plans[idx], &self.module.functions[idx], &edits[idx]); repair_plan(
&mut plans[func_idx],
&self.module.functions[func_idx],
&edit,
);
} }
}
for idx in 0..self.module.functions.len() {
let grave_mapping = self.module.functions[idx].delete_gravestones(); let grave_mapping = self.module.functions[idx].delete_gravestones();
if let Some(plans) = self.plans.as_mut() { if let Some(plans) = self.plans.as_mut() {
plans[idx].fix_gravestones(&grave_mapping); plans[idx].fix_gravestones(&grave_mapping);
......
...@@ -264,3 +264,49 @@ pub fn collapse_returns(editor: &mut FunctionEditor) -> Option<NodeID> { ...@@ -264,3 +264,49 @@ pub fn collapse_returns(editor: &mut FunctionEditor) -> Option<NodeID> {
}); });
new_return new_return
} }
pub fn contains_between_control_flow(func: &Function) -> bool {
let num_control = func.nodes.iter().filter(|node| node.is_control()).count();
assert!(num_control >= 2, "PANIC: A Hercules function must have at least two control nodes: a start node and at least one return node.");
num_control > 2
}
/*
* Top level function to ensure a Hercules function contains at least one
* control node that isn't the start or return nodes.
*/
pub fn ensure_between_control_flow(editor: &mut FunctionEditor) -> Option<NodeID> {
if !contains_between_control_flow(editor.func()) {
let ret = editor
.node_ids()
.skip(1)
.filter(|id| editor.func().nodes[id.idx()].is_control())
.next()
.unwrap();
let Node::Return { control, data } = editor.func().nodes[ret.idx()] else {
panic!("PANIC: A Hercules function with only two control nodes must have a return node be the other control node, other than the start node.")
};
assert_eq!(control, NodeID::new(0), "PANIC: The only other control node in a Hercules function, the return node, is not using the start node.");
let mut region_id = None;
editor.edit(|mut edit| {
edit = edit.delete_node(ret)?;
region_id = Some(edit.add_node(Node::Region {
preds: Box::new([NodeID::new(0)]),
}));
edit.add_node(Node::Return {
control: region_id.unwrap(),
data,
});
Ok(edit)
});
region_id
} else {
Some(
editor
.get_users(NodeID::new(0))
.filter(|id| editor.func().nodes[id.idx()].is_control())
.next()
.unwrap(),
)
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment