Print value aliases at referrent definition (#492)

* Print value aliases at referrent definition

Closes #488.
This commit is contained in:
Kaz Wesley
2018-09-04 15:02:46 -07:00
committed by Dan Gohman
parent 4045d50b7b
commit 7e571f4a49
4 changed files with 131 additions and 24 deletions

View File

@@ -1,6 +1,6 @@
//! Data flow graph tracking Instructions, Values, and EBBs.
use entity::{EntityMap, PrimaryMap};
use entity::{self, EntityMap, PrimaryMap};
use ir;
use ir::builder::ReplaceBuilder;
use ir::extfunc::ExtFuncData;
@@ -149,6 +149,38 @@ fn resolve_aliases(values: &PrimaryMap<Value, ValueData>, value: Value) -> Value
}
}
/// Iterator over all Values in a DFG
pub struct Values<'a> {
inner: entity::Iter<'a, Value, ValueData>,
}
/// Check for non-values
fn valid_valuedata(data: &ValueData) -> bool {
if let &ValueData::Alias {
ty: types::VOID,
original,
} = data
{
if original == Value::reserved_value() {
return false;
}
}
return true;
}
impl<'a> Iterator for Values<'a> {
type Item = Value;
fn next(&mut self) -> Option<Self::Item> {
return self
.inner
.by_ref()
.filter(|kv| valid_valuedata(kv.1))
.next()
.map(|kv| kv.0);
}
}
/// Handling values.
///
/// Values are either EBB parameters or instruction results.
@@ -158,6 +190,13 @@ impl DataFlowGraph {
self.values.push(data)
}
/// Get an iterator over all values.
pub fn values<'a>(&'a self) -> Values {
Values {
inner: self.values.iter(),
}
}
/// Check if a value reference is valid.
pub fn value_is_valid(&self, v: Value) -> bool {
self.values.is_valid(v)
@@ -932,9 +971,9 @@ impl DataFlowGraph {
}
/// Create a new value alias. This is only for use by the parser to create
/// aliases with specific values.
/// aliases with specific values, and the printer for testing.
#[cold]
pub fn make_value_alias_for_parser(&mut self, src: Value, dest: Value) {
pub fn make_value_alias_for_serialization(&mut self, src: Value, dest: Value) {
assert_ne!(src, Value::reserved_value());
assert_ne!(dest, Value::reserved_value());
@@ -951,9 +990,9 @@ impl DataFlowGraph {
/// If `v` is already defined as an alias, return its destination value.
/// Otherwise return None. This allows the parser to coalesce identical
/// alias definitions.
/// alias definitions, and the printer to identify an alias's immediate target.
#[cold]
pub fn value_alias_dest_for_parser(&self, v: Value) -> Option<Value> {
pub fn value_alias_dest_for_serialization(&self, v: Value) -> Option<Value> {
if let ValueData::Alias { original, .. } = self.values[v] {
Some(original)
} else {

View File

@@ -1,7 +1,8 @@
//! Utility routines for pretty-printing error messages.
use entity::EntityMap;
use ir;
use ir::entities::{AnyEntity, Inst};
use ir::entities::{AnyEntity, Inst, Value};
use ir::function::Function;
use isa::TargetIsa;
use result::CodegenError;
@@ -39,11 +40,12 @@ impl<'a> FuncWriter for PrettyVerifierError<'a> {
&mut self,
w: &mut Write,
func: &Function,
aliases: &EntityMap<Value, Vec<Value>>,
isa: Option<&TargetIsa>,
inst: Inst,
indent: usize,
) -> fmt::Result {
pretty_instruction_error(w, func, isa, inst, indent, &mut *self.0, self.1)
pretty_instruction_error(w, func, aliases, isa, inst, indent, &mut *self.0, self.1)
}
fn write_entity_definition(
@@ -61,6 +63,7 @@ impl<'a> FuncWriter for PrettyVerifierError<'a> {
fn pretty_instruction_error(
w: &mut Write,
func: &Function,
aliases: &EntityMap<Value, Vec<Value>>,
isa: Option<&TargetIsa>,
cur_inst: Inst,
indent: usize,
@@ -77,7 +80,7 @@ fn pretty_instruction_error(
let err = errors.remove(i);
if !printed_instr {
func_w.write_instruction(w, func, isa, cur_inst, indent)?;
func_w.write_instruction(w, func, aliases, isa, cur_inst, indent)?;
printed_instr = true;
}

View File

@@ -3,6 +3,7 @@
//! The `write` module provides the `write_function` function which converts an IR `Function` to an
//! equivalent textual form. This textual form can be read back by the `cranelift-reader` crate.
use entity::EntityMap;
use ir::entities::AnyEntity;
use ir::{DataFlowGraph, Ebb, Function, Inst, SigRef, Type, Value, ValueDef};
use isa::{RegInfo, TargetIsa};
@@ -17,6 +18,7 @@ pub trait FuncWriter {
&mut self,
w: &mut Write,
func: &Function,
aliases: &EntityMap<Value, Vec<Value>>,
isa: Option<&TargetIsa>,
inst: Inst,
ident: usize,
@@ -94,11 +96,12 @@ impl FuncWriter for PlainWriter {
&mut self,
w: &mut Write,
func: &Function,
aliases: &EntityMap<Value, Vec<Value>>,
isa: Option<&TargetIsa>,
inst: Inst,
indent: usize,
) -> fmt::Result {
write_instruction(w, func, isa, inst, indent)
write_instruction(w, func, aliases, isa, inst, indent)
}
}
@@ -108,6 +111,18 @@ pub fn write_function(w: &mut Write, func: &Function, isa: Option<&TargetIsa>) -
decorate_function(&mut PlainWriter, w, func, isa)
}
/// Create a reverse-alias map from a value to all aliases having that value as a direct target
fn alias_map(func: &Function) -> EntityMap<Value, Vec<Value>> {
let mut aliases = EntityMap::<_, Vec<_>>::new();
for v in func.dfg.values() {
// VADFS returns the immediate target of an alias
if let Some(k) = func.dfg.value_alias_dest_for_serialization(v) {
aliases[k].push(v);
}
}
aliases
}
/// Writes `func` to `w` as text.
/// write_function_plain is passed as 'closure' to print instructions as text.
/// pretty_function_error is passed as 'closure' to add error decoration.
@@ -123,12 +138,13 @@ pub fn decorate_function<FW: FuncWriter>(
write!(w, "function ")?;
write_spec(w, func, regs)?;
writeln!(w, " {{")?;
let aliases = alias_map(func);
let mut any = func_w.write_preamble(w, func, regs)?;
for ebb in &func.layout {
if any {
writeln!(w)?;
}
decorate_ebb(func_w, w, func, isa, ebb)?;
decorate_ebb(func_w, w, func, &aliases, isa, ebb)?;
any = true;
}
writeln!(w, "}}")
@@ -195,6 +211,7 @@ fn decorate_ebb<FW: FuncWriter>(
func_w: &mut FW,
w: &mut Write,
func: &Function,
aliases: &EntityMap<Value, Vec<Value>>,
isa: Option<&TargetIsa>,
ebb: Ebb,
) -> fmt::Result {
@@ -206,8 +223,11 @@ fn decorate_ebb<FW: FuncWriter>(
};
write_ebb_header(w, func, isa, ebb, indent)?;
for a in func.dfg.ebb_params(ebb).iter().cloned() {
write_value_aliases(w, aliases, a, indent)?;
}
for inst in func.layout.ebb_insts(ebb) {
func_w.write_instruction(w, func, isa, inst, indent)?;
func_w.write_instruction(w, func, aliases, isa, inst, indent)?;
}
Ok(())
@@ -251,13 +271,16 @@ fn type_suffix(func: &Function, inst: Inst) -> Option<Type> {
Some(rtype)
}
// Write out any value aliases appearing in `inst`.
fn write_value_aliases(w: &mut Write, func: &Function, inst: Inst, indent: usize) -> fmt::Result {
for &arg in func.dfg.inst_args(inst) {
let resolved = func.dfg.resolve_aliases(arg);
if resolved != arg {
writeln!(w, "{1:0$}{2} -> {3}", indent, "", arg, resolved)?;
}
/// Write out any aliases to the given target, including indirect aliases
fn write_value_aliases(
w: &mut Write,
aliases: &EntityMap<Value, Vec<Value>>,
target: Value,
indent: usize,
) -> fmt::Result {
for &a in &aliases[target] {
writeln!(w, "{1:0$}{2} -> {3}", indent, "", a, target)?;
write_value_aliases(w, aliases, a, indent)?;
}
Ok(())
}
@@ -265,13 +288,11 @@ fn write_value_aliases(w: &mut Write, func: &Function, inst: Inst, indent: usize
fn write_instruction(
w: &mut Write,
func: &Function,
aliases: &EntityMap<Value, Vec<Value>>,
isa: Option<&TargetIsa>,
inst: Inst,
indent: usize,
) -> fmt::Result {
// Value aliases come out on lines before the instruction using them.
write_value_aliases(w, func, inst, indent)?;
// Prefix containing source location, encoding, and value locations.
let mut s = String::with_capacity(16);
@@ -324,7 +345,13 @@ fn write_instruction(
}
write_operands(w, &func.dfg, isa, inst)?;
writeln!(w)
writeln!(w)?;
// Value aliases come out on lines after the instruction defining the referrent.
for r in func.dfg.inst_results(inst) {
write_value_aliases(w, aliases, *r, indent)?;
}
Ok(())
}
/// Write the operands of `inst` to `w` with a prepended space.
@@ -623,4 +650,40 @@ mod tests {
"function %foo() fast {\n ss0 = explicit_slot 4\n\nebb0(v0: i8, v1: f32x4):\n return\n}\n"
);
}
#[test]
fn aliases() {
use ir::InstBuilder;
let mut func = Function::new();
{
let ebb0 = func.dfg.make_ebb();
let mut pos = FuncCursor::new(&mut func);
pos.insert_ebb(ebb0);
// make some detached values for change_to_alias
let v0 = pos.func.dfg.append_ebb_param(ebb0, types::I32);
let v1 = pos.func.dfg.append_ebb_param(ebb0, types::I32);
let v2 = pos.func.dfg.append_ebb_param(ebb0, types::I32);
pos.func.dfg.detach_ebb_params(ebb0);
// alias to a param--will be printed at beginning of ebb defining param
let v3 = pos.func.dfg.append_ebb_param(ebb0, types::I32);
pos.func.dfg.change_to_alias(v0, v3);
// alias to an alias--should print attached to alias, not ultimate target
pos.func.dfg.make_value_alias_for_serialization(v0, v2); // v0 <- v2
// alias to a result--will be printed after instruction producing result
let _dummy0 = pos.ins().iconst(types::I32, 42);
let v4 = pos.ins().iadd(v0, v0);
pos.func.dfg.change_to_alias(v1, v4);
let _dummy1 = pos.ins().iconst(types::I32, 23);
let _v7 = pos.ins().iadd(v1, v1);
}
assert_eq!(
func.to_string(),
"function u0:0() fast {\nebb0(v3: i32):\n v0 -> v3\n v2 -> v0\n v4 = iconst.i32 42\n v5 = iadd v0, v0\n v1 -> v5\n v6 = iconst.i32 23\n v7 = iadd v1, v1\n}\n"
);
}
}