MLIR

Multi-Level IR Compiler Framework

'std' Dialect

This dialect provides documentation for operations within the Standard dialect.

Note: This dialect is a collection of operations for several different concepts, and should be split into multiple more-focused dialects accordingly.

Please post an RFC on the forum before adding or changing any operation in this dialect.

Operations 

std.assert (::mlir::AssertOp) 

Assert operation with message attribute

Syntax:

operation ::= `std.assert` $arg `,` $msg attr-dict

Assert operation with single boolean operand and an error message attribute. If the argument is true this operation has no effect. Otherwise, the program execution will abort. The provided error message may be used by a runtime to propagate the error to the user.

Example:

assert %b, "Expected ... to be true"

Attributes: 

AttributeMLIR TypeDescription
msg::mlir::StringAttrstring attribute

Operands: 

OperandDescription
arg1-bit signless integer

std.atomic_rmw (::mlir::AtomicRMWOp) 

atomic read-modify-write operation

Syntax:

operation ::= `std.atomic_rmw` $kind $value `,` $memref `[` $indices `]` attr-dict `:` `(` type($value) `,`
              type($memref) `)` `->` type($result)

The atomic_rmw operation provides a way to perform a read-modify-write sequence that is free from data races. The kind enumeration specifies the modification to perform. The value operand represents the new value to be applied during the modification. The memref operand represents the buffer that the read and write will be performed against, as accessed by the specified indices. The arity of the indices is the rank of the memref. The result represents the latest value that was stored.

Example:

%x = atomic_rmw "addf" %value, %I[%i] : (f32, memref<10xf32>) -> f32

Attributes: 

AttributeMLIR TypeDescription
kind::mlir::AtomicRMWKindAttrallowed 64-bit signless integer cases: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10

Operands: 

OperandDescription
valuesignless integer or floating-point
memrefmemref of signless integer or floating-point values
indicesindex

Results: 

ResultDescription
resultsignless integer or floating-point

std.atomic_yield (::mlir::AtomicYieldOp) 

yield operation for GenericAtomicRMWOp

Syntax:

operation ::= `std.atomic_yield` $result attr-dict `:` type($result)

“atomic_yield” yields an SSA value from a GenericAtomicRMWOp region.

Traits: HasParent, Terminator

Interfaces: NoSideEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands: 

OperandDescription
resultany type

std.br (::mlir::BranchOp) 

branch operation

Syntax:

operation ::= `std.br` $dest (`(` $destOperands^ `:` type($destOperands) `)`)? attr-dict

The br operation represents a branch operation in a function. The operation takes variable number of operands and produces no results. The operand number and types for each successor must match the arguments of the block successor.

Example:

^bb2:
  %2 = call @someFn()
  br ^bb3(%2 : tensor<*xf32>)
^bb3(%3: tensor<*xf32>):

Traits: Terminator

Interfaces: BranchOpInterface, NoSideEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands: 

OperandDescription
destOperandsany type

Successors: 

SuccessorDescription
destany successor

std.call_indirect (::mlir::CallIndirectOp) 

indirect call operation

Syntax:

operation ::= `std.call_indirect` $callee `(` $callee_operands `)` attr-dict `:` type($callee)

The call_indirect operation represents an indirect call to a value of function type. Functions are first class types in MLIR, and may be passed as arguments and merged together with block arguments. The operands and result types of the call must match the specified function type.

Function values can be created with the constant operation .

Example:

%31 = call_indirect %15(%0, %1)
        : (tensor<16xf32>, tensor<16xf32>) -> tensor<16xf32>

Interfaces: CallOpInterface

Operands: 

OperandDescription
calleefunction type
callee_operandsany type

Results: 

ResultDescription
resultsany type

std.call (::mlir::CallOp) 

call operation

Syntax:

operation ::= `std.call` $callee `(` $operands `)` attr-dict `:` functional-type($operands, results)

The call operation represents a direct call to a function that is within the same symbol scope as the call. The operands and result types of the call must match the specified function type. The callee is encoded as a symbol reference attribute named “callee”.

Example:

%2 = call @my_add(%0, %1) : (f32, f32) -> f32

Traits: MemRefsNormalizable

Interfaces: CallOpInterface, SymbolUserOpInterface

Attributes: 

AttributeMLIR TypeDescription
callee::mlir::FlatSymbolRefAttrflat symbol reference attribute

