MLIR

Multi-Level IR Compiler Framework

'index' Dialect

The Index dialect

The Index dialect contains operations for manipulating values of the builtin index type. The index type models target-specific values of pointer width, like intptr_t. Index values are typically used as loop bounds, array subscripts, tensor dimensions, etc.

The operations in this dialect operate exclusively on scalar index types. The dialect and its operations treat the index type as signless and contains signed and unsigned versions of certain operations where the distinction is meaningful. In particular, the operations and transformations are careful to be aware of the target-independent-ness of the index type, such as when folding.

The folding semantics of the Index dialect operations ensure that folding produces the same results irrespective of the eventual target pointer width. All index constants are stored in APInts of maximum index bitwidth: 64. Operations are folded using 64-bit integer arithmetic.

For operations where the values of the upper 32 bits don’t impact the values of the lower 32 bits, no additional handling is required because if the target is 32-bit, the truncated folded result will be the same as if the operation were computed with 32-bit arithmetic, and if the target is 64-bit, the fold result is valid by default.

Consider addition: an overflow in 32-bit is the same as truncating the result computed in 64-bit. For example, add(0x800000008, 0x800000008) is 0x1000000010 in 64-bit, which truncates to 0x10, the same result as truncating the operands first: add(0x08, 0x08). Specifically, an operation f can always be folded if it satisfies the following for all 64-bit values of a and b:

trunc(f(a, b)) = f(trunc(a), trunc(b))

When materializing target-specific code, constants just need to be truncated as appropriate.

Operations where the values of the upper 32 bits do impact the values of the lower 32 bits are not folded if the results would be different in 32-bit. These are operations that right shift – division, remainder, etc. These operations are only folded for subsets of a and b for which the above property is satisfied. This is checked per fold attempt.

Consider division: the 32-bit computation will differ from 64-bit if the latter results in a high bit shifted into the lower 32 bits. For example, div(0x100000002, 2) is 0x80000001 in 64-bit but 0x01 in 32-bit; it cannot be folded. However, div(0x200000002, 2) can be folded. The 64-bit result is 0x100000001, which truncated to 32 bits is 0x01. The 32-bit result of the operation with truncated operands div(0x02, 2) which is 0x01, the same as truncating the 64-bit result.

Operations 

source

index.add (index::AddOp) 

Index addition

Syntax:

operation ::= `index.add` $lhs `,` $rhs attr-dict

The index.add operation takes two index values and computes their sum.

Example:

// c = a + b
%c = index.add %a, %b

Traits: AlwaysSpeculatableImplTrait, Commutative

Interfaces: ConditionallySpeculatable, InferIntRangeInterface, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands: 

OperandDescription
lhsindex
rhsindex

Results: 

ResultDescription
resultindex

index.and (index::AndOp) 

Index bitwise and

Syntax:

operation ::= `index.and` $lhs `,` $rhs attr-dict

The index.and operation takes two index values and computes their bitwise and.

Example:

// c = a & b
%c = index.and %a, %b

Traits: AlwaysSpeculatableImplTrait, Commutative

Interfaces: ConditionallySpeculatable, InferIntRangeInterface, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands: 

OperandDescription
lhsindex
rhsindex

Results: 

ResultDescription
resultindex

index.bool.constant (index::BoolConstantOp) 

Boolean constant

Syntax:

operation ::= `index.bool.constant` attr-dict $value

The index.bool.constant operation produces an bool-typed SSA value equal to either true or false.

This operation is used to materialize bool constants that arise when folding index.cmp.

Example:

%0 = index.bool.constant true

Traits: AlwaysSpeculatableImplTrait, ConstantLike

Interfaces: ConditionallySpeculatable, InferIntRangeInterface, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface), OpAsmOpInterface

Effects: MemoryEffects::Effect{}

Attributes: 

AttributeMLIR TypeDescription
value::mlir::BoolAttrbool attribute

Results: 

ResultDescription
result1-bit signless integer

index.casts (index::CastSOp) 

Index signed cast

Syntax:

operation ::= `index.casts` $input attr-dict `:` type($input) `to` type($output)

The index.casts operation enables conversions between values of index type and concrete fixed-width integer types. If casting to a wider integer, the value is sign-extended. If casting to a narrower integer, the value is truncated.

Example:

// Cast to i32
%0 = index.casts %a : index to i32

// Cast from i64
%1 = index.casts %b : i64 to index

Traits: AlwaysSpeculatableImplTrait

Interfaces: CastOpInterface, ConditionallySpeculatable, InferIntRangeInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands: 

OperandDescription
inputinteger or index

Results: 

ResultDescription
outputinteger or index

index.castu (index::CastUOp) 

Index unsigned cast

Syntax:

