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() {
// Flips to true when a terminating instruction is seen. So that if additional
// 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] {
InstructionData::Branch { ty: _, opcode: _, ref data } => {
cfg.add_predecessor(data.destination, (ebb, inst));
@@ -109,9 +109,13 @@ mod tests {
#[test]
fn no_predecessors() {
let mut func = Function::new();
func.make_ebb();
func.make_ebb();
func.make_ebb();
let ebb0 = func.make_ebb();
let ebb1 = 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 nodes = cfg.iter().collect::<Vec<_>>();
assert_eq!(nodes.len(), 3);
@@ -129,18 +133,21 @@ mod tests {
let ebb0 = func.make_ebb();
let ebb1 = 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);
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);
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);
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);
func.append_inst(ebb1, jmp_ebb1_ebb2);
func.layout.append_inst(jmp_ebb1_ebb2, ebb1);
let cfg = ControlFlowGraph::new(&func);
let ebb0_predecessors = cfg.get_predecessors(ebb0).unwrap();

View File

@@ -2,9 +2,10 @@
use types::{Type, FunctionName, Signature, VOID};
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 std::fmt::{self, Display, Formatter};
use layout::Layout;
use std::fmt::{self, Debug, Display, Formatter};
use std::ops::{Index, IndexMut};
/// 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
/// container for those objects by implementing both `Index<Inst>` and `Index<Ebb>`.
///
#[derive(Debug)]
pub struct Function {
/// Name of this function. Mostly used by `.cton` files.
pub name: FunctionName,
@@ -38,9 +38,8 @@ pub struct Function {
/// Others index into this table.
extended_values: Vec<ValueData>,
// Linked list nodes for the layout order of instructions. Forms a double linked list per EBB,
// terminated in both ends by NO_INST.
inst_order: Vec<InstNode>,
/// Layout of EBBs and instructions in the function body.
pub layout: Layout,
}
impl Function {
@@ -54,7 +53,7 @@ impl Function {
instructions: Vec::new(),
extended_basic_blocks: 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 {
let inst = Inst::new(self.instructions.len());
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
}
@@ -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.
/// 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.
@@ -362,12 +337,6 @@ pub struct EbbData {
/// Last argument to this EBB, or `NO_VALUE` if the block has no arguments.
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 {
@@ -375,8 +344,6 @@ impl EbbData {
EbbData {
first_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.
/// This order is stable, but has little significance to the semantics of the function.
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.
@@ -590,6 +530,7 @@ mod tests {
let ebb = func.make_ebb();
assert_eq!(ebb.to_string(), "ebb0");
assert_eq!(func.ebb_args(ebb).next(), None);
func.layout.append_ebb(ebb);
let arg1 = func.append_ebb_arg(ebb, types::F32);
assert_eq!(arg1.to_string(), "vx0");
@@ -612,33 +553,29 @@ mod tests {
assert_eq!(ebbs.next(), Some(ebb));
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 {
opcode: Opcode::Iconst,
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(), None);
}
assert_eq!(func[ebb].first_inst, inst);
assert_eq!(func[ebb].last_inst, inst);
let inst2 = func.make_inst(InstructionData::Nullary {
opcode: Opcode::Iconst,
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(inst2));
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 {
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));
}
Ok(())
@@ -251,6 +251,7 @@ mod tests {
"function foo() {\n ss0 = stack_slot 4\n}\n");
let ebb = f.make_ebb();
f.layout.append_ebb(ebb);
assert_eq!(function_to_string(&f),
"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.
fn add_ebb(&mut self, src_ebb: Ebb, loc: &Location) -> Result<Ebb> {
let ebb = self.function.make_ebb();
self.function.layout.append_ebb(ebb);
if self.ebbs.insert(src_ebb, ebb).is_some() {
err!(loc, "duplicate EBB: {}", src_ebb)
} else {
@@ -704,7 +705,7 @@ impl<'a> Parser<'a> {
let ctrl_typevar = try!(self.infer_typevar(ctx, opcode, explicit_ctrl_type, &inst_data));
let inst = ctx.function.make_inst(inst_data);
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);
if results.len() != num_results {

View File

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