Operations


cir.alloca (::mlir::cir::AllocaOp)

Defines a scope-local variable

Syntax:

operation ::= `cir.alloca` $allocaType `,` `cir.ptr` type($addr) `,`
              `[` $name
              (`,` `init` $init^)?
              `]`
              (`ast` $ast^)? attr-dict

The cir.alloca operation defines a scope-local variable.

The presence init attribute indicates that the local variable represented by this alloca was originally initialized in C/C++ source code. In such cases, the first use contains the initialization (a cir.store, a cir.call to a ctor, etc).

The result type is a pointer to the input's type.

Example:

// int count = 3;
%0 = cir.alloca i32, !cir.ptr<i32>, ["count", init] {alignment = 4 : i64}

// int *ptr;
%1 = cir.alloca !cir.ptr<i32>, cir.ptr <!cir.ptr<i32>>, ["ptr"] {alignment = 8 : i64}
...

Attributes:

Attribute MLIR Type Description
allocaType ::mlir::TypeAttr any type attribute
name ::mlir::StringAttr string attribute
init ::mlir::UnitAttr unit attribute
alignment ::mlir::IntegerAttr 64-bit signless integer attribute whose minimum value is 0
ast ::mlir::cir::ASTVarDeclAttr Wraps a ‘const clang::VarDecl *' AST node.

Results:

Result Description
addr CIR pointer type

cir.await (::mlir::cir::AwaitOp)

Wraps C++ co_await implicit logic

Syntax:

operation ::= `cir.await` `(` $kind `,`
              `ready` `:` $ready `,`
              `suspend` `:` $suspend `,`
              `resume` `:` $resume `,`
              `)`
              attr-dict

The under the hood effect of using C++ co_await expr roughly translates to:

// co_await expr;

auto &&x = CommonExpr();
if (!x.await_ready()) {
   ...
   x.await_suspend(...);
   ...
}
x.await_resume();

cir.await represents this logic by using 3 regions:

  • ready: covers veto power from x.await_ready()
  • suspend: wraps actual x.await_suspend() logic
  • resume: handles x.await_resume()

Breaking this up in regions allow individual scrutiny of conditions which might lead to folding some of them out. Lowerings coming out of CIR, e.g. LLVM, should use the suspend region to track more lower level codegen (e.g. intrinsic emission for coro.save/coro.suspend).

There are also 3 flavors of cir.await available:

  • init: compiler generated initial suspend via implicit co_await.
  • user: also known as normal, representing user written co_await's.
  • final: compiler generated final suspend via implicit co_await.

From the C++ snippet we get:

  cir.scope {
    ... // auto &&x = CommonExpr();
    cir.await(user, ready : {
      ... // x.await_ready()
    }, suspend : {
      ... // x.await_suspend()
    }, resume : {
      ... // x.await_resume()
    })
  }

Note that resulution of the common expression is assumed to happen as part of the enclosing await scope.

Traits: NoRegionArguments, RecursivelySpeculatableImplTrait

Interfaces: ConditionallySpeculatable, RegionBranchOpInterface

Attributes:

Attribute MLIR Type Description
kind ::mlir::cir::AwaitKindAttr await kind

cir.base_class_addr (::mlir::cir::BaseClassAddrOp)

Get the base class address for a class/struct

Syntax:

operation ::= `cir.base_class_addr` `(`
              $derived_addr `:` `cir.ptr` type($derived_addr)
              `)` `->` `cir.ptr` type($base_addr) attr-dict

The cir.base_class_addr operaration gets the address of a particular base class given a derived class pointer.

Example:

TBD

Operands:

Operand Description
derived_addr CIR pointer type

Results:

Result Description
base_addr CIR pointer type

cir.binop (::mlir::cir::BinOp)

Binary operations (arith and logic)

Syntax:

operation ::= `cir.binop` `(` $kind `,` $lhs `,` $rhs  `)` `:` type($lhs) attr-dict

cir.binop performs the binary operation according to the specified opcode kind: [mul, div, rem, add, sub, shl, shr, and, xor, or].

It requires two input operands and has one result, all types should be the same.

%7 = binop(add, %1, %2) : i32
%7 = binop(mul, %1, %2) : i8

Traits: AlwaysSpeculatableImplTrait, SameOperandsAndResultType, SameTypeOperands

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Attributes:

Attribute MLIR Type Description
kind ::mlir::cir::BinOpKindAttr binary operation (arith and logic) kind

Operands:

