From 578fec90cd122d9626f507619a586490bdb7ae90 Mon Sep 17 00:00:00 2001 From: Jakob Stoklund Olesen Date: Wed, 15 Mar 2017 17:04:58 -0700 Subject: [PATCH] Add DataFlowGraph::redefine_first_value() This makes it possible to compute the first result of an instruction in a different way without overwriting the original instruction with replace(). --- lib/cretonne/src/ir/dfg.rs | 49 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/lib/cretonne/src/ir/dfg.rs b/lib/cretonne/src/ir/dfg.rs index 5a70c92608..a1eb864af2 100644 --- a/lib/cretonne/src/ir/dfg.rs +++ b/lib/cretonne/src/ir/dfg.rs @@ -5,7 +5,7 @@ use ir::entities::ExpandedValue; use ir::instructions::{Opcode, InstructionData, CallInfo}; use ir::extfunc::ExtFuncData; use entity_map::{EntityMap, PrimaryEntityData}; -use ir::builder::{InsertBuilder, ReplaceBuilder}; +use ir::builder::{InsertBuilder, ReplaceBuilder, InstBuilder}; use ir::layout::Cursor; use packed_option::PackedOption; use write::write_operands; @@ -455,6 +455,41 @@ impl DataFlowGraph { panic!("{} is not a secondary result value", value); } + /// Move the instruction at `pos` to a new `Inst` reference so its first result can be + /// redefined without overwriting the original instruction. + /// + /// The first result value of an instruction is intrinsically tied to the `Inst` reference, so + /// it is not possible to detach the value and attach it to something else. This function + /// copies the instruction pointed to by `pos` to a new `Inst` reference, making the original + /// `Inst` reference available to be redefined with `dfg.replace(inst)` above. + /// + /// Before: + /// + /// inst1: v1, vx2 = foo <-- pos + /// + /// After: + /// + /// inst7: v7, vx2 = foo + /// inst1: v1 = copy v7 <-- pos + /// + /// Returns the new `Inst` reference where the original instruction has been moved. + pub fn redefine_first_value(&mut self, pos: &mut Cursor) -> Inst { + let orig = pos.current_inst().expect("Cursor must point at an instruction"); + let data = self[orig].clone(); + // After cloning, any secondary values are attached to both copies. Don't do that, we only + // want them on the new clone. + self.detach_secondary_results(orig); + let new = self.make_inst(data); + pos.insert_inst(new); + // Replace the original instruction with a copy of the new value. + // This is likely to be immediately overwritten by something else, but this way we avoid + // leaving the DFG in a state with multiple references to secondary results and value + // lists. It also means that this method doesn't change the semantics of the program. + let new_value = self.first_result(new); + self.replace(orig).copy(new_value); + new + } + /// Get the first result of an instruction. /// /// If `Inst` doesn't produce any results, this returns a `Value` with a `VOID` type. @@ -819,9 +854,19 @@ mod tests { _ => panic!(), }; + // Redefine the first value out of `iadd_cout`. + assert_eq!(pos.prev_inst(), Some(iadd)); + let new_iadd = dfg.redefine_first_value(pos); + let new_s = dfg.first_result(new_iadd); + assert_eq!(dfg[iadd].opcode(), Opcode::Copy); + assert_eq!(dfg.inst_results(iadd).collect::>(), [s]); + assert_eq!(dfg.inst_results(new_iadd).collect::>(), [new_s, c]); + assert_eq!(dfg.resolve_copies(s), new_s); + pos.next_inst(); + // Detach the 'c' value from `iadd`. { - assert_eq!(dfg.detach_secondary_results(iadd), Some(c)); + assert_eq!(dfg.detach_secondary_results(new_iadd), Some(c)); assert_eq!(dfg.next_secondary_result(c), None); }