44 arith Dialect
44.1 Beginner Summary
The arith dialect is MLIR’s basic arithmetic dialect. It holds integer arithmetic, floating-point arithmetic, bitwise operations, comparisons, casts, constants, and selects.
For a beginner, arith is the dialect you expect to see almost everywhere. It is the scalar math layer that other dialects build on:
linalgregions usearith.addf,arith.mulf,arith.cmpi, and friends to describe element computations.scfloops usearith.constant,arith.addi, andarith.cmpifor loop math and conditions.memref,tensor, and lowering pipelines usearith.index_cast, integer arithmetic, and constants for indexing.- Target conversions lower
arithinto LLVM, SPIR-V, EmitC, AMDGPU, ArmSME, or runtime calls.
Most arith operations work on scalars, vectors, and tensors. On vectors and tensors, the operation applies elementwise.
44.2 Why This Dialect Exists
MLIR needs a shared, target-independent way to represent basic math. Without arith, every dialect would need its own addition, comparison, cast, and constant operations. That would make optimization and lowering much harder.
The arith dialect exists to provide:
- A common arithmetic vocabulary for integer, index, and floating-point values.
- Elementwise arithmetic on vectors and tensors.
- Explicit signed versus unsigned integer behavior.
- Explicit floating-point comparison predicates, fast-math flags, and rounding modes.
- Casts between integer, index, and floating-point types.
- A stable source for canonicalization, constant folding, range analysis, and target conversion.
The dialect assumes integers are bitvectors using two’s complement representation. Unless an operation says otherwise, poison inputs produce poison outputs, and vector or tensor poison behavior is elementwise.
44.3 When It Matters
The arith dialect matters in almost every nontrivial MLIR pipeline:
- In frontend lowering, it expresses literal constants and basic scalar computation.
- In high-level tensor code, it appears inside
linalg.genericbodies. - In loop code, it computes induction-derived values and conditions.
- In buffer and index code, it casts between
indexand fixed-width integers. - In optimization, it enables constant folding, canonicalization, integer range analysis, and narrowing.
- In target lowering, it is one of the main dialects converted to LLVM, SPIR-V, EmitC, or target-specific dialects.
44.4 When To Use It
Use arith when you need target-independent scalar or elementwise math:
- Use integer ops for fixed-width integer and
indexarithmetic. - Use floating-point ops for target-independent float math.
- Use comparison ops to produce
i1, vector-of-i1, or tensor-of-i1conditions. - Use cast ops to change between integer widths, index, and floating-point types.
- Use
arith.selectfor value selection without control-flow branching.
Avoid using arith for:
- Memory access. Use
memref,tensor, or bufferization dialects. - Structured loops. Use
scf,affine, or another control-flow dialect. - Target intrinsics. Lower to target dialects such as LLVM, SPIR-V, AMDGPU, or ArmSME when target details matter.
- High-level algebraic structure. Use
linalg,tensor,vector, or domain dialects before reducing everything to scalar math.
44.5 Core Concepts
44.5.1 Elementwise Semantics
Many arith operations accept scalar, vector, and tensor operands. For vectors and tensors, the operation is applied lane-by-lane or element-by-element:
arith.addi : vector<4xi32> means four independent i32 additions.
This is why arith appears both in scalar loop bodies and in vectorized IR.
44.5.2 Signed Versus Unsigned
Integer values in MLIR are signless by default, so the operation chooses signed or unsigned interpretation:
- Signed examples:
arith.divsi,arith.remsi,arith.maxsi,arith.minsi, signedarith.cmpipredicates likeslt. - Unsigned examples:
arith.divui,arith.remui,arith.maxui,arith.minui, unsignedarith.cmpipredicates likeult. - Bitwise operations such as
arith.andi,arith.ori, andarith.xorido not need signedness.
44.5.3 Overflow And Exact Flags
Some integer operations can carry overflow flags:
overflow<nsw>means no signed wrap.overflow<nuw>means no unsigned wrap.overflow<nsw, nuw>means both assumptions hold.
Some division and shift operations can carry exact, meaning the operation has no discarded nonzero remainder or shifted-out bits. These flags are promises to the optimizer. If the promise is false, the result can become poison or undefined in later lowering.
44.5.4 Floating-Point Flags And Rounding
Floating-point operations may carry:
- Rounding modes such as
to_nearest_even,downward,upward,toward_zero, andto_nearest_away. - Fast-math flags such as
nnan,ninf,nsz,reassoc,arcp,contract,afn, or groupedfast.
When no explicit rounding mode is present, Arith uses round-to-nearest ties-to-even for internal constant folding and canonicalization. Runtime behavior without an explicit rounding mode is deferred to the target backend.
44.5.5 Poison
The dialect documentation says Arith generally propagates poison. This matters because flags such as nsw, nuw, exact, and fast-math assumptions can give optimizers permission to replace code based on facts the program producer promised.
44.5.6 Attributes
Important Arith attributes include:
CmpIPredicate: integer comparison predicateseq,ne,slt,sle,sgt,sge,ult,ule,ugt,uge.CmpFPredicate: floating comparison predicates such asoeq,ogt,olt,ord,ueq,uno, plus always-true and always-false predicates.FastMathFlags: floating-point optimization flags.IntegerOverflowFlags:nswandnuw.RoundingMode: explicit floating-point rounding mode.AtomicRMWKind: shared arithmetic names used by atomic read-modify-write style operations in other dialects.
44.6 Operations
44.6.1 Constants And Selection
arith.constantcreates an integer, index, floating-point, vector, tensor, or other typed constant value.arith.selectchooses between two values using ani1, vector-of-i1, or tensor-of-i1condition.
44.6.2 Integer Arithmetic
arith.addiadds integers or indices and may carry overflow flags.arith.subisubtracts integers or indices and may carry overflow flags.arith.mulimultiplies integers or indices and may carry overflow flags.arith.divsiperforms signed integer division and may be markedexact.arith.divuiperforms unsigned integer division and may be markedexact.arith.ceildivsiperforms signed integer division rounded toward positive infinity.arith.ceildivuiperforms unsigned integer division rounded upward.arith.floordivsiperforms signed integer division rounded toward negative infinity.arith.remsicomputes signed integer remainder.arith.remuicomputes unsigned integer remainder.
44.6.3 Extended Integer Arithmetic
arith.addui_extendedcomputes unsigned addition and returns both the sum and overflow bit.arith.subui_extendedcomputes unsigned subtraction and returns both the difference and borrow bit.arith.mulsi_extendedcomputes signed multiplication and returns low and high halves.arith.mului_extendedcomputes unsigned multiplication and returns low and high halves.
44.6.4 Bitwise And Shift Operations
arith.andicomputes bitwise and.arith.oricomputes bitwise or.arith.xoricomputes bitwise xor.arith.shlishifts left and may carry overflow flags.arith.shrsiperforms signed arithmetic right shift and may be markedexact.arith.shruiperforms unsigned logical right shift and may be markedexact.
44.6.5 Floating-Point Arithmetic
arith.negfnegates a floating-point value.arith.addfadds floating-point values and may carry rounding and fast-math metadata.arith.subfsubtracts floating-point values and may carry rounding and fast-math metadata.arith.mulfmultiplies floating-point values and may carry rounding and fast-math metadata.arith.divfdivides floating-point values and may carry rounding and fast-math metadata.arith.remfcomputes floating-point remainder.arith.maximumfcomputes a maximum with NaN propagation semantics.arith.minimumfcomputes a minimum with NaN propagation semantics.arith.maxnumfcomputes a maximum-number style operation that handles NaN differently frommaximumf.arith.minnumfcomputes a minimum-number style operation that handles NaN differently fromminimumf.arith.flush_denormalsflushes denormal floating-point values to zero.
44.6.6 Integer Min And Max
arith.maxsicomputes signed integer maximum.arith.maxuicomputes unsigned integer maximum.arith.minsicomputes signed integer minimum.arith.minuicomputes unsigned integer minimum.
44.6.7 Casts Between Integer, Index, And Float
arith.extsisign-extends an integer to a wider integer type.arith.extuizero-extends an integer to a wider integer type and can carrynneg.arith.truncitruncates an integer to a narrower integer type and may carry overflow flags.arith.index_castcasts betweenindexand integer types using signed interpretation.arith.index_castuicasts betweenindexand integer types using unsigned interpretation and can carrynneg.arith.sitofpconverts signed integer to floating-point.arith.uitofpconverts unsigned integer to floating-point and can carrynneg.arith.fptosiconverts floating-point to signed integer.arith.fptouiconverts floating-point to unsigned integer.arith.extfextends a floating-point value to a wider floating-point type and may carry fast-math metadata.arith.truncftruncates a floating-point value to a narrower floating-point type and may carry rounding and fast-math metadata.arith.convertfconverts between floating-point types of the same bit width and may carry rounding and fast-math metadata.arith.bitcastreinterprets bits between equal-bit-width types.arith.scaling_extfupcasts input floats using scale values, useful for scaled low-precision floating formats.arith.scaling_truncfdowncasts floating-point values using scale values, useful for scaled low-precision floating formats.
44.6.8 Comparisons
arith.cmpicompares integer, index, vector, or tensor values using integer predicates.arith.cmpfcompares floating-point, vector, or tensor values using ordered or unordered floating predicates.
44.7 Transformations
Native Arith transformations include:
arith-expand: legalizes selected Arith ops into simpler Arith and vector operations that are easier to convert to LLVM. Options includeinclude-bf16,include-f8e8m0,include-f4e2m1, andinclude-flush-denormals.arith-unsigned-when-equivalent: uses integer range analysis to replace signed operations with unsigned equivalents when operands and results are proven non-negative.int-range-optimizations: runs integer range analysis and folds or rewrites operations based on known ranges, such as known-constant comparisons or trivial remainders.arith-int-range-narrowing: narrows integer operations to supported bit widths when range analysis proves it is safe. Theint-bitwidths-supportedoption names the allowed widths.arith-emulate-unsupported-floats: wraps unsupported floating-point operations withextfandtruncfto compute in a supported target type. Options includesource-typesandtarget-type.arith-emulate-wide-int: splits too-wide integer operations into operations on narrower integer halves. Thewidest-int-supportedoption controls the target integer width.
Arith also participates in canonicalization, constant folding, integer range inference, value bounds inference, bufferization interfaces, and sharding interfaces.
44.8 Conversions/Lowering Paths
Important conversion passes include:
convert-arith-to-llvm: lowers supported Arith operations to LLVM dialect. Theindex-bitwidthoption controls the bit width used forindex.convert-arith-to-spirv: lowers Arith operations to SPIR-V. It can emulate sub-32-bit scalar types and unsupported float types.convert-arith-to-emitc: lowers Arith operations to EmitC source-level operations.convert-arith-to-amdgpu: lowers selected Arith operations, currently focused on 8-bit float extension/truncation patterns, to AMDGPU-specific operations.convert-arith-to-arm-sme: lowers supported Arith operations to ArmSME dialect.convert-arith-to-apfloat: lowers supported Arith operations to APFloat runtime library calls for software floating-point behavior.
Arith is also a common lowering target:
tosa-to-arithlowers selected TOSA operations to Arith.- Affine lowering often produces Arith plus SCF.
- Many dialects use Arith inside generated loop bodies after lowering.
A typical lowering flow is:
- High-level dialects lower computation into
linalg,scf,vector, andarith. - Canonicalization and range-based Arith passes simplify scalar math.
- Expansion or emulation passes rewrite operations the target cannot directly support.
- Target conversion lowers Arith to LLVM, SPIR-V, EmitC, AMDGPU, ArmSME, or runtime calls.
44.9 Example IR
This example shows integer arithmetic with overflow and exactness flags.
func.func @integer_ops(%a: i32, %b: i32) -> (i32, i1, i32) {
%sum = arith.addi %a, %b overflow<nsw, nuw> : i32
%quot = arith.divsi %sum, %b exact : i32
%cmp = arith.cmpi sgt, %sum, %quot : i32
%chosen = arith.select %cmp, %sum, %quot : i32
return %sum, %cmp, %chosen : i32, i1, i32
}
This example shows floating-point rounding and fast-math metadata.
func.func @float_ops(%x: f32, %y: f32) -> (f32, i1, f32) {
%prod = arith.mulf %x, %y upward fastmath<contract> : f32
%mx = arith.maximumf %prod, %x : f32
%cmp = arith.cmpf ogt, %mx, %y : f32
%out = arith.select %cmp, %mx, %y : f32
return %prod, %cmp, %out : f32, i1, f32
}
This example shows casts between integer, index, and floating-point types.
func.func @casts(%i: i32, %f: f32, %idx: index) -> (i64, f64, index, i32) {
%wide_i = arith.extsi %i : i32 to i64
%wide_f = arith.extf %f fastmath<contract> : f32 to f64
%idx_from_i = arith.index_castui %i nneg : i32 to index
%i_from_idx = arith.index_cast %idx : index to i32
return %wide_i, %wide_f, %idx_from_i, %i_from_idx : i64, f64, index, i32
}
This example shows vector elementwise arithmetic and selection.
func.func @vector_ops(%a: vector<4xi32>, %b: vector<4xi32>, %mask: vector<4xi1>) -> vector<4xi32> {
%sum = arith.addi %a, %b : vector<4xi32>
%zero = arith.constant dense<0> : vector<4xi32>
%selected = arith.select %mask, %sum, %zero : vector<4xi1>, vector<4xi32>
return %selected : vector<4xi32>
}
44.10 Mental Model
Think of arith as MLIR’s target-independent calculator. It does not allocate memory, own control flow, or describe high-level algorithms. It computes values.
The dialect is small in concept but precise in semantics. The hard parts are not addition or multiplication themselves. The hard parts are:
- Whether an integer operation is signed or unsigned.
- Whether overflow is allowed to happen.
- Whether division or shift is exact.
- Whether floating-point operations can ignore NaNs, signed zero, infinities, or reassociation rules.
- Whether a cast preserves sign, zero-extends, truncates, rounds, or reinterprets bits.
If you keep those details straight, Arith IR is usually straightforward to read.
44.11 Gotchas
- Signless integer types do not imply signed behavior. The op or predicate chooses signed versus unsigned interpretation.
- Overflow flags are promises. Do not add
nsw,nuw, orexactunless the producer can prove them. arith.maximumfandarith.maxnumfare not identical; likewisearith.minimumfandarith.minnumfdiffer in NaN handling.- Floating-point fast-math flags can make transformations legal that would otherwise be invalid under strict IEEE behavior.
- Rounding modes affect constant folding and canonicalization.
indexis not a fixed-width integer in the source IR. Target conversions decide its bit width, often through data layout or pass options.arith.index_castandarith.index_castuidiffer by signed versus unsigned interpretation.arith.bitcastrequires equal total bit width; it does not numerically convert.- Most operations work elementwise on vectors and tensors, so a scalar-looking op name can still represent many lane operations.
- The dialect does not support manipulating
i0values.
44.12 Source Map
Primary source files:
mlir/include/mlir/Dialect/Arith/IR/ArithBase.tdmlir/include/mlir/Dialect/Arith/IR/ArithOps.tdmlir/include/mlir/Dialect/Arith/IR/ArithOpsInterfaces.tdmlir/lib/Dialect/Arith/IR/ArithOps.cppmlir/lib/Dialect/Arith/IR/ArithCanonicalization.tdmlir/include/mlir/Dialect/Arith/Transforms/Passes.tdmlir/lib/Dialect/Arith/Transforms/mlir/include/mlir/Conversion/Passes.tdmlir/lib/Conversion/ArithToLLVM/mlir/lib/Conversion/ArithToSPIRV/mlir/lib/Conversion/ArithToEmitC/mlir/lib/Conversion/ArithToAMDGPU/mlir/lib/Conversion/ArithToArmSME/mlir/lib/Conversion/ArithToAPFloat/mlir/lib/Conversion/TosaToArith/
Useful tests:
mlir/test/Dialect/Arith/ops.mlirmlir/test/Dialect/Arith/canonicalize.mlirmlir/test/Dialect/Arith/constant-fold.mlirmlir/test/Dialect/Arith/expand-ops.mlirmlir/test/Dialect/Arith/int-range-opts.mlirmlir/test/Dialect/Arith/emulate-wide-int.mlirmlir/test/Dialect/Arith/emulate-unsupported-floats.mlirmlir/test/Conversion/ArithToLLVM/mlir/test/Conversion/ArithToSPIRV/mlir/test/Conversion/ArithToEmitC/