Operand Description
lhs any type
rhs any type

Results:

Result Description
result any type

cir.brcond (::mlir::cir::BrCondOp)

Conditional branch

Syntax:

operation ::= `cir.brcond` $cond
              $destTrue (`(` $destOperandsTrue^ `:` type($destOperandsTrue) `)`)?
              `,`
              $destFalse (`(` $destOperandsFalse^ `:` type($destOperandsFalse) `)`)?
              attr-dict

The cir.brcond %cond, ^bb0, ^bb1 branches to ‘bb0' block in case %cond (which must be a !cir.bool type) evaluates to true, otherwise it branches to ‘bb1'.

Example:

  ...
    cir.brcond %a, ^bb3, ^bb4
  ^bb3:
    cir.return
  ^bb4:
    cir.yield

Traits: AlwaysSpeculatableImplTrait, SameVariadicOperandSize, Terminator

Interfaces: BranchOpInterface, ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands:

Operand Description
cond CIR bool type
destOperandsTrue any type
destOperandsFalse any type

Successors:

Successor Description
destTrue any successor
destFalse any successor

cir.br (::mlir::cir::BrOp)

Unconditional branch

Syntax:

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

The cir.br branches unconditionally to a block. Used to represent C/C++ goto's and general block branching.

Example:

  ...
    cir.br ^bb3
  ^bb3:
    cir.return

Traits: AlwaysSpeculatableImplTrait, Terminator

Interfaces: BranchOpInterface, ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands:

Operand Description
destOperands any type

Successors:

Successor Description
dest any successor

cir.call (::mlir::cir::CallOp)

call operation

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".

Since mlir::func::CallOp requires defining symbols to be tied with a mlir::func::FuncOp, a custom cir.call is needed to interop with cir.func. For now this is basically a simplified mlir::func::CallOp.

Example:

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

Interfaces: CallOpInterface, SymbolUserOpInterface

Attributes:

Attribute MLIR Type Description
callee ::mlir::FlatSymbolRefAttr flat symbol reference attribute

Operands:

Operand Description
operands any type

Results:

Result Description
«unnamed» any type

cir.cast (::mlir::cir::CastOp)

Conversion between values of different types

Syntax:

operation ::= `cir.cast` `(` $kind `,` $src `:` type($src) `)`
              `,` type($result) attr-dict

Apply C/C++ usual conversions rules between values. Currently supported kinds:

  • int_to_bool
  • array_to_ptrdecay
  • integral
  • bitcast
  • floating

This is effectively a subset of the rules from llvm-project/clang/include/clang/AST/OperationKinds.def; but note that some of the conversions aren't implemented in terms of cir.cast, lvalue-to-rvalue for instance is modeled as a regular cir.load.

%4 = cir.cast (int_to_bool, %3 : i32), !cir.bool
...
%x = cir.cast(array_to_ptrdecay, %0 : !cir.ptr<!cir.array<i32 x 10>>), !cir.ptr<i32>

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Attributes:

Attribute MLIR Type Description
kind ::mlir::cir::CastKindAttr cast kind

Operands:

Operand Description
src any type

Results:

Result Description
result any type

cir.cmp (::mlir::cir::CmpOp)

Compare values two values and produce a boolean result

Syntax:

operation ::= `cir.cmp` `(` $kind `,` $lhs `,` $rhs  `)` `:` type($lhs) `,` type($result) attr-dict

cir.cmp compares two input operands of the same type and produces a cir.bool result. The kinds of comparison available are: [lt,gt,ge,eq,ne]

%7 = cir.cmp(gt, %1, %2) : i32, !cir.bool

Traits: AlwaysSpeculatableImplTrait, SameTypeOperands

Interfaces: ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Attributes:

Attribute MLIR Type Description
kind ::mlir::cir::CmpOpKindAttr compare operation kind

Operands:

Operand Description
lhs any type
rhs any type

Results:

Result Description
result any type

cir.const (::mlir::cir::ConstantOp)

Defines a CIR constant

Syntax:

operation ::= `cir.const` `(` custom<ConstantValue>($value) `)` attr-dict `:` type($res)

The cir.const operation turns a literal into an SSA value. The data is attached to the operation as an attribute.

  %0 = cir.const(42 : i32) : i32
  %1 = cir.const(4.2 : f32) : f32
  %2 = cir.const(nullptr : !cir.ptr<i32>) : !cir.ptr<i32>

Traits: AlwaysSpeculatableImplTrait, ConstantLike

