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
|
||||
// instructions occur an error may be returned.
|
||||
for inst in func.layout.ebb_insts(ebb) {
|
||||
match func[inst] {
|
||||
match func.dfg[inst] {
|
||||
InstructionData::Branch { ty: _, opcode: _, ref data } => {
|
||||
cfg.add_predecessor(data.destination, (ebb, inst));
|
||||
}
|
||||
@@ -109,9 +109,9 @@ mod tests {
|
||||
#[test]
|
||||
fn no_predecessors() {
|
||||
let mut func = Function::new();
|
||||
let ebb0 = func.make_ebb();
|
||||
let ebb1 = func.make_ebb();
|
||||
let ebb2 = func.make_ebb();
|
||||
let ebb0 = func.dfg.make_ebb();
|
||||
let ebb1 = func.dfg.make_ebb();
|
||||
let ebb2 = func.dfg.make_ebb();
|
||||
func.layout.append_ebb(ebb0);
|
||||
func.layout.append_ebb(ebb1);
|
||||
func.layout.append_ebb(ebb2);
|
||||
@@ -130,9 +130,9 @@ mod tests {
|
||||
#[test]
|
||||
fn branches_and_jumps() {
|
||||
let mut func = Function::new();
|
||||
let ebb0 = func.make_ebb();
|
||||
let ebb1 = func.make_ebb();
|
||||
let ebb2 = func.make_ebb();
|
||||
let ebb0 = func.dfg.make_ebb();
|
||||
let ebb1 = func.dfg.make_ebb();
|
||||
let ebb2 = func.dfg.make_ebb();
|
||||
func.layout.append_ebb(ebb0);
|
||||
func.layout.append_ebb(ebb1);
|
||||
func.layout.append_ebb(ebb2);
|
||||
|
||||
@@ -1,18 +1,14 @@
|
||||
//! Representation of Cretonne IL functions.
|
||||
|
||||
use types::{Type, FunctionName, Signature, VOID};
|
||||
use types::{FunctionName, Signature};
|
||||
use entity_map::EntityRef;
|
||||
use entities::{Ebb, NO_EBB, Inst, Value, NO_VALUE, ExpandedValue, StackSlot};
|
||||
use instructions::*;
|
||||
use entities::{Ebb, NO_EBB, StackSlot};
|
||||
use dfg::DataFlowGraph;
|
||||
use layout::Layout;
|
||||
use std::fmt::{self, Debug, Display, Formatter};
|
||||
use std::ops::{Index, IndexMut};
|
||||
use std::ops::Index;
|
||||
|
||||
/// 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 {
|
||||
/// Name of this function. Mostly used by `.cton` files.
|
||||
pub name: FunctionName,
|
||||
@@ -26,17 +22,8 @@ pub struct Function {
|
||||
/// Stack slots allocated in this function.
|
||||
stack_slots: Vec<StackSlotData>,
|
||||
|
||||
/// Data about all of the instructions in the function. The instructions in this vector is not
|
||||
/// necessarily in program order. The `Inst` reference indexes into this vector.
|
||||
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>,
|
||||
/// Data flow graph containing the primary definition of all instructions, EBBs and values.
|
||||
pub dfg: DataFlowGraph,
|
||||
|
||||
/// Layout of EBBs and instructions in the function body.
|
||||
pub layout: Layout,
|
||||
@@ -50,9 +37,7 @@ impl Function {
|
||||
signature: sig,
|
||||
entry_block: NO_EBB,
|
||||
stack_slots: Vec::new(),
|
||||
instructions: Vec::new(),
|
||||
extended_basic_blocks: Vec::new(),
|
||||
extended_values: Vec::new(),
|
||||
dfg: DataFlowGraph::new(),
|
||||
layout: Layout::new(),
|
||||
}
|
||||
}
|
||||
@@ -83,175 +68,6 @@ impl Function {
|
||||
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 {
|
||||
@@ -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)]
|
||||
mod tests {
|
||||
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]
|
||||
fn stack_slot() {
|
||||
@@ -520,62 +148,4 @@ mod tests {
|
||||
assert_eq!(func[ss0].size, 4);
|
||||
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;
|
||||
|
||||
pub fn jump(func: &mut Function, dest: Ebb) -> Inst {
|
||||
func.make_inst(InstructionData::Jump {
|
||||
func.dfg.make_inst(InstructionData::Jump {
|
||||
opcode: Opcode::Jump,
|
||||
ty: types::VOID,
|
||||
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 {
|
||||
func.make_inst(InstructionData::Branch {
|
||||
func.dfg.make_inst(InstructionData::Branch {
|
||||
opcode: Opcode::Brz,
|
||||
ty: types::VOID,
|
||||
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 {
|
||||
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 {
|
||||
@@ -96,7 +96,7 @@ pub fn write_ebb_header(w: &mut Write, func: &Function, ebb: Ebb) -> Result {
|
||||
// ebb10(vx4: f64, vx5: b1):
|
||||
//
|
||||
|
||||
let mut args = func.ebb_args(ebb);
|
||||
let mut args = func.dfg.ebb_args(ebb);
|
||||
match args.next() {
|
||||
None => return writeln!(w, "{}:", ebb),
|
||||
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.
|
||||
//
|
||||
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() {
|
||||
return None;
|
||||
@@ -150,7 +150,7 @@ fn type_suffix(func: &Function, inst: Inst) -> Option<Type> {
|
||||
|
||||
// This polymorphic instruction doesn't support basic type inference.
|
||||
// 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(),
|
||||
"Polymorphic instruction must produce a result");
|
||||
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.
|
||||
let mut has_results = false;
|
||||
for r in func.inst_results(inst) {
|
||||
for r in func.dfg.inst_results(inst) {
|
||||
if !has_results {
|
||||
has_results = true;
|
||||
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.
|
||||
let opcode = func[inst].opcode();
|
||||
let opcode = func.dfg[inst].opcode();
|
||||
|
||||
match type_suffix(func, inst) {
|
||||
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.
|
||||
use instructions::InstructionData::*;
|
||||
match func[inst] {
|
||||
match func.dfg[inst] {
|
||||
Nullary { .. } => writeln!(w, ""),
|
||||
Unary { arg, .. } => writeln!(w, " {}", arg),
|
||||
UnaryImm { imm, .. } => writeln!(w, " {}", imm),
|
||||
@@ -250,16 +250,16 @@ mod tests {
|
||||
assert_eq!(function_to_string(&f),
|
||||
"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);
|
||||
assert_eq!(function_to_string(&f),
|
||||
"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),
|
||||
"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),
|
||||
"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.
|
||||
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);
|
||||
if self.ebbs.insert(src_ebb, ebb).is_some() {
|
||||
err!(loc, "duplicate EBB: {}", src_ebb)
|
||||
@@ -163,7 +163,7 @@ impl Context {
|
||||
// Rewrite all EBB and value references in the function.
|
||||
fn rewrite_references(&mut self) -> Result<()> {
|
||||
for &(inst, loc) in &self.inst_locs {
|
||||
match self.function[inst] {
|
||||
match self.function.dfg[inst] {
|
||||
InstructionData::Nullary { .. } |
|
||||
InstructionData::UnaryImm { .. } |
|
||||
InstructionData::UnaryIeee32 { .. } |
|
||||
@@ -646,7 +646,7 @@ impl<'a> Parser<'a> {
|
||||
// ebb-arg ::= Value(vx) ":" * Type(t)
|
||||
let t = try!(self.match_type("expected EBB argument type"));
|
||||
// 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)
|
||||
}
|
||||
|
||||
@@ -703,8 +703,8 @@ impl<'a> Parser<'a> {
|
||||
// or function call signature. We also need to create values with the right type for all
|
||||
// the instruction results.
|
||||
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);
|
||||
let inst = ctx.function.dfg.make_inst(inst_data);
|
||||
let num_results = ctx.function.dfg.make_inst_results(inst, ctrl_typevar);
|
||||
ctx.function.layout.append_inst(inst, ebb);
|
||||
ctx.add_inst_loc(inst, &opcode_loc);
|
||||
|
||||
@@ -720,7 +720,7 @@ impl<'a> Parser<'a> {
|
||||
// holds a reference to `ctx.function`.
|
||||
self.add_values(&mut ctx.values,
|
||||
results.into_iter(),
|
||||
ctx.function.inst_results(inst))
|
||||
ctx.function.dfg.inst_results(inst))
|
||||
}
|
||||
|
||||
// Type inference for polymorphic instructions.
|
||||
@@ -750,7 +750,7 @@ impl<'a> Parser<'a> {
|
||||
// layout of the blocks.
|
||||
let ctrl_src_value = inst_data.typevar_operand()
|
||||
.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,
|
||||
None => {
|
||||
return err!(self.loc,
|
||||
@@ -1119,12 +1119,12 @@ mod tests {
|
||||
let mut ebbs = func.layout.ebbs();
|
||||
|
||||
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 mut ebb4_args = func.ebb_args(ebb4);
|
||||
let mut ebb4_args = func.dfg.ebb_args(ebb4);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,14 +110,14 @@ impl<T: Write> CFGPrinter<T> {
|
||||
let inst_data = func.layout
|
||||
.ebb_insts(ebb)
|
||||
.filter(|inst| {
|
||||
match func[*inst] {
|
||||
match func.dfg[*inst] {
|
||||
InstructionData::Branch { ty: _, opcode: _, data: _ } => true,
|
||||
InstructionData::Jump { ty: _, opcode: _, data: _ } => true,
|
||||
_ => false,
|
||||
}
|
||||
})
|
||||
.map(|inst| {
|
||||
let op = match func[inst] {
|
||||
let op = match func.dfg[inst] {
|
||||
InstructionData::Branch { ty: _, opcode, ref data } => {
|
||||
Some((opcode, data.destination))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user