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(
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.
let mut select_top_phi_inputs = vec![];
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();
if let Node::Phi { control, data } = &mut node
&& *control == top_node
......@@ -372,7 +372,7 @@ pub fn outline(
if dom_return_values.contains(inside_id) {
// If this outside used value dominates this return,
// then return the value itself.
*inside_id
convert_id(*inside_id)
} else {
// If not, then return an Undef. Since this value
// doesn't dominate this return, it can't be used on
......@@ -408,7 +408,7 @@ pub fn outline(
// Return the return product.
outlined.nodes.push(Node::Return {
control: *exit,
control: convert_id(*exit),
data: construct_id,
});
}
......@@ -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.
*/
pub fn dumb_outline(
......@@ -568,7 +568,9 @@ pub fn dumb_outline(
dom: &DomTree,
to_be_function_id: FunctionID,
) -> Option<Function> {
collapse_returns(editor);
if !contains_between_control_flow(editor.func()) {
return None;
}
let partition = editor
.node_ids()
.filter(|id| {
......
......@@ -659,6 +659,39 @@ impl PassManager {
self.clear_analyses();
}
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_typing();
self.make_control_subgraphs();
......@@ -671,7 +704,6 @@ impl PassManager {
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)| {
......@@ -701,11 +733,23 @@ impl PassManager {
self.module.constants = constants_ref.take();
self.module.dynamic_constants = dynamic_constants_ref.take();
self.module.types = types_ref.take();
let edits: Vec<_> = editors.into_iter().map(|editor| editor.edits()).collect();
for idx in 0..edits.len() {
edits.extend(
editors
.into_iter()
.enumerate()
.map(|(idx, editor)| (idx, editor.edits())),
);
for (func_idx, edit) in edits {
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();
if let Some(plans) = self.plans.as_mut() {
plans[idx].fix_gravestones(&grave_mapping);
......
......@@ -264,3 +264,49 @@ pub fn collapse_returns(editor: &mut FunctionEditor) -> Option<NodeID> {
});
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