Interfaces: ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Attributes:

Attribute MLIR Type Description
value ::mlir::TypedAttr TypedAttr instance

Results:

Result Description
res any type

cir.func (::mlir::cir::FuncOp)

Declare or define a function

Similar to mlir::FuncOp built-in:

Operations within the function cannot implicitly capture values defined outside of the function, i.e. Functions are IsolatedFromAbove. All external references must use function arguments or attributes that establish a symbolic connection (e.g. symbols referenced by name via a string attribute like SymbolRefAttr). An external function declaration (used when referring to a function declared in some other module) has no body. While the MLIR textual form provides a nice inline syntax for function arguments, they are internally represented as "block arguments" to the first block in the region.

Only dialect attribute names may be specified in the attribute dictionaries for function arguments, results, or the function itself.

The function linkage information is specified by linkage, as defined by GlobalLinkageKind attribute.

A compiler builtin function must be marked as builtin for further processing when lowering from CIR.

The coroutine keyword is used to mark coroutine function, which requires at least one cir.await instruction to be used in its body.

The lambda translates to a C++ operator() that implements a lambda, this allow callsites to make certain assumptions about the real function nature when writing analysis. The verifier should, but do act on this keyword yet.

Example:

// External function definitions.
cir.func @abort()

// A function with internal linkage.
cir.func internal @count(%x: i64) -> (i64)
  return %x : i64
}

// Linkage information
cir.func linkonce_odr @some_method(...)

// Builtin function
cir.func builtin @__builtin_coro_end(!cir.ptr<i8>, !cir.bool) -> !cir.bool

// Coroutine
cir.func coroutine @_Z10silly_taskv() -> !CoroTask {
  ...
  cir.await(...)
  ...
}

Traits: AutomaticAllocationScope, IsolatedFromAbove

Interfaces: CallableOpInterface, FunctionOpInterface, Symbol

Attributes:

Attribute MLIR Type Description
sym_name ::mlir::StringAttr string attribute
function_type ::mlir::TypeAttr type attribute of function type
builtin ::mlir::UnitAttr unit attribute
coroutine ::mlir::UnitAttr unit attribute
lambda ::mlir::UnitAttr unit attribute
linkage ::mlir::cir::GlobalLinkageKindAttr Linkage type/kind
sym_visibility ::mlir::StringAttr string attribute
arg_attrs ::mlir::ArrayAttr Array of dictionary attributes
res_attrs ::mlir::ArrayAttr Array of dictionary attributes
aliasee ::mlir::FlatSymbolRefAttr flat symbol reference attribute
ast ::mlir::cir::ASTFunctionDeclAttr Wraps a ‘const clang::FunctionDecl *' AST node.

cir.get_global (::mlir::cir::GetGlobalOp)

Get the address of a global variable

Syntax:

operation ::= `cir.get_global` $name `:` `cir.ptr` type($addr) attr-dict

The cir.get_global operation retrieves the address pointing to a named global variable. If the global variable is marked constant, writing to the resulting address (such as through a cir.store operation) is undefined. Resulting type must always be a !cir.ptr<...> type.

Example:

%x = cir.get_global @foo : !cir.ptr<i32>

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface), SymbolUserOpInterface

Effects: MemoryEffects::Effect{}

Attributes:

Attribute MLIR Type Description
name ::mlir::FlatSymbolRefAttr flat symbol reference attribute

Results:

Result Description
addr CIR pointer type

cir.global (::mlir::cir::GlobalOp)

Declares or defines a global variable

Syntax:

operation ::= `cir.global` ($sym_visibility^)?
              (`constant` $constant^)?
              $linkage
              $sym_name
              custom<GlobalOpTypeAndInitialValue>($sym_type, $initial_value)
              attr-dict

The cir.global operation declares or defines a named global variable.

The backing memory for the variable is allocated statically and is described by the type of the variable.

The operation is a declaration if no inital_value is specified, else it is a definition.

The global variable can also be marked constant using the constant unit attribute. Writing to such constant global variables is undefined.

The linkage tracks C/C++ linkage types, currently very similar to LLVM's. Symbol visibility in sym_visibility is defined in terms of MLIR's visibility and verified to be in accordance to linkage.

Example:

// Public and constant variable with initial value.
cir.global public constant @c : i32 = 4;

Interfaces: Symbol

Attributes:

