Skip to main content

Builder

Struct Builder 

Source
pub struct Builder<'a> { /* private fields */ }
Expand description

A cursor that appends to the end of one block.

This is the shape lowering wants: it works on one block at a time, it appends, and it wants the value back so it can use it in the next instruction. Everything here is a thin wrapper over Func::create_inst and Func::append_inst, and anything the wrappers do not cover is done with those two directly.

Implementations§

Source§

impl<'a> Builder<'a>

Source

pub fn new(func: &'a mut Func, block: Block) -> Self

A cursor appending to that block, with every instruction taking that source location.

Source

pub fn at(self, span: Span) -> Self

The same cursor, with a source location for the instructions after this.

Source

pub fn set_span(&mut self, span: Span)

Sets the source location for the instructions after this.

Source

pub fn func(&mut self) -> &mut Func

The function being built.

Source

pub fn block(&self) -> Block

The block being appended to.

Source

pub fn inst(&mut self, data: InstData, results: &[Type]) -> Inst

Appends an instruction as it is, and gives back its results.

Source

pub fn value(&mut self, data: InstData, ty: Type) -> Value

The one value an instruction produces.

§Panics

Panics if it did not produce exactly one.

Source

pub fn iconst(&mut self, ty: Type, value: i128) -> Value

An integer constant.

§Panics

Panics if ty is not an integer type.

Source

pub fn fconst(&mut self, ty: Type, bits: u128) -> Value

A floating point constant, given as the bits of its format.

Source

pub fn binary( &mut self, opcode: Opcode, lhs: Value, rhs: Value, flags: Flags, ) -> Value

A two-operand instruction whose result has the type of its operands.

Source

pub fn checked( &mut self, opcode: Opcode, lhs: Value, rhs: Value, ) -> (Value, Value)

Arithmetic that answers with both the wrapped result and whether it wrapped.

The one shape in the IR whose result is two things, which is why it has a builder of its own rather than going through Builder::value. The first result is the answer in the type of the operands, the same as the ordinary form of the same arithmetic would give, and the second is one i1 per lane saying whether the exact answer needed more bits than that type has.

§Panics

Panics if the instruction did not produce exactly the two results it was created with, which is the same promise Builder::value makes about its one.

Source

pub fn unary(&mut self, opcode: Opcode, arg: Value, ty: Type) -> Value

A one-operand instruction whose result has the type given.

Source

pub fn icmp(&mut self, pred: IntPred, lhs: Value, rhs: Value) -> Value

An integer comparison, which produces one i1 per lane.

Source

pub fn select(&mut self, cond: Value, then: Value, other: Value) -> Value

One of two values, chosen by a bit, which is what a diamond becomes when it stops being one.

The type comes from the arms rather than from the bit, and the two arms have to agree, which the verifier checks. Both are evaluated, so the caller owes the argument that evaluating the one that is not chosen is harmless.

Source

pub fn fcmp( &mut self, pred: FloatPred, lhs: Value, rhs: Value, flags: Flags, ) -> Value

A floating point comparison, which produces one i1 per lane.

Source

pub fn mem_entry(&mut self) -> Value

Memory as the function found it, which is where a memory SSA chain starts.

It belongs at the top of the entry block and there is one of them in a function.

Source

pub fn load( &mut self, ty: Type, addr: Value, info: MemInfo, flags: Flags, ) -> Value

A read of that type from that address.

Source

pub fn store( &mut self, value: Value, addr: Value, info: MemInfo, flags: Flags, ) -> Inst

A write of a value to an address.

Source

pub fn atomic_load( &mut self, ty: Type, addr: Value, info: MemInfo, flags: Flags, ) -> Value

The same read, ordered.

A separate opcode rather than an ordering on Builder::load, because the two are not the same thing to anything that moves code: a plain load may be moved, duplicated and dropped, and this one may not. The IR verifier is what keeps the pair honest, since it refuses an ordering on a plain access and refuses an unordered one here, so no pass has to remember to check the payload before deciding a load is free.

Source

pub fn atomic_store( &mut self, value: Value, addr: Value, info: MemInfo, flags: Flags, ) -> Inst

The same write, ordered.

Source

pub fn cmpxchg( &mut self, addr: Value, expected: Value, desired: Value, info: MemInfo, flags: Flags, ) -> (Value, Value)

A compare and exchange, which answers what it found and whether that was what was expected.

Two values out of one instruction, in that order, because a caller that had to ask twice would be asking about two different moments. The type of the first is the type of the value expected, which is what says how wide the access is, and the type of the second is Type::I1 whatever the width was.

Source

pub fn atomic_rmw( &mut self, op: RmwOp, addr: Value, operand: Value, info: MemInfo, flags: Flags, ) -> Value

A read, an operation on what was read, and a write back, with nothing able to get between them.

The value it answers is the one that was there before, which is the convention every machine and every language in this area uses, and a caller that wanted the value afterwards works it out from the two it already has rather than asking for a second flavour of the instruction. The type of that value is the type of the operand, which is what says how wide the access is.

Source

pub fn fence(&mut self, order: MemOrder) -> Inst

A barrier, which touches no address and is its ordering and nothing else.

Source

pub fn jump(&mut self, target: Block, args: &[Value]) -> Inst

An unconditional branch.

Source

pub fn block_addr(&mut self, target: Block) -> Value

The address of a block, which is a value a later indirect_br can branch to.

The block is a target here in the same sense a branch’s is, so everything that asks an instruction which blocks it names finds this one, and a block whose address is taken is not mistaken for a block nothing mentions.

Source

pub fn indirect_br(&mut self, addr: Value, targets: &[Block]) -> Inst

A branch to an address, which arrives at one of the blocks listed.

Every block the address can hold has to be there. The list is what the rest of the compiler reads, so a block left out of it is a block the branch is saying it never reaches, and none of it is checked against the addresses anybody took.

Source

pub fn br_if( &mut self, cond: Value, then_block: Block, then_args: &[Value], else_block: Block, else_args: &[Value], ) -> Inst

A two-way branch, taking the first target when the condition is one.

Source

pub fn switch( &mut self, value: Value, default: Block, cases: &[(i128, Block)], ) -> Inst

A branch on an integer, taking the target its value selects and the default when it selects none.

The cases are values and blocks rather than a table with the default in it, because the order the side table wants, which is the default first, is not an order anybody building a switch has their cases in.

Source

pub fn ret(&mut self, values: &[Value]) -> Inst

A return of the values the signature says.

Source

pub fn unreachable(&mut self) -> Inst

A place control does not reach.

Source

pub fn call(&mut self, callee: Symbol, signature: Sig, args: &[Value]) -> Inst

A direct call, with the results its signature says it produces.

Source

pub fn call_varargs( &mut self, callee: Symbol, signature: Sig, args: &[Value], varargs: &[Abi], ) -> Inst

The same, saying how the arguments the signature does not name travel.

Empty says they all travel as the values in hand, which is what Builder::call passes and is the usual case. Anything else has one entry for each argument past the ones the signature names.

Source

pub fn inline_asm( &mut self, info: AsmInfo, args: &[Value], results: &[Type], flags: Flags, ) -> Inst

Inline assembly, which is a terminator when the info carries targets.

The targets are built by the caller, because the frontend is the only thing that knows which block is the one control reaches when the assembly does not jump, and that block has to come first.

Trait Implementations§

Source§

impl<'a> Debug for Builder<'a>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

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

§

impl<'a> Freeze for Builder<'a>

§

impl<'a> RefUnwindSafe for Builder<'a>

§

impl<'a> Send for Builder<'a>

§

impl<'a> Sync for Builder<'a>

§

impl<'a> Unpin for Builder<'a>

§

impl<'a> UnsafeUnpin for Builder<'a>

Blanket Implementations§

Source§

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

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

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

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where 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 T
where 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 T
where U: Into<T>,

Source§

type Error = !

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

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

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

Source§

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.