operation ::= `index.castu` $input attr-dict `:` type($input) `to` type($output)

The index.castu operation enables conversions between values of index type and concrete fixed-width integer types. If casting to a wider integer, the value is zero-extended. If casting to a narrower integer, the value is truncated.

Example:

// Cast to i32
%0 = index.castu %a : index to i32

// Cast from i64
%1 = index.castu %b : i64 to index

Traits: AlwaysSpeculatableImplTrait

Interfaces: CastOpInterface, ConditionallySpeculatable, InferIntRangeInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands: 

OperandDescription
inputinteger or index

Results: 

ResultDescription
outputinteger or index

index.ceildivs (index::CeilDivSOp) 

Index signed ceil division

Syntax:

operation ::= `index.ceildivs` $lhs `,` $rhs attr-dict

The index.ceildivs operation takes two index values and computes their signed quotient. Treats the leading bit as the sign and rounds towards positive infinity, i.e. 7 / -2 = -3.

Note: division by zero and signed division overflow are undefined behaviour.

Example:

// c = ceil(a / b)
%c = index.ceildivs %a, %b

Interfaces: InferIntRangeInterface, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands: 

OperandDescription
lhsindex
rhsindex

Results: 

ResultDescription
resultindex

index.ceildivu (index::CeilDivUOp) 

Index unsigned ceil division

Syntax:

operation ::= `index.ceildivu` $lhs `,` $rhs attr-dict

The index.ceildivu operation takes two index values and computes their unsigned quotient. Treats the leading bit as the most significant and rounds towards positive infinity, i.e. 6 / -2 = 1.

Note: division by zero is undefined behaviour.

Example:

// c = ceil(a / b)
%c = index.ceildivu %a, %b

Interfaces: InferIntRangeInterface, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands: 

OperandDescription
lhsindex
rhsindex

Results: 

ResultDescription
resultindex

index.cmp (index::CmpOp) 

Index compare

Syntax:

operation ::= `index.cmp` `` $pred `(` $lhs `,` $rhs `)` attr-dict

The index.cmp operation takes two index values and compares them according to the comparison predicate and returns an i1. The following comparisons are supported:

  • eq: equal
  • ne: not equal
  • slt: signed less than
  • sle: signed less than or equal
  • sgt: signed greater than
  • sge: signed greater than or equal
  • ult: unsigned less than
  • ule: unsigned less than or equal
  • ugt: unsigned greater than
  • uge: unsigned greater than or equal

The result is 1 if the comparison is true and 0 otherwise.

Example:

// Signed less than comparison.
%0 = index.cmp slt(%a, %b)

// Unsigned greater than or equal comparison.
%1 = index.cmp uge(%a, %b)

// Not equal comparison.
%2 = index.cmp ne(%a, %b)

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, InferIntRangeInterface, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Attributes: 

AttributeMLIR TypeDescription
pred::mlir::index::IndexCmpPredicateAttr
index comparison predicate kind

Enum cases:

  • eq (EQ)
  • ne (NE)
  • slt (SLT)
  • sle (SLE)
  • sgt (SGT)
  • sge (SGE)
  • ult (ULT)
  • ule (ULE)
  • ugt (UGT)
  • uge (UGE)

Operands: 

OperandDescription
lhsindex
rhsindex

Results: 

ResultDescription
result1-bit signless integer

index.constant (index::ConstantOp) 

Index constant

Syntax:

operation ::= `index.constant` attr-dict $value

The index.constant operation produces an index-typed SSA value equal to some index-typed integer constant.

Example:

%0 = index.constant 42

Traits: AlwaysSpeculatableImplTrait, ConstantLike

Interfaces: ConditionallySpeculatable, InferIntRangeInterface, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface), OpAsmOpInterface

Effects: MemoryEffects::Effect{}

Attributes: 

AttributeMLIR TypeDescription
value::mlir::IntegerAttrindex attribute

Results: 

ResultDescription
resultindex

index.divs (index::DivSOp) 

Index signed division

Syntax:

operation ::= `index.divs` $lhs `,` $rhs attr-dict

The index.divs operation takes two index values and computes their signed quotient. Treats the leading bit as the sign and rounds towards zero, i.e. 6 / -2 = -3.

Note: division by zero and signed division overflow are undefined behaviour.

Example:

// c = a / b
%c = index.divs %a, %b

Interfaces: InferIntRangeInterface, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands: 

OperandDescription
lhsindex
rhsindex

Results: 

ResultDescription
resultindex

index.divu (index::DivUOp) 

Index unsigned division

Syntax:

operation ::= `index.divu` $lhs `,` $rhs attr-dict

The index.divu operation takes two index values and computes their unsigned quotient. Treats the leading bit as the most significant and rounds towards zero, i.e. 6 / -2 = 0.

