pub struct FunctionBuilder<'a> {
    pub func: &'a mut Function,
    /* private fields */
}
Expand description

Temporary object used to build a single Cranelift IR Function.

Fields§

§func: &'a mut Function

The function currently being built. This field is public so the function can be re-borrowed.

Implementations§

source§

impl<'a> FunctionBuilder<'a>

This module allows you to create a function in Cranelift IR in a straightforward way, hiding all the complexity of its internal representation.

The module is parametrized by one type which is the representation of variables in your origin language. It offers a way to conveniently append instruction to your program flow. You are responsible to split your instruction flow into extended blocks (declared with create_block) whose properties are:

  • branch and jump instructions can only point at the top of extended blocks;
  • the last instruction of each block is a terminator instruction which has no natural successor, and those instructions can only appear at the end of extended blocks.

The parameters of Cranelift IR instructions are Cranelift IR values, which can only be created as results of other Cranelift IR instructions. To be able to create variables redefined multiple times in your program, use the def_var and use_var command, that will maintain the correspondence between your variables and Cranelift IR SSA values.

The first block for which you call switch_to_block will be assumed to be the beginning of the function.

At creation, a FunctionBuilder instance borrows an already allocated Function which it modifies with the information stored in the mutable borrowed FunctionBuilderContext. The function passed in argument should be newly created with Function::with_name_signature(), whereas the FunctionBuilderContext can be kept as is between two function translations.

Errors

The functions below will panic in debug mode whenever you try to modify the Cranelift IR function in a way that violate the coherence of the code. For instance: switching to a new Block 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.

source

pub fn new( func: &'a mut Function, func_ctx: &'a mut FunctionBuilderContext ) -> FunctionBuilder<'a>

Creates a new FunctionBuilder structure that will operate on a Function using a FunctionBuilderContext.

source

pub fn current_block(&self) -> Option<Block>

Get the block that this builder is currently at.

source

pub fn set_srcloc(&mut self, srcloc: SourceLoc)

Set the source location that should be assigned to all new instructions.

source

pub fn create_block(&mut self) -> Block

Creates a new Block and returns its reference.

source

pub fn set_cold_block(&mut self, block: Block)

Mark a block as “cold”.

This will try to move it out of the ordinary path of execution when lowered to machine code.

source

pub fn insert_block_after(&mut self, block: Block, after: Block)

Insert block in the layout after the existing block after.

source

pub fn switch_to_block(&mut self, block: Block)

After the call to this function, new instructions will be inserted into the designated block, in the order they are declared. You must declare the types of the Block arguments you will use here.

When inserting the terminator instruction (which doesn’t have a fallthrough to its immediate successor), the block will be declared filled and it will not be possible to append instructions to it.

source

pub fn seal_block(&mut self, block: Block)

Declares that all the predecessors of this block are known.

Function to call with block as soon as the last branch instruction to block has been created. Forgetting to call this method on every block will cause inconsistencies in the produced functions.

source

pub fn seal_all_blocks(&mut self)

Effectively calls seal_block on all unsealed blocks in the function.

It’s more efficient to seal Blocks as soon as possible, during translation, but for frontends where this is impractical to do, this function can be used at the end of translating all blocks to ensure that everything is sealed.

source

pub fn try_declare_var( &mut self, var: Variable, ty: Type ) -> Result<(), DeclareVariableError>

Declares the type of a variable, so that it can be used later (by calling FunctionBuilder::use_var). This function will return an error if the variable has been previously declared.

source

pub fn declare_var(&mut self, var: Variable, ty: Type)

In order to use a variable (by calling FunctionBuilder::use_var), you need to first declare its type with this method.

source

pub fn try_use_var(&mut self, var: Variable) -> Result<Value, UseVariableError>

Returns the Cranelift IR necessary to use a previously defined user variable, returning an error if this is not possible.

source

pub fn use_var(&mut self, var: Variable) -> Value

Returns the Cranelift IR value corresponding to the utilization at the current program position of a previously defined user variable.

source

pub fn try_def_var( &mut self, var: Variable, val: Value ) -> Result<(), DefVariableError>

Registers a new definition of a user variable. This function will return an error if the value supplied does not match the type the variable was declared to have.

source

pub fn def_var(&mut self, var: Variable, val: Value)

Register a new definition of a user variable. The type of the value must be the same as the type registered for the variable.

source

pub fn set_val_label(&mut self, val: Value, label: ValueLabel)

Set label for Value

This will not do anything unless func.dfg.collect_debug_info is called first.

source

pub fn create_jump_table(&mut self, data: JumpTableData) -> JumpTable

Creates a jump table in the function, to be used by br_table instructions.

source

pub fn create_sized_stack_slot(&mut self, data: StackSlotData) -> StackSlot

Creates a sized stack slot in the function, to be used by stack_load, stack_store and stack_addr instructions.

source

pub fn create_dynamic_stack_slot( &mut self, data: DynamicStackSlotData ) -> DynamicStackSlot

Creates a dynamic stack slot in the function, to be used by dynamic_stack_load, dynamic_stack_store and dynamic_stack_addr instructions.

source

pub fn import_signature(&mut self, signature: Signature) -> SigRef

Adds a signature which can later be used to declare an external function import.

source

pub fn import_function(&mut self, data: ExtFuncData) -> FuncRef

Declare an external function import.

source

pub fn create_global_value(&mut self, data: GlobalValueData) -> GlobalValue

Declares a global value accessible to the function.

source

pub fn ins<'short>(&'short mut self) -> FuncInstBuilder<'short, 'a>