Attribute MLIR Type Description
sym_name ::mlir::StringAttr string attribute
sym_visibility ::mlir::StringAttr string attribute
sym_type ::mlir::TypeAttr any type attribute
linkage ::mlir::cir::GlobalLinkageKindAttr Linkage type/kind
initial_value ::mlir::Attribute any attribute
constant ::mlir::UnitAttr unit attribute
alignment ::mlir::IntegerAttr 64-bit signless integer attribute

cir.if (::mlir::cir::IfOp)

The if-then-else operation

The cir.if operation represents an if-then-else construct for conditionally executing two regions of code. The operand is a cir.bool type.

Examples:

cir.if %b  {
  ...
} else {
  ...
}

cir.if %c  {
  ...
}

cir.if %c  {
  ...
  cir.br ^a
^a:
  cir.yield
}

cir.if defines no values and the ‘else' can be omitted. cir.yield must explicitly terminate the region if it has more than one block.

Traits: AutomaticAllocationScope, NoRegionArguments, RecursivelySpeculatableImplTrait

Interfaces: ConditionallySpeculatable, RegionBranchOpInterface

Operands:

Operand Description
condition CIR bool type

cir.load (::mlir::cir::LoadOp)

Load value from memory adddress

Syntax:

operation ::= `cir.load` (`deref` $isDeref^)? $addr `:` `cir.ptr` type($addr) `,`
              type($result) attr-dict

cir.load reads a value (lvalue to rvalue conversion) given an address backed up by a cir.ptr type. A unit attribute deref can be used to mark the resulting value as used by another operation to dereference a pointer.

Example:


// Read from local variable, address in %0.
%1 = cir.load %0 : !cir.ptr<i32>, i32

// Load address from memory at address %0. %3 is used by at least one
// operation that dereferences a pointer.
%3 = cir.load deref %0 : cir.ptr <!cir.ptr<i32>>

Interfaces: InferTypeOpInterface

Attributes:

Attribute MLIR Type Description
isDeref ::mlir::UnitAttr unit attribute

Operands:

Operand Description
addr CIR pointer type

Results:

Result Description
result any type

cir.loop (::mlir::cir::LoopOp)

Loop

Syntax:

operation ::= `cir.loop` $kind
              `(`
              `cond` `:` $cond `,`
              `step` `:` $step
              `)`
              $body
              attr-dict

cir.loop represents C/C++ loop forms. It defines 3 blocks:

  • cond: region can contain multiple blocks, terminated by regular cir.yield when control should yield back to the parent, and cir.yield continue when execution continues to another region. The region destination depends on the loop form specified.
  • step: region with one block, containing code to compute the loop step, must be terminated with cir.yield.
  • body: region for the loop's body, can contain an arbitrary number of blocks.

The loop form: for, while and dowhile must also be specified and each implies the loop regions execution order.

  // while (true) {
  //  i = i + 1;
  // }
  cir.loop while(cond :  {
    cir.yield continue
  }, step :  {
    cir.yield
  })  {
    %3 = cir.load %1 : cir.ptr <i32>, i32
    %4 = cir.const(1 : i32) : i32
    %5 = cir.binop(add, %3, %4) : i32
    cir.store %5, %1 : i32, cir.ptr <i32>
    cir.yield
  }

Traits: NoRegionArguments, RecursivelySpeculatableImplTrait

Interfaces: ConditionallySpeculatable, LoopLikeOpInterface, RegionBranchOpInterface

Attributes:

Attribute MLIR Type Description
kind ::mlir::cir::LoopOpKindAttr Loop kind

cir.ptr_stride (::mlir::cir::PtrStrideOp)

Pointer access with stride

Syntax:

operation ::= `cir.ptr_stride` `(` $base `:` type($base) `,` $stride `:` type($stride) `)`
              `,` type($result) attr-dict

Given a base pointer as operand, provides a new pointer after applying a stride. Currently only used for array subscripts.

%3 = cir.const(0 : i32) : i32
%4 = cir.ptr_stride(%2 : !cir.ptr<i32>, %3 : i32), !cir.ptr<i32>

Traits: AlwaysSpeculatableImplTrait, SameFirstOperandAndResultType

Interfaces: ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands:

Operand Description
base any type
stride integer

Results:

Result Description
result any type

cir.return (::mlir::cir::ReturnOp)

Return from function

Syntax:

operation ::= `cir.return` ($input^ `:` type($input))? attr-dict

The "return" operation represents a return operation within a function. The operation takes an optional operand and produces no results. The operand type must match the signature of the function that contains the operation.

  func @foo() -> i32 {
    ...
    cir.return %0 : i32
  }

