Replace inst_order with Layout in Function.

The Layout also handles EBB layout, so new append_ebb calls are necessary.

- Rewrite callers to use the public data member 'layout'.
- Implement Debug for Function in terms of the write module to avoid deriving
  it.
This commit is contained in:
Jakob Stoklund Olesen
2016-07-18 18:23:32 -07:00
parent 0ef0937016
commit d73c2c9dc0
5 changed files with 58 additions and 105 deletions

View File

@@ -55,7 +55,7 @@ impl ControlFlowGraph {
for ebb in func.ebbs_numerically() { for ebb in func.ebbs_numerically() {
// Flips to true when a terminating instruction is seen. So that if additional // Flips to true when a terminating instruction is seen. So that if additional
// instructions occur an error may be returned. // instructions occur an error may be returned.
for inst in func.ebb_insts(ebb) { for inst in func.layout.ebb_insts(ebb) {
match func[inst] { match func[inst] {
InstructionData::Branch { ty: _, opcode: _, ref data } => { InstructionData::Branch { ty: _, opcode: _, ref data } => {
cfg.add_predecessor(data.destination, (ebb, inst)); cfg.add_predecessor(data.destination, (ebb, inst));
@@ -109,9 +109,13 @@ mod tests {
#[test] #[test]
fn no_predecessors() { fn no_predecessors() {
let mut func = Function::new(); let mut func = Function::new();
func.make_ebb(); let ebb0 = func.make_ebb();
func.make_ebb(); let ebb1 = func.make_ebb();
func.make_ebb(); let ebb2 = func.make_ebb();
func.layout.append_ebb(ebb0);
func.layout.append_ebb(ebb1);
func.layout.append_ebb(ebb2);
let cfg = ControlFlowGraph::new(&func); let cfg = ControlFlowGraph::new(&func);
let nodes = cfg.iter().collect::<Vec<_>>(); let nodes = cfg.iter().collect::<Vec<_>>();
assert_eq!(nodes.len(), 3); assert_eq!(nodes.len(), 3);
@@ -129,18 +133,21 @@ mod tests {
let ebb0 = func.make_ebb(); let ebb0 = func.make_ebb();
let ebb1 = func.make_ebb(); let ebb1 = func.make_ebb();
let ebb2 = func.make_ebb(); let ebb2 = func.make_ebb();
func.layout.append_ebb(ebb0);
func.layout.append_ebb(ebb1);
func.layout.append_ebb(ebb2);
let br_ebb0_ebb2 = make_inst::branch(&mut func, ebb2); let br_ebb0_ebb2 = make_inst::branch(&mut func, ebb2);
func.append_inst(ebb0, br_ebb0_ebb2); func.layout.append_inst(br_ebb0_ebb2, ebb0);
let jmp_ebb0_ebb1 = make_inst::jump(&mut func, ebb1); let jmp_ebb0_ebb1 = make_inst::jump(&mut func, ebb1);
func.append_inst(ebb0, jmp_ebb0_ebb1); func.layout.append_inst(jmp_ebb0_ebb1, ebb0);
let br_ebb1_ebb1 = make_inst::branch(&mut func, ebb1); let br_ebb1_ebb1 = make_inst::branch(&mut func, ebb1);
func.append_inst(ebb1, br_ebb1_ebb1); func.layout.append_inst(br_ebb1_ebb1, ebb1);
let jmp_ebb1_ebb2 = make_inst::jump(&mut func, ebb2); let jmp_ebb1_ebb2 = make_inst::jump(&mut func, ebb2);
func.append_inst(ebb1, jmp_ebb1_ebb2); func.layout.append_inst(jmp_ebb1_ebb2, ebb1);
let cfg = ControlFlowGraph::new(&func); let cfg = ControlFlowGraph::new(&func);
let ebb0_predecessors = cfg.get_predecessors(ebb0).unwrap(); let ebb0_predecessors = cfg.get_predecessors(ebb0).unwrap();

View File

@@ -2,9 +2,10 @@
use types::{Type, FunctionName, Signature, VOID}; use types::{Type, FunctionName, Signature, VOID};
use entity_map::EntityRef; use entity_map::EntityRef;
use entities::{Ebb, NO_EBB, Inst, NO_INST, Value, NO_VALUE, ExpandedValue, StackSlot}; use entities::{Ebb, NO_EBB, Inst, Value, NO_VALUE, ExpandedValue, StackSlot};
use instructions::*; use instructions::*;
use std::fmt::{self, Display, Formatter}; use layout::Layout;
use std::fmt::{self, Debug, Display, Formatter};
use std::ops::{Index, IndexMut}; use std::ops::{Index, IndexMut};
/// A function. /// A function.
@@ -12,7 +13,6 @@ use std::ops::{Index, IndexMut};
/// The `Function` struct owns all of its instructions and extended basic blocks, and it works as a /// The `Function` struct owns all of its instructions and extended basic blocks, and it works as a
/// container for those objects by implementing both `Index<Inst>` and `Index<Ebb>`. /// container for those objects by implementing both `Index<Inst>` and `Index<Ebb>`.
/// ///
#[derive(Debug)]
pub struct Function { pub struct Function {
/// Name of this function. Mostly used by `.cton` files. /// Name of this function. Mostly used by `.cton` files.
pub name: FunctionName, pub name: FunctionName,
@@ -38,9 +38,8 @@ pub struct Function {
/// Others index into this table. /// Others index into this table.
extended_values: Vec<ValueData>, extended_values: Vec<ValueData>,
// Linked list nodes for the layout order of instructions. Forms a double linked list per EBB, /// Layout of EBBs and instructions in the function body.
// terminated in both ends by NO_INST. pub layout: Layout,
inst_order: Vec<InstNode>,
} }
impl Function { impl Function {
@@ -54,7 +53,7 @@ impl Function {
instructions: Vec::new(), instructions: Vec::new(),
extended_basic_blocks: Vec::new(), extended_basic_blocks: Vec::new(),
extended_values: Vec::new(), extended_values: Vec::new(),
inst_order: Vec::new(), layout: Layout::new(),
} }
} }
@@ -94,11 +93,6 @@ impl Function {
pub fn make_inst(&mut self, data: InstructionData) -> Inst { pub fn make_inst(&mut self, data: InstructionData) -> Inst {
let inst = Inst::new(self.instructions.len()); let inst = Inst::new(self.instructions.len());
self.instructions.push(data); self.instructions.push(data);
self.inst_order.push(InstNode {
prev: NO_INST,
next: NO_INST,
});
debug_assert_eq!(self.instructions.len(), self.inst_order.len());
inst inst
} }
@@ -234,32 +228,6 @@ impl Function {
} }
} }
/// Append an instruction to a basic block.
pub fn append_inst(&mut self, ebb: Ebb, inst: Inst) {
let old_last = self[ebb].last_inst;
self.inst_order[inst.index()] = InstNode {
prev: old_last,
next: NO_INST,
};
if old_last == NO_INST {
assert!(self[ebb].first_inst == NO_INST);
self[ebb].first_inst = inst;
} else {
self.inst_order[old_last.index()].next = inst;
}
self[ebb].last_inst = inst;
}
/// Iterate through the instructions in `ebb`.
pub fn ebb_insts<'a>(&'a self, ebb: Ebb) -> EbbInsts<'a> {
EbbInsts {
func: self,
cur: self[ebb].first_inst,
}
}
// Values. // Values.
/// Allocate an extended value entry. /// Allocate an extended value entry.
@@ -286,6 +254,13 @@ impl Function {
} }
} }
impl Debug for Function {
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
use write::function_to_string;
fmt.write_str(&function_to_string(self))
}
}
// ====--------------------------------------------------------------------------------------====// // ====--------------------------------------------------------------------------------------====//
// //
// Stack slot implementation. // Stack slot implementation.
@@ -362,12 +337,6 @@ pub struct EbbData {
/// Last argument to this EBB, or `NO_VALUE` if the block has no arguments. /// Last argument to this EBB, or `NO_VALUE` if the block has no arguments.
last_arg: Value, last_arg: Value,
/// First instruction in this block, or `NO_INST`.
first_inst: Inst,
/// Last instruction in this block, or `NO_INST`.
last_inst: Inst,
} }
impl EbbData { impl EbbData {
@@ -375,8 +344,6 @@ impl EbbData {
EbbData { EbbData {
first_arg: NO_VALUE, first_arg: NO_VALUE,
last_arg: NO_VALUE, last_arg: NO_VALUE,
first_inst: NO_INST,
last_inst: NO_INST,
} }
} }
} }
@@ -395,26 +362,6 @@ impl IndexMut<Ebb> for Function {
} }
} }
pub struct EbbInsts<'a> {
func: &'a Function,
cur: Inst,
}
impl<'a> Iterator for EbbInsts<'a> {
type Item = Inst;
fn next(&mut self) -> Option<Self::Item> {
let prev = self.cur;
if prev == NO_INST {
None
} else {
// Advance self.cur to the next inst.
self.cur = self.func.inst_order[prev.index()].next;
Some(prev)
}
}
}
/// Iterate through all EBBs in a function in numerical order. /// Iterate through all EBBs in a function in numerical order.
/// This order is stable, but has little significance to the semantics of the function. /// This order is stable, but has little significance to the semantics of the function.
pub struct NumericalEbbs { pub struct NumericalEbbs {
@@ -460,13 +407,6 @@ impl IndexMut<Inst> for Function {
} }
} }
/// A node in a double linked list of instructions is a basic block.
#[derive(Debug)]
struct InstNode {
prev: Inst,
next: Inst,
}
// ====--------------------------------------------------------------------------------------====// // ====--------------------------------------------------------------------------------------====//
// //
// Value implementation. // Value implementation.
@@ -590,6 +530,7 @@ mod tests {
let ebb = func.make_ebb(); let ebb = func.make_ebb();
assert_eq!(ebb.to_string(), "ebb0"); assert_eq!(ebb.to_string(), "ebb0");
assert_eq!(func.ebb_args(ebb).next(), None); assert_eq!(func.ebb_args(ebb).next(), None);
func.layout.append_ebb(ebb);
let arg1 = func.append_ebb_arg(ebb, types::F32); let arg1 = func.append_ebb_arg(ebb, types::F32);
assert_eq!(arg1.to_string(), "vx0"); assert_eq!(arg1.to_string(), "vx0");
@@ -612,33 +553,29 @@ mod tests {
assert_eq!(ebbs.next(), Some(ebb)); assert_eq!(ebbs.next(), Some(ebb));
assert_eq!(ebbs.next(), None); assert_eq!(ebbs.next(), None);
assert_eq!(func.ebb_insts(ebb).next(), None); assert_eq!(func.layout.ebb_insts(ebb).next(), None);
let inst = func.make_inst(InstructionData::Nullary { let inst = func.make_inst(InstructionData::Nullary {
opcode: Opcode::Iconst, opcode: Opcode::Iconst,
ty: types::I32, ty: types::I32,
}); });
func.append_inst(ebb, inst); func.layout.append_inst(inst, ebb);
{ {
let mut ii = func.ebb_insts(ebb); let mut ii = func.layout.ebb_insts(ebb);
assert_eq!(ii.next(), Some(inst)); assert_eq!(ii.next(), Some(inst));
assert_eq!(ii.next(), None); assert_eq!(ii.next(), None);
} }
assert_eq!(func[ebb].first_inst, inst);
assert_eq!(func[ebb].last_inst, inst);
let inst2 = func.make_inst(InstructionData::Nullary { let inst2 = func.make_inst(InstructionData::Nullary {
opcode: Opcode::Iconst, opcode: Opcode::Iconst,
ty: types::I32, ty: types::I32,
}); });
func.append_inst(ebb, inst2); func.layout.append_inst(inst2, ebb);
{ {
let mut ii = func.ebb_insts(ebb); let mut ii = func.layout.ebb_insts(ebb);
assert_eq!(ii.next(), Some(inst)); assert_eq!(ii.next(), Some(inst));
assert_eq!(ii.next(), Some(inst2)); assert_eq!(ii.next(), Some(inst2));
assert_eq!(ii.next(), None); assert_eq!(ii.next(), None);
} }
assert_eq!(func[ebb].first_inst, inst);
assert_eq!(func[ebb].last_inst, inst2);
} }
} }