Returns an object with the InstBuilder trait that allows to conveniently append an instruction to the current Block being built.

source

pub fn ensure_inserted_block(&mut self)

Make sure that the current block is inserted in the layout.

source

pub fn cursor(&mut self) -> FuncCursor<'_>

Returns a FuncCursor pointed at the current position ready for inserting instructions.

This can be used to insert SSA code that doesn’t need to access locals and that doesn’t need to know about FunctionBuilder at all.

source

pub fn append_block_params_for_function_params(&mut self, block: Block)

Append parameters to the given Block corresponding to the function parameters. This can be used to set up the block parameters for the entry block.

source

pub fn append_block_params_for_function_returns(&mut self, block: Block)

Append parameters to the given Block corresponding to the function return values. This can be used to set up the block parameters for a function exit block.

source

pub fn finalize(self)

Declare that translation of the current function is complete.

This resets the state of the FunctionBuilderContext in preparation to be used for another function.

source§

impl<'a> FunctionBuilder<'a>

All the functions documented in the previous block are write-only and help you build a valid Cranelift IR functions via multiple debug asserts. However, you might need to improve the performance of your translation perform more complex transformations to your Cranelift IR function. The functions below help you inspect the function you’re creating and modify it in ways that can be unsafe if used incorrectly.

source

pub fn block_params(&self, block: Block) -> &[Value]

Retrieves all the parameters for a Block currently inferred from the jump instructions inserted that target it and the SSA construction.

source

pub fn signature(&self, sigref: SigRef) -> Option<&Signature>

Retrieves the signature with reference sigref previously added with import_signature.

source

pub fn append_block_param(&mut self, block: Block, ty: Type) -> Value

Creates a parameter for a specific Block by appending it to the list of already existing parameters.

Note: this function has to be called at the creation of the Block before adding instructions to it, otherwise this could interfere with SSA construction.

source

pub fn inst_results(&self, inst: Inst) -> &[Value]

Returns the result values of an instruction.

source

pub fn change_jump_destination( &mut self, inst: Inst, old_block: Block, new_block: Block )

Changes the destination of a jump instruction after creation.

Note: You are responsible for maintaining the coherence with the arguments of other jump instructions.

source

pub fn is_unreachable(&self) -> bool

Returns true if and only if the current Block is sealed and has no predecessors declared.

The entry block of a function is never unreachable.

source§

impl<'a> FunctionBuilder<'a>

Helper functions

source

pub fn call_memcpy( &mut self, config: TargetFrontendConfig, dest: Value, src: Value, size: Value )

Calls libc.memcpy

Copies the size bytes from src to dest, assumes that src + size won’t overlap onto dest. If dest and src overlap, the behavior is undefined. Applications in which dest and src might overlap should use call_memmove instead.

source

pub fn emit_small_memory_copy( &mut self, config: TargetFrontendConfig, dest: Value, src: Value, size: u64, dest_align: u8, src_align: u8, non_overlapping: bool, flags: MemFlags )

Optimised memcpy or memmove for small copies.

Codegen safety

The following properties must hold to prevent UB:

  • src_align and dest_align are an upper-bound on the alignment of src respectively dest.
  • If non_overlapping is true, then this must be correct.
source

pub fn call_memset( &mut self, config: TargetFrontendConfig, buffer: Value, ch: Value, size: Value )

Calls libc.memset

Writes size bytes of i8 value ch to memory starting at buffer.

source

pub fn emit_small_memset( &mut self, config: TargetFrontendConfig, buffer: Value, ch: u8, size: u64, buffer_align: u8, flags: MemFlags )

Calls libc.memset

Writes size bytes of value ch to memory starting at buffer.

source

pub fn call_memmove( &mut self, config: TargetFrontendConfig, dest: Value, source: Value, size: Value )

Calls libc.memmove

Copies size bytes from memory starting at source to memory starting at dest. source is always read before writing to dest.

source

pub fn call_memcmp( &mut self, config: TargetFrontendConfig, left: Value, right: Value, size: Value ) -> Value

Calls libc.memcmp

Compares size bytes from memory starting at left to memory starting at right. Returns 0 if all n bytes are equal. If the first difference is at offset i, returns a positive integer if ugt(left[i], right[i]) and a negative integer if ult(left[i], right[i]).

Returns a C int, which is currently always types::I32.

source

pub fn emit_small_memory_compare( &mut self, config: TargetFrontendConfig, int_cc: IntCC, left: Value, right: Value, size: u64, left_align: NonZeroU8, right_align: NonZeroU8, flags: MemFlags ) -> Value

Optimised Self::call_memcmp for small copies.

This implements the byte slice comparison int_cc(left[..size], right[..size]).

left_align and right_align are the statically-known alignments of the left and right pointers respectively. These are used to know whether to mark loads as aligned. It’s always fine to pass 1 for these, but passing something higher than the true alignment may trap or otherwise misbehave as described in MemFlags::aligned.

Note that memcmp is a big-endian and unsigned comparison. As such, this panics when called with IntCC::Signed*.

Auto Trait Implementations§

§

impl<'a> RefUnwindSafe for FunctionBuilder<'a>

§

impl<'a> Send for FunctionBuilder<'a>

§

impl<'a> Sync for FunctionBuilder<'a>

§

impl<'a> Unpin for FunctionBuilder<'a>

§

impl<'a> !UnwindSafe for FunctionBuilder<'a>

Blanket Implementations§

source§

impl<T> Any for Twhere T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for Twhere T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for Twhere T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for Twhere U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T, U> TryFrom<U> for Twhere U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for Twhere U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.