Remove FunctionBuilderContext from API, and change FunctionBuilder API

This commit is contained in:
Aaron Power
2019-03-21 10:32:42 +01:00
committed by Dan Gohman
parent 0273eb84e0
commit 8fd1128990
11 changed files with 162 additions and 172 deletions

View File

@@ -20,22 +20,22 @@ use std::vec::Vec;
/// In order to reduce memory reallocations when compiling multiple functions, /// In order to reduce memory reallocations when compiling multiple functions,
/// `FunctionBuilderContext` holds various data structures which are cleared between /// `FunctionBuilderContext` holds various data structures which are cleared between
/// functions, rather than dropped, preserving the underlying allocations. /// functions, rather than dropped, preserving the underlying allocations.
pub struct FunctionBuilderContext { struct FunctionBuilderContext {
ssa: SSABuilder, ssa: SSABuilder,
ebbs: SecondaryMap<Ebb, EbbData>, ebbs: SecondaryMap<Ebb, EbbData>,
types: SecondaryMap<Variable, Type>, types: SecondaryMap<Variable, Type>,
} }
/// Temporary object used to build a single Cranelift IR `Function`. /// Temporary object used to build a single Cranelift IR `Function`.
pub struct FunctionBuilder<'a> { pub struct FunctionBuilder {
/// The function currently being built. /// The function currently being built.
/// This field is public so the function can be re-borrowed. /// This field is public so the function can be re-borrowed.
pub func: &'a mut Function, pub func: Function,
/// Source location to assign to all new instructions. /// Source location to assign to all new instructions.
srcloc: ir::SourceLoc, srcloc: ir::SourceLoc,
func_ctx: &'a mut FunctionBuilderContext, func_ctx: FunctionBuilderContext,
position: Position, position: Position,
} }
@@ -75,8 +75,9 @@ impl Position {
} }
impl FunctionBuilderContext { impl FunctionBuilderContext {
/// Creates a FunctionBuilderContext structure. The structure is automatically cleared after /// Creates a FunctionBuilderContext structure. The structure is
/// each [`FunctionBuilder`](struct.FunctionBuilder.html) completes translating a function. /// automatically cleared after each `FunctionBuilder` completes translating
/// a function.
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
ssa: SSABuilder::new(), ssa: SSABuilder::new(),
@@ -90,26 +91,22 @@ impl FunctionBuilderContext {
self.ebbs.clear(); self.ebbs.clear();
self.types.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 /// Implementation of the [`InstBuilder`](cranelift_codegen::ir::InstBuilder) that has
/// one convenience method per Cranelift IR instruction. /// one convenience method per Cranelift IR instruction.
pub struct FuncInstBuilder<'short, 'long: 'short> { pub struct FuncInstBuilder<'short> {
builder: &'short mut FunctionBuilder<'long>, builder: &'short mut FunctionBuilder,
ebb: Ebb, ebb: Ebb,
} }
impl<'short, 'long> FuncInstBuilder<'short, 'long> { impl<'short> FuncInstBuilder<'short> {
fn new(builder: &'short mut FunctionBuilder<'long>, ebb: Ebb) -> Self { fn new(builder: &'short mut FunctionBuilder, ebb: Ebb) -> Self {
Self { builder, ebb } Self { builder, ebb }
} }
} }
impl<'short, 'long> InstBuilderBase<'short> for FuncInstBuilder<'short, 'long> { impl<'short> InstBuilderBase<'short> for FuncInstBuilder<'short> {
fn data_flow_graph(&self) -> &DataFlowGraph { fn data_flow_graph(&self) -> &DataFlowGraph {
&self.builder.func.dfg &self.builder.func.dfg
} }
@@ -203,12 +200,9 @@ impl<'short, 'long> InstBuilderBase<'short> for FuncInstBuilder<'short, 'long> {
/// The first block for which you call `switch_to_block` will be assumed to be the beginning of /// The first block for which you call `switch_to_block` will be assumed to be the beginning of
/// the function. /// the function.
/// ///
/// At creation, a `FunctionBuilder` instance borrows an already allocated `Function` which it /// At creation, a `FunctionBuilder` instance borrows an already allocated
/// modifies with the information stored in the mutable borrowed /// `Function`. The function passed in should be newly created with
/// [`FunctionBuilderContext`](struct.FunctionBuilderContext.html). The function passed in /// [`Function::with_name_signature()`](Function::with_name_signature).
/// 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 /// # Errors
/// ///
@@ -216,15 +210,13 @@ impl<'short, 'long> InstBuilderBase<'short> for FuncInstBuilder<'short, 'long> {
/// function in a way that violate the coherence of the code. For instance: switching to a new /// 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 /// `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. /// return instruction with arguments that don't match the function's signature.
impl<'a> FunctionBuilder<'a> { impl FunctionBuilder {
/// Creates a new FunctionBuilder structure that will operate on a `Function` using a /// Creates a new FunctionBuilder structure that will operate on a `Function`.
/// `FunctionBuilderContext`. pub fn new(func: Function) -> Self {
pub fn new(func: &'a mut Function, func_ctx: &'a mut FunctionBuilderContext) -> Self {
debug_assert!(func_ctx.is_empty());
Self { Self {
func, func,
srcloc: Default::default(), srcloc: Default::default(),
func_ctx, func_ctx: FunctionBuilderContext::new(),
position: Position::default(), position: Position::default(),
} }
} }
@@ -279,7 +271,7 @@ impl<'a> FunctionBuilder<'a> {
/// created. Forgetting to call this method on every block will cause inconsistencies in the /// created. Forgetting to call this method on every block will cause inconsistencies in the
/// produced functions. /// produced functions.
pub fn seal_block(&mut self, ebb: Ebb) { pub fn seal_block(&mut self, ebb: Ebb) {
let side_effects = self.func_ctx.ssa.seal_ebb_header_block(ebb, self.func); let side_effects = self.func_ctx.ssa.seal_ebb_header_block(ebb, &mut self.func);
self.handle_ssa_side_effects(side_effects); self.handle_ssa_side_effects(side_effects);
} }
@@ -290,7 +282,7 @@ impl<'a> FunctionBuilder<'a> {
/// function can be used at the end of translating all blocks to ensure /// function can be used at the end of translating all blocks to ensure
/// that everything is sealed. /// that everything is sealed.
pub fn seal_all_blocks(&mut self) { pub fn seal_all_blocks(&mut self) {
let side_effects = self.func_ctx.ssa.seal_all_ebb_header_blocks(self.func); let side_effects = self.func_ctx.ssa.seal_all_ebb_header_blocks(&mut self.func);
self.handle_ssa_side_effects(side_effects); self.handle_ssa_side_effects(side_effects);
} }
@@ -311,7 +303,7 @@ impl<'a> FunctionBuilder<'a> {
}); });
self.func_ctx self.func_ctx
.ssa .ssa
.use_var(self.func, var, ty, self.position.basic_block.unwrap()) .use_var(&mut self.func, var, ty, self.position.basic_block.unwrap())
}; };
self.handle_ssa_side_effects(side_effects); self.handle_ssa_side_effects(side_effects);
val val
@@ -393,7 +385,7 @@ impl<'a> FunctionBuilder<'a> {
/// Returns an object with the [`InstBuilder`](cranelift_codegen::ir::InstBuilder) /// Returns an object with the [`InstBuilder`](cranelift_codegen::ir::InstBuilder)
/// trait that allows to conveniently append an instruction to the current `Ebb` being built. /// trait that allows to conveniently append an instruction to the current `Ebb` being built.
pub fn ins<'short>(&'short mut self) -> FuncInstBuilder<'short, 'a> { pub fn ins<'short>(&'short mut self) -> FuncInstBuilder<'short> {
let ebb = self let ebb = self
.position .position
.ebb .ebb
@@ -423,7 +415,7 @@ impl<'a> FunctionBuilder<'a> {
/// need to know about `FunctionBuilder` at all. /// need to know about `FunctionBuilder` at all.
pub fn cursor(&mut self) -> FuncCursor { pub fn cursor(&mut self) -> FuncCursor {
self.ensure_inserted_ebb(); self.ensure_inserted_ebb();
FuncCursor::new(self.func) FuncCursor::new(&mut self.func)
.with_srcloc(self.srcloc) .with_srcloc(self.srcloc)
.at_bottom(self.position.ebb.unwrap()) .at_bottom(self.position.ebb.unwrap())
} }
@@ -459,10 +451,21 @@ impl<'a> FunctionBuilder<'a> {
} }
} }
/// Declare that translation of the current function is complete. This /// Clears the current state of the `FunctionBuilder` while preserving
/// resets the state of the `FunctionBuilder` in preparation to be used /// 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
/// for another function. /// for another function.
pub fn finalize(&mut self) { pub fn finalize(&mut self) -> ir::Function {
// Check that all the `Ebb`s are filled and sealed. // Check that all the `Ebb`s are filled and sealed.
debug_assert!( debug_assert!(
self.func_ctx self.func_ctx
@@ -492,13 +495,8 @@ impl<'a> FunctionBuilder<'a> {
} }
} }
// Clear the state (but preserve the allocated buffers) in preparation self.clear();
// for translation another function. std::mem::replace(&mut self.func, Function::new())
self.func_ctx.clear();
// Reset srcloc and position to initial states.
self.srcloc = Default::default();
self.position = Position::default();
} }
} }
@@ -507,7 +505,7 @@ impl<'a> FunctionBuilder<'a> {
/// performance of your translation perform more complex transformations to your Cranelift IR /// 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 /// function. The functions below help you inspect the function you're creating and modify it
/// in ways that can be unsafe if used incorrectly. /// in ways that can be unsafe if used incorrectly.
impl<'a> FunctionBuilder<'a> { impl FunctionBuilder {
/// Retrieves all the parameters for an `Ebb` currently inferred from the jump instructions /// Retrieves all the parameters for an `Ebb` currently inferred from the jump instructions
/// inserted that target it and the SSA construction. /// inserted that target it and the SSA construction.
pub fn ebb_params(&self, ebb: Ebb) -> &[Value] { pub fn ebb_params(&self, ebb: Ebb) -> &[Value] {
@@ -593,7 +591,7 @@ impl<'a> FunctionBuilder<'a> {
} }
/// Helper functions /// Helper functions
impl<'a> FunctionBuilder<'a> { impl FunctionBuilder {
/// Calls libc.memcpy /// Calls libc.memcpy
/// ///
/// Copies the `size` bytes from `src` to `dest`, assumes that `src + size` /// Copies the `size` bytes from `src` to `dest`, assumes that `src + size`
@@ -853,7 +851,7 @@ fn greatest_divisible_power_of_two(size: u64) -> u64 {
} }
// Helper functions // Helper functions
impl<'a> FunctionBuilder<'a> { impl FunctionBuilder {
fn move_to_next_basic_block(&mut self) { fn move_to_next_basic_block(&mut self) {
self.position.basic_block = PackedOption::from( self.position.basic_block = PackedOption::from(
self.func_ctx self.func_ctx
@@ -888,7 +886,7 @@ impl<'a> FunctionBuilder<'a> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::greatest_divisible_power_of_two; use super::greatest_divisible_power_of_two;
use crate::frontend::{FunctionBuilder, FunctionBuilderContext}; use crate::frontend::FunctionBuilder;
use crate::Variable; use crate::Variable;
use cranelift_codegen::entity::EntityRef; use cranelift_codegen::entity::EntityRef;
use cranelift_codegen::ir::types::*; use cranelift_codegen::ir::types::*;
@@ -903,10 +901,9 @@ mod tests {
sig.returns.push(AbiParam::new(I32)); sig.returns.push(AbiParam::new(I32));
sig.params.push(AbiParam::new(I32)); sig.params.push(AbiParam::new(I32));
let mut fn_ctx = FunctionBuilderContext::new(); let func = {
let mut func = Function::with_name_signature(ExternalName::testcase("sample"), sig); let func = Function::with_name_signature(ExternalName::testcase("sample"), sig);
{ let mut builder = FunctionBuilder::new(func);
let mut builder = FunctionBuilder::new(&mut func, &mut fn_ctx);
let block0 = builder.create_ebb(); let block0 = builder.create_ebb();
let block1 = builder.create_ebb(); let block1 = builder.create_ebb();
@@ -981,8 +978,8 @@ mod tests {
builder.seal_all_blocks(); builder.seal_all_blocks();
} }
builder.finalize(); builder.finalize()
} };
let flags = settings::Flags::new(settings::builder()); let flags = settings::Flags::new(settings::builder());
// println!("{}", func.display(None)); // println!("{}", func.display(None));
@@ -1019,10 +1016,9 @@ mod tests {
let mut sig = Signature::new(target.default_call_conv()); let mut sig = Signature::new(target.default_call_conv());
sig.returns.push(AbiParam::new(I32)); sig.returns.push(AbiParam::new(I32));
let mut fn_ctx = FunctionBuilderContext::new(); let func = {
let mut func = Function::with_name_signature(ExternalName::testcase("sample"), sig); let func = Function::with_name_signature(ExternalName::testcase("sample"), sig);
{ let mut builder = FunctionBuilder::new(func);
let mut builder = FunctionBuilder::new(&mut func, &mut fn_ctx);
let block0 = builder.create_ebb(); let block0 = builder.create_ebb();
let x = Variable::new(0); let x = Variable::new(0);
@@ -1041,8 +1037,8 @@ mod tests {
builder.ins().return_(&[size]); builder.ins().return_(&[size]);
builder.seal_all_blocks(); builder.seal_all_blocks();
builder.finalize(); builder.finalize()
} };
assert_eq!( assert_eq!(
func.display(None).to_string(), func.display(None).to_string(),
@@ -1080,10 +1076,9 @@ ebb0:
let mut sig = Signature::new(target.default_call_conv()); let mut sig = Signature::new(target.default_call_conv());
sig.returns.push(AbiParam::new(I32)); sig.returns.push(AbiParam::new(I32));
let mut fn_ctx = FunctionBuilderContext::new(); let func = {
let mut func = Function::with_name_signature(ExternalName::testcase("sample"), sig); let func = Function::with_name_signature(ExternalName::testcase("sample"), sig);
{ let mut builder = FunctionBuilder::new(func);
let mut builder = FunctionBuilder::new(&mut func, &mut fn_ctx);
let block0 = builder.create_ebb(); let block0 = builder.create_ebb();
let x = Variable::new(0); let x = Variable::new(0);
@@ -1100,8 +1095,8 @@ ebb0:
builder.ins().return_(&[dest]); builder.ins().return_(&[dest]);
builder.seal_all_blocks(); builder.seal_all_blocks();
builder.finalize(); builder.finalize()
} };
assert_eq!( assert_eq!(
func.display(None).to_string(), func.display(None).to_string(),
@@ -1137,10 +1132,9 @@ ebb0:
let mut sig = Signature::new(target.default_call_conv()); let mut sig = Signature::new(target.default_call_conv());
sig.returns.push(AbiParam::new(I32)); sig.returns.push(AbiParam::new(I32));
let mut fn_ctx = FunctionBuilderContext::new(); let func = {
let mut func = Function::with_name_signature(ExternalName::testcase("sample"), sig); let func = Function::with_name_signature(ExternalName::testcase("sample"), sig);
{ let mut builder = FunctionBuilder::new(func);
let mut builder = FunctionBuilder::new(&mut func, &mut fn_ctx);
let block0 = builder.create_ebb(); let block0 = builder.create_ebb();
let x = Variable::new(0); let x = Variable::new(0);
@@ -1157,8 +1151,8 @@ ebb0:
builder.ins().return_(&[dest]); builder.ins().return_(&[dest]);
builder.seal_all_blocks(); builder.seal_all_blocks();
builder.finalize(); builder.finalize()
} };
assert_eq!( assert_eq!(
func.display(None).to_string(), func.display(None).to_string(),
@@ -1197,10 +1191,9 @@ ebb0:
let mut sig = Signature::new(target.default_call_conv()); let mut sig = Signature::new(target.default_call_conv());
sig.returns.push(AbiParam::new(I32)); sig.returns.push(AbiParam::new(I32));
let mut fn_ctx = FunctionBuilderContext::new(); let func = {
let mut func = Function::with_name_signature(ExternalName::testcase("sample"), sig); let func = Function::with_name_signature(ExternalName::testcase("sample"), sig);
{ let mut builder = FunctionBuilder::new(func);
let mut builder = FunctionBuilder::new(&mut func, &mut fn_ctx);
let block0 = builder.create_ebb(); let block0 = builder.create_ebb();
let y = Variable::new(16); let y = Variable::new(16);
@@ -1214,8 +1207,8 @@ ebb0:
builder.ins().return_(&[dest]); builder.ins().return_(&[dest]);
builder.seal_all_blocks(); builder.seal_all_blocks();
builder.finalize(); builder.finalize()
} };
assert_eq!( assert_eq!(
func.display(None).to_string(), func.display(None).to_string(),
@@ -1249,10 +1242,9 @@ ebb0:
let mut sig = Signature::new(target.default_call_conv()); let mut sig = Signature::new(target.default_call_conv());
sig.returns.push(AbiParam::new(I32)); sig.returns.push(AbiParam::new(I32));
let mut fn_ctx = FunctionBuilderContext::new(); let func = {
let mut func = Function::with_name_signature(ExternalName::testcase("sample"), sig); let func = Function::with_name_signature(ExternalName::testcase("sample"), sig);
{ let mut builder = FunctionBuilder::new(func);
let mut builder = FunctionBuilder::new(&mut func, &mut fn_ctx);
let block0 = builder.create_ebb(); let block0 = builder.create_ebb();
let y = Variable::new(16); let y = Variable::new(16);
@@ -1266,8 +1258,8 @@ ebb0:
builder.ins().return_(&[dest]); builder.ins().return_(&[dest]);
builder.seal_all_blocks(); builder.seal_all_blocks();
builder.finalize(); builder.finalize()
} };
assert_eq!( assert_eq!(
func.display(None).to_string(), func.display(None).to_string(),

View File

@@ -3,7 +3,7 @@
//! Provides a straightforward way to create a Cranelift IR function and fill it with instructions //! Provides a straightforward way to create a Cranelift IR function and fill it with instructions
//! corresponding to your source program written in another language. //! corresponding to your source program written in another language.
//! //!
//! To get started, create an [`FunctionBuilderContext`](struct.FunctionBuilderContext.html) and //! To get started, create an [`Function`](../cranelift_codegen/ir/function/struct.Function.html) and
//! pass it as an argument to a [`FunctionBuilder`](struct.FunctionBuilder.html). //! pass it as an argument to a [`FunctionBuilder`](struct.FunctionBuilder.html).
//! //!
//! # Mutable variables and Cranelift IR values //! # Mutable variables and Cranelift IR values
@@ -61,7 +61,7 @@
//! } //! }
//! ``` //! ```
//! //!
//! Here is how you build the corresponding Cranelift IR function using `FunctionBuilderContext`: //! Here is how you build the corresponding Cranelift IR function using `Function`:
//! //!
//! ```rust //! ```rust
//! extern crate cranelift_codegen; //! extern crate cranelift_codegen;
@@ -73,16 +73,15 @@
//! use cranelift_codegen::isa::CallConv; //! use cranelift_codegen::isa::CallConv;
//! use cranelift_codegen::settings; //! use cranelift_codegen::settings;
//! use cranelift_codegen::verifier::verify_function; //! use cranelift_codegen::verifier::verify_function;
//! use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext, Variable}; //! use cranelift_frontend::{FunctionBuilder, Variable};
//! //!
//! fn main() { //! fn main() {
//! let mut sig = Signature::new(CallConv::SystemV); //! let mut sig = Signature::new(CallConv::SystemV);
//! sig.returns.push(AbiParam::new(I32)); //! sig.returns.push(AbiParam::new(I32));
//! sig.params.push(AbiParam::new(I32)); //! sig.params.push(AbiParam::new(I32));
//! let mut fn_builder_ctx = FunctionBuilderContext::new(); //! let func = {
//! let mut func = Function::with_name_signature(ExternalName::user(0, 0), sig); //! let 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 block0 = builder.create_ebb(); //! let block0 = builder.create_ebb();
//! let block1 = builder.create_ebb(); //! let block1 = builder.create_ebb();
@@ -152,8 +151,8 @@
//! builder.ins().jump(block1, &[]); //! builder.ins().jump(block1, &[]);
//! builder.seal_block(block1); //! builder.seal_block(block1);
//! //!
//! builder.finalize(); //! builder.finalize()
//! } //! };
//! //!
//! let flags = settings::Flags::new(settings::builder()); //! let flags = settings::Flags::new(settings::builder());
//! let res = verify_function(&func, &flags); //! let res = verify_function(&func, &flags);
@@ -195,7 +194,7 @@ use hashmap_core::HashMap;
#[cfg(feature = "std")] #[cfg(feature = "std")]
use std::collections::HashMap; use std::collections::HashMap;
pub use crate::frontend::{FunctionBuilder, FunctionBuilderContext}; pub use crate::frontend::FunctionBuilder;
pub use crate::switch::Switch; pub use crate::switch::Switch;
pub use crate::variable::Variable; pub use crate::variable::Variable;

View File

@@ -173,9 +173,7 @@ impl SSABuilder {
self.variables.clear(); self.variables.clear();
self.blocks.clear(); self.blocks.clear();
self.ebb_headers.clear(); self.ebb_headers.clear();
debug_assert!(self.calls.is_empty()); debug_assert!(self.is_empty());
debug_assert!(self.results.is_empty());
debug_assert!(self.side_effects.is_empty());
} }
/// Tests whether an `SSABuilder` is in a cleared state. /// Tests whether an `SSABuilder` is in a cleared state.

View File

@@ -16,12 +16,11 @@ type EntryIndex = u64;
/// # use cranelift_codegen::ir::types::*; /// # use cranelift_codegen::ir::types::*;
/// # use cranelift_codegen::ir::{ExternalName, Function, Signature, InstBuilder}; /// # use cranelift_codegen::ir::{ExternalName, Function, Signature, InstBuilder};
/// # use cranelift_codegen::isa::CallConv; /// # use cranelift_codegen::isa::CallConv;
/// # use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext, Switch}; /// # use cranelift_frontend::{FunctionBuilder, Switch};
/// # /// #
/// # let mut sig = Signature::new(CallConv::SystemV); /// # 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 func = Function::with_name_signature(ExternalName::user(0, 0), sig);
/// # let mut builder = FunctionBuilder::new(&mut func, &mut fn_builder_ctx); /// # let mut builder = FunctionBuilder::new(func);
/// # /// #
/// # let entry = builder.create_ebb(); /// # let entry = builder.create_ebb();
/// # builder.switch_to_block(entry); /// # builder.switch_to_block(entry);
@@ -289,16 +288,13 @@ impl ContiguousCaseRange {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use crate::frontend::FunctionBuilderContext;
use cranelift_codegen::ir::Function; use cranelift_codegen::ir::Function;
use std::string::ToString; use std::string::ToString;
macro_rules! setup { macro_rules! setup {
($default:expr, [$($index:expr,)*]) => {{ ($default:expr, [$($index:expr,)*]) => {{
let mut func = Function::new(); let func = {
let mut func_ctx = FunctionBuilderContext::new(); let mut bx = FunctionBuilder::new(Function::new());
{
let mut bx = FunctionBuilder::new(&mut func, &mut func_ctx);
let ebb = bx.create_ebb(); let ebb = bx.create_ebb();
bx.switch_to_block(ebb); bx.switch_to_block(ebb);
let val = bx.ins().iconst(types::I8, 0); let val = bx.ins().iconst(types::I8, 0);
@@ -308,7 +304,9 @@ mod tests {
switch.set_entry($index, ebb); switch.set_entry($index, ebb);
)* )*
switch.emit(&mut bx, val, Ebb::with_number($default).unwrap()); switch.emit(&mut bx, val, Ebb::with_number($default).unwrap());
} bx.seal_all_blocks();
bx.finalize()
};
func func
.to_string() .to_string()
.trim_start_matches("function u0:0() fast {\n") .trim_start_matches("function u0:0() fast {\n")

View File

@@ -1,6 +1,6 @@
//! A basic `Variable` implementation. //! A basic `Variable` implementation.
//! //!
//! `FunctionBuilderContext`, `FunctionBuilder`, and related types have a `Variable` //! `FunctionBuilder` and related types have a `Variable`
//! type parameter, to allow frontends that identify variables with //! type parameter, to allow frontends that identify variables with
//! their own index types to use them directly. Frontends which don't //! their own index types to use them directly. Frontends which don't
//! can use the `Variable` defined here. //! can use the `Variable` defined here.

View File

@@ -7,7 +7,6 @@ fn main() {
let mut module: Module<SimpleJITBackend> = let mut module: Module<SimpleJITBackend> =
Module::new(SimpleJITBuilder::new(default_libcall_names())); Module::new(SimpleJITBuilder::new(default_libcall_names()));
let mut ctx = module.make_context(); let mut ctx = module.make_context();
let mut func_ctx = FunctionBuilderContext::new();
let mut sig_a = module.make_signature(); let mut sig_a = module.make_signature();
sig_a.params.push(AbiParam::new(types::I32)); sig_a.params.push(AbiParam::new(types::I32));
@@ -25,8 +24,8 @@ fn main() {
ctx.func.signature = sig_a; ctx.func.signature = sig_a;
ctx.func.name = ExternalName::user(0, func_a.as_u32()); ctx.func.name = ExternalName::user(0, func_a.as_u32());
{ ctx.func = {
let mut bcx: FunctionBuilder = FunctionBuilder::new(&mut ctx.func, &mut func_ctx); let mut bcx: FunctionBuilder = FunctionBuilder::new(ctx.func);
let ebb = bcx.create_ebb(); let ebb = bcx.create_ebb();
bcx.switch_to_block(ebb); bcx.switch_to_block(ebb);
@@ -36,15 +35,15 @@ fn main() {
let add = bcx.ins().iadd(cst, param); let add = bcx.ins().iadd(cst, param);
bcx.ins().return_(&[add]); bcx.ins().return_(&[add]);
bcx.seal_all_blocks(); bcx.seal_all_blocks();
bcx.finalize(); bcx.finalize()
} };
module.define_function(func_a, &mut ctx).unwrap(); module.define_function(func_a, &mut ctx).unwrap();
module.clear_context(&mut ctx); module.clear_context(&mut ctx);
ctx.func.signature = sig_b; ctx.func.signature = sig_b;
ctx.func.name = ExternalName::user(0, func_b.as_u32()); ctx.func.name = ExternalName::user(0, func_b.as_u32());
{ ctx.func = {
let mut bcx: FunctionBuilder = FunctionBuilder::new(&mut ctx.func, &mut func_ctx); let mut bcx: FunctionBuilder = FunctionBuilder::new(ctx.func);
let ebb = bcx.create_ebb(); let ebb = bcx.create_ebb();
bcx.switch_to_block(ebb); bcx.switch_to_block(ebb);
@@ -58,8 +57,8 @@ fn main() {
}; };
bcx.ins().return_(&[value]); bcx.ins().return_(&[value]);
bcx.seal_all_blocks(); bcx.seal_all_blocks();
bcx.finalize(); bcx.finalize()
} };
module.define_function(func_b, &mut ctx).unwrap(); module.define_function(func_b, &mut ctx).unwrap();
module.clear_context(&mut ctx); module.clear_context(&mut ctx);

View File

@@ -37,14 +37,16 @@ fn define_simple_function(module: &mut Module<SimpleJITBackend>) -> FuncId {
.unwrap(); .unwrap();
let mut ctx = Context::new(); let mut ctx = Context::new();
ctx.func = Function::with_name_signature(ExternalName::user(0, func_id.as_u32()), sig);
let mut func_ctx = FunctionBuilderContext::new(); ctx.func = {
{ let func = Function::with_name_signature(ExternalName::user(0, func_id.as_u32()), sig);
let mut bcx: FunctionBuilder = FunctionBuilder::new(&mut ctx.func, &mut func_ctx); let mut bcx: FunctionBuilder = FunctionBuilder::new(func);
let ebb = bcx.create_ebb(); let ebb = bcx.create_ebb();
bcx.switch_to_block(ebb); bcx.switch_to_block(ebb);
bcx.ins().return_(&[]); bcx.ins().return_(&[]);
} bcx.seal_all_blocks();
bcx.finalize()
};
module.define_function(func_id, &mut ctx).unwrap(); module.define_function(func_id, &mut ctx).unwrap();
@@ -85,11 +87,9 @@ fn switch_error() {
call_conv: CallConv::SystemV, call_conv: CallConv::SystemV,
}; };
let mut func = Function::with_name_signature(ExternalName::user(0, 0), sig); let func = {
let func = Function::with_name_signature(ExternalName::user(0, 0), sig);
let mut func_ctx = FunctionBuilderContext::new(); let mut bcx: FunctionBuilder = FunctionBuilder::new(func);
{
let mut bcx: FunctionBuilder = FunctionBuilder::new(&mut func, &mut func_ctx);
let start = bcx.create_ebb(); let start = bcx.create_ebb();
let bb0 = bcx.create_ebb(); let bb0 = bcx.create_ebb();
let bb1 = bcx.create_ebb(); let bb1 = bcx.create_ebb();
@@ -134,8 +134,8 @@ fn switch_error() {
bcx.ins().return_(&[r]); bcx.ins().return_(&[r]);
bcx.seal_all_blocks(); bcx.seal_all_blocks();
bcx.finalize(); bcx.finalize()
} };
let flags = settings::Flags::new(settings::builder()); let flags = settings::Flags::new(settings::builder());
match cranelift_codegen::verify_function(&func, &flags) { match cranelift_codegen::verify_function(&func, &flags) {
@@ -164,10 +164,9 @@ fn libcall_function() {
.unwrap(); .unwrap();
let mut ctx = Context::new(); let mut ctx = Context::new();
ctx.func = Function::with_name_signature(ExternalName::user(0, func_id.as_u32()), sig); ctx.func = {
let mut func_ctx = FunctionBuilderContext::new(); let func = Function::with_name_signature(ExternalName::user(0, func_id.as_u32()), sig);
{ let mut bcx: FunctionBuilder = FunctionBuilder::new(func);
let mut bcx: FunctionBuilder = FunctionBuilder::new(&mut ctx.func, &mut func_ctx);
let ebb = bcx.create_ebb(); let ebb = bcx.create_ebb();
bcx.switch_to_block(ebb); bcx.switch_to_block(ebb);
@@ -189,7 +188,11 @@ fn libcall_function() {
bcx.call_memset(module.target_config(), buffer, zero, size); bcx.call_memset(module.target_config(), buffer, zero, size);
bcx.ins().return_(&[]); bcx.ins().return_(&[]);
}
bcx.seal_all_blocks();
bcx.finalize()
};
module.define_function(func_id, &mut ctx).unwrap(); module.define_function(func_id, &mut ctx).unwrap();

View File

@@ -43,7 +43,7 @@ pub mod prelude {
pub use crate::codegen::isa; pub use crate::codegen::isa;
pub use crate::codegen::settings::{self, Configurable}; pub use crate::codegen::settings::{self, Configurable};
pub use crate::frontend::{FunctionBuilder, FunctionBuilderContext, Variable}; pub use crate::frontend::{FunctionBuilder, Variable};
} }
/// Version number of this crate. /// Version number of this crate.

View File

@@ -81,7 +81,7 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
* `get_global` and `set_global` are handled by the environment. * `get_global` and `set_global` are handled by the environment.
***********************************************************************************/ ***********************************************************************************/
Operator::GetGlobal { global_index } => { Operator::GetGlobal { global_index } => {
let val = match state.get_global(builder.func, *global_index, environ)? { let val = match state.get_global(&mut builder.func, *global_index, environ)? {
GlobalVariable::Const(val) => val, GlobalVariable::Const(val) => val,
GlobalVariable::Memory { gv, offset, ty } => { GlobalVariable::Memory { gv, offset, ty } => {
let addr = builder.ins().global_value(environ.pointer_type(), gv); let addr = builder.ins().global_value(environ.pointer_type(), gv);
@@ -92,7 +92,7 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
state.push1(val); state.push1(val);
} }
Operator::SetGlobal { global_index } => { Operator::SetGlobal { global_index } => {
match state.get_global(builder.func, *global_index, environ)? { match state.get_global(&mut builder.func, *global_index, environ)? {
GlobalVariable::Const(_) => panic!("global #{} is a constant", *global_index), GlobalVariable::Const(_) => panic!("global #{} is a constant", *global_index),
GlobalVariable::Memory { gv, offset, ty } => { GlobalVariable::Memory { gv, offset, ty } => {
let addr = builder.ins().global_value(environ.pointer_type(), gv); let addr = builder.ins().global_value(environ.pointer_type(), gv);
@@ -367,7 +367,8 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
* argument referring to an index in the external functions table of the module. * argument referring to an index in the external functions table of the module.
************************************************************************************/ ************************************************************************************/
Operator::Call { function_index } => { Operator::Call { function_index } => {
let (fref, num_args) = state.get_direct_func(builder.func, *function_index, environ)?; let (fref, num_args) =
state.get_direct_func(&mut builder.func, *function_index, environ)?;
let call = environ.translate_call( let call = environ.translate_call(
builder.cursor(), builder.cursor(),
FuncIndex::from_u32(*function_index), FuncIndex::from_u32(*function_index),
@@ -388,8 +389,8 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
Operator::CallIndirect { index, table_index } => { Operator::CallIndirect { index, table_index } => {
// `index` is the index of the function's signature and `table_index` is the index of // `index` is the index of the function's signature and `table_index` is the index of
// the table to search the function in. // the table to search the function in.
let (sigref, num_args) = state.get_indirect_sig(builder.func, *index, environ)?; let (sigref, num_args) = state.get_indirect_sig(&mut builder.func, *index, environ)?;
let table = state.get_table(builder.func, *table_index, environ)?; let table = state.get_table(&mut builder.func, *table_index, environ)?;
let callee = state.pop1(); let callee = state.pop1();
let call = environ.translate_call_indirect( let call = environ.translate_call_indirect(
builder.cursor(), builder.cursor(),
@@ -417,13 +418,13 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
// The WebAssembly MVP only supports one linear memory, but we expect the reserved // The WebAssembly MVP only supports one linear memory, but we expect the reserved
// argument to be a memory index. // argument to be a memory index.
let heap_index = MemoryIndex::from_u32(*reserved); let heap_index = MemoryIndex::from_u32(*reserved);
let heap = state.get_heap(builder.func, *reserved, environ)?; let heap = state.get_heap(&mut builder.func, *reserved, environ)?;
let val = state.pop1(); let val = state.pop1();
state.push1(environ.translate_memory_grow(builder.cursor(), heap_index, heap, val)?) state.push1(environ.translate_memory_grow(builder.cursor(), heap_index, heap, val)?)
} }
Operator::MemorySize { reserved } => { Operator::MemorySize { reserved } => {
let heap_index = MemoryIndex::from_u32(*reserved); let heap_index = MemoryIndex::from_u32(*reserved);
let heap = state.get_heap(builder.func, *reserved, environ)?; let heap = state.get_heap(&mut builder.func, *reserved, environ)?;
state.push1(environ.translate_memory_size(builder.cursor(), heap_index, heap)?); state.push1(environ.translate_memory_size(builder.cursor(), heap_index, heap)?);
} }
/******************************* Load instructions *********************************** /******************************* Load instructions ***********************************
@@ -1231,7 +1232,7 @@ fn translate_load<FE: FuncEnvironment + ?Sized>(
) -> WasmResult<()> { ) -> WasmResult<()> {
let addr32 = state.pop1(); let addr32 = state.pop1();
// We don't yet support multiple linear memories. // We don't yet support multiple linear memories.
let heap = state.get_heap(builder.func, 0, environ)?; let heap = state.get_heap(&mut builder.func, 0, environ)?;
let (base, offset) = get_heap_addr(heap, addr32, offset, environ.pointer_type(), builder); 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 // 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 // alignment immediate says it's aligned, because WebAssembly's immediate
@@ -1256,7 +1257,7 @@ fn translate_store<FE: FuncEnvironment + ?Sized>(
let val_ty = builder.func.dfg.value_type(val); let val_ty = builder.func.dfg.value_type(val);
// We don't yet support multiple linear memories. // We don't yet support multiple linear memories.
let heap = state.get_heap(builder.func, 0, environ)?; let heap = state.get_heap(&mut builder.func, 0, environ)?;
let (base, offset) = get_heap_addr(heap, addr32, offset, environ.pointer_type(), builder); let (base, offset) = get_heap_addr(heap, addr32, offset, environ.pointer_type(), builder);
// See the comments in `translate_load` about the flags. // See the comments in `translate_load` about the flags.
let flags = MemFlags::new(); let flags = MemFlags::new();

View File

@@ -533,8 +533,7 @@ impl<'data> ModuleEnvironment<'data> for DummyEnvironment {
func.collect_debug_info(); func.collect_debug_info();
} }
self.trans self.trans
.translate(body_bytes, body_offset, &mut func, &mut func_environ)?; .translate(body_bytes, body_offset, func, &mut func_environ)?
func
}; };
self.func_bytecode_sizes.push(body_bytes.len()); self.func_bytecode_sizes.push(body_bytes.len());
self.info.function_bodies.push(func); self.info.function_bodies.push(func);

View File

@@ -12,7 +12,7 @@ use crate::wasm_unsupported;
use cranelift_codegen::entity::EntityRef; use cranelift_codegen::entity::EntityRef;
use cranelift_codegen::ir::{self, Ebb, InstBuilder, ValueLabel}; use cranelift_codegen::ir::{self, Ebb, InstBuilder, ValueLabel};
use cranelift_codegen::timing; use cranelift_codegen::timing;
use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext, Variable}; use cranelift_frontend::{FunctionBuilder, Variable};
use log::info; use log::info;
use wasmparser::{self, BinaryReader}; 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 /// by a `FuncEnvironment` object. A single translator instance can be reused to translate multiple
/// functions which will reduce heap allocation traffic. /// functions which will reduce heap allocation traffic.
pub struct FuncTranslator { pub struct FuncTranslator {
func_ctx: FunctionBuilderContext, builder: FunctionBuilder,
state: TranslationState, state: TranslationState,
} }
@@ -30,7 +30,7 @@ impl FuncTranslator {
/// Create a new translator. /// Create a new translator.
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
func_ctx: FunctionBuilderContext::new(), builder: FunctionBuilder::new(ir::Function::new()),
state: TranslationState::new(), state: TranslationState::new(),
} }
} }
@@ -57,9 +57,9 @@ impl FuncTranslator {
&mut self, &mut self,
code: &[u8], code: &[u8],
code_offset: usize, code_offset: usize,
func: &mut ir::Function, func: ir::Function,
environ: &mut FE, environ: &mut FE,
) -> WasmResult<()> { ) -> WasmResult<ir::Function> {
self.translate_from_reader( self.translate_from_reader(
BinaryReader::new_with_offset(code, code_offset), BinaryReader::new_with_offset(code, code_offset),
func, func,
@@ -71,9 +71,9 @@ impl FuncTranslator {
pub fn translate_from_reader<FE: FuncEnvironment + ?Sized>( pub fn translate_from_reader<FE: FuncEnvironment + ?Sized>(
&mut self, &mut self,
mut reader: BinaryReader, mut reader: BinaryReader,
func: &mut ir::Function, func: ir::Function,
environ: &mut FE, environ: &mut FE,
) -> WasmResult<()> { ) -> WasmResult<ir::Function> {
let _tt = timing::wasm_translate_function(); let _tt = timing::wasm_translate_function();
info!( info!(
"translate({} bytes, {}{})", "translate({} bytes, {}{})",
@@ -84,31 +84,32 @@ impl FuncTranslator {
debug_assert_eq!(func.dfg.num_ebbs(), 0, "Function must be empty"); debug_assert_eq!(func.dfg.num_ebbs(), 0, "Function must be empty");
debug_assert_eq!(func.dfg.num_insts(), 0, "Function must be empty"); debug_assert_eq!(func.dfg.num_insts(), 0, "Function must be empty");
// This clears the `FunctionBuilderContext`. self.builder.func = func;
let mut builder = FunctionBuilder::new(func, &mut self.func_ctx); self.builder.set_srcloc(cur_srcloc(&reader));
builder.set_srcloc(cur_srcloc(&reader)); let entry_block = self.builder.create_ebb();
let entry_block = builder.create_ebb(); self.builder
builder.append_ebb_params_for_function_params(entry_block); .append_ebb_params_for_function_params(entry_block);
builder.switch_to_block(entry_block); // This also creates values for the arguments. self.builder.switch_to_block(entry_block); // This also creates values for the arguments.
builder.seal_block(entry_block); // Declare all predecessors known. self.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 // 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. // `environ`. The callback functions may need to insert things in the entry block.
builder.ensure_inserted_ebb(); self.builder.ensure_inserted_ebb();
let num_params = declare_wasm_parameters(&mut builder, entry_block); let num_params = declare_wasm_parameters(&mut self.builder, entry_block);
// Set up the translation state with a single pushed control block representing the whole // Set up the translation state with a single pushed control block representing the whole
// function and its return values. // function and its return values.
let exit_block = builder.create_ebb(); let exit_block = self.builder.create_ebb();
builder.append_ebb_params_for_function_returns(exit_block); self.builder
self.state.initialize(&builder.func.signature, exit_block); .append_ebb_params_for_function_returns(exit_block);
self.state
.initialize(&self.builder.func.signature, exit_block);
parse_local_decls(&mut reader, &mut builder, num_params, environ)?; parse_local_decls(&mut reader, &mut self.builder, num_params, environ)?;
parse_function_body(reader, &mut builder, &mut self.state, environ)?; parse_function_body(reader, &mut self.builder, &mut self.state, environ)?;
builder.finalize(); Ok(self.builder.finalize())
Ok(())
} }
} }
@@ -288,8 +289,8 @@ mod tests {
ctx.func.signature.params.push(ir::AbiParam::new(I32)); ctx.func.signature.params.push(ir::AbiParam::new(I32));
ctx.func.signature.returns.push(ir::AbiParam::new(I32)); ctx.func.signature.returns.push(ir::AbiParam::new(I32));
trans ctx.func = trans
.translate(&BODY, 0, &mut ctx.func, &mut runtime.func_env()) .translate(&BODY, 0, ctx.func, &mut runtime.func_env())
.unwrap(); .unwrap();
debug!("{}", ctx.func.display(None)); debug!("{}", ctx.func.display(None));
ctx.verify(&flags).unwrap(); ctx.verify(&flags).unwrap();
@@ -327,8 +328,8 @@ mod tests {
ctx.func.signature.params.push(ir::AbiParam::new(I32)); ctx.func.signature.params.push(ir::AbiParam::new(I32));
ctx.func.signature.returns.push(ir::AbiParam::new(I32)); ctx.func.signature.returns.push(ir::AbiParam::new(I32));
trans ctx.func = trans
.translate(&BODY, 0, &mut ctx.func, &mut runtime.func_env()) .translate(&BODY, 0, ctx.func, &mut runtime.func_env())
.unwrap(); .unwrap();
debug!("{}", ctx.func.display(None)); debug!("{}", ctx.func.display(None));
ctx.verify(&flags).unwrap(); ctx.verify(&flags).unwrap();
@@ -374,8 +375,8 @@ mod tests {
ctx.func.name = ir::ExternalName::testcase("infloop"); ctx.func.name = ir::ExternalName::testcase("infloop");
ctx.func.signature.returns.push(ir::AbiParam::new(I32)); ctx.func.signature.returns.push(ir::AbiParam::new(I32));
trans ctx.func = trans
.translate(&BODY, 0, &mut ctx.func, &mut runtime.func_env()) .translate(&BODY, 0, ctx.func, &mut runtime.func_env())
.unwrap(); .unwrap();
debug!("{}", ctx.func.display(None)); debug!("{}", ctx.func.display(None));
ctx.verify(&flags).unwrap(); ctx.verify(&flags).unwrap();