Operands: 

OperandDescription
operandsany type

Results: 

ResultDescription
«unnamed»any type

std.cond_br (::mlir::CondBranchOp) 

conditional branch operation

Syntax:

operation ::= `std.cond_br` $condition `,`
              $trueDest (`(` $trueDestOperands^ `:` type($trueDestOperands) `)`)? `,`
              $falseDest (`(` $falseDestOperands^ `:` type($falseDestOperands) `)`)?
              attr-dict

The cond_br terminator operation represents a conditional branch on a boolean (1-bit integer) value. If the bit is set, then the first destination is jumped to; if it is false, the second destination is chosen. The count and types of operands must align with the arguments in the corresponding target blocks.

The MLIR conditional branch operation is not allowed to target the entry block for a region. The two destinations of the conditional branch operation are allowed to be the same.

The following example illustrates a function with a conditional branch operation that targets the same block.

Example:

func @select(%a: i32, %b: i32, %flag: i1) -> i32 {
  // Both targets are the same, operands differ
  cond_br %flag, ^bb1(%a : i32), ^bb1(%b : i32)

^bb1(%x : i32) :
  return %x : i32
}

Traits: AttrSizedOperandSegments, Terminator

Interfaces: BranchOpInterface, NoSideEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands: 

OperandDescription
condition1-bit signless integer
trueDestOperandsany type
falseDestOperandsany type

Successors: 

SuccessorDescription
trueDestany successor
falseDestany successor

std.constant (::mlir::ConstantOp) 

constant

Syntax:

operation ::= ssa-id `=` `std.constant` attribute-value `:` type

The constant operation produces an SSA value equal to some constant specified by an attribute. This is the way that MLIR uses to form simple integer and floating point constants, as well as more exotic things like references to functions and tensor/vector constants.

Example:

// Complex constant
%1 = constant [1.0 : f32, 1.0 : f32] : complex<f32>

// Reference to function @myfn.
%2 = constant @myfn : (tensor<16xf32>, f32) -> tensor<16xf32>

// Equivalent generic forms
%1 = "std.constant"() {value = [1.0 : f32, 1.0 : f32] : complex<f32>}
   : () -> complex<f32>
%2 = "std.constant"() {value = @myfn}
   : () -> ((tensor<16xf32>, f32) -> tensor<16xf32>)

MLIR does not allow direct references to functions in SSA operands because the compiler is multithreaded, and disallowing SSA values to directly reference a function simplifies this ( rationale ).

Traits: ConstantLike

Interfaces: NoSideEffect (MemoryEffectOpInterface), OpAsmOpInterface

Effects: MemoryEffects::Effect{}

Attributes: 

AttributeMLIR TypeDescription
value::mlir::Attributeany attribute

Results: 

ResultDescription
«unnamed»any type

std.generic_atomic_rmw (::mlir::GenericAtomicRMWOp) 

atomic read-modify-write operation with a region

The generic_atomic_rmw operation provides a way to perform a read-modify-write sequence that is free from data races. The memref operand represents the buffer that the read and write will be performed against, as accessed by the specified indices. The arity of the indices is the rank of the memref. The result represents the latest value that was stored. The region contains the code for the modification itself. The entry block has a single argument that represents the value stored in memref[indices] before the write is performed. No side-effecting ops are allowed in the body of GenericAtomicRMWOp.

Example:

%x = generic_atomic_rmw %I[%i] : memref<10xf32> {
  ^bb0(%current_value : f32):
    %c1 = arith.constant 1.0 : f32
    %inc = arith.addf %c1, %current_value : f32
    atomic_yield %inc : f32
}

Traits: SingleBlockImplicitTerminator

Operands: 

OperandDescription
memrefmemref of signless integer or floating-point values
indicesindex

Results: 

ResultDescription
resultsignless integer or floating-point

std.rank (::mlir::RankOp) 

rank operation

Syntax:

operation ::= `std.rank` $memrefOrTensor attr-dict `:` type($memrefOrTensor)

The rank operation takes a memref/tensor operand and returns its rank.

Example:

%1 = rank %arg0 : tensor<*xf32>
%2 = rank %arg1 : memref<*xf32>

Interfaces: InferTypeOpInterface, NoSideEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands: 

OperandDescription
memrefOrTensorany memref or tensor type

