Use DataFlowGraph in Function.
Replace the three tables instructions, extended_basic_blocks, and extended_values with a single 'dfg' public member. Clients using Function are changed to refer to func.layout and func.dfg respectively.
This commit is contained in:
@@ -56,7 +56,7 @@ impl ControlFlowGraph {
|
|||||||
// 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.layout.ebb_insts(ebb) {
|
for inst in func.layout.ebb_insts(ebb) {
|
||||||
match func[inst] {
|
match func.dfg[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,9 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn no_predecessors() {
|
fn no_predecessors() {
|
||||||
let mut func = Function::new();
|
let mut func = Function::new();
|
||||||
let ebb0 = func.make_ebb();
|
let ebb0 = func.dfg.make_ebb();
|
||||||
let ebb1 = func.make_ebb();
|
let ebb1 = func.dfg.make_ebb();
|
||||||
let ebb2 = func.make_ebb();
|
let ebb2 = func.dfg.make_ebb();
|
||||||
func.layout.append_ebb(ebb0);
|
func.layout.append_ebb(ebb0);
|
||||||
func.layout.append_ebb(ebb1);
|
func.layout.append_ebb(ebb1);
|
||||||
func.layout.append_ebb(ebb2);
|
func.layout.append_ebb(ebb2);
|
||||||
@@ -130,9 +130,9 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn branches_and_jumps() {
|
fn branches_and_jumps() {
|
||||||
let mut func = Function::new();
|
let mut func = Function::new();
|
||||||
let ebb0 = func.make_ebb();
|
let ebb0 = func.dfg.make_ebb();
|
||||||
let ebb1 = func.make_ebb();
|
let ebb1 = func.dfg.make_ebb();
|
||||||
let ebb2 = func.make_ebb();
|
let ebb2 = func.dfg.make_ebb();
|
||||||
func.layout.append_ebb(ebb0);
|
func.layout.append_ebb(ebb0);
|
||||||
func.layout.append_ebb(ebb1);
|
func.layout.append_ebb(ebb1);
|
||||||
func.layout.append_ebb(ebb2);
|
func.layout.append_ebb(ebb2);
|
||||||
|
|||||||
@@ -1,18 +1,14 @@
|
|||||||
//! Representation of Cretonne IL functions.
|
//! Representation of Cretonne IL functions.
|
||||||
|
|
||||||
use types::{Type, FunctionName, Signature, VOID};
|
use types::{FunctionName, Signature};
|
||||||
use entity_map::EntityRef;
|
use entity_map::EntityRef;
|
||||||
use entities::{Ebb, NO_EBB, Inst, Value, NO_VALUE, ExpandedValue, StackSlot};
|
use entities::{Ebb, NO_EBB, StackSlot};
|
||||||
use instructions::*;
|
use dfg::DataFlowGraph;
|
||||||
use layout::Layout;
|
use layout::Layout;
|
||||||
use std::fmt::{self, Debug, Display, Formatter};
|
use std::fmt::{self, Debug, Display, Formatter};
|
||||||
use std::ops::{Index, IndexMut};
|
use std::ops::Index;
|
||||||
|
|
||||||
/// A function.
|
/// A function.
|
||||||
///
|
|
||||||
/// 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>`.
|
|
||||||
///
|
|
||||||
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,
|
||||||
@@ -26,17 +22,8 @@ pub struct Function {
|
|||||||
/// Stack slots allocated in this function.
|
/// Stack slots allocated in this function.
|
||||||
stack_slots: Vec<StackSlotData>,
|
stack_slots: Vec<StackSlotData>,
|
||||||
|
|
||||||
/// Data about all of the instructions in the function. The instructions in this vector is not
|
/// Data flow graph containing the primary definition of all instructions, EBBs and values.
|
||||||
/// necessarily in program order. The `Inst` reference indexes into this vector.
|
pub dfg: DataFlowGraph,
|
||||||
instructions: Vec<InstructionData>,
|
|
||||||
|
|
||||||
/// Extended basic blocks in the function, not necessarily in program order. The `Ebb`
|
|
||||||
/// reference indexes into this vector.
|
|
||||||
extended_basic_blocks: Vec<EbbData>,
|
|
||||||
|
|
||||||
/// Extended value table. Most `Value` references refer directly to their defining instruction.
|
|
||||||
/// Others index into this table.
|
|
||||||
extended_values: Vec<ValueData>,
|
|
||||||
|
|
||||||
/// Layout of EBBs and instructions in the function body.
|
/// Layout of EBBs and instructions in the function body.
|
||||||
pub layout: Layout,
|
pub layout: Layout,
|
||||||
@@ -50,9 +37,7 @@ impl Function {
|
|||||||
signature: sig,
|
signature: sig,
|
||||||
entry_block: NO_EBB,
|
entry_block: NO_EBB,
|
||||||
stack_slots: Vec::new(),
|
stack_slots: Vec::new(),
|
||||||
instructions: Vec::new(),
|
dfg: DataFlowGraph::new(),
|
||||||
extended_basic_blocks: Vec::new(),
|
|
||||||
extended_values: Vec::new(),
|
|
||||||
layout: Layout::new(),
|
layout: Layout::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -83,175 +68,6 @@ impl Function {
|
|||||||
end: self.stack_slots.len(),
|
end: self.stack_slots.len(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Instructions.
|
|
||||||
|
|
||||||
/// Create a new instruction.
|
|
||||||
///
|
|
||||||
/// The type of the first result is indicated by `data.ty`. If the instruction produces
|
|
||||||
/// multiple results, also call `make_inst_results` to allocate value table entries.
|
|
||||||
pub fn make_inst(&mut self, data: InstructionData) -> Inst {
|
|
||||||
let inst = Inst::new(self.instructions.len());
|
|
||||||
self.instructions.push(data);
|
|
||||||
inst
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create result values for an instruction that produces multiple results.
|
|
||||||
///
|
|
||||||
/// Instructions that produce 0 or 1 result values only need to be created with `make_inst`. If
|
|
||||||
/// the instruction may produce more than 1 result, call `make_inst_results` to allocate
|
|
||||||
/// `Value` table entries for the additional results.
|
|
||||||
///
|
|
||||||
/// The result value types are determined from the instruction's value type constraints and the
|
|
||||||
/// provided `ctrl_typevar` type for polymorphic instructions. For non-polymorphic
|
|
||||||
/// instructions, `ctrl_typevar` is ignored, and `VOID` can be used.
|
|
||||||
///
|
|
||||||
/// The type of the first result value is also set, even if it was already set in the
|
|
||||||
/// `InstructionData` passed to `make_inst`. If this function is called with a single-result
|
|
||||||
/// instruction, that is the only effect.
|
|
||||||
///
|
|
||||||
/// Returns the number of results produced by the instruction.
|
|
||||||
pub fn make_inst_results(&mut self, inst: Inst, ctrl_typevar: Type) -> usize {
|
|
||||||
let constraints = self[inst].opcode().constraints();
|
|
||||||
let fixed_results = constraints.fixed_results();
|
|
||||||
|
|
||||||
// Additional values form a linked list starting from the second result value. Generate
|
|
||||||
// the list backwards so we don't have to modify value table entries in place. (This
|
|
||||||
// causes additional result values to be numbered backwards which is not the aestetic
|
|
||||||
// choice, but since it is only visible in extremely rare instructions with 3+ results,
|
|
||||||
// we don't care).
|
|
||||||
let mut head = NO_VALUE;
|
|
||||||
let mut first_type = Type::default();
|
|
||||||
|
|
||||||
// TBD: Function call return values for direct and indirect function calls.
|
|
||||||
|
|
||||||
if fixed_results > 0 {
|
|
||||||
for res_idx in (1..fixed_results).rev() {
|
|
||||||
head = self.make_value(ValueData::Def {
|
|
||||||
ty: constraints.result_type(res_idx, ctrl_typevar),
|
|
||||||
def: inst,
|
|
||||||
next: head,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
first_type = constraints.result_type(0, ctrl_typevar);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the second_result pointer in `inst`.
|
|
||||||
if head != NO_VALUE {
|
|
||||||
*self[inst]
|
|
||||||
.second_result_mut()
|
|
||||||
.expect("instruction format doesn't allow multiple results") = head;
|
|
||||||
}
|
|
||||||
*self[inst].first_type_mut() = first_type;
|
|
||||||
|
|
||||||
fixed_results
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the first result of an instruction.
|
|
||||||
///
|
|
||||||
/// If `Inst` doesn't produce any results, this returns a `Value` with a `VOID` type.
|
|
||||||
pub fn first_result(&self, inst: Inst) -> Value {
|
|
||||||
Value::new_direct(inst)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Iterate through all the results of an instruction.
|
|
||||||
pub fn inst_results<'a>(&'a self, inst: Inst) -> Values<'a> {
|
|
||||||
Values {
|
|
||||||
func: self,
|
|
||||||
cur: if self[inst].first_type() == VOID {
|
|
||||||
NO_VALUE
|
|
||||||
} else {
|
|
||||||
Value::new_direct(inst)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Basic blocks
|
|
||||||
|
|
||||||
/// Create a new basic block.
|
|
||||||
pub fn make_ebb(&mut self) -> Ebb {
|
|
||||||
let ebb = Ebb::new(self.extended_basic_blocks.len());
|
|
||||||
self.extended_basic_blocks.push(EbbData::new());
|
|
||||||
ebb
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Reference the representation of an EBB.
|
|
||||||
fn ebb(&self, ebb: Ebb) -> &EbbData {
|
|
||||||
&self.extended_basic_blocks[ebb.index()]
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Mutably reference the representation of an EBB.
|
|
||||||
fn ebb_mut(&mut self, ebb: Ebb) -> &mut EbbData {
|
|
||||||
&mut self.extended_basic_blocks[ebb.index()]
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Iterate over all the EBBs in order of creation.
|
|
||||||
pub fn ebbs_numerically(&self) -> NumericalEbbs {
|
|
||||||
NumericalEbbs {
|
|
||||||
cur: 0,
|
|
||||||
limit: self.extended_basic_blocks.len(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Append an argument with type `ty` to `ebb`.
|
|
||||||
pub fn append_ebb_arg(&mut self, ebb: Ebb, ty: Type) -> Value {
|
|
||||||
let val = self.make_value(ValueData::Argument {
|
|
||||||
ty: ty,
|
|
||||||
ebb: ebb,
|
|
||||||
next: NO_VALUE,
|
|
||||||
});
|
|
||||||
|
|
||||||
let last_arg = self.ebb(ebb).last_arg;
|
|
||||||
match last_arg.expand() {
|
|
||||||
// If last_arg = NO_VALUE, we're adding the first EBB argument.
|
|
||||||
ExpandedValue::None => self.ebb_mut(ebb).first_arg = val,
|
|
||||||
ExpandedValue::Table(index) => {
|
|
||||||
// Append to linked list of arguments.
|
|
||||||
if let ValueData::Argument { ref mut next, .. } = self.extended_values[index] {
|
|
||||||
*next = val;
|
|
||||||
} else {
|
|
||||||
panic!("wrong type of extended value referenced by Ebb::last_arg");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ExpandedValue::Direct(_) => panic!("Direct value cannot appear as EBB argument"),
|
|
||||||
}
|
|
||||||
self.ebb_mut(ebb).last_arg = val;
|
|
||||||
|
|
||||||
val
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Iterate through the arguments to an EBB.
|
|
||||||
pub fn ebb_args<'a>(&'a self, ebb: Ebb) -> Values<'a> {
|
|
||||||
Values {
|
|
||||||
func: self,
|
|
||||||
cur: self.ebb(ebb).first_arg,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Values.
|
|
||||||
|
|
||||||
/// Allocate an extended value entry.
|
|
||||||
fn make_value(&mut self, data: ValueData) -> Value {
|
|
||||||
let vref = Value::new_table(self.extended_values.len());
|
|
||||||
self.extended_values.push(data);
|
|
||||||
vref
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the type of a value.
|
|
||||||
pub fn value_type(&self, v: Value) -> Type {
|
|
||||||
use entities::ExpandedValue::*;
|
|
||||||
use self::ValueData::*;
|
|
||||||
match v.expand() {
|
|
||||||
Direct(i) => self[i].first_type(),
|
|
||||||
Table(i) => {
|
|
||||||
match self.extended_values[i] {
|
|
||||||
Def { ty, .. } => ty,
|
|
||||||
Argument { ty, .. } => ty,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => panic!("NO_VALUE has no type"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for Function {
|
impl Debug for Function {
|
||||||
@@ -316,197 +132,9 @@ impl Iterator for StackSlotIter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ====--------------------------------------------------------------------------------------====//
|
|
||||||
//
|
|
||||||
// Extended basic block implementation.
|
|
||||||
//
|
|
||||||
// ====--------------------------------------------------------------------------------------====//
|
|
||||||
|
|
||||||
/// Contents of an extended basic block.
|
|
||||||
///
|
|
||||||
/// Arguments for an extended basic block are values that dominate everything in the EBB. All
|
|
||||||
/// branches to this EBB must provide matching arguments, and the arguments to the entry EBB must
|
|
||||||
/// match the function arguments.
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct EbbData {
|
|
||||||
/// First argument to this EBB, or `NO_VALUE` if the block has no arguments.
|
|
||||||
///
|
|
||||||
/// The arguments are all ValueData::Argument entries that form a linked list from `first_arg`
|
|
||||||
/// to `last_arg`.
|
|
||||||
first_arg: Value,
|
|
||||||
|
|
||||||
/// Last argument to this EBB, or `NO_VALUE` if the block has no arguments.
|
|
||||||
last_arg: Value,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl EbbData {
|
|
||||||
fn new() -> EbbData {
|
|
||||||
EbbData {
|
|
||||||
first_arg: NO_VALUE,
|
|
||||||
last_arg: NO_VALUE,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Index<Ebb> for Function {
|
|
||||||
type Output = EbbData;
|
|
||||||
|
|
||||||
fn index<'a>(&'a self, ebb: Ebb) -> &'a EbbData {
|
|
||||||
&self.extended_basic_blocks[ebb.index()]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IndexMut<Ebb> for Function {
|
|
||||||
fn index_mut<'a>(&'a mut self, ebb: Ebb) -> &'a mut EbbData {
|
|
||||||
&mut self.extended_basic_blocks[ebb.index()]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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 {
|
|
||||||
cur: usize,
|
|
||||||
limit: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Iterator for NumericalEbbs {
|
|
||||||
type Item = Ebb;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
if self.cur < self.limit {
|
|
||||||
let prev = Ebb::new(self.cur);
|
|
||||||
self.cur += 1;
|
|
||||||
Some(prev)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ====--------------------------------------------------------------------------------------====//
|
|
||||||
//
|
|
||||||
// Instruction implementation.
|
|
||||||
//
|
|
||||||
// The InstructionData layout is defined in the `instructions` module.
|
|
||||||
//
|
|
||||||
// ====--------------------------------------------------------------------------------------====//
|
|
||||||
|
|
||||||
/// Allow immutable access to instructions via function indexing.
|
|
||||||
impl Index<Inst> for Function {
|
|
||||||
type Output = InstructionData;
|
|
||||||
|
|
||||||
fn index<'a>(&'a self, inst: Inst) -> &'a InstructionData {
|
|
||||||
&self.instructions[inst.index()]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Allow mutable access to instructions via function indexing.
|
|
||||||
impl IndexMut<Inst> for Function {
|
|
||||||
fn index_mut<'a>(&'a mut self, inst: Inst) -> &'a mut InstructionData {
|
|
||||||
&mut self.instructions[inst.index()]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ====--------------------------------------------------------------------------------------====//
|
|
||||||
//
|
|
||||||
// Value implementation.
|
|
||||||
//
|
|
||||||
// ====--------------------------------------------------------------------------------------====//
|
|
||||||
|
|
||||||
// Most values are simply the first value produced by an instruction.
|
|
||||||
// Other values have an entry in the value table.
|
|
||||||
#[derive(Debug)]
|
|
||||||
enum ValueData {
|
|
||||||
// Value is defined by an instruction, but it is not the first result.
|
|
||||||
Def {
|
|
||||||
ty: Type,
|
|
||||||
def: Inst,
|
|
||||||
next: Value, // Next result defined by `def`.
|
|
||||||
},
|
|
||||||
|
|
||||||
// Value is an EBB argument.
|
|
||||||
Argument {
|
|
||||||
ty: Type,
|
|
||||||
ebb: Ebb,
|
|
||||||
next: Value, // Next argument to `ebb`.
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Iterate through a list of related value references, such as:
|
|
||||||
///
|
|
||||||
/// - All results defined by an instruction.
|
|
||||||
/// - All arguments to an EBB
|
|
||||||
///
|
|
||||||
/// A value iterator borrows a Function reference.
|
|
||||||
pub struct Values<'a> {
|
|
||||||
func: &'a Function,
|
|
||||||
cur: Value,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Iterator for Values<'a> {
|
|
||||||
type Item = Value;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
let prev = self.cur;
|
|
||||||
|
|
||||||
// Advance self.cur to the next value, or NO_VALUE.
|
|
||||||
self.cur = match prev.expand() {
|
|
||||||
ExpandedValue::Direct(inst) => self.func[inst].second_result().unwrap_or_default(),
|
|
||||||
ExpandedValue::Table(index) => {
|
|
||||||
match self.func.extended_values[index] {
|
|
||||||
ValueData::Def { next, .. } => next,
|
|
||||||
ValueData::Argument { next, .. } => next,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ExpandedValue::None => return None,
|
|
||||||
};
|
|
||||||
|
|
||||||
Some(prev)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use types;
|
|
||||||
use instructions::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn make_inst() {
|
|
||||||
let mut func = Function::new();
|
|
||||||
|
|
||||||
let idata = InstructionData::Nullary {
|
|
||||||
opcode: Opcode::Iconst,
|
|
||||||
ty: types::I32,
|
|
||||||
};
|
|
||||||
let inst = func.make_inst(idata);
|
|
||||||
assert_eq!(inst.to_string(), "inst0");
|
|
||||||
|
|
||||||
// Immutable reference resolution.
|
|
||||||
let ins = &func[inst];
|
|
||||||
assert_eq!(ins.opcode(), Opcode::Iconst);
|
|
||||||
assert_eq!(ins.first_type(), types::I32);
|
|
||||||
|
|
||||||
// Result iterator.
|
|
||||||
let mut res = func.inst_results(inst);
|
|
||||||
assert!(res.next().is_some());
|
|
||||||
assert!(res.next().is_none());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn no_results() {
|
|
||||||
let mut func = Function::new();
|
|
||||||
|
|
||||||
let idata = InstructionData::Nullary {
|
|
||||||
opcode: Opcode::Trap,
|
|
||||||
ty: types::VOID,
|
|
||||||
};
|
|
||||||
let inst = func.make_inst(idata);
|
|
||||||
|
|
||||||
// Result iterator should be empty.
|
|
||||||
let mut res = func.inst_results(inst);
|
|
||||||
assert_eq!(res.next(), None);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn stack_slot() {
|
fn stack_slot() {
|
||||||
@@ -520,62 +148,4 @@ mod tests {
|
|||||||
assert_eq!(func[ss0].size, 4);
|
assert_eq!(func[ss0].size, 4);
|
||||||
assert_eq!(func[ss1].size, 8);
|
assert_eq!(func[ss1].size, 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn ebb() {
|
|
||||||
let mut func = Function::new();
|
|
||||||
|
|
||||||
assert_eq!(func.ebbs_numerically().next(), None);
|
|
||||||
|
|
||||||
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");
|
|
||||||
{
|
|
||||||
let mut args1 = func.ebb_args(ebb);
|
|
||||||
assert_eq!(args1.next(), Some(arg1));
|
|
||||||
assert_eq!(args1.next(), None);
|
|
||||||
}
|
|
||||||
let arg2 = func.append_ebb_arg(ebb, types::I16);
|
|
||||||
assert_eq!(arg2.to_string(), "vx1");
|
|
||||||
{
|
|
||||||
let mut args2 = func.ebb_args(ebb);
|
|
||||||
assert_eq!(args2.next(), Some(arg1));
|
|
||||||
assert_eq!(args2.next(), Some(arg2));
|
|
||||||
assert_eq!(args2.next(), None);
|
|
||||||
}
|
|
||||||
|
|
||||||
// The numerical ebb iterator doesn't capture the function.
|
|
||||||
let mut ebbs = func.ebbs_numerically();
|
|
||||||
assert_eq!(ebbs.next(), Some(ebb));
|
|
||||||
assert_eq!(ebbs.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.layout.append_inst(inst, ebb);
|
|
||||||
{
|
|
||||||
let mut ii = func.layout.ebb_insts(ebb);
|
|
||||||
assert_eq!(ii.next(), Some(inst));
|
|
||||||
assert_eq!(ii.next(), None);
|
|
||||||
}
|
|
||||||
|
|
||||||
let inst2 = func.make_inst(InstructionData::Nullary {
|
|
||||||
opcode: Opcode::Iconst,
|
|
||||||
ty: types::I32,
|
|
||||||
});
|
|
||||||
func.layout.append_inst(inst2, 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use instructions::{InstructionData, Opcode, VariableArgs, JumpData, BranchData};
|
|||||||
use types;
|
use types;
|
||||||
|
|
||||||
pub fn jump(func: &mut Function, dest: Ebb) -> Inst {
|
pub fn jump(func: &mut Function, dest: Ebb) -> Inst {
|
||||||
func.make_inst(InstructionData::Jump {
|
func.dfg.make_inst(InstructionData::Jump {
|
||||||
opcode: Opcode::Jump,
|
opcode: Opcode::Jump,
|
||||||
ty: types::VOID,
|
ty: types::VOID,
|
||||||
data: Box::new(JumpData {
|
data: Box::new(JumpData {
|
||||||
@@ -17,7 +17,7 @@ pub fn jump(func: &mut Function, dest: Ebb) -> Inst {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn branch(func: &mut Function, dest: Ebb) -> Inst {
|
pub fn branch(func: &mut Function, dest: Ebb) -> Inst {
|
||||||
func.make_inst(InstructionData::Branch {
|
func.dfg.make_inst(InstructionData::Branch {
|
||||||
opcode: Opcode::Brz,
|
opcode: Opcode::Brz,
|
||||||
ty: types::VOID,
|
ty: types::VOID,
|
||||||
data: Box::new(BranchData {
|
data: Box::new(BranchData {
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ fn write_preamble(w: &mut Write, func: &Function) -> io::Result<bool> {
|
|||||||
// ====--------------------------------------------------------------------------------------====//
|
// ====--------------------------------------------------------------------------------------====//
|
||||||
|
|
||||||
pub fn write_arg(w: &mut Write, func: &Function, arg: Value) -> Result {
|
pub fn write_arg(w: &mut Write, func: &Function, arg: Value) -> Result {
|
||||||
write!(w, "{}: {}", arg, func.value_type(arg))
|
write!(w, "{}: {}", arg, func.dfg.value_type(arg))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write_ebb_header(w: &mut Write, func: &Function, ebb: Ebb) -> Result {
|
pub fn write_ebb_header(w: &mut Write, func: &Function, ebb: Ebb) -> Result {
|
||||||
@@ -96,7 +96,7 @@ pub fn write_ebb_header(w: &mut Write, func: &Function, ebb: Ebb) -> Result {
|
|||||||
// ebb10(vx4: f64, vx5: b1):
|
// ebb10(vx4: f64, vx5: b1):
|
||||||
//
|
//
|
||||||
|
|
||||||
let mut args = func.ebb_args(ebb);
|
let mut args = func.dfg.ebb_args(ebb);
|
||||||
match args.next() {
|
match args.next() {
|
||||||
None => return writeln!(w, "{}:", ebb),
|
None => return writeln!(w, "{}:", ebb),
|
||||||
Some(arg) => {
|
Some(arg) => {
|
||||||
@@ -133,7 +133,7 @@ pub fn write_ebb(w: &mut Write, func: &Function, ebb: Ebb) -> Result {
|
|||||||
// if it can't be trivially inferred.
|
// if it can't be trivially inferred.
|
||||||
//
|
//
|
||||||
fn type_suffix(func: &Function, inst: Inst) -> Option<Type> {
|
fn type_suffix(func: &Function, inst: Inst) -> Option<Type> {
|
||||||
let constraints = func[inst].opcode().constraints();
|
let constraints = func.dfg[inst].opcode().constraints();
|
||||||
|
|
||||||
if !constraints.is_polymorphic() {
|
if !constraints.is_polymorphic() {
|
||||||
return None;
|
return None;
|
||||||
@@ -150,7 +150,7 @@ fn type_suffix(func: &Function, inst: Inst) -> Option<Type> {
|
|||||||
|
|
||||||
// This polymorphic instruction doesn't support basic type inference.
|
// This polymorphic instruction doesn't support basic type inference.
|
||||||
// The controlling type variable is required to be the type of the first result.
|
// The controlling type variable is required to be the type of the first result.
|
||||||
let rtype = func.value_type(func.first_result(inst));
|
let rtype = func.dfg.value_type(func.dfg.first_result(inst));
|
||||||
assert!(!rtype.is_void(),
|
assert!(!rtype.is_void(),
|
||||||
"Polymorphic instruction must produce a result");
|
"Polymorphic instruction must produce a result");
|
||||||
Some(rtype)
|
Some(rtype)
|
||||||
@@ -161,7 +161,7 @@ pub fn write_instruction(w: &mut Write, func: &Function, inst: Inst) -> Result {
|
|||||||
|
|
||||||
// First write out the result values, if any.
|
// First write out the result values, if any.
|
||||||
let mut has_results = false;
|
let mut has_results = false;
|
||||||
for r in func.inst_results(inst) {
|
for r in func.dfg.inst_results(inst) {
|
||||||
if !has_results {
|
if !has_results {
|
||||||
has_results = true;
|
has_results = true;
|
||||||
try!(write!(w, "{}", r));
|
try!(write!(w, "{}", r));
|
||||||
@@ -174,7 +174,7 @@ pub fn write_instruction(w: &mut Write, func: &Function, inst: Inst) -> Result {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Then the opcode, possibly with a '.type' suffix.
|
// Then the opcode, possibly with a '.type' suffix.
|
||||||
let opcode = func[inst].opcode();
|
let opcode = func.dfg[inst].opcode();
|
||||||
|
|
||||||
match type_suffix(func, inst) {
|
match type_suffix(func, inst) {
|
||||||
Some(suf) => try!(write!(w, "{}.{}", opcode, suf)),
|
Some(suf) => try!(write!(w, "{}.{}", opcode, suf)),
|
||||||
@@ -183,7 +183,7 @@ pub fn write_instruction(w: &mut Write, func: &Function, inst: Inst) -> Result {
|
|||||||
|
|
||||||
// Then the operands, depending on format.
|
// Then the operands, depending on format.
|
||||||
use instructions::InstructionData::*;
|
use instructions::InstructionData::*;
|
||||||
match func[inst] {
|
match func.dfg[inst] {
|
||||||
Nullary { .. } => writeln!(w, ""),
|
Nullary { .. } => writeln!(w, ""),
|
||||||
Unary { arg, .. } => writeln!(w, " {}", arg),
|
Unary { arg, .. } => writeln!(w, " {}", arg),
|
||||||
UnaryImm { imm, .. } => writeln!(w, " {}", imm),
|
UnaryImm { imm, .. } => writeln!(w, " {}", imm),
|
||||||
@@ -250,16 +250,16 @@ mod tests {
|
|||||||
assert_eq!(function_to_string(&f),
|
assert_eq!(function_to_string(&f),
|
||||||
"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.dfg.make_ebb();
|
||||||
f.layout.append_ebb(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");
|
||||||
|
|
||||||
f.append_ebb_arg(ebb, types::I8);
|
f.dfg.append_ebb_arg(ebb, types::I8);
|
||||||
assert_eq!(function_to_string(&f),
|
assert_eq!(function_to_string(&f),
|
||||||
"function foo() {\n ss0 = stack_slot 4\n\nebb0(vx0: i8):\n}\n");
|
"function foo() {\n ss0 = stack_slot 4\n\nebb0(vx0: i8):\n}\n");
|
||||||
|
|
||||||
f.append_ebb_arg(ebb, types::F32.by(4).unwrap());
|
f.dfg.append_ebb_arg(ebb, types::F32.by(4).unwrap());
|
||||||
assert_eq!(function_to_string(&f),
|
assert_eq!(function_to_string(&f),
|
||||||
"function foo() {\n ss0 = stack_slot 4\n\nebb0(vx0: i8, vx1: f32x4):\n}\n");
|
"function foo() {\n ss0 = stack_slot 4\n\nebb0(vx0: i8, vx1: f32x4):\n}\n");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -100,7 +100,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.dfg.make_ebb();
|
||||||
self.function.layout.append_ebb(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)
|
||||||
@@ -163,7 +163,7 @@ impl Context {
|
|||||||
// Rewrite all EBB and value references in the function.
|
// Rewrite all EBB and value references in the function.
|
||||||
fn rewrite_references(&mut self) -> Result<()> {
|
fn rewrite_references(&mut self) -> Result<()> {
|
||||||
for &(inst, loc) in &self.inst_locs {
|
for &(inst, loc) in &self.inst_locs {
|
||||||
match self.function[inst] {
|
match self.function.dfg[inst] {
|
||||||
InstructionData::Nullary { .. } |
|
InstructionData::Nullary { .. } |
|
||||||
InstructionData::UnaryImm { .. } |
|
InstructionData::UnaryImm { .. } |
|
||||||
InstructionData::UnaryIeee32 { .. } |
|
InstructionData::UnaryIeee32 { .. } |
|
||||||
@@ -646,7 +646,7 @@ impl<'a> Parser<'a> {
|
|||||||
// ebb-arg ::= Value(vx) ":" * Type(t)
|
// ebb-arg ::= Value(vx) ":" * Type(t)
|
||||||
let t = try!(self.match_type("expected EBB argument type"));
|
let t = try!(self.match_type("expected EBB argument type"));
|
||||||
// Allocate the EBB argument and add the mapping.
|
// Allocate the EBB argument and add the mapping.
|
||||||
let value = ctx.function.append_ebb_arg(ebb, t);
|
let value = ctx.function.dfg.append_ebb_arg(ebb, t);
|
||||||
ctx.add_value(vx, value, &vx_location)
|
ctx.add_value(vx, value, &vx_location)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -703,8 +703,8 @@ impl<'a> Parser<'a> {
|
|||||||
// or function call signature. We also need to create values with the right type for all
|
// or function call signature. We also need to create values with the right type for all
|
||||||
// the instruction results.
|
// the instruction results.
|
||||||
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.dfg.make_inst(inst_data);
|
||||||
let num_results = ctx.function.make_inst_results(inst, ctrl_typevar);
|
let num_results = ctx.function.dfg.make_inst_results(inst, ctrl_typevar);
|
||||||
ctx.function.layout.append_inst(inst, ebb);
|
ctx.function.layout.append_inst(inst, ebb);
|
||||||
ctx.add_inst_loc(inst, &opcode_loc);
|
ctx.add_inst_loc(inst, &opcode_loc);
|
||||||
|
|
||||||
@@ -720,7 +720,7 @@ impl<'a> Parser<'a> {
|
|||||||
// holds a reference to `ctx.function`.
|
// holds a reference to `ctx.function`.
|
||||||
self.add_values(&mut ctx.values,
|
self.add_values(&mut ctx.values,
|
||||||
results.into_iter(),
|
results.into_iter(),
|
||||||
ctx.function.inst_results(inst))
|
ctx.function.dfg.inst_results(inst))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Type inference for polymorphic instructions.
|
// Type inference for polymorphic instructions.
|
||||||
@@ -750,7 +750,7 @@ impl<'a> Parser<'a> {
|
|||||||
// layout of the blocks.
|
// layout of the blocks.
|
||||||
let ctrl_src_value = inst_data.typevar_operand()
|
let ctrl_src_value = inst_data.typevar_operand()
|
||||||
.expect("Constraints <-> Format inconsistency");
|
.expect("Constraints <-> Format inconsistency");
|
||||||
ctx.function.value_type(match ctx.values.get(&ctrl_src_value) {
|
ctx.function.dfg.value_type(match ctx.values.get(&ctrl_src_value) {
|
||||||
Some(&v) => v,
|
Some(&v) => v,
|
||||||
None => {
|
None => {
|
||||||
return err!(self.loc,
|
return err!(self.loc,
|
||||||
@@ -1119,12 +1119,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.ebb_args(ebb0).next(), None);
|
assert_eq!(func.dfg.ebb_args(ebb0).next(), None);
|
||||||
|
|
||||||
let ebb4 = ebbs.next().unwrap();
|
let ebb4 = ebbs.next().unwrap();
|
||||||
let mut ebb4_args = func.ebb_args(ebb4);
|
let mut ebb4_args = func.dfg.ebb_args(ebb4);
|
||||||
let arg0 = ebb4_args.next().unwrap();
|
let arg0 = ebb4_args.next().unwrap();
|
||||||
assert_eq!(func.value_type(arg0), types::I32);
|
assert_eq!(func.dfg.value_type(arg0), types::I32);
|
||||||
assert_eq!(ebb4_args.next(), None);
|
assert_eq!(ebb4_args.next(), None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -110,14 +110,14 @@ impl<T: Write> CFGPrinter<T> {
|
|||||||
let inst_data = func.layout
|
let inst_data = func.layout
|
||||||
.ebb_insts(ebb)
|
.ebb_insts(ebb)
|
||||||
.filter(|inst| {
|
.filter(|inst| {
|
||||||
match func[*inst] {
|
match func.dfg[*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.dfg[inst] {
|
||||||
InstructionData::Branch { ty: _, opcode, ref data } => {
|
InstructionData::Branch { ty: _, opcode, ref data } => {
|
||||||
Some((opcode, data.destination))
|
Some((opcode, data.destination))
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user