Traits: HasParent<FuncOp, ScopeOp, IfOp, SwitchOp, LoopOp>, Terminator

Operands:

Operand Description
input any type

cir.scope (::mlir::cir::ScopeOp)

Represents a C/C++ scope

cir.scope contains one region and defines a strict "scope" for all new values produced within its blocks.

The region can contain an arbitrary number of blocks but usually defaults to one and can optionally return a value (useful for representing values coming out of C++ full-expressions) via cir.yield:

%rvalue = cir.scope {
  ...
  cir.yield %value
}

If cir.scope yields no value, the cir.yield can be left out, and will be inserted implicitly.

Traits: AutomaticAllocationScope, NoRegionArguments, RecursivelySpeculatableImplTrait

Interfaces: ConditionallySpeculatable, RegionBranchOpInterface

Results:

Result Description
results any type

cir.store (::mlir::cir::StoreOp)

Store value to memory address

Syntax:

operation ::= `cir.store` $value `,` $addr attr-dict `:` type($value) `,` `cir.ptr` type($addr)

cir.store stores a value (first operand) to the memory address specified in the second operand.

Example:

// Store a function argument to local storage, address in %0.
cir.store %arg0, %0 : i32, !cir.ptr<i32>

Operands:

Operand Description
value any type
addr CIR pointer type

cir.struct_element_addr (::mlir::cir::StructElementAddr)

Get the address of a member of a struct

The cir.struct_element_addr operaration gets the address of a particular named member from the input struct.

Example:

!ty_22struct2EBar22 = type !cir.struct<"struct.Bar", i32, i8>
...
%0 = cir.alloca !ty_22struct2EBar22, cir.ptr <!ty_22struct2EBar22>
...
%1 = cir.struct_element_addr %0, "Bar.a"
%2 = cir.load %1 : cir.ptr <int>, int
...

Attributes:

Attribute MLIR Type Description
member_name ::mlir::StringAttr string attribute

Operands:

Operand Description
struct_addr CIR pointer type

Results:

Result Description
result CIR pointer type

cir.switch (::mlir::cir::SwitchOp)

Switch operation

Syntax:

operation ::= `cir.switch` custom<SwitchOp>(
              $regions, $cases, $condition, type($condition)
              )
              attr-dict

The cir.switch operation represents C/C++ switch functionality for conditionally executing multiple regions of code. The operand to an switch is an integral condition value.

A variadic list of "case" attribute operands and regions track the possible control flow within cir.switch. A case must be in one of the following forms:

  • equal, <constant>: equality of the second case operand against the condition.
  • anyof, [constant-list]: equals to any of the values in a subsequent following list.
  • default: any other value.

Each case region must be explicitly terminated.

Examples:

cir.switch (%b : i32) [
  case (equal, 20) {
    ...
    cir.yield break
  },
  case (anyof, [1, 2, 3] : i32) {
    ...
    cir.return ...
  }
  case (default) {
    ...
    cir.yield fallthrough
  }
]

Traits: AutomaticAllocationScope, NoRegionArguments, RecursivelySpeculatableImplTrait, SameVariadicOperandSize

Interfaces: ConditionallySpeculatable, RegionBranchOpInterface

Attributes:

Attribute MLIR Type Description
cases ::mlir::ArrayAttr cir.switch case array attribute

Operands:

Operand Description
condition integer

cir.ternary (::mlir::cir::TernaryOp)

The cond ? a : b C/C++ ternary operation

Syntax:

operation ::= `cir.ternary` `(` $cond `,`
              `true` $trueRegion `,`
              `false` $falseRegion
              `)` `:` type($result) attr-dict

The cir.ternary operation represents C/C++ ternary, much like a select operation. First argument is a cir.bool condition to evaluate, followed by two regions to execute (true or false). This is different from cir.if since each region is one block sized and the cir.yield closing the block scope should have one argument.

Example:

// x = cond ? a : b;

%x = cir.ternary (%cond, true_region {
  ...
  cir.yield %a : i32
}, false_region {
  ...
  cir.yield %b : i32
}) -> i32

Traits: AutomaticAllocationScope, NoRegionArguments, RecursivelySpeculatableImplTrait

Interfaces: ConditionallySpeculatable, RegionBranchOpInterface

Operands:

Operand Description
cond CIR bool type

Results:

Result Description
result any type