Note: division by zero is undefined behaviour.

Example:

// c = a / b
%c = index.divu %a, %b

Interfaces: InferIntRangeInterface, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands: 

OperandDescription
lhsindex
rhsindex

Results: 

ResultDescription
resultindex

index.floordivs (index::FloorDivSOp) 

Index signed floor division

Syntax:

operation ::= `index.floordivs` $lhs `,` $rhs attr-dict

The index.floordivs operation takes two index values and computes their signed quotient. Treats the leading bit as the sign and rounds towards negative infinity, i.e. 5 / -2 = -3.

Note: division by zero and signed division overflow are undefined behaviour.

Example:

// c = floor(a / b)
%c = index.floordivs %a, %b

Interfaces: InferIntRangeInterface, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands: 

OperandDescription
lhsindex
rhsindex

Results: 

ResultDescription
resultindex

index.maxs (index::MaxSOp) 

Index signed maximum

Syntax:

operation ::= `index.maxs` $lhs `,` $rhs attr-dict

The index.maxs operation takes two index values and computes their signed maximum value. Treats the leading bit as the sign, i.e. max(-2, 6) = 6.

Example:

// c = max(a, b)
%c = index.maxs %a, %b

Traits: AlwaysSpeculatableImplTrait, Commutative

Interfaces: ConditionallySpeculatable, InferIntRangeInterface, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands: 

OperandDescription
lhsindex
rhsindex

Results: 

ResultDescription
resultindex

index.maxu (index::MaxUOp) 

Index unsigned maximum

Syntax:

operation ::= `index.maxu` $lhs `,` $rhs attr-dict

The index.maxu operation takes two index values and computes their unsigned maximum value. Treats the leading bit as the most significant, i.e. max(15, 6) = 15 or max(-2, 6) = -2.

Example:

// c = max(a, b)
%c = index.maxu %a, %b

Traits: AlwaysSpeculatableImplTrait, Commutative

Interfaces: ConditionallySpeculatable, InferIntRangeInterface, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands: 

OperandDescription
lhsindex
rhsindex

Results: 

ResultDescription
resultindex

index.mins (index::MinSOp) 

Index signed minimum

Syntax:

operation ::= `index.mins` $lhs `,` $rhs attr-dict

The index.mins operation takes two index values and computes their signed minimum value. Treats the leading bit as the sign, i.e. min(-2, 6) = -2.

Example:

// c = min(a, b)
%c = index.mins %a, %b

Traits: AlwaysSpeculatableImplTrait, Commutative

Interfaces: ConditionallySpeculatable, InferIntRangeInterface, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands: 

OperandDescription
lhsindex
rhsindex

Results: 

ResultDescription
resultindex

index.minu (index::MinUOp) 

Index unsigned minimum

Syntax:

operation ::= `index.minu` $lhs `,` $rhs attr-dict

The index.minu operation takes two index values and computes their unsigned minimum value. Treats the leading bit as the most significant, i.e. min(15, 6) = 6 or min(-2, 6) = 6.

Example:

// c = min(a, b)
%c = index.minu %a, %b

Traits: AlwaysSpeculatableImplTrait, Commutative

Interfaces: ConditionallySpeculatable, InferIntRangeInterface, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands: 

OperandDescription
lhsindex
rhsindex

Results: 

ResultDescription
resultindex

index.mul (index::MulOp) 

Index multiplication

Syntax:

operation ::= `index.mul` $lhs `,` $rhs attr-dict

The index.mul operation takes two index values and computes their product.

Example:

// c = a * b
%c = index.mul %a, %b

Traits: AlwaysSpeculatableImplTrait, Commutative

Interfaces: ConditionallySpeculatable, InferIntRangeInterface, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands: 

OperandDescription
lhsindex
rhsindex

Results: 

ResultDescription
resultindex

index.or (index::OrOp) 

Index bitwise or

Syntax:

operation ::= `index.or` $lhs `,` $rhs attr-dict

The index.or operation takes two index values and computes their bitwise or.

Example:

// c = a | b
%c = index.or %a, %b

Traits: AlwaysSpeculatableImplTrait, Commutative

Interfaces: ConditionallySpeculatable, InferIntRangeInterface, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands: 

OperandDescription
lhsindex
rhsindex

Results: 

ResultDescription
resultindex

index.rems (index::RemSOp) 

Index signed remainder

Syntax:

operation ::= `index.rems` $lhs `,` $rhs attr-dict

The index.rems operation takes two index values and computes their signed remainder. Treats the leading bit as the sign, i.e. 6 % -2 = 0.

Example:

// c = a % b
%c = index.rems %a, %b

Interfaces: InferIntRangeInterface, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands: 

