From 6db94bb9809c318a91f841f08c3709beaa9fe34c Mon Sep 17 00:00:00 2001 From: Jakob Stoklund Olesen Date: Wed, 19 Oct 2016 19:25:28 -0700 Subject: [PATCH] Switch InstrBuilder to the one-shot builder pattern. All the InstrBuilder methods now consume the builder, and the non-leaf methods return the dfg mutable reference they were holding. This makes it possible to construct instruction builders that are only safe to use once because they are doing more advanced value rewriting. --- lib/cretonne/meta/gen_instr.py | 34 ++++++++++++++++++++-------------- lib/cretonne/src/ir/builder.rs | 24 +++++++++++++++--------- 2 files changed, 35 insertions(+), 23 deletions(-) diff --git a/lib/cretonne/meta/gen_instr.py b/lib/cretonne/meta/gen_instr.py index 4e854fe32c..21bd8bcd85 100644 --- a/lib/cretonne/meta/gen_instr.py +++ b/lib/cretonne/meta/gen_instr.py @@ -347,7 +347,7 @@ def gen_format_constructor(iform, fmt): """ # Construct method arguments. - args = ['&mut self', 'opcode: Opcode'] + args = ['self', 'opcode: Opcode'] if iform.multiple_results: args.append('ctrl_typevar: Type') @@ -361,7 +361,9 @@ def gen_format_constructor(iform, fmt): for idx, kind in enumerate(iform.kinds): args.append('op{}: {}'.format(idx, kind.rust_type)) - proto = '{}({}) -> Inst'.format(iform.name, ', '.join(args)) + proto = '{}({})'.format(iform.name, ', '.join(args)) + proto += " -> (Inst, &'f mut DataFlowGraph)" + fmt.line('#[allow(non_snake_case)]') with fmt.indented('fn {} {{'.format(proto), '}'): # Generate the instruction data. @@ -414,7 +416,7 @@ def gen_inst_builder(inst, fmt): """ # Construct method arguments. - args = ['&mut self'] + args = ['self'] # The controlling type variable will be inferred from the input values if # possible. Otherwise, it is the first method argument. @@ -481,18 +483,21 @@ def gen_inst_builder(inst, fmt): args.extend(op.name for op in inst.ins) args = ', '.join(args) - fmt.line('let inst = self.{}({});'.format(inst.format.name, args)) + # Call to the format constructor, + fcall = 'self.{}({})'.format(inst.format.name, args) if len(inst.value_results) == 0: - fmt.line('inst') - elif len(inst.value_results) == 1: - fmt.line('self.data_flow_graph().first_result(inst)') - else: - fmt.line( - 'let mut results = ' + - 'self.data_flow_graph().inst_results(inst);') - fmt.line('({})'.format(', '.join( - len(inst.value_results) * ['results.next().unwrap()']))) + fmt.line(fcall + '.0') + return + + if len(inst.value_results) == 1: + fmt.line('Value::new_direct({}.0)'.format(fcall)) + return + + fmt.line('let (inst, dfg) = {};'.format(fcall)) + fmt.line('let mut results = dfg.inst_results(inst);') + fmt.line('({})'.format(', '.join( + len(inst.value_results) * ['results.next().unwrap()']))) def gen_builder(insts, fmt): @@ -514,7 +519,8 @@ def gen_builder(insts, fmt): There is also a method per instruction format. These methods all return an `Inst`. """) - with fmt.indented("pub trait InstBuilder: InstBuilderBase {", '}'): + with fmt.indented( + "pub trait InstBuilder<'f>: InstBuilderBase<'f> {", '}'): for inst in insts: gen_inst_builder(inst, fmt) for f in cretonne.InstructionFormat.all_formats: diff --git a/lib/cretonne/src/ir/builder.rs b/lib/cretonne/src/ir/builder.rs index a360263138..6ad50d9ab8 100644 --- a/lib/cretonne/src/ir/builder.rs +++ b/lib/cretonne/src/ir/builder.rs @@ -17,7 +17,7 @@ use ir::condcodes::{IntCC, FloatCC}; /// /// Any data type that implements `InstBuilderBase` also gets all the methods of the `InstBuilder` /// trait. -pub trait InstBuilderBase { +pub trait InstBuilderBase<'f>: Sized { /// Get an immutable reference to the data flow graph that will hold the constructed /// instructions. fn data_flow_graph(&self) -> &DataFlowGraph; @@ -26,14 +26,17 @@ pub trait InstBuilderBase { /// /// 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; + fn simple_instruction(self, data: InstructionData) -> (Inst, &'f mut DataFlowGraph); /// 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; + fn complex_instruction(self, + data: InstructionData, + ctrl_typevar: Type) + -> (Inst, &'f mut DataFlowGraph); } // Include trait code generated by `meta/gen_instr.py`. @@ -43,7 +46,7 @@ pub trait InstBuilderBase { include!(concat!(env!("OUT_DIR"), "/builder.rs")); /// Any type implementing `InstBuilderBase` gets all the `InstBuilder` methods for free. -impl InstBuilder for T {} +impl<'f, T: InstBuilderBase<'f>> InstBuilder<'f> for T {} /// Instruction builder. /// @@ -78,21 +81,24 @@ impl<'c, 'fc, 'fd> Builder<'c, 'fc, 'fd> { } } -impl<'c, 'fc, 'fd> InstBuilderBase for Builder<'c, 'fc, 'fd> { +impl<'c, 'fc, 'fd> InstBuilderBase<'fd> for Builder<'c, 'fc, 'fd> { fn data_flow_graph(&self) -> &DataFlowGraph { self.dfg } - fn simple_instruction(&mut self, data: InstructionData) -> Inst { + fn simple_instruction(self, data: InstructionData) -> (Inst, &'fd mut DataFlowGraph) { let inst = self.dfg.make_inst(data); self.pos.insert_inst(inst); - inst + (inst, self.dfg) } - fn complex_instruction(&mut self, data: InstructionData, ctrl_typevar: Type) -> Inst { + fn complex_instruction(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 + (inst, self.dfg) } }