diff --git a/cranelift/frontend/src/frontend.rs b/cranelift/frontend/src/frontend.rs index 37ac4b95dc..fbd2428e1c 100644 --- a/cranelift/frontend/src/frontend.rs +++ b/cranelift/frontend/src/frontend.rs @@ -20,22 +20,22 @@ use std::vec::Vec; /// In order to reduce memory reallocations when compiling multiple functions, /// `FunctionBuilderContext` holds various data structures which are cleared between /// functions, rather than dropped, preserving the underlying allocations. -struct FunctionBuilderContext { +pub struct FunctionBuilderContext { ssa: SSABuilder, ebbs: SecondaryMap, types: SecondaryMap, } /// Temporary object used to build a single Cranelift IR `Function`. -pub struct FunctionBuilder { +pub struct FunctionBuilder<'a> { /// The function currently being built. /// This field is public so the function can be re-borrowed. - pub func: Function, + pub func: &'a mut Function, /// Source location to assign to all new instructions. srcloc: ir::SourceLoc, - func_ctx: FunctionBuilderContext, + func_ctx: &'a mut FunctionBuilderContext, position: Position, } @@ -75,9 +75,8 @@ impl Position { } impl FunctionBuilderContext { - /// Creates a FunctionBuilderContext structure. The structure is - /// automatically cleared after each `FunctionBuilder` completes translating - /// a function. + /// Creates a FunctionBuilderContext structure. The structure is automatically cleared after + /// each [`FunctionBuilder`](struct.FunctionBuilder.html) completes translating a function. pub fn new() -> Self { Self { ssa: SSABuilder::new(), @@ -91,22 +90,26 @@ impl FunctionBuilderContext { self.ebbs.clear(); self.types.clear(); } + + fn is_empty(&self) -> bool { + self.ssa.is_empty() && self.ebbs.is_empty() && self.types.is_empty() + } } /// Implementation of the [`InstBuilder`](cranelift_codegen::ir::InstBuilder) that has /// one convenience method per Cranelift IR instruction. -pub struct FuncInstBuilder<'short> { - builder: &'short mut FunctionBuilder, +pub struct FuncInstBuilder<'short, 'long: 'short> { + builder: &'short mut FunctionBuilder<'long>, ebb: Ebb, } -impl<'short> FuncInstBuilder<'short> { - fn new(builder: &'short mut FunctionBuilder, ebb: Ebb) -> Self { +impl<'short, 'long> FuncInstBuilder<'short, 'long> { + fn new(builder: &'short mut FunctionBuilder<'long>, ebb: Ebb) -> Self { Self { builder, ebb } } } -impl<'short> InstBuilderBase<'short> for FuncInstBuilder<'short> { +impl<'short, 'long> InstBuilderBase<'short> for FuncInstBuilder<'short, 'long> { fn data_flow_graph(&self) -> &DataFlowGraph { &self.builder.func.dfg } @@ -200,9 +203,12 @@ impl<'short> InstBuilderBase<'short> for FuncInstBuilder<'short> { /// The first block for which you call `switch_to_block` will be assumed to be the beginning of /// the function. /// -/// At creation, a `FunctionBuilder` instance borrows an already allocated -/// `Function`. The function passed in should be newly created with -/// [`Function::with_name_signature()`](Function::with_name_signature). +/// At creation, a `FunctionBuilder` instance borrows an already allocated `Function` which it +/// modifies with the information stored in the mutable borrowed +/// [`FunctionBuilderContext`](struct.FunctionBuilderContext.html). The function passed in +/// argument should be newly created with +/// [`Function::with_name_signature()`](Function::with_name_signature), whereas the +/// `FunctionBuilderContext` can be kept as is between two function translations. /// /// # Errors /// @@ -210,13 +216,15 @@ impl<'short> InstBuilderBase<'short> for FuncInstBuilder<'short> { /// function in a way that violate the coherence of the code. For instance: switching to a new /// `Ebb` when you haven't filled the current one with a terminator instruction, inserting a /// return instruction with arguments that don't match the function's signature. -impl FunctionBuilder { - /// Creates a new FunctionBuilder structure that will operate on a `Function`. - pub fn new(func: Function) -> Self { +impl<'a> FunctionBuilder<'a> { + /// Creates a new FunctionBuilder structure that will operate on a `Function` using a + /// `FunctionBuilderContext`. + pub fn new(func: &'a mut Function, func_ctx: &'a mut FunctionBuilderContext) -> Self { + debug_assert!(func_ctx.is_empty()); Self { func, srcloc: Default::default(), - func_ctx: FunctionBuilderContext::new(), + func_ctx, position: Position::default(), } } @@ -271,7 +279,7 @@ impl FunctionBuilder { /// created. Forgetting to call this method on every block will cause inconsistencies in the /// produced functions. pub fn seal_block(&mut self, ebb: Ebb) { - let side_effects = self.func_ctx.ssa.seal_ebb_header_block(ebb, &mut self.func); + let side_effects = self.func_ctx.ssa.seal_ebb_header_block(ebb, self.func); self.handle_ssa_side_effects(side_effects); } @@ -282,7 +290,7 @@ impl FunctionBuilder { /// function can be used at the end of translating all blocks to ensure /// that everything is sealed. pub fn seal_all_blocks(&mut self) { - let side_effects = self.func_ctx.ssa.seal_all_ebb_header_blocks(&mut self.func); + let side_effects = self.func_ctx.ssa.seal_all_ebb_header_blocks(self.func); self.handle_ssa_side_effects(side_effects); } @@ -303,7 +311,7 @@ impl FunctionBuilder { }); self.func_ctx .ssa - .use_var(&mut self.func, var, ty, self.position.basic_block.unwrap()) + .use_var(self.func, var, ty, self.position.basic_block.unwrap()) }; self.handle_ssa_side_effects(side_effects); val @@ -385,7 +393,7 @@ impl FunctionBuilder { /// Returns an object with the [`InstBuilder`](cranelift_codegen::ir::InstBuilder) /// trait that allows to conveniently append an instruction to the current `Ebb` being built. - pub fn ins<'short>(&'short mut self) -> FuncInstBuilder<'short> { + pub fn ins<'short>(&'short mut self) -> FuncInstBuilder<'short, 'a> { let ebb = self .position .ebb @@ -415,7 +423,7 @@ impl FunctionBuilder { /// need to know about `FunctionBuilder` at all. pub fn cursor(&mut self) -> FuncCursor { self.ensure_inserted_ebb(); - FuncCursor::new(&mut self.func) + FuncCursor::new(self.func) .with_srcloc(self.srcloc) .at_bottom(self.position.ebb.unwrap()) } @@ -451,21 +459,10 @@ impl FunctionBuilder { } } - /// Clears the current state of the `FunctionBuilder` while preserving - /// allocations for reuse in translating another function. - pub fn clear(&mut self) { - // Clear the state (but preserve the allocated buffers) in preparation - // for translation another function. - self.func_ctx.clear(); - // Reset srcloc and position to initial states. - self.srcloc = Default::default(); - self.position = Position::default(); - } - - /// Declare that translation of the current function is complete, and return the completed - /// function. This resets the state of the `FunctionBuilder` in preparation to be used + /// Declare that translation of the current function is complete. This + /// resets the state of the `FunctionBuilder` in preparation to be used /// for another function. - pub fn finalize(&mut self) -> ir::Function { + pub fn finalize(&mut self) { // Check that all the `Ebb`s are filled and sealed. debug_assert!( self.func_ctx @@ -495,8 +492,13 @@ impl FunctionBuilder { } } - self.clear(); - std::mem::replace(&mut self.func, Function::new()) + // Clear the state (but preserve the allocated buffers) in preparation + // for translation another function. + self.func_ctx.clear(); + + // Reset srcloc and position to initial states. + self.srcloc = Default::default(); + self.position = Position::default(); } } @@ -505,7 +507,7 @@ impl FunctionBuilder { /// performance of your translation perform more complex transformations to your Cranelift IR /// function. The functions below help you inspect the function you're creating and modify it /// in ways that can be unsafe if used incorrectly. -impl FunctionBuilder { +impl<'a> FunctionBuilder<'a> { /// Retrieves all the parameters for an `Ebb` currently inferred from the jump instructions /// inserted that target it and the SSA construction. pub fn ebb_params(&self, ebb: Ebb) -> &[Value] { @@ -594,7 +596,7 @@ impl FunctionBuilder { } /// Helper functions -impl FunctionBuilder { +impl<'a> FunctionBuilder<'a> { /// Calls libc.memcpy /// /// Copies the `size` bytes from `src` to `dest`, assumes that `src + size` @@ -854,7 +856,7 @@ fn greatest_divisible_power_of_two(size: u64) -> u64 { } // Helper functions -impl FunctionBuilder { +impl<'a> FunctionBuilder<'a> { fn move_to_next_basic_block(&mut self) { self.position.basic_block = PackedOption::from( self.func_ctx @@ -889,7 +891,7 @@ impl FunctionBuilder { #[cfg(test)] mod tests { use super::greatest_divisible_power_of_two; - use crate::frontend::FunctionBuilder; + use crate::frontend::{FunctionBuilder, FunctionBuilderContext}; use crate::Variable; use cranelift_codegen::entity::EntityRef; use cranelift_codegen::ir::types::*; @@ -904,9 +906,10 @@ mod tests { sig.returns.push(AbiParam::new(I32)); sig.params.push(AbiParam::new(I32)); - let func = { - let func = Function::with_name_signature(ExternalName::testcase("sample"), sig); - let mut builder = FunctionBuilder::new(func); + let mut fn_ctx = FunctionBuilderContext::new(); + let mut func = Function::with_name_signature(ExternalName::testcase("sample"), sig); + { + let mut builder = FunctionBuilder::new(&mut func, &mut fn_ctx); let block0 = builder.create_ebb(); let block1 = builder.create_ebb(); @@ -988,8 +991,8 @@ mod tests { builder.seal_all_blocks(); } - builder.finalize() - }; + builder.finalize(); + } let flags = settings::Flags::new(settings::builder()); // println!("{}", func.display(None)); @@ -1026,9 +1029,10 @@ mod tests { let mut sig = Signature::new(target.default_call_conv()); sig.returns.push(AbiParam::new(I32)); - let func = { - let func = Function::with_name_signature(ExternalName::testcase("sample"), sig); - let mut builder = FunctionBuilder::new(func); + let mut fn_ctx = FunctionBuilderContext::new(); + let mut func = Function::with_name_signature(ExternalName::testcase("sample"), sig); + { + let mut builder = FunctionBuilder::new(&mut func, &mut fn_ctx); let block0 = builder.create_ebb(); let x = Variable::new(0); @@ -1047,8 +1051,8 @@ mod tests { builder.ins().return_(&[size]); builder.seal_all_blocks(); - builder.finalize() - }; + builder.finalize(); + } assert_eq!( func.display(None).to_string(), @@ -1086,9 +1090,10 @@ ebb0: let mut sig = Signature::new(target.default_call_conv()); sig.returns.push(AbiParam::new(I32)); - let func = { - let func = Function::with_name_signature(ExternalName::testcase("sample"), sig); - let mut builder = FunctionBuilder::new(func); + let mut fn_ctx = FunctionBuilderContext::new(); + let mut func = Function::with_name_signature(ExternalName::testcase("sample"), sig); + { + let mut builder = FunctionBuilder::new(&mut func, &mut fn_ctx); let block0 = builder.create_ebb(); let x = Variable::new(0); @@ -1105,8 +1110,8 @@ ebb0: builder.ins().return_(&[dest]); builder.seal_all_blocks(); - builder.finalize() - }; + builder.finalize(); + } assert_eq!( func.display(None).to_string(), @@ -1142,9 +1147,10 @@ ebb0: let mut sig = Signature::new(target.default_call_conv()); sig.returns.push(AbiParam::new(I32)); - let func = { - let func = Function::with_name_signature(ExternalName::testcase("sample"), sig); - let mut builder = FunctionBuilder::new(func); + let mut fn_ctx = FunctionBuilderContext::new(); + let mut func = Function::with_name_signature(ExternalName::testcase("sample"), sig); + { + let mut builder = FunctionBuilder::new(&mut func, &mut fn_ctx); let block0 = builder.create_ebb(); let x = Variable::new(0); @@ -1161,8 +1167,8 @@ ebb0: builder.ins().return_(&[dest]); builder.seal_all_blocks(); - builder.finalize() - }; + builder.finalize(); + } assert_eq!( func.display(None).to_string(), @@ -1201,9 +1207,10 @@ ebb0: let mut sig = Signature::new(target.default_call_conv()); sig.returns.push(AbiParam::new(I32)); - let func = { - let func = Function::with_name_signature(ExternalName::testcase("sample"), sig); - let mut builder = FunctionBuilder::new(func); + let mut fn_ctx = FunctionBuilderContext::new(); + let mut func = Function::with_name_signature(ExternalName::testcase("sample"), sig); + { + let mut builder = FunctionBuilder::new(&mut func, &mut fn_ctx); let block0 = builder.create_ebb(); let y = Variable::new(16); @@ -1217,8 +1224,8 @@ ebb0: builder.ins().return_(&[dest]); builder.seal_all_blocks(); - builder.finalize() - }; + builder.finalize(); + } assert_eq!( func.display(None).to_string(), @@ -1252,9 +1259,10 @@ ebb0: let mut sig = Signature::new(target.default_call_conv()); sig.returns.push(AbiParam::new(I32)); - let func = { - let func = Function::with_name_signature(ExternalName::testcase("sample"), sig); - let mut builder = FunctionBuilder::new(func); + let mut fn_ctx = FunctionBuilderContext::new(); + let mut func = Function::with_name_signature(ExternalName::testcase("sample"), sig); + { + let mut builder = FunctionBuilder::new(&mut func, &mut fn_ctx); let block0 = builder.create_ebb(); let y = Variable::new(16); @@ -1268,8 +1276,8 @@ ebb0: builder.ins().return_(&[dest]); builder.seal_all_blocks(); - builder.finalize() - }; + builder.finalize(); + } assert_eq!( func.display(None).to_string(), diff --git a/cranelift/frontend/src/lib.rs b/cranelift/frontend/src/lib.rs index 14cd7502dc..eff5c655fd 100644 --- a/cranelift/frontend/src/lib.rs +++ b/cranelift/frontend/src/lib.rs @@ -3,7 +3,7 @@ //! Provides a straightforward way to create a Cranelift IR function and fill it with instructions //! corresponding to your source program written in another language. //! -//! To get started, create an [`Function`](../cranelift_codegen/ir/function/struct.Function.html) and +//! To get started, create an [`FunctionBuilderContext`](struct.FunctionBuilderContext.html) and //! pass it as an argument to a [`FunctionBuilder`](struct.FunctionBuilder.html). //! //! # Mutable variables and Cranelift IR values @@ -61,7 +61,7 @@ //! } //! ``` //! -//! Here is how you build the corresponding Cranelift IR function using `Function`: +//! Here is how you build the corresponding Cranelift IR function using `FunctionBuilderContext`: //! //! ```rust //! extern crate cranelift_codegen; @@ -73,15 +73,16 @@ //! use cranelift_codegen::isa::CallConv; //! use cranelift_codegen::settings; //! use cranelift_codegen::verifier::verify_function; -//! use cranelift_frontend::{FunctionBuilder, Variable}; +//! use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext, Variable}; //! //! fn main() { //! let mut sig = Signature::new(CallConv::SystemV); //! sig.returns.push(AbiParam::new(I32)); //! sig.params.push(AbiParam::new(I32)); -//! let func = { -//! let func = Function::with_name_signature(ExternalName::user(0, 0), sig); -//! let mut builder = FunctionBuilder::new(func); +//! let mut fn_builder_ctx = FunctionBuilderContext::new(); +//! let mut func = Function::with_name_signature(ExternalName::user(0, 0), sig); +//! { +//! let mut builder = FunctionBuilder::new(&mut func, &mut fn_builder_ctx); //! //! let block0 = builder.create_ebb(); //! let block1 = builder.create_ebb(); @@ -151,8 +152,8 @@ //! builder.ins().jump(block1, &[]); //! builder.seal_block(block1); //! -//! builder.finalize() -//! }; +//! builder.finalize(); +//! } //! //! let flags = settings::Flags::new(settings::builder()); //! let res = verify_function(&func, &flags); @@ -194,7 +195,7 @@ use hashmap_core::HashMap; #[cfg(feature = "std")] use std::collections::HashMap; -pub use crate::frontend::FunctionBuilder; +pub use crate::frontend::{FunctionBuilder, FunctionBuilderContext}; pub use crate::switch::Switch; pub use crate::variable::Variable; diff --git a/cranelift/frontend/src/ssa.rs b/cranelift/frontend/src/ssa.rs index 43300f4ded..b3b74fac9b 100644 --- a/cranelift/frontend/src/ssa.rs +++ b/cranelift/frontend/src/ssa.rs @@ -176,7 +176,9 @@ impl SSABuilder { self.variables.clear(); self.blocks.clear(); self.ebb_headers.clear(); - debug_assert!(self.is_empty()); + debug_assert!(self.calls.is_empty()); + debug_assert!(self.results.is_empty()); + debug_assert!(self.side_effects.is_empty()); } /// Tests whether an `SSABuilder` is in a cleared state. diff --git a/cranelift/frontend/src/switch.rs b/cranelift/frontend/src/switch.rs index 33b2001655..0b1ca746cb 100644 --- a/cranelift/frontend/src/switch.rs +++ b/cranelift/frontend/src/switch.rs @@ -16,11 +16,12 @@ type EntryIndex = u64; /// # use cranelift_codegen::ir::types::*; /// # use cranelift_codegen::ir::{ExternalName, Function, Signature, InstBuilder}; /// # use cranelift_codegen::isa::CallConv; -/// # use cranelift_frontend::{FunctionBuilder, Switch}; +/// # use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext, Switch}; /// # /// # let mut sig = Signature::new(CallConv::SystemV); +/// # let mut fn_builder_ctx = FunctionBuilderContext::new(); /// # let mut func = Function::with_name_signature(ExternalName::user(0, 0), sig); -/// # let mut builder = FunctionBuilder::new(func); +/// # let mut builder = FunctionBuilder::new(&mut func, &mut fn_builder_ctx); /// # /// # let entry = builder.create_ebb(); /// # builder.switch_to_block(entry); @@ -288,13 +289,16 @@ impl ContiguousCaseRange { #[cfg(test)] mod tests { use super::*; + use crate::frontend::FunctionBuilderContext; use cranelift_codegen::ir::Function; use std::string::ToString; macro_rules! setup { ($default:expr, [$($index:expr,)*]) => {{ - let func = { - let mut bx = FunctionBuilder::new(Function::new()); + let mut func = Function::new(); + let mut func_ctx = FunctionBuilderContext::new(); + { + let mut bx = FunctionBuilder::new(&mut func, &mut func_ctx); let ebb = bx.create_ebb(); bx.switch_to_block(ebb); let val = bx.ins().iconst(types::I8, 0); @@ -304,9 +308,7 @@ mod tests { switch.set_entry($index, ebb); )* switch.emit(&mut bx, val, Ebb::with_number($default).unwrap()); - bx.seal_all_blocks(); - bx.finalize() - }; + } func .to_string() .trim_start_matches("function u0:0() fast {\n") diff --git a/cranelift/frontend/src/variable.rs b/cranelift/frontend/src/variable.rs index 1a061beb97..dddcd7490b 100644 --- a/cranelift/frontend/src/variable.rs +++ b/cranelift/frontend/src/variable.rs @@ -1,6 +1,6 @@ //! A basic `Variable` implementation. //! -//! `FunctionBuilder` and related types have a `Variable` +//! `FunctionBuilderContext`, `FunctionBuilder`, and related types have a `Variable` //! type parameter, to allow frontends that identify variables with //! their own index types to use them directly. Frontends which don't //! can use the `Variable` defined here. diff --git a/cranelift/simplejit/examples/simplejit-minimal.rs b/cranelift/simplejit/examples/simplejit-minimal.rs index 2fc28367eb..3b8e147830 100644 --- a/cranelift/simplejit/examples/simplejit-minimal.rs +++ b/cranelift/simplejit/examples/simplejit-minimal.rs @@ -7,6 +7,7 @@ fn main() { let mut module: Module = Module::new(SimpleJITBuilder::new(default_libcall_names())); let mut ctx = module.make_context(); + let mut func_ctx = FunctionBuilderContext::new(); let mut sig_a = module.make_signature(); sig_a.params.push(AbiParam::new(types::I32)); @@ -24,8 +25,8 @@ fn main() { ctx.func.signature = sig_a; ctx.func.name = ExternalName::user(0, func_a.as_u32()); - ctx.func = { - let mut bcx: FunctionBuilder = FunctionBuilder::new(ctx.func); + { + let mut bcx: FunctionBuilder = FunctionBuilder::new(&mut ctx.func, &mut func_ctx); let ebb = bcx.create_ebb(); bcx.switch_to_block(ebb); @@ -35,15 +36,15 @@ fn main() { let add = bcx.ins().iadd(cst, param); bcx.ins().return_(&[add]); bcx.seal_all_blocks(); - bcx.finalize() - }; + bcx.finalize(); + } module.define_function(func_a, &mut ctx).unwrap(); module.clear_context(&mut ctx); ctx.func.signature = sig_b; ctx.func.name = ExternalName::user(0, func_b.as_u32()); - ctx.func = { - let mut bcx: FunctionBuilder = FunctionBuilder::new(ctx.func); + { + let mut bcx: FunctionBuilder = FunctionBuilder::new(&mut ctx.func, &mut func_ctx); let ebb = bcx.create_ebb(); bcx.switch_to_block(ebb); @@ -57,8 +58,8 @@ fn main() { }; bcx.ins().return_(&[value]); bcx.seal_all_blocks(); - bcx.finalize() - }; + bcx.finalize(); + } module.define_function(func_b, &mut ctx).unwrap(); module.clear_context(&mut ctx); diff --git a/cranelift/simplejit/tests/basic.rs b/cranelift/simplejit/tests/basic.rs index ea3f9cb5fd..a3932b1d6a 100644 --- a/cranelift/simplejit/tests/basic.rs +++ b/cranelift/simplejit/tests/basic.rs @@ -37,16 +37,14 @@ fn define_simple_function(module: &mut Module) -> FuncId { .unwrap(); let mut ctx = Context::new(); - - ctx.func = { - let func = Function::with_name_signature(ExternalName::user(0, func_id.as_u32()), sig); - let mut bcx: FunctionBuilder = FunctionBuilder::new(func); + ctx.func = Function::with_name_signature(ExternalName::user(0, func_id.as_u32()), sig); + let mut func_ctx = FunctionBuilderContext::new(); + { + let mut bcx: FunctionBuilder = FunctionBuilder::new(&mut ctx.func, &mut func_ctx); let ebb = bcx.create_ebb(); bcx.switch_to_block(ebb); bcx.ins().return_(&[]); - bcx.seal_all_blocks(); - bcx.finalize() - }; + } module.define_function(func_id, &mut ctx).unwrap(); @@ -87,9 +85,11 @@ fn switch_error() { call_conv: CallConv::SystemV, }; - let func = { - let func = Function::with_name_signature(ExternalName::user(0, 0), sig); - let mut bcx: FunctionBuilder = FunctionBuilder::new(func); + let mut func = Function::with_name_signature(ExternalName::user(0, 0), sig); + + let mut func_ctx = FunctionBuilderContext::new(); + { + let mut bcx: FunctionBuilder = FunctionBuilder::new(&mut func, &mut func_ctx); let start = bcx.create_ebb(); let bb0 = bcx.create_ebb(); let bb1 = bcx.create_ebb(); @@ -134,8 +134,8 @@ fn switch_error() { bcx.ins().return_(&[r]); bcx.seal_all_blocks(); - bcx.finalize() - }; + bcx.finalize(); + } let flags = settings::Flags::new(settings::builder()); match cranelift_codegen::verify_function(&func, &flags) { @@ -164,9 +164,10 @@ fn libcall_function() { .unwrap(); let mut ctx = Context::new(); - ctx.func = { - let func = Function::with_name_signature(ExternalName::user(0, func_id.as_u32()), sig); - let mut bcx: FunctionBuilder = FunctionBuilder::new(func); + ctx.func = Function::with_name_signature(ExternalName::user(0, func_id.as_u32()), sig); + let mut func_ctx = FunctionBuilderContext::new(); + { + let mut bcx: FunctionBuilder = FunctionBuilder::new(&mut ctx.func, &mut func_ctx); let ebb = bcx.create_ebb(); bcx.switch_to_block(ebb); @@ -188,11 +189,7 @@ fn libcall_function() { bcx.call_memset(module.target_config(), buffer, zero, size); bcx.ins().return_(&[]); - - bcx.seal_all_blocks(); - - bcx.finalize() - }; + } module.define_function(func_id, &mut ctx).unwrap(); diff --git a/cranelift/umbrella/src/lib.rs b/cranelift/umbrella/src/lib.rs index acb0e972d8..f97ed443ce 100644 --- a/cranelift/umbrella/src/lib.rs +++ b/cranelift/umbrella/src/lib.rs @@ -43,7 +43,7 @@ pub mod prelude { pub use crate::codegen::isa; pub use crate::codegen::settings::{self, Configurable}; - pub use crate::frontend::{FunctionBuilder, Variable}; + pub use crate::frontend::{FunctionBuilder, FunctionBuilderContext, Variable}; } /// Version number of this crate. diff --git a/cranelift/wasm/src/code_translator.rs b/cranelift/wasm/src/code_translator.rs index e5ce5a0c32..c420147550 100644 --- a/cranelift/wasm/src/code_translator.rs +++ b/cranelift/wasm/src/code_translator.rs @@ -81,7 +81,7 @@ pub fn translate_operator( * `get_global` and `set_global` are handled by the environment. ***********************************************************************************/ Operator::GetGlobal { global_index } => { - let val = match state.get_global(&mut builder.func, *global_index, environ)? { + let val = match state.get_global(builder.func, *global_index, environ)? { GlobalVariable::Const(val) => val, GlobalVariable::Memory { gv, offset, ty } => { let addr = builder.ins().global_value(environ.pointer_type(), gv); @@ -92,7 +92,7 @@ pub fn translate_operator( state.push1(val); } Operator::SetGlobal { global_index } => { - match state.get_global(&mut builder.func, *global_index, environ)? { + match state.get_global(builder.func, *global_index, environ)? { GlobalVariable::Const(_) => panic!("global #{} is a constant", *global_index), GlobalVariable::Memory { gv, offset, ty } => { let addr = builder.ins().global_value(environ.pointer_type(), gv); @@ -367,8 +367,7 @@ pub fn translate_operator( * argument referring to an index in the external functions table of the module. ************************************************************************************/ Operator::Call { function_index } => { - let (fref, num_args) = - state.get_direct_func(&mut builder.func, *function_index, environ)?; + let (fref, num_args) = state.get_direct_func(builder.func, *function_index, environ)?; let call = environ.translate_call( builder.cursor(), FuncIndex::from_u32(*function_index), @@ -389,8 +388,8 @@ pub fn translate_operator( Operator::CallIndirect { index, table_index } => { // `index` is the index of the function's signature and `table_index` is the index of // the table to search the function in. - let (sigref, num_args) = state.get_indirect_sig(&mut builder.func, *index, environ)?; - let table = state.get_table(&mut builder.func, *table_index, environ)?; + let (sigref, num_args) = state.get_indirect_sig(builder.func, *index, environ)?; + let table = state.get_table(builder.func, *table_index, environ)?; let callee = state.pop1(); let call = environ.translate_call_indirect( builder.cursor(), @@ -418,13 +417,13 @@ pub fn translate_operator( // The WebAssembly MVP only supports one linear memory, but we expect the reserved // argument to be a memory index. let heap_index = MemoryIndex::from_u32(*reserved); - let heap = state.get_heap(&mut builder.func, *reserved, environ)?; + let heap = state.get_heap(builder.func, *reserved, environ)?; let val = state.pop1(); state.push1(environ.translate_memory_grow(builder.cursor(), heap_index, heap, val)?) } Operator::MemorySize { reserved } => { let heap_index = MemoryIndex::from_u32(*reserved); - let heap = state.get_heap(&mut builder.func, *reserved, environ)?; + let heap = state.get_heap(builder.func, *reserved, environ)?; state.push1(environ.translate_memory_size(builder.cursor(), heap_index, heap)?); } /******************************* Load instructions *********************************** @@ -1238,7 +1237,7 @@ fn translate_load( ) -> WasmResult<()> { let addr32 = state.pop1(); // We don't yet support multiple linear memories. - let heap = state.get_heap(&mut builder.func, 0, environ)?; + let heap = state.get_heap(builder.func, 0, environ)?; let (base, offset) = get_heap_addr(heap, addr32, offset, environ.pointer_type(), builder); // Note that we don't set `is_aligned` here, even if the load instruction's // alignment immediate says it's aligned, because WebAssembly's immediate @@ -1263,7 +1262,7 @@ fn translate_store( let val_ty = builder.func.dfg.value_type(val); // We don't yet support multiple linear memories. - let heap = state.get_heap(&mut builder.func, 0, environ)?; + let heap = state.get_heap(builder.func, 0, environ)?; let (base, offset) = get_heap_addr(heap, addr32, offset, environ.pointer_type(), builder); // See the comments in `translate_load` about the flags. let flags = MemFlags::new(); diff --git a/cranelift/wasm/src/environ/dummy.rs b/cranelift/wasm/src/environ/dummy.rs index 98cdb3f44e..fde1e6b19d 100644 --- a/cranelift/wasm/src/environ/dummy.rs +++ b/cranelift/wasm/src/environ/dummy.rs @@ -543,7 +543,8 @@ impl<'data> ModuleEnvironment<'data> for DummyEnvironment { func.collect_debug_info(); } self.trans - .translate(body_bytes, body_offset, func, &mut func_environ)? + .translate(body_bytes, body_offset, &mut func, &mut func_environ)?; + func }; self.func_bytecode_sizes.push(body_bytes.len()); self.info.function_bodies.push(func); diff --git a/cranelift/wasm/src/func_translator.rs b/cranelift/wasm/src/func_translator.rs index ed5c51e59f..b49cffd474 100644 --- a/cranelift/wasm/src/func_translator.rs +++ b/cranelift/wasm/src/func_translator.rs @@ -12,7 +12,7 @@ use crate::wasm_unsupported; use cranelift_codegen::entity::EntityRef; use cranelift_codegen::ir::{self, Ebb, InstBuilder, ValueLabel}; use cranelift_codegen::timing; -use cranelift_frontend::{FunctionBuilder, Variable}; +use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext, Variable}; use log::info; use wasmparser::{self, BinaryReader}; @@ -22,7 +22,7 @@ use wasmparser::{self, BinaryReader}; /// by a `FuncEnvironment` object. A single translator instance can be reused to translate multiple /// functions which will reduce heap allocation traffic. pub struct FuncTranslator { - builder: FunctionBuilder, + func_ctx: FunctionBuilderContext, state: TranslationState, } @@ -30,7 +30,7 @@ impl FuncTranslator { /// Create a new translator. pub fn new() -> Self { Self { - builder: FunctionBuilder::new(ir::Function::new()), + func_ctx: FunctionBuilderContext::new(), state: TranslationState::new(), } } @@ -57,9 +57,9 @@ impl FuncTranslator { &mut self, code: &[u8], code_offset: usize, - func: ir::Function, + func: &mut ir::Function, environ: &mut FE, - ) -> WasmResult { + ) -> WasmResult<()> { self.translate_from_reader( BinaryReader::new_with_offset(code, code_offset), func, @@ -71,9 +71,9 @@ impl FuncTranslator { pub fn translate_from_reader( &mut self, mut reader: BinaryReader, - func: ir::Function, + func: &mut ir::Function, environ: &mut FE, - ) -> WasmResult { + ) -> WasmResult<()> { let _tt = timing::wasm_translate_function(); info!( "translate({} bytes, {}{})", @@ -84,32 +84,31 @@ impl FuncTranslator { debug_assert_eq!(func.dfg.num_ebbs(), 0, "Function must be empty"); debug_assert_eq!(func.dfg.num_insts(), 0, "Function must be empty"); - self.builder.func = func; - self.builder.set_srcloc(cur_srcloc(&reader)); - let entry_block = self.builder.create_ebb(); - self.builder - .append_ebb_params_for_function_params(entry_block); - self.builder.switch_to_block(entry_block); // This also creates values for the arguments. - self.builder.seal_block(entry_block); // Declare all predecessors known. + // This clears the `FunctionBuilderContext`. + let mut builder = FunctionBuilder::new(func, &mut self.func_ctx); + builder.set_srcloc(cur_srcloc(&reader)); + let entry_block = builder.create_ebb(); + builder.append_ebb_params_for_function_params(entry_block); + builder.switch_to_block(entry_block); // This also creates values for the arguments. + builder.seal_block(entry_block); // Declare all predecessors known. // Make sure the entry block is inserted in the layout before we make any callbacks to // `environ`. The callback functions may need to insert things in the entry block. - self.builder.ensure_inserted_ebb(); + builder.ensure_inserted_ebb(); - let num_params = declare_wasm_parameters(&mut self.builder, entry_block); + let num_params = declare_wasm_parameters(&mut builder, entry_block); // Set up the translation state with a single pushed control block representing the whole // function and its return values. - let exit_block = self.builder.create_ebb(); - self.builder - .append_ebb_params_for_function_returns(exit_block); - self.state - .initialize(&self.builder.func.signature, exit_block); + let exit_block = builder.create_ebb(); + builder.append_ebb_params_for_function_returns(exit_block); + self.state.initialize(&builder.func.signature, exit_block); - parse_local_decls(&mut reader, &mut self.builder, num_params, environ)?; - parse_function_body(reader, &mut self.builder, &mut self.state, environ)?; + parse_local_decls(&mut reader, &mut builder, num_params, environ)?; + parse_function_body(reader, &mut builder, &mut self.state, environ)?; - Ok(self.builder.finalize()) + builder.finalize(); + Ok(()) } } @@ -289,8 +288,8 @@ mod tests { ctx.func.signature.params.push(ir::AbiParam::new(I32)); ctx.func.signature.returns.push(ir::AbiParam::new(I32)); - ctx.func = trans - .translate(&BODY, 0, ctx.func, &mut runtime.func_env()) + trans + .translate(&BODY, 0, &mut ctx.func, &mut runtime.func_env()) .unwrap(); debug!("{}", ctx.func.display(None)); ctx.verify(&flags).unwrap(); @@ -328,8 +327,8 @@ mod tests { ctx.func.signature.params.push(ir::AbiParam::new(I32)); ctx.func.signature.returns.push(ir::AbiParam::new(I32)); - ctx.func = trans - .translate(&BODY, 0, ctx.func, &mut runtime.func_env()) + trans + .translate(&BODY, 0, &mut ctx.func, &mut runtime.func_env()) .unwrap(); debug!("{}", ctx.func.display(None)); ctx.verify(&flags).unwrap(); @@ -375,8 +374,8 @@ mod tests { ctx.func.name = ir::ExternalName::testcase("infloop"); ctx.func.signature.returns.push(ir::AbiParam::new(I32)); - ctx.func = trans - .translate(&BODY, 0, ctx.func, &mut runtime.func_env()) + trans + .translate(&BODY, 0, &mut ctx.func, &mut runtime.func_env()) .unwrap(); debug!("{}", ctx.func.display(None)); ctx.verify(&flags).unwrap();