Revert "Remove FunctionBuilderContext from API, and change FunctionBuilder API"
This reverts commit 39e638af99dbe6537bc935bfb1a74669b62877b3.
This commit is contained in:
committed by
Benjamin Bouvier
parent
8d62d5f724
commit
5426e42a27
@@ -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.
|
||||||
struct FunctionBuilderContext {
|
pub 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 {
|
pub struct FunctionBuilder<'a> {
|
||||||
/// 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: Function,
|
pub func: &'a mut 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: FunctionBuilderContext,
|
func_ctx: &'a mut FunctionBuilderContext,
|
||||||
position: Position,
|
position: Position,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,9 +75,8 @@ impl Position {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl FunctionBuilderContext {
|
impl FunctionBuilderContext {
|
||||||
/// Creates a FunctionBuilderContext structure. The structure is
|
/// Creates a FunctionBuilderContext structure. The structure is automatically cleared after
|
||||||
/// automatically cleared after each `FunctionBuilder` completes translating
|
/// each [`FunctionBuilder`](struct.FunctionBuilder.html) completes translating a function.
|
||||||
/// a function.
|
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
ssa: SSABuilder::new(),
|
ssa: SSABuilder::new(),
|
||||||
@@ -91,22 +90,26 @@ 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> {
|
pub struct FuncInstBuilder<'short, 'long: 'short> {
|
||||||
builder: &'short mut FunctionBuilder,
|
builder: &'short mut FunctionBuilder<'long>,
|
||||||
ebb: Ebb,
|
ebb: Ebb,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'short> FuncInstBuilder<'short> {
|
impl<'short, 'long> FuncInstBuilder<'short, 'long> {
|
||||||
fn new(builder: &'short mut FunctionBuilder, ebb: Ebb) -> Self {
|
fn new(builder: &'short mut FunctionBuilder<'long>, ebb: Ebb) -> Self {
|
||||||
Self { builder, ebb }
|
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 {
|
fn data_flow_graph(&self) -> &DataFlowGraph {
|
||||||
&self.builder.func.dfg
|
&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 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
|
/// At creation, a `FunctionBuilder` instance borrows an already allocated `Function` which it
|
||||||
/// `Function`. The function passed in should be newly created with
|
/// modifies with the information stored in the mutable borrowed
|
||||||
/// [`Function::with_name_signature()`](Function::with_name_signature).
|
/// [`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
|
/// # 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
|
/// 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 FunctionBuilder {
|
impl<'a> FunctionBuilder<'a> {
|
||||||
/// Creates a new FunctionBuilder structure that will operate on a `Function`.
|
/// Creates a new FunctionBuilder structure that will operate on a `Function` using a
|
||||||
pub fn new(func: Function) -> Self {
|
/// `FunctionBuilderContext`.
|
||||||
|
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: FunctionBuilderContext::new(),
|
func_ctx,
|
||||||
position: Position::default(),
|
position: Position::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -271,7 +279,7 @@ impl FunctionBuilder {
|
|||||||
/// 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, &mut self.func);
|
let side_effects = self.func_ctx.ssa.seal_ebb_header_block(ebb, self.func);
|
||||||
self.handle_ssa_side_effects(side_effects);
|
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
|
/// 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(&mut self.func);
|
let side_effects = self.func_ctx.ssa.seal_all_ebb_header_blocks(self.func);
|
||||||
self.handle_ssa_side_effects(side_effects);
|
self.handle_ssa_side_effects(side_effects);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -303,7 +311,7 @@ impl FunctionBuilder {
|
|||||||
});
|
});
|
||||||
self.func_ctx
|
self.func_ctx
|
||||||
.ssa
|
.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);
|
self.handle_ssa_side_effects(side_effects);
|
||||||
val
|
val
|
||||||
@@ -385,7 +393,7 @@ impl FunctionBuilder {
|
|||||||
|
|
||||||
/// 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> {
|
pub fn ins<'short>(&'short mut self) -> FuncInstBuilder<'short, 'a> {
|
||||||
let ebb = self
|
let ebb = self
|
||||||
.position
|
.position
|
||||||
.ebb
|
.ebb
|
||||||
@@ -415,7 +423,7 @@ impl FunctionBuilder {
|
|||||||
/// 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(&mut self.func)
|
FuncCursor::new(self.func)
|
||||||
.with_srcloc(self.srcloc)
|
.with_srcloc(self.srcloc)
|
||||||
.at_bottom(self.position.ebb.unwrap())
|
.at_bottom(self.position.ebb.unwrap())
|
||||||
}
|
}
|
||||||
@@ -451,21 +459,10 @@ impl FunctionBuilder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Clears the current state of the `FunctionBuilder` while preserving
|
/// Declare that translation of the current function is complete. This
|
||||||
/// allocations for reuse in translating another function.
|
/// resets the state of the `FunctionBuilder` in preparation to be used
|
||||||
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) -> ir::Function {
|
pub fn finalize(&mut self) {
|
||||||
// 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
|
||||||
@@ -495,8 +492,13 @@ impl FunctionBuilder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.clear();
|
// Clear the state (but preserve the allocated buffers) in preparation
|
||||||
std::mem::replace(&mut self.func, Function::new())
|
// 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
|
/// 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 FunctionBuilder {
|
impl<'a> FunctionBuilder<'a> {
|
||||||
/// 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] {
|
||||||
@@ -594,7 +596,7 @@ impl FunctionBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Helper functions
|
/// Helper functions
|
||||||
impl FunctionBuilder {
|
impl<'a> FunctionBuilder<'a> {
|
||||||
/// 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`
|
||||||
@@ -854,7 +856,7 @@ fn greatest_divisible_power_of_two(size: u64) -> u64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Helper functions
|
// Helper functions
|
||||||
impl FunctionBuilder {
|
impl<'a> FunctionBuilder<'a> {
|
||||||
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
|
||||||
@@ -889,7 +891,7 @@ impl FunctionBuilder {
|
|||||||
#[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;
|
use crate::frontend::{FunctionBuilder, FunctionBuilderContext};
|
||||||
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::*;
|
||||||
@@ -904,9 +906,10 @@ 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 func = {
|
let mut fn_ctx = FunctionBuilderContext::new();
|
||||||
let func = Function::with_name_signature(ExternalName::testcase("sample"), sig);
|
let mut 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();
|
||||||
@@ -988,8 +991,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));
|
||||||
@@ -1026,9 +1029,10 @@ 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 func = {
|
let mut fn_ctx = FunctionBuilderContext::new();
|
||||||
let func = Function::with_name_signature(ExternalName::testcase("sample"), sig);
|
let mut 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);
|
||||||
@@ -1047,8 +1051,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(),
|
||||||
@@ -1086,9 +1090,10 @@ 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 func = {
|
let mut fn_ctx = FunctionBuilderContext::new();
|
||||||
let func = Function::with_name_signature(ExternalName::testcase("sample"), sig);
|
let mut 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);
|
||||||
@@ -1105,8 +1110,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(),
|
||||||
@@ -1142,9 +1147,10 @@ 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 func = {
|
let mut fn_ctx = FunctionBuilderContext::new();
|
||||||
let func = Function::with_name_signature(ExternalName::testcase("sample"), sig);
|
let mut 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);
|
||||||
@@ -1161,8 +1167,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(),
|
||||||
@@ -1201,9 +1207,10 @@ 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 func = {
|
let mut fn_ctx = FunctionBuilderContext::new();
|
||||||
let func = Function::with_name_signature(ExternalName::testcase("sample"), sig);
|
let mut 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);
|
||||||
@@ -1217,8 +1224,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(),
|
||||||
@@ -1252,9 +1259,10 @@ 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 func = {
|
let mut fn_ctx = FunctionBuilderContext::new();
|
||||||
let func = Function::with_name_signature(ExternalName::testcase("sample"), sig);
|
let mut 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);
|
||||||
@@ -1268,8 +1276,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(),
|
||||||
|
|||||||
@@ -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 [`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).
|
//! 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 `Function`:
|
//! Here is how you build the corresponding Cranelift IR function using `FunctionBuilderContext`:
|
||||||
//!
|
//!
|
||||||
//! ```rust
|
//! ```rust
|
||||||
//! extern crate cranelift_codegen;
|
//! extern crate cranelift_codegen;
|
||||||
@@ -73,15 +73,16 @@
|
|||||||
//! 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, Variable};
|
//! use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext, 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 func = {
|
//! let mut fn_builder_ctx = FunctionBuilderContext::new();
|
||||||
//! let 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(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();
|
||||||
@@ -151,8 +152,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);
|
||||||
@@ -194,7 +195,7 @@ use hashmap_core::HashMap;
|
|||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
pub use crate::frontend::FunctionBuilder;
|
pub use crate::frontend::{FunctionBuilder, FunctionBuilderContext};
|
||||||
pub use crate::switch::Switch;
|
pub use crate::switch::Switch;
|
||||||
pub use crate::variable::Variable;
|
pub use crate::variable::Variable;
|
||||||
|
|
||||||
|
|||||||
@@ -176,7 +176,9 @@ 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.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.
|
/// Tests whether an `SSABuilder` is in a cleared state.
|
||||||
|
|||||||
@@ -16,11 +16,12 @@ 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, Switch};
|
/// # use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext, 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(func);
|
/// # let mut builder = FunctionBuilder::new(&mut func, &mut fn_builder_ctx);
|
||||||
/// #
|
/// #
|
||||||
/// # let entry = builder.create_ebb();
|
/// # let entry = builder.create_ebb();
|
||||||
/// # builder.switch_to_block(entry);
|
/// # builder.switch_to_block(entry);
|
||||||
@@ -288,13 +289,16 @@ 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 func = {
|
let mut func = Function::new();
|
||||||
let mut bx = FunctionBuilder::new(Function::new());
|
let mut func_ctx = FunctionBuilderContext::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);
|
||||||
@@ -304,9 +308,7 @@ 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")
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
//! A basic `Variable` implementation.
|
//! 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
|
//! 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.
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ 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));
|
||||||
@@ -24,8 +25,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(ctx.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);
|
||||||
@@ -35,15 +36,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(ctx.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);
|
||||||
@@ -57,8 +58,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);
|
||||||
|
|
||||||
|
|||||||
@@ -37,16 +37,14 @@ 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);
|
||||||
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);
|
||||||
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();
|
||||||
|
|
||||||
@@ -87,9 +85,11 @@ fn switch_error() {
|
|||||||
call_conv: CallConv::SystemV,
|
call_conv: CallConv::SystemV,
|
||||||
};
|
};
|
||||||
|
|
||||||
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 bcx: FunctionBuilder = FunctionBuilder::new(func);
|
let mut func_ctx = FunctionBuilderContext::new();
|
||||||
|
{
|
||||||
|
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,9 +164,10 @@ fn libcall_function() {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let mut ctx = Context::new();
|
let mut ctx = Context::new();
|
||||||
ctx.func = {
|
ctx.func = Function::with_name_signature(ExternalName::user(0, func_id.as_u32()), sig);
|
||||||
let 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(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);
|
||||||
|
|
||||||
@@ -188,11 +189,7 @@ 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();
|
||||||
|
|
||||||
|
|||||||
@@ -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, Variable};
|
pub use crate::frontend::{FunctionBuilder, FunctionBuilderContext, Variable};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Version number of this crate.
|
/// Version number of this crate.
|
||||||
|
|||||||
@@ -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(&mut builder.func, *global_index, environ)? {
|
let val = match state.get_global(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(&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::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,8 +367,7 @@ 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) =
|
let (fref, num_args) = state.get_direct_func(builder.func, *function_index, environ)?;
|
||||||
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),
|
||||||
@@ -389,8 +388,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(&mut builder.func, *index, environ)?;
|
let (sigref, num_args) = state.get_indirect_sig(builder.func, *index, environ)?;
|
||||||
let table = state.get_table(&mut builder.func, *table_index, environ)?;
|
let table = state.get_table(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(),
|
||||||
@@ -418,13 +417,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(&mut builder.func, *reserved, environ)?;
|
let heap = state.get_heap(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(&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)?);
|
state.push1(environ.translate_memory_size(builder.cursor(), heap_index, heap)?);
|
||||||
}
|
}
|
||||||
/******************************* Load instructions ***********************************
|
/******************************* Load instructions ***********************************
|
||||||
@@ -1238,7 +1237,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(&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);
|
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
|
||||||
@@ -1263,7 +1262,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(&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);
|
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();
|
||||||
|
|||||||
@@ -543,7 +543,8 @@ impl<'data> ModuleEnvironment<'data> for DummyEnvironment {
|
|||||||
func.collect_debug_info();
|
func.collect_debug_info();
|
||||||
}
|
}
|
||||||
self.trans
|
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.func_bytecode_sizes.push(body_bytes.len());
|
||||||
self.info.function_bodies.push(func);
|
self.info.function_bodies.push(func);
|
||||||
|
|||||||
@@ -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, Variable};
|
use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext, 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 {
|
||||||
builder: FunctionBuilder,
|
func_ctx: FunctionBuilderContext,
|
||||||
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 {
|
||||||
builder: FunctionBuilder::new(ir::Function::new()),
|
func_ctx: FunctionBuilderContext::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: ir::Function,
|
func: &mut ir::Function,
|
||||||
environ: &mut FE,
|
environ: &mut FE,
|
||||||
) -> WasmResult<ir::Function> {
|
) -> WasmResult<()> {
|
||||||
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: ir::Function,
|
func: &mut ir::Function,
|
||||||
environ: &mut FE,
|
environ: &mut FE,
|
||||||
) -> WasmResult<ir::Function> {
|
) -> WasmResult<()> {
|
||||||
let _tt = timing::wasm_translate_function();
|
let _tt = timing::wasm_translate_function();
|
||||||
info!(
|
info!(
|
||||||
"translate({} bytes, {}{})",
|
"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_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");
|
||||||
|
|
||||||
self.builder.func = func;
|
// This clears the `FunctionBuilderContext`.
|
||||||
self.builder.set_srcloc(cur_srcloc(&reader));
|
let mut builder = FunctionBuilder::new(func, &mut self.func_ctx);
|
||||||
let entry_block = self.builder.create_ebb();
|
builder.set_srcloc(cur_srcloc(&reader));
|
||||||
self.builder
|
let entry_block = builder.create_ebb();
|
||||||
.append_ebb_params_for_function_params(entry_block);
|
builder.append_ebb_params_for_function_params(entry_block);
|
||||||
self.builder.switch_to_block(entry_block); // This also creates values for the arguments.
|
builder.switch_to_block(entry_block); // This also creates values for the arguments.
|
||||||
self.builder.seal_block(entry_block); // Declare all predecessors known.
|
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.
|
||||||
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
|
// 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 = self.builder.create_ebb();
|
let exit_block = builder.create_ebb();
|
||||||
self.builder
|
builder.append_ebb_params_for_function_returns(exit_block);
|
||||||
.append_ebb_params_for_function_returns(exit_block);
|
self.state.initialize(&builder.func.signature, exit_block);
|
||||||
self.state
|
|
||||||
.initialize(&self.builder.func.signature, exit_block);
|
|
||||||
|
|
||||||
parse_local_decls(&mut reader, &mut self.builder, num_params, environ)?;
|
parse_local_decls(&mut reader, &mut builder, num_params, environ)?;
|
||||||
parse_function_body(reader, &mut self.builder, &mut self.state, 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.params.push(ir::AbiParam::new(I32));
|
||||||
ctx.func.signature.returns.push(ir::AbiParam::new(I32));
|
ctx.func.signature.returns.push(ir::AbiParam::new(I32));
|
||||||
|
|
||||||
ctx.func = trans
|
trans
|
||||||
.translate(&BODY, 0, ctx.func, &mut runtime.func_env())
|
.translate(&BODY, 0, &mut 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();
|
||||||
@@ -328,8 +327,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));
|
||||||
|
|
||||||
ctx.func = trans
|
trans
|
||||||
.translate(&BODY, 0, ctx.func, &mut runtime.func_env())
|
.translate(&BODY, 0, &mut 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();
|
||||||
@@ -375,8 +374,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));
|
||||||
|
|
||||||
ctx.func = trans
|
trans
|
||||||
.translate(&BODY, 0, ctx.func, &mut runtime.func_env())
|
.translate(&BODY, 0, &mut 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();
|
||||||
|
|||||||
Reference in New Issue
Block a user