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:
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user