AffineForOperation

Struct AffineForOperation 

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

A for operation. For operation.

Syntax:

operation   ::= `affine.for` ssa-id `=` lower-bound `to` upper-bound
                (`step` integer-literal)? `{` op* `}`

lower-bound ::= `max`? affine-map-attribute dim-and-symbol-use-list | shorthand-bound
upper-bound ::= `min`? affine-map-attribute dim-and-symbol-use-list | shorthand-bound
shorthand-bound ::= ssa-id | `-`? integer-literal

The affine.for operation represents an affine loop nest. It has one region containing its body. This region must contain one block that terminates with affine.yield. Note: when affine.for is printed in custom format, the terminator is omitted. The block has one argument of index type that represents the induction variable of the loop.

The affine.for operation executes its body a number of times iterating from a lower bound to an upper bound by a stride. The stride, represented by step, is a positive constant integer which defaults to “1” if not present. The lower and upper bounds specify a half-open range: the range includes the lower bound but does not include the upper bound.

The lower and upper bounds of a affine.for operation are represented as an application of an affine mapping to a list of SSA values passed to the map. The same restrictions hold for these SSA values as for all bindings of SSA values to dimensions and symbols.

The affine mappings for the bounds may return multiple results, in which case the max/min keywords are required (for the lower/upper bound respectively), and the bound is the maximum/minimum of the returned values. There is no semantic ambiguity, but MLIR syntax requires the use of these keywords to make things more obvious to human readers.

Many upper and lower bounds are simple, so MLIR accepts two custom form syntaxes: the form that accepts a single ‘ssa-id’ (e.g. %N) is shorthand for applying that SSA value to a function that maps a single symbol to itself, e.g., ()[s]->(s)()[%N]. The integer literal form (e.g. -42) is shorthand for a nullary mapping function that returns the constant value (e.g. ()->(-42)()).

Example showing reverse iteration of the inner loop:

#map57 = affine_map<(d0)[s0] -> (s0 - d0 - 1)>

func.func @simple_example(%A: memref<?x?xf32>, %B: memref<?x?xf32>) {
  %N = dim %A, 0 : memref<?x?xf32>
  affine.for %i = 0 to %N step 1 {
    affine.for %j = 0 to %N {   // implicitly steps by 1
      %0 = affine.apply #map57(%j)[%N]
      %tmp = call @F1(%A, %i, %0) : (memref<?x?xf32>, index, index)->(f32)
      call @F2(%tmp, %B, %i, %0) : (f32, memref<?x?xf32>, index, index)->()
    }
  }
  return
}

affine.for can also operate on loop-carried variables (iter_args) and return the final values after loop termination. The initial values of the variables are passed as additional SSA operands to the affine.for following the operands for the loop’s lower and upper bounds. The operation’s region has equivalent arguments for each variable representing the value of the variable at the current iteration.

The region must terminate with an affine.yield that passes all the current iteration variables to the next iteration, or to the affine.for’s results if at the last iteration. For affine.for’s that execute zero iterations, the initial values of the loop-carried variables (corresponding to the SSA operands) will be the op’s results.

For example, to sum-reduce a memref:

func.func @reduce(%buffer: memref<1024xf32>) -> (f32) {
 // Initial sum set to 0.
 %sum_0 = arith.constant 0.0 : f32
 // iter_args binds initial values to the loop's region arguments.
 %sum = affine.for %i = 0 to 10 step 2
     iter_args(%sum_iter = %sum_0) -> (f32) {
   %t = affine.load %buffer[%i] : memref<1024xf32>
   %sum_next = arith.addf %sum_iter, %t : f32
   // Yield current iteration sum to next iteration %sum_iter or to %sum
   // if final iteration.
   affine.yield %sum_next : f32
 }
 return %sum : f32
}
%res:2 = affine.for %i = 0 to 128 iter_args(%arg0 = %init0, %arg1 = %init1)
           -> (index, index) {
  %y0 = arith.addi %arg0, %c1 : index
  %y1 = arith.addi %arg1, %c2 : index
  affine.yield %y0, %y1 : index, index
}

If the affine.for defines any values, a yield terminator must be explicitly present. The number and types of the “affine.for” results must match the initial values in the iter_args binding and the yield operands.

Implementations§

Source§

impl<'c> AffineForOperation<'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>, ) -> AffineForOperationBuilder<'c, Unset, Unset, Unset, Unset, Unset, Unset, Unset, Unset>

Creates a builder.

Source

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

Source

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

Source

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

Source

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

Source

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

Source

pub fn lower_bound_map(&self) -> Result<Attribute<'c>, Error>

Source

pub fn set_lower_bound_map(&mut self, value: Attribute<'c>)

Source

pub fn upper_bound_map(&self) -> Result<Attribute<'c>, Error>

Source

pub fn set_upper_bound_map(&mut self, value: Attribute<'c>)

Source

pub fn step(&self) -> Result<IntegerAttribute<'c>, Error>

Source

pub fn set_step(&mut self, value: IntegerAttribute<'c>)

Trait Implementations§

Source§

impl<'c> Clone for AffineForOperation<'c>

Source§

fn clone(&self) -> AffineForOperation<'c>

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl<'c> Debug for AffineForOperation<'c>

Source§

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

Formats the value using the given formatter. Read more
Source§

impl<'b> From<AffineForOperation<'b>> for AffineDialectOperation<'b>

Source§

fn from(op: AffineForOperation<'b>) -> Self

Converts to this type from the input type.
Source§

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

Source§

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

Converts to this type from the input type.
Source§

impl<'c> PartialEq for AffineForOperation<'c>

Source§

fn eq(&self, other: &AffineForOperation<'c>) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

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

Source§

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.
Source§

impl<'c> Eq for AffineForOperation<'c>

Source§

impl<'c> StructuralPartialEq for AffineForOperation<'c>

Auto Trait Implementations§

§

impl<'c> Freeze for AffineForOperation<'c>

§

impl<'c> RefUnwindSafe for AffineForOperation<'c>

§

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

§

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

§

impl<'c> Unpin for AffineForOperation<'c>

§

impl<'c> UnwindSafe for AffineForOperation<'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> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. 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> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

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

Source§

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

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.