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