Avoid allocating jump arguments on the heap.

Instead of allocating a vector to store jump arguments for processing
later, just have the later code rescan through the predecessors to
obtain the values, which are memoized.

This also eliminates a linear search through the predecessor list when
splitting a critical edge.
This commit is contained in:
Dan Gohman
2017-09-01 12:11:30 -07:00
parent 9bc4264a33
commit 28779dc7e4

View File

@@ -168,7 +168,7 @@ where
enum ZeroOneOrMore<T> { enum ZeroOneOrMore<T> {
Zero(), Zero(),
One(T), One(T),
More(Vec<T>), More(),
} }
#[derive(Debug)] #[derive(Debug)]
@@ -409,7 +409,7 @@ where
temp_arg_var: Variable, temp_arg_var: Variable,
dest_ebb: Ebb, dest_ebb: Ebb,
) -> (Value, SideEffects) { ) -> (Value, SideEffects) {
let mut pred_values: ZeroOneOrMore<(Block, Inst, Value)> = ZeroOneOrMore::Zero(); let mut pred_values: ZeroOneOrMore<Value> = ZeroOneOrMore::Zero();
let ty = dfg.value_type(temp_arg_val); let ty = dfg.value_type(temp_arg_val);
let mut side_effects = SideEffects::new(); let mut side_effects = SideEffects::new();
@@ -418,7 +418,7 @@ where
// `use_var`'s traversal won't revisit these predecesors. // `use_var`'s traversal won't revisit these predecesors.
let mut preds = Vec::new(); let mut preds = Vec::new();
mem::swap(&mut preds, &mut self.predecessors_mut(dest_ebb)); mem::swap(&mut preds, &mut self.predecessors_mut(dest_ebb));
for &(pred, last_inst) in &preds { for &(pred, _) in &preds {
// For each predecessor, we query what is the local SSA value corresponding // For each predecessor, we query what is the local SSA value corresponding
// to var and we put it as an argument of the branch instruction. // to var and we put it as an argument of the branch instruction.
let (pred_val, local_side_effects) = let (pred_val, local_side_effects) =
@@ -426,29 +426,21 @@ where
match pred_values { match pred_values {
ZeroOneOrMore::Zero() => { ZeroOneOrMore::Zero() => {
if pred_val != temp_arg_val { if pred_val != temp_arg_val {
pred_values = ZeroOneOrMore::One((pred, last_inst, pred_val)) pred_values = ZeroOneOrMore::One(pred_val);
} }
} }
ZeroOneOrMore::One((old_pred, old_last_inst, old_val)) => { ZeroOneOrMore::One(old_val) => {
if pred_val != temp_arg_val && pred_val != old_val { if pred_val != temp_arg_val && pred_val != old_val {
// TODO: find a way to not allocate a vector pred_values = ZeroOneOrMore::More();
pred_values = ZeroOneOrMore::More(vec![
(old_pred, old_last_inst, old_val),
(pred, last_inst, pred_val),
]);
} }
} }
ZeroOneOrMore::More(ref mut jump_args_to_append) => { ZeroOneOrMore::More() => {}
jump_args_to_append.push((pred, last_inst, pred_val)); };
}
}
side_effects.append(local_side_effects); side_effects.append(local_side_effects);
} }
// Now that we're done iterating, move the predecessors list back.
debug_assert!(self.predecessors(dest_ebb).is_empty()); debug_assert!(self.predecessors(dest_ebb).is_empty());
*self.predecessors_mut(dest_ebb) = preds;
match pred_values { let result_val = match pred_values {
ZeroOneOrMore::Zero() => { ZeroOneOrMore::Zero() => {
// The variable is used but never defined before. This is an irregularity in the // The variable is used but never defined before. This is an irregularity in the
// code, but rather than throwing an error we silently initialize the variable to // code, but rather than throwing an error we silently initialize the variable to
@@ -470,38 +462,54 @@ where
panic!("value used but never declared and initialization not supported") panic!("value used but never declared and initialization not supported")
}; };
side_effects.instructions_added_to_ebbs.push(dest_ebb); side_effects.instructions_added_to_ebbs.push(dest_ebb);
(val, side_effects) val
} }
ZeroOneOrMore::One((_, _, pred_val)) => { ZeroOneOrMore::One(pred_val) => {
// Here all the predecessors use a single value to represent our variable // Here all the predecessors use a single value to represent our variable
// so we don't need to have it as an ebb argument. // so we don't need to have it as an ebb argument.
// We need to replace all the occurences of val with pred_val but since // We need to replace all the occurences of val with pred_val but since
// we can't afford a re-writing pass right now we just declare an alias. // we can't afford a re-writing pass right now we just declare an alias.
dfg.remove_ebb_arg(temp_arg_val); dfg.remove_ebb_arg(temp_arg_val);
dfg.change_to_alias(temp_arg_val, pred_val); dfg.change_to_alias(temp_arg_val, pred_val);
(pred_val, side_effects) pred_val
} }
ZeroOneOrMore::More(jump_args_to_append) => { ZeroOneOrMore::More() => {
// There is disagreement in the predecessors on which value to use so we have // There is disagreement in the predecessors on which value to use so we have
// to keep the ebb argument. // to keep the ebb argument.
for (pred_block, last_inst, pred_val) in jump_args_to_append { for &mut (ref mut pred_block, ref mut last_inst) in &mut preds {
match self.append_jump_argument( // We already did a full `use_var` above, so we can do just the fast path.
dfg, let pred_val = *self.variables
layout, .get(temp_arg_var)
last_inst, .unwrap()
pred_block, .get(&pred_block)
dest_ebb, .unwrap();
pred_val, if let Some((middle_ebb, middle_block, middle_jump_inst)) =
temp_arg_var, self.append_jump_argument(
jts, dfg,
) { layout,
None => (), *last_inst,
Some(middle_ebb) => side_effects.split_ebbs_created.push(middle_ebb), *pred_block,
}; dest_ebb,
pred_val,
temp_arg_var,
jts,
)
{
*pred_block = middle_block;
*last_inst = middle_jump_inst;
side_effects.split_ebbs_created.push(middle_ebb);
}
} }
(temp_arg_val, side_effects) debug_assert!(self.predecessors(dest_ebb).is_empty());
temp_arg_val
} }
} };
// Now that we're done, move the predecessors list back.
debug_assert!(self.predecessors(dest_ebb).is_empty());
*self.predecessors_mut(dest_ebb) = preds;
(result_val, side_effects)
} }
/// Appends a jump argument to a jump instruction, returns ebb created in case of /// Appends a jump argument to a jump instruction, returns ebb created in case of
@@ -516,7 +524,7 @@ where
val: Value, val: Value,
var: Variable, var: Variable,
jts: &mut JumpTables, jts: &mut JumpTables,
) -> Option<Ebb> { ) -> Option<(Ebb, Block, Inst)> {
match dfg[jump_inst].analyze_branch(&dfg.value_lists) { match dfg[jump_inst].analyze_branch(&dfg.value_lists) {
BranchInfo::NotABranch => { BranchInfo::NotABranch => {
panic!("you have declared a non-branch instruction as a predecessor to an ebb"); panic!("you have declared a non-branch instruction as a predecessor to an ebb");
@@ -553,11 +561,8 @@ where
let mut cur = Cursor::new(layout); let mut cur = Cursor::new(layout);
cur.goto_bottom(middle_ebb); cur.goto_bottom(middle_ebb);
let middle_jump_inst = dfg.ins(&mut cur).jump(dest_ebb, &[val]); let middle_jump_inst = dfg.ins(&mut cur).jump(dest_ebb, &[val]);
let dest_header_block = self.header_block(dest_ebb);
self.blocks[dest_header_block].add_predecessor(block, middle_jump_inst);
self.blocks[dest_header_block].remove_predecessor(jump_inst);
self.def_var(var, val, block); self.def_var(var, val, block);
Some(middle_ebb) Some((middle_ebb, block, middle_jump_inst))
} }
} }
} }