diff --git a/lib/cretonne/meta/cretonne/__init__.py b/lib/cretonne/meta/cretonne/__init__.py index a38126f98f..d9005d6572 100644 --- a/lib/cretonne/meta/cretonne/__init__.py +++ b/lib/cretonne/meta/cretonne/__init__.py @@ -795,7 +795,19 @@ class Instruction(object): InstructionGroup.append(self) def __str__(self): - return self.name + prefix = ', '.join(o.name for o in self.outs) + if prefix: + prefix = prefix + ' = ' + suffix = ', '.join(o.name for o in self.ins) + return '{}{} {}'.format(prefix, self.name, suffix) + + def blurb(self): + """Get the first line of the doc comment""" + for line in self.__doc__.split('\n'): + line = line.strip() + if line: + return line + return "" def _verify_polymorphic(self): """ diff --git a/lib/cretonne/meta/gen_instr.py b/lib/cretonne/meta/gen_instr.py index 8ae6d47ef7..4e854fe32c 100644 --- a/lib/cretonne/meta/gen_instr.py +++ b/lib/cretonne/meta/gen_instr.py @@ -177,14 +177,7 @@ def gen_opcodes(groups, fmt): for i in g.instructions: instrs.append(i) i.number = len(instrs) - # Build a doc comment. - prefix = ', '.join(o.name for o in i.outs) - if prefix: - prefix = prefix + ' = ' - suffix = ', '.join(o.name for o in i.ins) - fmt.doc_comment( - '`{}{} {}`. ({})' - .format(prefix, i.name, suffix, i.format.name)) + fmt.doc_comment('`{}`. ({})'.format(i, i.format.name)) # Document polymorphism. if i.is_polymorphic: if i.use_typevar_operand: @@ -370,7 +363,7 @@ def gen_format_constructor(iform, fmt): proto = '{}({}) -> Inst'.format(iform.name, ', '.join(args)) fmt.line('#[allow(non_snake_case)]') - with fmt.indented('pub fn {} {{'.format(proto), '}'): + with fmt.indented('fn {} {{'.format(proto), '}'): # Generate the instruction data. with fmt.indented( 'let data = InstructionData::{} {{'.format(iform.name), '};'): @@ -388,11 +381,9 @@ def gen_format_constructor(iform, fmt): # Create result values if necessary. if iform.multiple_results: - fmt.line('let inst = self.insert_inst(data);') - fmt.line('self.dfg.make_inst_results(inst, ctrl_typevar);') - fmt.line('inst') + fmt.line('self.complex_instruction(data, ctrl_typevar)') else: - fmt.line('self.insert_inst(data)') + fmt.line('self.simple_instruction(data)') def gen_member_inits(iform, fmt): @@ -452,8 +443,8 @@ def gen_inst_builder(inst, fmt): method = inst.name if method == 'return': - # Avoid Rust keywords - method = '_' + method + # Avoid Rust keywords by appending '_'. + method += '_' if len(tmpl_types) > 0: tmpl = '<{}>'.format(', '.join(tmpl_types)) @@ -461,8 +452,9 @@ def gen_inst_builder(inst, fmt): tmpl = '' proto = '{}{}({}) -> {}'.format(method, tmpl, ', '.join(args), rtype) + fmt.doc_comment('`{}`\n\n{}'.format(inst, inst.blurb())) fmt.line('#[allow(non_snake_case)]') - with fmt.indented('pub fn {} {{'.format(proto), '}'): + with fmt.indented('fn {} {{'.format(proto), '}'): # Convert all of the `Into<>` arguments. for arg in into_args: fmt.line('let {} = {}.into();'.format(arg, arg)) @@ -478,7 +470,7 @@ def gen_inst_builder(inst, fmt): elif inst.is_polymorphic: # Infer the controlling type variable from the input operands. fmt.line( - 'let ctrl_typevar = self.dfg.value_type({});' + 'let ctrl_typevar = self.data_flow_graph().value_type({});' .format(inst.ins[inst.format.typevar_operand].name)) args.append('ctrl_typevar') else: @@ -494,9 +486,11 @@ def gen_inst_builder(inst, fmt): if len(inst.value_results) == 0: fmt.line('inst') elif len(inst.value_results) == 1: - fmt.line('self.dfg.first_result(inst)') + fmt.line('self.data_flow_graph().first_result(inst)') else: - fmt.line('let mut results = self.dfg.inst_results(inst);') + fmt.line( + 'let mut results = ' + + 'self.data_flow_graph().inst_results(inst);') fmt.line('({})'.format(', '.join( len(inst.value_results) * ['results.next().unwrap()']))) @@ -505,16 +499,26 @@ def gen_builder(insts, fmt): """ Generate a Builder trait with methods for all instructions. """ - fmt.doc_comment( - 'Methods for inserting instructions by instruction format.') - with fmt.indented("impl<'a> Builder<'a> {", '}'): - for f in cretonne.InstructionFormat.all_formats: - gen_format_constructor(f, fmt) + fmt.doc_comment(""" + Convenience methods for building instructions. - fmt.doc_comment('Methods for inserting instructions by opcode.') - with fmt.indented("impl<'a> Builder<'a> {", '}'): + The `InstrBuilder` trait has one method per instruction opcode for + conveniently constructing the instruction with minimum arguments. + Polymorphic instructions infer their result types from the input + arguments when possible. In some cases, an explicit `result_type` + or `ctrl_typevar` argument is required. + + The opcode methods return the new instruction's result values, or + the `Inst` itself for instructions that don't have any results. + + There is also a method per instruction format. These methods all + return an `Inst`. + """) + with fmt.indented("pub trait InstBuilder: InstBuilderBase {", '}'): for inst in insts: gen_inst_builder(inst, fmt) + for f in cretonne.InstructionFormat.all_formats: + gen_format_constructor(f, fmt) def generate(isas, out_dir): diff --git a/lib/cretonne/src/cfg.rs b/lib/cretonne/src/cfg.rs index aab576ae82..59ced57d82 100644 --- a/lib/cretonne/src/cfg.rs +++ b/lib/cretonne/src/cfg.rs @@ -139,7 +139,7 @@ impl ControlFlowGraph { #[cfg(test)] mod tests { use super::*; - use ir::{Function, Builder, Cursor, VariableArgs, types}; + use ir::{Function, Builder, InstBuilder, Cursor, VariableArgs, types}; #[test] fn empty() { diff --git a/lib/cretonne/src/dominator_tree.rs b/lib/cretonne/src/dominator_tree.rs index 0e34a2c021..85d224060d 100644 --- a/lib/cretonne/src/dominator_tree.rs +++ b/lib/cretonne/src/dominator_tree.rs @@ -116,7 +116,7 @@ impl DominatorTree { #[cfg(test)] mod test { use super::*; - use ir::{Function, Builder, Cursor, VariableArgs, types}; + use ir::{Function, Builder, InstBuilder, Cursor, VariableArgs, types}; use ir::entities::NO_INST; use cfg::ControlFlowGraph; diff --git a/lib/cretonne/src/ir/builder.rs b/lib/cretonne/src/ir/builder.rs index f8510bb7f4..e8646d0dd1 100644 --- a/lib/cretonne/src/ir/builder.rs +++ b/lib/cretonne/src/ir/builder.rs @@ -9,6 +9,42 @@ use ir::{Opcode, Type, Inst, Value, Ebb, JumpTable, VariableArgs, SigRef, FuncRe use ir::immediates::{Imm64, Uimm8, Ieee32, Ieee64, ImmVector}; use ir::condcodes::{IntCC, FloatCC}; +/// Base trait for instruction builders. +/// +/// The `InstBuilderBase` trait provides the basic functionality required by the methods of the +/// generated `InstBuilder` trait. These methods should not normally be used directly. Use the +/// methods in the `InstBuilder trait instead. +/// +/// Any data type that implements `InstBuilderBase` also gets all the methods of the `InstBuilder` +/// trait. +pub trait InstBuilderBase { + /// Get an immutable reference to the data flow graph that will hold the constructed + /// instructions. + fn data_flow_graph(&self) -> &DataFlowGraph; + + /// Insert a simple instruction and return a reference to it. + /// + /// A 'simple' instruction has at most one result, and the `data.ty` field must contain the + /// result type or `VOID` for an instruction with no result values. + fn simple_instruction(&mut self, data: InstructionData) -> Inst; + + /// Insert a simple instruction and return a reference to it. + /// + /// A 'complex' instruction may produce multiple results, and the result types may depend on a + /// controlling type variable. For non-polymorphic instructions with multiple results, pass + /// `VOID` for the `ctrl_typevar` argument. + fn complex_instruction(&mut self, data: InstructionData, ctrl_typevar: Type) -> Inst; +} + +// Include trait code generated by `meta/gen_instr.py`. +// +// This file defines the `InstBuilder` trait as an extension of `InstBuilderBase` with methods per +// instruction format and per opcode. +include!(concat!(env!("OUT_DIR"), "/builder.rs")); + +/// Any type implementing `InstBuilderBase` gets all the `InstBuilder` methods for free. +impl InstBuilder for T {} + /// Instruction builder. /// /// A `Builder` holds mutable references to a data flow graph and a layout cursor. It provides @@ -40,16 +76,23 @@ impl<'a> Builder<'a> { pub fn insert_ebb(&mut self, ebb: Ebb) { self.pos.insert_ebb(ebb); } +} - // Create and insert an instruction. - // This method is used by the generated format-specific methods. - fn insert_inst(&mut self, data: InstructionData) -> Inst { +impl<'a> InstBuilderBase for Builder<'a> { + fn data_flow_graph(&self) -> &DataFlowGraph { + self.dfg + } + + fn simple_instruction(&mut self, data: InstructionData) -> Inst { let inst = self.dfg.make_inst(data); self.pos.insert_inst(inst); inst } -} -// Include code generated by `meta/gen_instr.py`. This file includes `Builder` methods per -// instruction format and per opcode for inserting instructions. -include!(concat!(env!("OUT_DIR"), "/builder.rs")); + fn complex_instruction(&mut self, data: InstructionData, ctrl_typevar: Type) -> Inst { + let inst = self.dfg.make_inst(data); + self.dfg.make_inst_results(inst, ctrl_typevar); + self.pos.insert_inst(inst); + inst + } +} diff --git a/lib/cretonne/src/ir/mod.rs b/lib/cretonne/src/ir/mod.rs index 5056d9b29e..0812496032 100644 --- a/lib/cretonne/src/ir/mod.rs +++ b/lib/cretonne/src/ir/mod.rs @@ -24,4 +24,4 @@ pub use ir::jumptable::JumpTableData; pub use ir::dfg::{DataFlowGraph, ValueDef}; pub use ir::layout::{Layout, Cursor}; pub use ir::function::Function; -pub use ir::builder::Builder; +pub use ir::builder::{Builder, InstBuilder};