Results: 

ResultDescription
«unnamed»index

std.return (::mlir::ReturnOp) 

return operation

Syntax:

operation ::= `std.return` attr-dict ($operands^ `:` type($operands))?

The return operation represents a return operation within a function. The operation takes variable number of operands and produces no results. The operand number and types must match the signature of the function that contains the operation.

Example:

func @foo() : (i32, f8) {
  ...
  return %0, %1 : i32, f8
}

Traits: HasParent, MemRefsNormalizable, ReturnLike, Terminator

Interfaces: NoSideEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands: 

OperandDescription
operandsany type

std.select (::mlir::SelectOp) 

select operation

The select operation chooses one value based on a binary condition supplied as its first operand. If the value of the first operand is 1, the second operand is chosen, otherwise the third operand is chosen. The second and the third operand must have the same type.

The operation applies to vectors and tensors elementwise given the shape of all operands is identical. The choice is made for each element individually based on the value at the same position as the element in the condition operand. If an i1 is provided as the condition, the entire vector or tensor is chosen.

The select operation combined with cmpi can be used to implement min and max with signed or unsigned comparison semantics.

Example:

// Custom form of scalar selection.
%x = select %cond, %true, %false : i32

// Generic form of the same operation.
%x = "std.select"(%cond, %true, %false) : (i1, i32, i32) -> i32

// Element-wise vector selection.
%vx = std.select %vcond, %vtrue, %vfalse : vector<42xi1>, vector<42xf32>

// Full vector selection.
%vx = std.select %cond, %vtrue, %vfalse : vector<42xf32>

Traits: Elementwise, Scalarizable, Tensorizable, Vectorizable

Interfaces: InferTypeOpInterface, NoSideEffect (MemoryEffectOpInterface), VectorUnrollOpInterface

Effects: MemoryEffects::Effect{}

Operands: 

OperandDescription
conditionbool-like
true_valueany type
false_valueany type

Results: 

ResultDescription
resultany type

std.splat (::mlir::SplatOp) 

splat or broadcast operation

Syntax:

operation ::= `std.splat` $input attr-dict `:` type($aggregate)

Broadcast the operand to all elements of the result vector or tensor. The operand has to be of integer/index/float type. When the result is a tensor, it has to be statically shaped.

Example:

%s = load %A[%i] : memref<128xf32>
%v = splat %s : vector<4xf32>
%t = splat %s : tensor<8x16xi32>

TODO: This operation is easy to extend to broadcast to dynamically shaped tensors in the same way dynamically shaped memrefs are handled.

// Broadcasts %s to a 2-d dynamically shaped tensor, with %m, %n binding
// to the sizes of the two dynamic dimensions.
%m = "foo"() : () -> (index)
%n = "bar"() : () -> (index)
%t = splat %s [%m, %n] : tensor<?x?xi32>

Interfaces: NoSideEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands: 

OperandDescription
inputinteger/index/float type

Results: 

ResultDescription
aggregatevector of any type values or statically shaped tensor of any type values

std.switch (::mlir::SwitchOp) 

switch operation

Syntax:

operation ::= `std.switch` $flag `:` type($flag) `,` `[` `\n`
              custom<SwitchOpCases>(ref(type($flag)),$defaultDestination,
              $defaultOperands,
              type($defaultOperands),
              $case_values,
              $caseDestinations,
              $caseOperands,
              type($caseOperands))
              `]`
              attr-dict

The switch terminator operation represents a switch on a signless integer value. If the flag matches one of the specified cases, then the corresponding destination is jumped to. If the flag does not match any of the cases, the default destination is jumped to. The count and types of operands must align with the arguments in the corresponding target blocks.

Example:

switch %flag : i32, [
  default: ^bb1(%a : i32),
  42: ^bb1(%b : i32),
  43: ^bb3(%c : i32)
]

Traits: AttrSizedOperandSegments, Terminator

Interfaces: BranchOpInterface, NoSideEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Attributes: 

AttributeMLIR TypeDescription
case_values::mlir::DenseIntElementsAttrinteger elements attribute
case_operand_segments::mlir::DenseIntElementsAttr32-bit signless integer elements attribute

Operands: 

OperandDescription
flaginteger
defaultOperandsany type
caseOperandsany type

Successors: 

SuccessorDescription
defaultDestinationany successor
caseDestinationsany successor