View File

@@ -114,7 +114,7 @@ pub fn write_ebb_header(w: &mut Write, func: &Function, ebb: Ebb) -> Result {
pub fn write_ebb(w: &mut Write, func: &Function, ebb: Ebb) -> Result { pub fn write_ebb(w: &mut Write, func: &Function, ebb: Ebb) -> Result {
try!(write_ebb_header(w, func, ebb)); try!(write_ebb_header(w, func, ebb));
for inst in func.ebb_insts(ebb) { for inst in func.layout.ebb_insts(ebb) {
try!(write_instruction(w, func, inst)); try!(write_instruction(w, func, inst));
} }
Ok(()) Ok(())
@@ -251,6 +251,7 @@ mod tests {
"function foo() {\n ss0 = stack_slot 4\n}\n"); "function foo() {\n ss0 = stack_slot 4\n}\n");
let ebb = f.make_ebb(); let ebb = f.make_ebb();
f.layout.append_ebb(ebb);
assert_eq!(function_to_string(&f), assert_eq!(function_to_string(&f),
"function foo() {\n ss0 = stack_slot 4\n\nebb0:\n}\n"); "function foo() {\n ss0 = stack_slot 4\n\nebb0:\n}\n");

View File

@@ -101,6 +101,7 @@ impl Context {
// Allocate a new EBB and add a mapping src_ebb -> Ebb. // Allocate a new EBB and add a mapping src_ebb -> Ebb.
fn add_ebb(&mut self, src_ebb: Ebb, loc: &Location) -> Result<Ebb> { fn add_ebb(&mut self, src_ebb: Ebb, loc: &Location) -> Result<Ebb> {
let ebb = self.function.make_ebb(); let ebb = self.function.make_ebb();
self.function.layout.append_ebb(ebb);
if self.ebbs.insert(src_ebb, ebb).is_some() { if self.ebbs.insert(src_ebb, ebb).is_some() {
err!(loc, "duplicate EBB: {}", src_ebb) err!(loc, "duplicate EBB: {}", src_ebb)
} else { } else {
@@ -704,7 +705,7 @@ impl<'a> Parser<'a> {
let ctrl_typevar = try!(self.infer_typevar(ctx, opcode, explicit_ctrl_type, &inst_data)); let ctrl_typevar = try!(self.infer_typevar(ctx, opcode, explicit_ctrl_type, &inst_data));
let inst = ctx.function.make_inst(inst_data); let inst = ctx.function.make_inst(inst_data);
let num_results = ctx.function.make_inst_results(inst, ctrl_typevar); let num_results = ctx.function.make_inst_results(inst, ctrl_typevar);
ctx.function.append_inst(ebb, inst); ctx.function.layout.append_inst(inst, ebb);
ctx.add_inst_loc(inst, &opcode_loc); ctx.add_inst_loc(inst, &opcode_loc);
if results.len() != num_results { if results.len() != num_results {

View File

@@ -29,7 +29,11 @@ struct CFGPrinter<T: Write> {
impl<T: Write> CFGPrinter<T> { impl<T: Write> CFGPrinter<T> {
pub fn new(writer: T) -> CFGPrinter<T> { pub fn new(writer: T) -> CFGPrinter<T> {
CFGPrinter{level: 0, writer: writer, buffer: String::new()} CFGPrinter {
level: 0,
writer: writer,
buffer: String::new(),
}
} }
pub fn print(&mut self, func: &Function) -> Result<(), String> { pub fn print(&mut self, func: &Function) -> Result<(), String> {
@@ -103,23 +107,24 @@ impl<T: Write> CFGPrinter<T> {
fn ebb_subgraphs(&mut self, func: &Function) { fn ebb_subgraphs(&mut self, func: &Function) {
for ebb in func.ebbs_numerically() { for ebb in func.ebbs_numerically() {
let inst_data = func.ebb_insts(ebb) let inst_data = func.layout
.ebb_insts(ebb)
.filter(|inst| { .filter(|inst| {
match func[*inst] { match func[*inst] {
InstructionData::Branch { ty: _, opcode: _, data: _ } => true, InstructionData::Branch { ty: _, opcode: _, data: _ } => true,
InstructionData::Jump { ty: _, opcode: _, data: _ } => true, InstructionData::Jump { ty: _, opcode: _, data: _ } => true,
_ => false _ => false,
} }
}) })
.map(|inst| { .map(|inst| {
let op = match func[inst] { let op = match func[inst] {
InstructionData::Branch { ty: _, opcode, ref data } => { InstructionData::Branch { ty: _, opcode, ref data } => {
Some((opcode, data.destination)) Some((opcode, data.destination))
}, }
InstructionData::Jump { ty: _, opcode, ref data } => { InstructionData::Jump { ty: _, opcode, ref data } => {
Some((opcode, data.destination)) Some((opcode, data.destination))
}, }
_ => None _ => None,
}; };
(inst, op) (inst, op)
}) })
@@ -132,7 +137,10 @@ impl<T: Write> CFGPrinter<T> {
} }
self.append(&format!("{} [shape=record, label=\"{}{}{}\"]", self.append(&format!("{} [shape=record, label=\"{}{}{}\"]",
ebb, "{", insts.join(" | "), "}")); ebb,
"{",
insts.join(" | "),
"}"));
self.newline(); self.newline();
} }
} }
@@ -145,7 +153,6 @@ impl<T: Write> CFGPrinter<T> {
} }
} }
} }
} }
fn print_cfg(filename: String) -> CommandResult { fn print_cfg(filename: String) -> CommandResult {