Keep EBB arguments in a ValueList.

This is the first step of the value list refactoring which will replace
linked lists of values with value lists.

- Keep a ValueList in the EbbData struct containing all the EBB
  arguments.
- Change dfg.ebb_args() to return a slice instead of an iterator.

This leaves us in a temporary hybrid state where we maintain both a
linked list and a ValueList vector of the EBB arguments.
This commit is contained in:
Jakob Stoklund Olesen
2017-04-11 11:36:50 -07:00
parent 1c890f317d
commit ccba325b6c
6 changed files with 40 additions and 48 deletions

View File

@@ -222,6 +222,11 @@ impl<T: EntityRef> ListPool<T> {
} }
impl<T: EntityRef> EntityList<T> { impl<T: EntityRef> EntityList<T> {
/// Create a new empty list.
pub fn new() -> Self {
Default::default()
}
/// Returns `true` if the list has a length of 0. /// Returns `true` if the list has a length of 0.
pub fn is_empty(&self) -> bool { pub fn is_empty(&self) -> bool {
// 0 is a magic value for the empty list. Any list in the pool array must have a positive // 0 is a magic value for the empty list. Any list in the pool array must have a positive

View File

@@ -1,6 +1,6 @@
//! Data flow graph tracking Instructions, Values, and EBBs. //! Data flow graph tracking Instructions, Values, and EBBs.
use ir::{Ebb, Inst, Value, Type, SigRef, Signature, FuncRef, ValueListPool}; use ir::{Ebb, Inst, Value, Type, SigRef, Signature, FuncRef, ValueList, ValueListPool};
use ir::entities::ExpandedValue; use ir::entities::ExpandedValue;
use ir::instructions::{Opcode, InstructionData, CallInfo}; use ir::instructions::{Opcode, InstructionData, CallInfo};
use ir::extfunc::ExtFuncData; use ir::extfunc::ExtFuncData;
@@ -687,17 +687,7 @@ impl DataFlowGraph {
/// Get the number of arguments on `ebb`. /// Get the number of arguments on `ebb`.
pub fn num_ebb_args(&self, ebb: Ebb) -> usize { pub fn num_ebb_args(&self, ebb: Ebb) -> usize {
match self.ebbs[ebb].last_arg.expand() { self.ebbs[ebb].args.len(&self.value_lists)
None => 0,
Some(last_arg) => {
if let ExpandedValue::Table(idx) = last_arg.expand() {
if let ValueData::Arg { num, .. } = self.extended_values[idx] {
return num as usize + 1;
}
}
panic!("inconsistent value table entry for EBB argument");
}
}
} }
/// Append an argument with type `ty` to `ebb`. /// Append an argument with type `ty` to `ebb`.
@@ -712,12 +702,9 @@ impl DataFlowGraph {
val val
} }
/// Iterate through the arguments to an EBB. /// Get the arguments to an EBB.
pub fn ebb_args(&self, ebb: Ebb) -> Values { pub fn ebb_args(&self, ebb: Ebb) -> &[Value] {
Values { self.ebbs[ebb].args.as_slice(&self.value_lists)
dfg: self,
cur: self.ebbs[ebb].first_arg.into(),
}
} }
/// Replace an EBB argument with a new value of type `ty`. /// Replace an EBB argument with a new value of type `ty`.
@@ -752,6 +739,8 @@ impl DataFlowGraph {
old_data); old_data);
}; };
self.ebbs[ebb].args.as_mut_slice(&mut self.value_lists)[num as usize] = new_arg;
// Now fix up the linked lists. // Now fix up the linked lists.
if self.ebbs[ebb].last_arg.expand() == Some(old_arg) { if self.ebbs[ebb].last_arg.expand() == Some(old_arg) {
self.ebbs[ebb].last_arg = new_arg.into(); self.ebbs[ebb].last_arg = new_arg.into();
@@ -804,6 +793,7 @@ impl DataFlowGraph {
let first = self.ebbs[ebb].first_arg.into(); let first = self.ebbs[ebb].first_arg.into();
self.ebbs[ebb].first_arg = None.into(); self.ebbs[ebb].first_arg = None.into();
self.ebbs[ebb].last_arg = None.into(); self.ebbs[ebb].last_arg = None.into();
self.ebbs[ebb].args.clear(&mut self.value_lists);
first first
} }
@@ -815,6 +805,7 @@ impl DataFlowGraph {
/// ///
/// In almost all cases, you should be using `append_ebb_arg()` instead of this method. /// In almost all cases, you should be using `append_ebb_arg()` instead of this method.
pub fn attach_ebb_arg(&mut self, ebb: Ebb, arg: Value) { pub fn attach_ebb_arg(&mut self, ebb: Ebb, arg: Value) {
self.ebbs[ebb].args.push(arg, &mut self.value_lists);
let arg_num = match self.ebbs[ebb].last_arg.map(|v| v.expand()) { let arg_num = match self.ebbs[ebb].last_arg.map(|v| v.expand()) {
// If last_argument is `None`, we're adding the first EBB argument. // If last_argument is `None`, we're adding the first EBB argument.
None => { None => {
@@ -861,6 +852,9 @@ impl DataFlowGraph {
// match the function arguments. // match the function arguments.
#[derive(Clone)] #[derive(Clone)]
struct EbbData { struct EbbData {
// List of arguments to this EBB.
args: ValueList,
// First argument to this EBB, or `None` if the block has no arguments. // First argument to this EBB, or `None` if the block has no arguments.
// //
// The arguments are all `ValueData::Argument` entries that form a linked list from `first_arg` // The arguments are all `ValueData::Argument` entries that form a linked list from `first_arg`
@@ -874,6 +868,7 @@ struct EbbData {
impl EbbData { impl EbbData {
fn new() -> EbbData { fn new() -> EbbData {
EbbData { EbbData {
args: ValueList::new(),
first_arg: None.into(), first_arg: None.into(),
last_arg: None.into(), last_arg: None.into(),
} }
@@ -966,28 +961,20 @@ mod tests {
let ebb = dfg.make_ebb(); let ebb = dfg.make_ebb();
assert_eq!(ebb.to_string(), "ebb0"); assert_eq!(ebb.to_string(), "ebb0");
assert_eq!(dfg.num_ebb_args(ebb), 0); assert_eq!(dfg.num_ebb_args(ebb), 0);
assert_eq!(dfg.ebb_args(ebb).next(), None); assert_eq!(dfg.ebb_args(ebb), &[]);
assert_eq!(dfg.detach_ebb_args(ebb), None); assert_eq!(dfg.detach_ebb_args(ebb), None);
assert_eq!(dfg.num_ebb_args(ebb), 0); assert_eq!(dfg.num_ebb_args(ebb), 0);
assert_eq!(dfg.ebb_args(ebb).next(), None); assert_eq!(dfg.ebb_args(ebb), &[]);
let arg1 = dfg.append_ebb_arg(ebb, types::F32); let arg1 = dfg.append_ebb_arg(ebb, types::F32);
assert_eq!(arg1.to_string(), "vx0"); assert_eq!(arg1.to_string(), "vx0");
assert_eq!(dfg.num_ebb_args(ebb), 1); assert_eq!(dfg.num_ebb_args(ebb), 1);
{ assert_eq!(dfg.ebb_args(ebb), &[arg1]);
let mut args1 = dfg.ebb_args(ebb);
assert_eq!(args1.next(), Some(arg1));
assert_eq!(args1.next(), None);
}
let arg2 = dfg.append_ebb_arg(ebb, types::I16); let arg2 = dfg.append_ebb_arg(ebb, types::I16);
assert_eq!(arg2.to_string(), "vx1"); assert_eq!(arg2.to_string(), "vx1");
assert_eq!(dfg.num_ebb_args(ebb), 2); assert_eq!(dfg.num_ebb_args(ebb), 2);
{ assert_eq!(dfg.ebb_args(ebb), &[arg1, arg2]);
let mut args2 = dfg.ebb_args(ebb);
assert_eq!(args2.next(), Some(arg1));
assert_eq!(args2.next(), Some(arg2));
assert_eq!(args2.next(), None);
}
assert_eq!(dfg.value_def(arg1), ValueDef::Arg(ebb, 0)); assert_eq!(dfg.value_def(arg1), ValueDef::Arg(ebb, 0));
assert_eq!(dfg.value_def(arg2), ValueDef::Arg(ebb, 1)); assert_eq!(dfg.value_def(arg2), ValueDef::Arg(ebb, 1));
@@ -997,7 +984,7 @@ mod tests {
// Swap the two EBB arguments. // Swap the two EBB arguments.
let take1 = dfg.detach_ebb_args(ebb).unwrap(); let take1 = dfg.detach_ebb_args(ebb).unwrap();
assert_eq!(dfg.num_ebb_args(ebb), 0); assert_eq!(dfg.num_ebb_args(ebb), 0);
assert_eq!(dfg.ebb_args(ebb).next(), None); assert_eq!(dfg.ebb_args(ebb), &[]);
let take2 = dfg.next_ebb_arg(take1).unwrap(); let take2 = dfg.next_ebb_arg(take1).unwrap();
assert_eq!(take1, arg1); assert_eq!(take1, arg1);
assert_eq!(take2, arg2); assert_eq!(take2, arg2);
@@ -1005,7 +992,7 @@ mod tests {
dfg.attach_ebb_arg(ebb, take2); dfg.attach_ebb_arg(ebb, take2);
let arg3 = dfg.append_ebb_arg(ebb, types::I32); let arg3 = dfg.append_ebb_arg(ebb, types::I32);
dfg.attach_ebb_arg(ebb, take1); dfg.attach_ebb_arg(ebb, take1);
assert_eq!(dfg.ebb_args(ebb).collect::<Vec<_>>(), [take2, arg3, take1]); assert_eq!(dfg.ebb_args(ebb), &[take2, arg3, take1]);
} }
#[test] #[test]
@@ -1018,24 +1005,24 @@ mod tests {
let new1 = dfg.replace_ebb_arg(arg1, types::I64); let new1 = dfg.replace_ebb_arg(arg1, types::I64);
assert_eq!(dfg.value_type(arg1), types::F32); assert_eq!(dfg.value_type(arg1), types::F32);
assert_eq!(dfg.value_type(new1), types::I64); assert_eq!(dfg.value_type(new1), types::I64);
assert_eq!(dfg.ebb_args(ebb).collect::<Vec<_>>(), [new1]); assert_eq!(dfg.ebb_args(ebb), &[new1]);
dfg.attach_ebb_arg(ebb, arg1); dfg.attach_ebb_arg(ebb, arg1);
assert_eq!(dfg.ebb_args(ebb).collect::<Vec<_>>(), [new1, arg1]); assert_eq!(dfg.ebb_args(ebb), &[new1, arg1]);
let new2 = dfg.replace_ebb_arg(arg1, types::I8); let new2 = dfg.replace_ebb_arg(arg1, types::I8);
assert_eq!(dfg.value_type(arg1), types::F32); assert_eq!(dfg.value_type(arg1), types::F32);
assert_eq!(dfg.value_type(new2), types::I8); assert_eq!(dfg.value_type(new2), types::I8);
assert_eq!(dfg.ebb_args(ebb).collect::<Vec<_>>(), [new1, new2]); assert_eq!(dfg.ebb_args(ebb), &[new1, new2]);
dfg.attach_ebb_arg(ebb, arg1); dfg.attach_ebb_arg(ebb, arg1);
assert_eq!(dfg.ebb_args(ebb).collect::<Vec<_>>(), [new1, new2, arg1]); assert_eq!(dfg.ebb_args(ebb), &[new1, new2, arg1]);
let new3 = dfg.replace_ebb_arg(new2, types::I16); let new3 = dfg.replace_ebb_arg(new2, types::I16);
assert_eq!(dfg.value_type(new1), types::I64); assert_eq!(dfg.value_type(new1), types::I64);
assert_eq!(dfg.value_type(new2), types::I8); assert_eq!(dfg.value_type(new2), types::I8);
assert_eq!(dfg.value_type(new3), types::I16); assert_eq!(dfg.value_type(new3), types::I16);
assert_eq!(dfg.ebb_args(ebb).collect::<Vec<_>>(), [new1, new3, arg1]); assert_eq!(dfg.ebb_args(ebb), &[new1, new3, arg1]);
} }
#[test] #[test]

View File

@@ -182,7 +182,7 @@ impl LiveValueTracker {
// Now add all the live arguments to `ebb`. // Now add all the live arguments to `ebb`.
let first_arg = self.live.values.len(); let first_arg = self.live.values.len();
for value in dfg.ebb_args(ebb) { for &value in dfg.ebb_args(ebb) {
let lr = liveness let lr = liveness
.get(value) .get(value)
.expect("EBB argument value has no live range"); .expect("EBB argument value has no live range");

View File

@@ -151,7 +151,7 @@ impl<'a> Verifier<'a> {
} }
// Arguments belong to the correct ebb. // Arguments belong to the correct ebb.
for arg in self.func.dfg.ebb_args(ebb) { for &arg in self.func.dfg.ebb_args(ebb) {
match self.func.dfg.value_def(arg) { match self.func.dfg.value_def(arg) {
ValueDef::Arg(arg_ebb, _) => { ValueDef::Arg(arg_ebb, _) => {
if ebb != arg_ebb { if ebb != arg_ebb {
@@ -405,7 +405,7 @@ impl<'a> Verifier<'a> {
return err!(ebb, "entry block arguments must match function signature"); return err!(ebb, "entry block arguments must match function signature");
} }
for (i, arg) in self.func.dfg.ebb_args(ebb).enumerate() { for (i, &arg) in self.func.dfg.ebb_args(ebb).iter().enumerate() {
let arg_type = self.func.dfg.value_type(arg); let arg_type = self.func.dfg.value_type(arg);
if arg_type != expected_types[i].value_type { if arg_type != expected_types[i].value_type {
return err!(ebb, return err!(ebb,
@@ -510,7 +510,8 @@ impl<'a> Verifier<'a> {
let iter = self.func let iter = self.func
.dfg .dfg
.ebb_args(ebb) .ebb_args(ebb)
.map(|v| self.func.dfg.value_type(v)); .iter()
.map(|&v| self.func.dfg.value_type(v));
self.typecheck_variable_args_iterator(inst, iter)?; self.typecheck_variable_args_iterator(inst, iter)?;
} }
BranchInfo::Table(table) => { BranchInfo::Table(table) => {

View File

@@ -95,7 +95,7 @@ pub fn write_ebb_header(w: &mut Write, func: &Function, ebb: Ebb) -> Result {
write!(w, " ")?; write!(w, " ")?;
} }
let mut args = func.dfg.ebb_args(ebb); let mut args = func.dfg.ebb_args(ebb).iter().cloned();
match args.next() { match args.next() {
None => return writeln!(w, "{}:", ebb), None => return writeln!(w, "{}:", ebb),
Some(arg) => { Some(arg) => {

View File

@@ -1895,13 +1895,12 @@ mod tests {
let mut ebbs = func.layout.ebbs(); let mut ebbs = func.layout.ebbs();
let ebb0 = ebbs.next().unwrap(); let ebb0 = ebbs.next().unwrap();
assert_eq!(func.dfg.ebb_args(ebb0).next(), None); assert_eq!(func.dfg.ebb_args(ebb0), &[]);
let ebb4 = ebbs.next().unwrap(); let ebb4 = ebbs.next().unwrap();
let mut ebb4_args = func.dfg.ebb_args(ebb4); let ebb4_args = func.dfg.ebb_args(ebb4);
let arg0 = ebb4_args.next().unwrap(); assert_eq!(ebb4_args.len(), 1);
assert_eq!(func.dfg.value_type(arg0), types::I32); assert_eq!(func.dfg.value_type(ebb4_args[0]), types::I32);
assert_eq!(ebb4_args.next(), None);
} }
#[test] #[test]