diff --git a/lib/codegen/src/ir/dfg.rs b/lib/codegen/src/ir/dfg.rs index 9db7364002..6d799a43c9 100644 --- a/lib/codegen/src/ir/dfg.rs +++ b/lib/codegen/src/ir/dfg.rs @@ -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: 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 { + 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 { + pub fn value_alias_dest_for_serialization(&self, v: Value) -> Option { if let ValueData::Alias { original, .. } = self.values[v] { Some(original) } else { diff --git a/lib/codegen/src/print_errors.rs b/lib/codegen/src/print_errors.rs index 6e14182b1d..db557c865e 100644 --- a/lib/codegen/src/print_errors.rs +++ b/lib/codegen/src/print_errors.rs @@ -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>, 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>, 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; } diff --git a/lib/codegen/src/write.rs b/lib/codegen/src/write.rs index 71714727ae..24cfdbe284 100644 --- a/lib/codegen/src/write.rs +++ b/lib/codegen/src/write.rs @@ -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>, isa: Option<&TargetIsa>, inst: Inst, ident: usize, @@ -94,11 +96,12 @@ impl FuncWriter for PlainWriter { &mut self, w: &mut Write, func: &Function, + aliases: &EntityMap>, 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> { + 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( 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( func_w: &mut FW, w: &mut Write, func: &Function, + aliases: &EntityMap>, isa: Option<&TargetIsa>, ebb: Ebb, ) -> fmt::Result { @@ -206,8 +223,11 @@ fn decorate_ebb( }; 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 { 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>, + 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>, 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" + ); + } } diff --git a/lib/reader/src/parser.rs b/lib/reader/src/parser.rs index ee04728213..d1e14da50c 100644 --- a/lib/reader/src/parser.rs +++ b/lib/reader/src/parser.rs @@ -1688,7 +1688,7 @@ impl<'a> Parser<'a> { // Allow duplicate definitions of aliases, as long as they are identical. if ctx.map.contains_value(result) { - if let Some(old) = ctx.function.dfg.value_alias_dest_for_parser(result) { + if let Some(old) = ctx.function.dfg.value_alias_dest_for_serialization(result) { if old != dest { return err!( self.loc, @@ -1708,7 +1708,9 @@ impl<'a> Parser<'a> { return err!(self.loc, "value {} is not yet defined", dest); } - ctx.function.dfg.make_value_alias_for_parser(dest, result); + ctx.function + .dfg + .make_value_alias_for_serialization(dest, result); ctx.aliases.push(result); Ok(())