diff --git a/lib/cretonne/src/ir/builder.rs b/lib/cretonne/src/ir/builder.rs index 59de1f68b5..697acfebd5 100644 --- a/lib/cretonne/src/ir/builder.rs +++ b/lib/cretonne/src/ir/builder.rs @@ -4,7 +4,7 @@ //! function. Many of its methods are generated from the meta language instruction definitions. use ir::types; -use ir::{InstructionData, DataFlowGraph, Cursor, CursorBase}; +use ir::{InstructionData, DataFlowGraph}; use ir::{Opcode, Type, Inst, Value, Ebb, JumpTable, SigRef, FuncRef, StackSlot, ValueList, MemFlags}; use ir::immediates::{Imm64, Uimm8, Ieee32, Ieee64, Offset32, Uoffset32}; @@ -43,23 +43,44 @@ include!(concat!(env!("OUT_DIR"), "/builder.rs")); /// Any type implementing `InstBuilderBase` gets all the `InstBuilder` methods for free. impl<'f, T: InstBuilderBase<'f>> InstBuilder<'f> for T {} -/// Builder that inserts an instruction at the current cursor position. +/// Base trait for instruction inserters. /// -/// An `InsertBuilder` holds mutable references to a data flow graph and a layout cursor. It -/// provides convenience methods for creating and inserting instructions at the current cursor -/// position. -pub struct InsertBuilder<'c, 'fc: 'c, 'fd> { - pos: &'c mut Cursor<'fc>, - dfg: &'fd mut DataFlowGraph, +/// This is an alternative base trait for an instruction builder to implement. +/// +/// An instruction inserter can be adapted into an instruction builder by wrapping it in an +/// `InsertBuilder`. This provides some common functionality for instruction builders that insert +/// new instructions, as opposed to the `ReplaceBuilder` which overwrites existing instructions. +pub trait InstInserterBase<'f>: Sized { + /// Get an immutable reference to the data flow graph. + fn data_flow_graph(&self) -> &DataFlowGraph; + + /// Get a mutable reference to the data flow graph. + fn data_flow_graph_mut(&mut self) -> &mut DataFlowGraph; + + /// Insert a new instruction which belongs to the DFG. + fn insert_built_inst(self, inst: Inst, ctrl_typevar: Type) -> &'f mut DataFlowGraph; } -impl<'c, 'fc, 'fd> InsertBuilder<'c, 'fc, 'fd> { +use std::marker::PhantomData; + +/// Builder that inserts an instruction at the current position. +/// +/// An `InsertBuilder` is a wrapper for an `InstInserterBase` that turns it into an instruction +/// builder with some additional facilities for creating instructions that reuse existing values as +/// their results. +pub struct InsertBuilder<'f, IIB: InstInserterBase<'f>> { + inserter: IIB, + unused: PhantomData<&'f u32>, +} + +impl<'f, IIB: InstInserterBase<'f>> InsertBuilder<'f, IIB> { /// Create a new builder which inserts instructions at `pos`. /// The `dfg` and `pos.layout` references should be from the same `Function`. - pub fn new(dfg: &'fd mut DataFlowGraph, - pos: &'c mut Cursor<'fc>) - -> InsertBuilder<'c, 'fc, 'fd> { - InsertBuilder { dfg, pos } + pub fn new(inserter: IIB) -> InsertBuilder<'f, IIB> { + InsertBuilder { + inserter, + unused: PhantomData, + } } /// Reuse result values in `reuse`. @@ -69,13 +90,13 @@ impl<'c, 'fc, 'fd> InsertBuilder<'c, 'fc, 'fd> { /// missing result values will be allocated as normal. /// /// The `reuse` argument is expected to be an array of `Option`. - pub fn with_results(self, reuse: Array) -> InsertReuseBuilder<'c, 'fc, 'fd, Array> + pub fn with_results(self, reuse: Array) -> InsertReuseBuilder<'f, IIB, Array> where Array: AsRef<[Option]> { InsertReuseBuilder { - dfg: self.dfg, - pos: self.pos, + inserter: self.inserter, reuse, + unused: PhantomData, } } @@ -86,57 +107,65 @@ impl<'c, 'fc, 'fd> InsertBuilder<'c, 'fc, 'fd> { /// /// This method should only be used when building an instruction with exactly one result. Use /// `with_results()` for the more general case. - pub fn with_result(self, v: Value) -> InsertReuseBuilder<'c, 'fc, 'fd, [Option; 1]> { + pub fn with_result(self, v: Value) -> InsertReuseBuilder<'f, IIB, [Option; 1]> { // TODO: Specialize this to return a different builder that just attaches `v` instead of // calling `make_inst_results_reusing()`. self.with_results([Some(v)]) } } -impl<'c, 'fc, 'fd> InstBuilderBase<'fd> for InsertBuilder<'c, 'fc, 'fd> { +impl<'f, IIB: InstInserterBase<'f>> InstBuilderBase<'f> for InsertBuilder<'f, IIB> { fn data_flow_graph(&self) -> &DataFlowGraph { - self.dfg + self.inserter.data_flow_graph() } fn data_flow_graph_mut(&mut self) -> &mut DataFlowGraph { - self.dfg + self.inserter.data_flow_graph_mut() } - fn build(self, data: InstructionData, ctrl_typevar: Type) -> (Inst, &'fd mut DataFlowGraph) { - let inst = self.dfg.make_inst(data); - self.dfg.make_inst_results(inst, ctrl_typevar); - self.pos.insert_inst(inst); - (inst, self.dfg) + fn build(mut self, data: InstructionData, ctrl_typevar: Type) -> (Inst, &'f mut DataFlowGraph) { + let inst; + { + let dfg = self.inserter.data_flow_graph_mut(); + inst = dfg.make_inst(data); + dfg.make_inst_results(inst, ctrl_typevar); + } + (inst, self.inserter.insert_built_inst(inst, ctrl_typevar)) } } /// Builder that inserts a new instruction like `InsertBuilder`, but reusing result values. -pub struct InsertReuseBuilder<'c, 'fc: 'c, 'fd, Array> - where Array: AsRef<[Option]> +pub struct InsertReuseBuilder<'f, IIB, Array> + where IIB: InstInserterBase<'f>, + Array: AsRef<[Option]> { - pos: &'c mut Cursor<'fc>, - dfg: &'fd mut DataFlowGraph, + inserter: IIB, reuse: Array, + unused: PhantomData<&'f u32>, } -impl<'c, 'fc, 'fd, Array> InstBuilderBase<'fd> for InsertReuseBuilder<'c, 'fc, 'fd, Array> - where Array: AsRef<[Option]> +impl<'f, IIB, Array> InstBuilderBase<'f> for InsertReuseBuilder<'f, IIB, Array> + where IIB: InstInserterBase<'f>, + Array: AsRef<[Option]> { fn data_flow_graph(&self) -> &DataFlowGraph { - self.dfg + self.inserter.data_flow_graph() } fn data_flow_graph_mut(&mut self) -> &mut DataFlowGraph { - self.dfg + self.inserter.data_flow_graph_mut() } - fn build(self, data: InstructionData, ctrl_typevar: Type) -> (Inst, &'fd mut DataFlowGraph) { - let inst = self.dfg.make_inst(data); - // Make an `Interator>`. - let ru = self.reuse.as_ref().iter().cloned(); - self.dfg.make_inst_results_reusing(inst, ctrl_typevar, ru); - self.pos.insert_inst(inst); - (inst, self.dfg) + fn build(mut self, data: InstructionData, ctrl_typevar: Type) -> (Inst, &'f mut DataFlowGraph) { + let inst; + { + let dfg = self.inserter.data_flow_graph_mut(); + inst = dfg.make_inst(data); + // Make an `Interator>`. + let ru = self.reuse.as_ref().iter().cloned(); + dfg.make_inst_results_reusing(inst, ctrl_typevar, ru); + } + (inst, self.inserter.insert_built_inst(inst, ctrl_typevar)) } } diff --git a/lib/cretonne/src/ir/dfg.rs b/lib/cretonne/src/ir/dfg.rs index 49d4d13d6a..959b29c8e8 100644 --- a/lib/cretonne/src/ir/dfg.rs +++ b/lib/cretonne/src/ir/dfg.rs @@ -5,7 +5,7 @@ use isa::TargetIsa; use ir::builder::{InsertBuilder, ReplaceBuilder}; use ir::extfunc::ExtFuncData; use ir::instructions::{Opcode, InstructionData, CallInfo}; -use ir::layout::Cursor; +use ir::layout::{Cursor, LayoutCursorInserter}; use ir::types; use ir::{Ebb, Inst, Value, Type, SigRef, Signature, FuncRef, ValueList, ValueListPool}; use write::write_operands; @@ -486,8 +486,8 @@ impl DataFlowGraph { /// Create an `InsertBuilder` that will insert an instruction at the cursor's current position. pub fn ins<'c, 'fc: 'c, 'fd>(&'fd mut self, at: &'c mut Cursor<'fc>) - -> InsertBuilder<'c, 'fc, 'fd> { - InsertBuilder::new(self, at) + -> InsertBuilder<'fd, LayoutCursorInserter<'c, 'fc, 'fd>> { + InsertBuilder::new(LayoutCursorInserter::new(at, self)) } /// Create a `ReplaceBuilder` that will replace `inst` with a new instruction in place. diff --git a/lib/cretonne/src/ir/layout.rs b/lib/cretonne/src/ir/layout.rs index 081a289053..b219a13bb2 100644 --- a/lib/cretonne/src/ir/layout.rs +++ b/lib/cretonne/src/ir/layout.rs @@ -7,7 +7,8 @@ use std::cmp; use std::iter::{Iterator, IntoIterator}; use entity_map::EntityMap; use packed_option::PackedOption; -use ir::entities::{Ebb, Inst}; +use ir::{Ebb, Inst, Type, DataFlowGraph}; +use ir::builder::InstInserterBase; use ir::progpoint::{ProgramOrder, ExpandedProgramPoint}; /// The `Layout` struct determines the layout of EBBs and instructions in a function. It does not @@ -1044,6 +1045,38 @@ impl<'f> Cursor<'f> { } } +/// An instruction inserter which can be used to build and insert instructions at a cursor +/// position. +/// +/// This is used by `dfg.ins()`. +pub struct LayoutCursorInserter<'c, 'fc: 'c, 'fd> { + pos: &'c mut Cursor<'fc>, + dfg: &'fd mut DataFlowGraph, +} + +impl<'c, 'fc: 'c, 'fd> LayoutCursorInserter<'c, 'fc, 'fd> { + /// Create a new inserter. Don't use this, use `dfg.ins(pos)`. + pub fn new(pos: &'c mut Cursor<'fc>, + dfg: &'fd mut DataFlowGraph) + -> LayoutCursorInserter<'c, 'fc, 'fd> { + LayoutCursorInserter { pos, dfg } + } +} + +impl<'c, 'fc: 'c, 'fd> InstInserterBase<'fd> for LayoutCursorInserter<'c, 'fc, 'fd> { + fn data_flow_graph(&self) -> &DataFlowGraph { + self.dfg + } + + fn data_flow_graph_mut(&mut self) -> &mut DataFlowGraph { + self.dfg + } + + fn insert_built_inst(self, inst: Inst, _ctrl_typevar: Type) -> &'fd mut DataFlowGraph { + self.pos.insert_inst(inst); + self.dfg + } +} #[cfg(test)] mod tests { diff --git a/lib/cretonne/src/ir/mod.rs b/lib/cretonne/src/ir/mod.rs index dfea1048b5..443d70bd1c 100644 --- a/lib/cretonne/src/ir/mod.rs +++ b/lib/cretonne/src/ir/mod.rs @@ -17,22 +17,21 @@ mod memflags; mod progpoint; mod valueloc; -pub use ir::funcname::FunctionName; +pub use ir::builder::{InstBuilder, InstBuilderBase, InstInserterBase, InsertBuilder}; +pub use ir::dfg::{DataFlowGraph, ValueDef}; +pub use ir::entities::{Ebb, Inst, Value, StackSlot, JumpTable, FuncRef, SigRef}; pub use ir::extfunc::{Signature, CallConv, ArgumentType, ArgumentExtension, ArgumentPurpose, ExtFuncData}; -pub use ir::types::Type; -pub use ir::entities::{Ebb, Inst, Value, StackSlot, JumpTable, FuncRef, SigRef}; -pub use ir::instructions::{Opcode, InstructionData, VariableArgs, ValueList, ValueListPool}; -pub use ir::stackslot::{StackSlots, StackSlotKind, StackSlotData}; -pub use ir::jumptable::JumpTableData; -pub use ir::valueloc::{ValueLoc, ArgumentLoc}; -pub use ir::dfg::{DataFlowGraph, ValueDef}; -pub use ir::layout::{Layout, CursorBase, Cursor}; +pub use ir::funcname::FunctionName; pub use ir::function::Function; -pub use ir::builder::InstBuilder; -pub use ir::progpoint::{ProgramPoint, ProgramOrder, ExpandedProgramPoint}; +pub use ir::instructions::{Opcode, InstructionData, VariableArgs, ValueList, ValueListPool}; +pub use ir::jumptable::JumpTableData; +pub use ir::layout::{Layout, CursorBase, Cursor}; pub use ir::memflags::MemFlags; -pub use ir::builder::InstBuilderBase; +pub use ir::progpoint::{ProgramPoint, ProgramOrder, ExpandedProgramPoint}; +pub use ir::stackslot::{StackSlots, StackSlotKind, StackSlotData}; +pub use ir::types::Type; +pub use ir::valueloc::{ValueLoc, ArgumentLoc}; use binemit; use entity_map::EntityMap;