cir.unary (::mlir::cir::UnaryOp)

Unary operations

Syntax:

operation ::= `cir.unary` `(` $kind `,` $input `)` `:` type($input) `,` type($result) attr-dict

cir.unary performs the unary operation according to the specified opcode kind: [inc, dec, plus, minus, not].

Note for inc and dec: the operation corresponds only to the addition/subtraction, its input is expect to come from a load and the result to be used by a corresponding store.

It requires one input operand and has one result, both types should be the same.

%7 = cir.unary(inc, %1) : i32 -> i32
%8 = cir.unary(dec, %2) : i32 -> i32

Traits: AlwaysSpeculatableImplTrait, SameOperandsAndResultType

Interfaces: ConditionallySpeculatable, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Attributes:

Attribute MLIR Type Description
kind ::mlir::cir::UnaryOpKindAttr unary operation kind

Operands:

Operand Description
input any type

Results:

Result Description
result any type

cir.vtable.address_point (::mlir::cir::VTableAddrPointOp)

Get the vtable (global variable) address point

Syntax:

operation ::= `cir.vtable.address_point` `(` $name `,`
              `vtable_index` `=` $vtable_index `,`
              `address_point_index` `=` $address_point_index
              `)`
              `:` `cir.ptr` type($addr) attr-dict

The vtable.address_point operation retrieves the "effective" address (address point) of a C++ virtual table. An object internal __vptr gets initializated on top of the value returned by this operation.

vtable_index provides the appropriate vtable within the vtable group (as specified by Itanium ABI), and addr_point_index the actual address point within that vtable.

The return type is always a !cir.ptr<!cir.ptr<() -> i32>>.

Example:

cir.global linkonce_odr @_ZTV1B = ...
...
%3 = cir.vtable.address_point(@_ZTV1B, vtable_index = 0, address_point_index = 2) : cir.ptr <!cir.ptr<() -> i32>>

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, NoMemoryEffect (MemoryEffectOpInterface), SymbolUserOpInterface

Effects: MemoryEffects::Effect{}

Attributes:

Attribute MLIR Type Description
name ::mlir::FlatSymbolRefAttr flat symbol reference attribute
vtable_index ::mlir::IntegerAttr 32-bit signless integer attribute
address_point_index ::mlir::IntegerAttr 32-bit signless integer attribute

Results:

Result Description
addr CIR pointer type

cir.yield (::mlir::cir::YieldOp)

Terminate CIR regions

Syntax:

operation ::= `cir.yield` ($kind^)? ($args^ `:` type($args))? attr-dict

The cir.yield operation terminates regions on different CIR operations: cir.if, cir.scope, cir.switch, cir.loop, cir.await and cir.ternary.

Might yield an SSA value and the semantics of how the values are yielded is defined by the parent operation.

Optionally, cir.yield can be annotated with extra kind specifiers:

  • break: breaking out of the innermost cir.switch / cir.loop semantics, cannot be used if not dominated by these parent operations.
  • fallthrough: execution falls to the next region in cir.switch case list. Only available inside cir.switch regions.
  • continue: only allowed under cir.loop, continue execution to the next loop step.
  • nosuspend: specific to the ready region inside cir.await op, it makes control-flow to be transfered back to the parent, preventing suspension.

As a general rule, cir.yield must be explicitly used whenever a region has more than one block and no terminator, or within cir.switch regions not cir.return terminated.

Examples:

cir.if %4 {
  ...
  cir.yield
}

cir.switch (%5) [
  case (equal, 3) {
    ...
    cir.yield fallthrough
  }, ...
]

cir.loop (cond : {...}, step : {...}) {
  ...
  cir.yield continue
}

cir.await(init, ready : {
  // Call std::suspend_always::await_ready
  %18 = cir.call @_ZNSt14suspend_always11await_readyEv(...)
  cir.if %18 {
    // yields back to the parent.
    cir.yield nosuspend
  }
  cir.yield // control-flow to the next region for suspension.
}, ...)

cir.scope {
  ...
  cir.yield
}

%x = cir.scope {
  ...
  cir.yield %val
}

%y = cir.ternary {
  ...
  cir.yield %val : i32
} : i32

Traits: HasParent<IfOp, ScopeOp, SwitchOp, LoopOp, AwaitOp, TernaryOp>, ReturnLike, Terminator

Attributes:

Attribute MLIR Type Description
kind ::mlir::cir::YieldOpKindAttr yield kind

Operands:

Operand Description
args any type