OperandDescription
lhsindex
rhsindex

Results: 

ResultDescription
resultindex

index.remu (index::RemUOp) 

Index unsigned remainder

Syntax:

operation ::= `index.remu` $lhs `,` $rhs attr-dict

The index.remu operation takes two index values and computes their unsigned remainder. Treats the leading bit as the most significant, i.e. 6 % -2 = 6.

Example:

// c = a % b
%c = index.remu %a, %b

Interfaces: InferIntRangeInterface, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands: 

OperandDescription
lhsindex
rhsindex

Results: 

ResultDescription
resultindex

index.shl (index::ShlOp) 

Index shift left

Syntax:

operation ::= `index.shl` $lhs `,` $rhs attr-dict

The index.shl operation shifts an index value to the left by a variable amount. The low order bits are filled with zeroes. The RHS operand is always treated as unsigned. If the RHS operand is equal to or greater than the index bitwidth, the result is a poison value.

Example:

// c = a << b
%c = index.shl %a, %b

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, InferIntRangeInterface, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands: 

OperandDescription
lhsindex
rhsindex

Results: 

ResultDescription
resultindex

index.shrs (index::ShrSOp) 

Signed index shift right

Syntax:

operation ::= `index.shrs` $lhs `,` $rhs attr-dict

The index.shrs operation shifts an index value to the right by a variable amount. The LHS operand is treated as signed. The high order bits are filled with copies of the most significant bit. If the RHS operand is equal to or greater than the index bitwidth, the result is a poison value.

Example:

// c = a >> b
%c = index.shrs %a, %b

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, InferIntRangeInterface, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands: 

OperandDescription
lhsindex
rhsindex

Results: 

ResultDescription
resultindex

index.shru (index::ShrUOp) 

Unsigned index shift right

Syntax:

operation ::= `index.shru` $lhs `,` $rhs attr-dict

The index.shru operation shifts an index value to the right by a variable amount. The LHS operand is treated as unsigned. The high order bits are filled with zeroes. If the RHS operand is equal to or greater than the index bitwidth, the result is a poison value.

Example:

// c = a >> b
%c = index.shru %a, %b

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, InferIntRangeInterface, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands: 

OperandDescription
lhsindex
rhsindex

Results: 

ResultDescription
resultindex

index.sizeof (index::SizeOfOp) 

Size in bits of the index type

Syntax:

operation ::= `index.sizeof` attr-dict

The index.sizeof operation produces an index-typed SSA value equal to the size in bits of the index type. For example, on 32-bit systems, the result is 32 : index, and on 64-bit systems, the result is 64 : index.

Example:

%0 = index.sizeof

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, InferIntRangeInterface, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Results: 

ResultDescription
resultindex

index.sub (index::SubOp) 

Index subtraction

Syntax:

operation ::= `index.sub` $lhs `,` $rhs attr-dict

The index.sub operation takes two index values and computes the difference of the first from the second operand.

Example:

// c = a - b
%c = index.sub %a, %b

Traits: AlwaysSpeculatableImplTrait

Interfaces: ConditionallySpeculatable, InferIntRangeInterface, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands: 

OperandDescription
lhsindex
rhsindex

Results: 

ResultDescription
resultindex

index.xor (index::XOrOp) 

Index bitwise xor

Syntax:

operation ::= `index.xor` $lhs `,` $rhs attr-dict

The index.xor operation takes two index values and computes their bitwise xor.

Example:

// c = a ^ b
%c = index.xor %a, %b

Traits: AlwaysSpeculatableImplTrait, Commutative

Interfaces: ConditionallySpeculatable, InferIntRangeInterface, InferTypeOpInterface, NoMemoryEffect (MemoryEffectOpInterface)

Effects: MemoryEffects::Effect{}

Operands: 

OperandDescription
lhsindex
rhsindex

Results: 

ResultDescription
resultindex

Attributes 

IndexCmpPredicateAttr 

index comparison predicate kind

Syntax:

#index.cmp_predicate<
  ::mlir::index::IndexCmpPredicate   # value
>

Enum cases:

  • eq (EQ)
  • ne (NE)
  • slt (SLT)
  • sle (SLE)
  • sgt (SGT)
  • sge (SGE)
  • ult (ULT)
  • ule (ULE)
  • ugt (UGT)
  • uge (UGE)

Parameters: 

ParameterC++ typeDescription
value::mlir::index::IndexCmpPredicatean enum of type IndexCmpPredicate

Enums 

IndexCmpPredicate 

index comparison predicate kind

Cases: 

SymbolValueString
EQ0eq
NE1ne
SLT2slt
SLE3sle
SGT4sgt
SGE5sge
ULT6ult
ULE7ule
UGT8ugt
UGE9uge