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:
@@ -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) => {
|
|
||||||
jump_args_to_append.push((pred, last_inst, pred_val));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ZeroOneOrMore::More() => {}
|
||||||
|
};
|
||||||
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.
|
||||||
|
let pred_val = *self.variables
|
||||||
|
.get(temp_arg_var)
|
||||||
|
.unwrap()
|
||||||
|
.get(&pred_block)
|
||||||
|
.unwrap();
|
||||||
|
if let Some((middle_ebb, middle_block, middle_jump_inst)) =
|
||||||
|
self.append_jump_argument(
|
||||||
dfg,
|
dfg,
|
||||||
layout,
|
layout,
|
||||||
last_inst,
|
*last_inst,
|
||||||
pred_block,
|
*pred_block,
|
||||||
dest_ebb,
|
dest_ebb,
|
||||||
pred_val,
|
pred_val,
|
||||||
temp_arg_var,
|
temp_arg_var,
|
||||||
jts,
|
jts,
|
||||||
) {
|
)
|
||||||
None => (),
|
{
|
||||||
Some(middle_ebb) => side_effects.split_ebbs_created.push(middle_ebb),
|
*pred_block = middle_block;
|
||||||
|
*last_inst = middle_jump_inst;
|
||||||
|
side_effects.split_ebbs_created.push(middle_ebb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
debug_assert!(self.predecessors(dest_ebb).is_empty());
|
||||||
|
temp_arg_val
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
|
||||||
(temp_arg_val, side_effects)
|
// 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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user