pub struct WhileOperation<'c> { /* private fields */ }
Expand description

A while operation. A generic ‘while’ loop.

This operation represents a generic “while”/“do-while” loop that keeps iterating as long as a condition is satisfied. There is no restriction on the complexity of the condition. It consists of two regions (with single block each): “before” region and “after” region. The names of regions indicates whether they execute before or after the condition check. Therefore, if the main loop payload is located in the “before” region, the operation is a “do-while” loop. Otherwise, it is a “while” loop.

The “before” region terminates with a special operation, scf.condition, that accepts as its first operand an i1 value indicating whether to proceed to the “after” region (value is true) or not. The two regions communicate by means of region arguments. Initially, the “before” region accepts as arguments the operands of the scf.while operation and uses them to evaluate the condition. It forwards the trailing, non-condition operands of the scf.condition terminator either to the “after” region if the control flow is transferred there or to results of the scf.while operation otherwise. The “after” region takes as arguments the values produced by the “before” region and uses scf.yield to supply new arguments for the “before” region, into which it transfers the control flow unconditionally.

A simple “while” loop can be represented as follows.

%res = scf.while (%arg1 = %init1) : (f32) -> f32 {
  // "Before" region.
  // In a "while" loop, this region computes the condition.
  %condition = call @evaluate_condition(%arg1) : (f32) -> i1

  // Forward the argument (as result or "after" region argument).
  scf.condition(%condition) %arg1 : f32

} do {
^bb0(%arg2: f32):
  // "After" region.
  // In a "while" loop, this region is the loop body.
  %next = call @payload(%arg2) : (f32) -> f32

  // Forward the new value to the "before" region.
  // The operand types must match the types of the `scf.while` operands.
  scf.yield %next : f32
}

A simple “do-while” loop can be represented by reducing the “after” block to a simple forwarder.

%res = scf.while (%arg1 = %init1) : (f32) -> f32 {
  // "Before" region.
  // In a "do-while" loop, this region contains the loop body.
  %next = call @payload(%arg1) : (f32) -> f32

  // And also evaluates the condition.
  %condition = call @evaluate_condition(%arg1) : (f32) -> i1

  // Loop through the "after" region.
  scf.condition(%condition) %next : f32

} do {
^bb0(%arg2: f32):
  // "After" region.
  // Forwards the values back to "before" region unmodified.
  scf.yield %arg2 : f32
}

Note that the types of region arguments need not to match with each other. The op expects the operand types to match with argument types of the “before” region; the result types to match with the trailing operand types of the terminator of the “before” region, and with the argument types of the “after” region. The following scheme can be used to share the results of some operations executed in the “before” region with the “after” region, avoiding the need to recompute them.

%res = scf.while (%arg1 = %init1) : (f32) -> i64 {
  // One can perform some computations, e.g., necessary to evaluate the
  // condition, in the "before" region and forward their results to the
  // "after" region.
  %shared = call @shared_compute(%arg1) : (f32) -> i64

  // Evaluate the condition.
  %condition = call @evaluate_condition(%arg1, %shared) : (f32, i64) -> i1

  // Forward the result of the shared computation to the "after" region.
  // The types must match the arguments of the "after" region as well as
  // those of the `scf.while` results.
  scf.condition(%condition) %shared : i64

} do {
^bb0(%arg2: i64) {
  // Use the partial result to compute the rest of the payload in the
  // "after" region.
  %res = call @payload(%arg2) : (i64) -> f32

  // Forward the new value to the "before" region.
  // The operand types must match the types of the `scf.while` operands.
  scf.yield %res : f32
}

The custom syntax for this operation is as follows.

op ::= `scf.while` assignments `:` function-type region `do` region
       `attributes` attribute-dict
initializer ::= /* empty */ | `(` assignment-list `)`
assignment-list ::= assignment | assignment `,` assignment-list
assignment ::= ssa-value `=` ssa-value

Implementations§

source§

impl<'c> WhileOperation<'c>

source

pub fn name() -> &'static str

Returns a name.

source

pub fn as_operation(&self) -> &Operation<'c>

Returns a generic operation.

source

pub fn builder( context: &'c Context, location: Location<'c> ) -> WhileOperationBuilder<'c, Unset, Unset, Unset, Unset>

Creates a builder.

source

pub fn results(&self) -> impl Iterator<Item = OperationResult<'c, '_>>

source

pub fn inits(&self) -> impl Iterator<Item = Value<'c, '_>>

source

pub fn before(&self) -> Result<RegionRef<'c, '_>, Error>

source

pub fn after(&self) -> Result<RegionRef<'c, '_>, Error>

Trait Implementations§

source§

impl<'c> From<WhileOperation<'c>> for Operation<'c>

source§

fn from(operation: WhileOperation<'c>) -> Self

Converts to this type from the input type.
source§

impl<'c> TryFrom<Operation<'c>> for WhileOperation<'c>

§

type Error = Error

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

fn try_from(operation: Operation<'c>) -> Result<Self, Self::Error>

Performs the conversion.

Auto Trait Implementations§

§

impl<'c> RefUnwindSafe for WhileOperation<'c>

§

impl<'c> !Send for WhileOperation<'c>

§

impl<'c> !Sync for WhileOperation<'c>

§

impl<'c> Unpin for WhileOperation<'c>

§

impl<'c> UnwindSafe for WhileOperation<'c>

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>,

§

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 T
where 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.