45 math Dialect
45.1 Beginner Summary
The math dialect contains mathematical operations that are more specialized than ordinary arithmetic.
The arith dialect handles basic arithmetic such as add, subtract, multiply, divide, compare, and casts. The math dialect handles operations such as:
- Trigonometric functions like
math.sin,math.cos, andmath.atan2. - Exponentials and logarithms like
math.exp,math.log, andmath.powf. - Rounding operations like
math.ceil,math.floor, andmath.roundeven. - Fused and compound operations like
math.fma,math.sincos, andmath.clampf. - Floating-point classification like
math.isnanandmath.isfinite. - Integer bit operations like
math.ctlz,math.cttz, andmath.ctpop.
Most operations work on scalars, vectors, and tensors. Vector and tensor forms are elementwise unless an operation says otherwise.
Think of math as MLIR’s portable vocabulary for elementary math functions before the compiler has chosen a final implementation strategy.
45.2 Why This Dialect Exists
Elementary math is deceptively target-dependent.
The expression:
sin(x)
could lower to:
- An LLVM intrinsic.
- A
libmcall. - A CUDA libdevice call.
- An AMD OCML or ROCDL call.
- A SPIR-V GLSL or OpenCL extended instruction.
- An EmitC
call_opaque. - A compiler-generated software helper function.
- A polynomial approximation.
Those choices depend on the target, precision requirements, available runtime libraries, vector support, fast-math flags, and whether the operation appears on scalar, vector, or tensor types.
The math dialect keeps the source-level mathematical intent visible while the compiler is still making those choices.
It also separates ordinary arithmetic from math-library semantics. For example, arith.mulf is a multiplication operation. math.fma is a fused multiply-add. math.exp is an exponential function. math.powf carries the semantics of floating-point exponentiation, not merely a sequence of multiplies.
45.3 When It Matters
The math dialect matters when a compiler needs to preserve a mathematical operation long enough to choose the right target implementation.
It commonly appears in pipelines for:
- Numerical kernels.
- ML model lowering.
- GPU code generation.
- Vectorized CPU code generation.
- Scientific and signal-processing code.
- Low-precision floating-point legalization.
- Runtime-library lowering.
- Fast-math optimization.
A typical flow looks like this:
higher-level tensor/vector/scalar IR
-> math.sin, math.exp, math.fma, math.isfinite, ...
-> canonicalize and math-specific transforms
-> choose target lowering
-> LLVM / libm / NVVM / ROCDL / SPIR-V / XeVM / EmitC / helper funcs
The key point is that math is often a middle-level dialect. It is specific enough for optimization, but not yet tied to one runtime library or target ISA.
45.4 When To Use It
Use the math dialect when your IR needs a named mathematical operation whose semantics should remain visible.
Use it for:
- Elementary floating-point functions.
- Integer absolute value and bit-counting operations.
- Floating-point classification predicates.
- Fused multiply-add.
- Combined sine/cosine computation.
- Power operations.
- Rounding operations that are distinct from casts.
- Elementwise math on vectors and tensors.
- Lowering frontends that have source-level math functions.
Do not use math for basic arithmetic when arith directly expresses the operation. Use arith.addf, arith.mulf, arith.divf, arith.addi, and similar operations for ordinary arithmetic. Use math when the operation has a library-like, intrinsic-like, or special semantic meaning.
45.5 Core Concepts
45.5.1 Elementwise Semantics
Math operations can apply to:
- Scalar values such as
f32,f64, ori32. - Vector values such as
vector<4xf32>. - Tensor values such as
tensor<?xf32>.
For vectors and tensors, operations are elementwise unless explicitly stated otherwise.
%s = math.sin %x : f32
%v = math.sin %vec : vector<4xf32>
%t = math.sin %tensor : tensor<?xf32>
The operation is the same mathematical function. The container type controls how many elements are mapped.
45.5.2 Math Versus Arith
The arith dialect owns primitive arithmetic. The math dialect owns elementary math functions and related operations.
Examples:
- Use
arith.addfforx + y. - Use
arith.mulfforx * y. - Use
math.fmawhen the operation must be fused asx * y + z. - Use
math.expfor the exponential function. - Use
math.sqrtfor square root. - Use
math.ctlzfor count-leading-zeros.
This split helps the compiler keep simple arithmetic simple while still tracking operations that may require target intrinsics or runtime calls.
45.5.3 Fast-Math Flags
Many floating-point Math operations implement MLIR’s fast-math interface.
Fast-math flags communicate which IEEE-style constraints a compiler may relax. For example, an operation may carry fastmath<contract> or fastmath<afn>.
These flags matter for transformations and target lowering:
math-uplift-to-fmarequires fast-math flags that allow contraction.convert-math-to-xevmlowers selected operations to native OpenCL math intrinsics only whenafnis present, unless configured otherwise.- LLVM lowering carries fast-math information into LLVM operations and intrinsics.
Fast-math flags are not decoration. They are part of the optimization contract.
45.5.4 Rounding Mode
Most Math operations do not carry an explicit rounding mode.
The dialect documentation says the default rounding mode used internally for constant folding and canonicalization is round-to-nearest, ties-to-even. Runtime behavior without an explicit rounding mode is deferred to the backend.
math.fma is special: it can carry an optional explicit IEEE-754 rounding mode. When no rounding mode is present, LLVM lowering uses the ordinary LLVM FMA intrinsic. When a rounding mode is present, LLVM lowering uses the constrained FMA intrinsic.
45.5.5 Low-Precision Floating Point
Targets often lack direct support for math library functions on types smaller than f32, such as f16, bf16, or 8-bit float types.
The math-extend-to-supported-types pass handles this by extending unsupported inputs to a supported type, applying the math operation there, and truncating the result back to the original type. By default, f32 and f64 are treated as supported.
math.fma is intentionally excluded from this pass because low-precision FMA is often directly supported by hardware.
45.5.6 Approximation And Target Choice
Some lowering paths preserve precise library semantics. Others intentionally choose approximate or native target functions.
The math dialect itself records the mathematical operation. Later passes decide whether to lower to a precise function, an approximate implementation, or a target-native instruction. Fast-math flags and pass options are often what make that decision legal.
45.6 Operations
45.6.1 Floating-Point Unary Functions
These operations take one floating-point-like operand and return the same type:
math.absf: floating-point absolute value.math.acos: inverse cosine.math.acosh: inverse hyperbolic cosine.math.asin: inverse sine.math.asinh: inverse hyperbolic sine.math.atan: inverse tangent.math.atanh: inverse hyperbolic tangent.math.cbrt: cube root.math.ceil: ceiling.math.cos: cosine.math.cosh: hyperbolic cosine.math.erf: error function.math.erfc: complementary error function.math.exp: base-e exponential.math.exp2: base-2 exponential.math.expm1:exp(x) - 1, represented directly for accuracy.math.floor: floor.math.log: natural logarithm.math.log10: base-10 logarithm.math.log1p:log(1 + x), represented directly for accuracy.math.log2: base-2 logarithm.math.round: round halfway cases away from zero.math.roundeven: round halfway cases to even.math.rsqrt: reciprocal square root.math.sin: sine.math.sinh: hyperbolic sine.math.sqrt: square root.math.tan: tangent.math.tanh: hyperbolic tangent.math.trunc: round toward zero in floating-point format.
Most of these operations can fold constants and carry fast-math flags.
45.6.2 Floating-Point Binary And Ternary Functions
math.atan2 computes the two-argument arctangent.
math.copysign returns the magnitude of the first operand with the sign of the second operand.
math.powf raises a floating-point base to a floating-point exponent.
math.fpowi raises a floating-point base to a signed integer exponent. The base and result have floating-point type; the exponent has integer or index-like type with the same scalar/vector/tensor shape.
math.fma computes fused multiply-add. It takes three floating-point operands and returns one floating-point result of the same type. It may carry an explicit rounding mode.
math.clampf clamps a value to a floating-point range:
clampf(value, min, max) = maxf(minf(value, max), min)
If min > max, the result is poison.
45.6.3 Combined Sine And Cosine
math.sincos computes sine and cosine together and returns two results.
%sin, %cos = math.sincos %x : f32
This can be more efficient than computing math.sin and math.cos separately when both values are needed. The math-sincos-fusion pass can fuse matching math.sin and math.cos operations into this operation.
45.6.4 Integer Math
math.absi computes integer absolute value.
math.ipowi raises a signed integer base to an integer power.
math.ctlz counts leading zero bits.
math.cttz counts trailing zero bits.
math.ctpop counts set bits.
These operations work on integer scalars, vectors, or tensors.
45.6.5 Floating-Point Classification
These operations take a floating-point-like operand and return an i1-like result with the same shape:
math.isfinite: true for normal, subnormal, or zero values; false for infinities and NaNs.math.isinf: true for positive or negative infinity.math.isnan: true for NaN.math.isnormal: true for normal finite values, excluding zero and subnormal values.
For example, a vector<4xf32> input produces a vector<4xi1> result.
45.7 Transformations
45.7.1 Canonicalization And Folding
Many Math operations fold constants and simplify obvious identities.
Canonicalization can simplify operations such as:
- Constant
math.powf,math.exp2,math.expm1, andmath.rsqrt. math.sincosof constants.- Floating-point classification on constant values.
- Integer bit-counting on constant values.
The dialect also provides algebraic simplification patterns in the source tree. These can rewrite selected math expressions when the required fast-math conditions are met. For example, powers with special exponents can simplify to more direct operations.
45.7.2 math-uplift-to-fma
math-uplift-to-fma rewrites a multiply-add pattern into math.fma when fast-math flags allow contraction.
This matters because a fused multiply-add has different semantics from a separate multiply followed by add. The pass is conservative and uses fast-math information to decide when that change is legal.
45.7.3 math-extend-to-supported-types
math-extend-to-supported-types legalizes math operations on low-precision floating-point types.
It inserts arith.extf before the math operation and arith.truncf after it. The pass has options for:
target-type, defaulting tof32.extra-types, for target-supported types beyond the implicitf32andf64.
This pass does not rewrite math.fma.
45.7.4 math-expand-ops
math-expand-ops expands selected Math operations into more fundamental operations.
The local implementation registers expansions for:
math.ctlzmath.sinhmath.coshmath.tanmath.tanhmath.asinhmath.acoshmath.atanhmath.fmamath.ceilmath.exp2math.powfmath.fpowimath.roundmath.roundevenmath.rsqrtmath.clampf
The pass accepts an ops option so a pipeline can request only selected expansions, such as ops=tanh,tan.
45.7.5 math-sincos-fusion
math-sincos-fusion fuses matching math.sin and math.cos operations into math.sincos.
This is useful when the target has a combined sin/cos instruction or library call, or when computing both together is cheaper than two separate calls.
45.7.6 Polynomial Approximation Patterns
The Math transform library also contains polynomial approximation patterns used by tests and target-specific pipelines.
These approximate selected f32 math functions using combinations of arithmetic and math.fma. They are useful when a compiler wants an inline approximation instead of a library call, but they are a deliberate numerical choice and should not be treated as the default lowering for every target.
45.8 Conversions And Lowering Paths
45.8.1 convert-math-to-llvm
convert-math-to-llvm lowers supported Math operations to LLVM dialect operations and intrinsics.
The local conversion includes direct LLVM lowering for operations such as math.absf, math.absi, math.ceil, math.copysign, math.cos, math.exp, math.exp2, math.floor, math.fma, math.fpowi, math.log, math.log2, math.log10, math.powf, math.round, math.roundeven, math.sin, math.sqrt, math.tan, math.tanh, math.trunc, math.ctlz, math.cttz, math.ctpop, and selected classification operations.
Some operations lower by expansion during LLVM conversion. For example:
math.expm1lowers asexp(x) - 1.math.log1pmay lower aslog(1 + x)whenapproximate-log1pis enabled.math.rsqrtlowers as1 / sqrt(x).math.sincoslowers to an LLVM sincos intrinsic followed by value extraction.
45.8.2 convert-math-to-libm
convert-math-to-libm lowers supported floating-point Math operations to libm function calls.
Examples include:
math.sintosinforsin.math.exptoexpforexp.math.logtologforlog.math.powftopowforpow.math.sqrttosqrtforsqrt.math.fmatofmaforfma.
This path is appropriate for CPU-style lowering when the final program can link against the math library.
45.8.3 convert-math-to-apfloat
convert-math-to-apfloat lowers supported Math operations to APFloat-based runtime library calls.
APFloat is a software floating-point implementation. This path is useful when the target needs software emulation instead of native hardware or ordinary libm behavior.
45.8.4 convert-math-to-funcs
convert-math-to-funcs lowers supported Math operations to calls to compiler-generated helper functions.
In this checkout, the pass is especially relevant for math.fpowi and optionally math.ctlz. It has options controlling:
- The minimum exponent integer width for converting
math.fpowi. - Whether to convert
math.ctlzto a software implementation.
The generated functions use ordinary MLIR control flow and arithmetic, with LLVM linkage attributes used for generated helper linkage.
45.8.5 GPU And Accelerator Lowerings
convert-math-to-nvvm lowers supported Math operations to CUDA libdevice calls, and in some cases NVVM-specific behavior. It handles scalarization of vector math where needed.
convert-math-to-rocdl lowers supported Math operations to AMDGPU/ROCDL library calls, including OCML-style function names. It has a chipset option for AMDGPU architecture-specific patterns.
convert-math-to-spirv lowers supported Math operations to SPIR-V operations or extended instructions.
convert-math-to-xevm lowers supported operations to native XeVM/SPIR-V or OpenCL-style math intrinsics. Its default behavior is precision-aware: native OpenCL native_ intrinsics are selected for supported Math ops marked with the afn fast-math flag, unless the pass is configured to convert all supported ops to OpenCL intrinsics.
45.8.6 convert-math-to-emitc
convert-math-to-emitc lowers supported Math operations to EmitC call_opaque operations targeting libc or libm functions.
This is different from convert-math-to-funcs: EmitC lowering preserves calls that the C or C++ output can print as external library calls, with an option to select the language target.
45.8.7 Choosing A Lowering
There is no single correct Math lowering path.
Use:
convert-math-to-llvmwhen LLVM intrinsics are the desired representation.convert-math-to-libmwhen linking against libm is appropriate.convert-math-to-apfloatwhen software floating-point emulation is needed.convert-math-to-funcswhen compiler-generated helper implementations are preferred.convert-math-to-nvvmfor CUDA/NVVM pipelines.convert-math-to-rocdlfor AMDGPU/ROCDL pipelines.convert-math-to-spirvfor SPIR-V pipelines.convert-math-to-xevmfor XeVM/OpenCL-style native math lowering.convert-math-to-emitcfor C/C++ emission through EmitC.
45.9 Example IR
45.9.1 Elementwise Scalar, Vector, And Tensor Math
func.func @elementwise(%x: f32, %v: vector<4xf32>, %t: tensor<?xf32>)
-> (f32, vector<4xf32>, tensor<?xf32>) {
%s = math.exp %x : f32
%vv = math.sin %v : vector<4xf32>
%tt = math.sqrt %t : tensor<?xf32>
return %s, %vv, %tt : f32, vector<4xf32>, tensor<?xf32>
}
The same dialect operation family works on scalar, vector, and tensor shapes. The vector and tensor cases are elementwise.
45.9.2 FMA, Sincos, Fast-Math, And Rounding
func.func @fused(%a: f32, %b: f32, %c: f32) -> (f32, f32, f32) {
%fma = math.fma %a, %b, %c to_nearest_even fastmath<contract> : f32
%sin, %cos = math.sincos %a fastmath<contract> : f32
return %fma, %sin, %cos : f32, f32, f32
}
This example shows two important target-lowering signals: a fused operation and fast-math flags.
45.9.3 Classification And Integer Bit Counting
func.func @classify_and_count(%x: f32, %bits: i32) -> (i1, i1, i32) {
%nan = math.isnan %x : f32
%finite = math.isfinite %x : f32
%leading = math.ctlz %bits : i32
return %nan, %finite, %leading : i1, i1, i32
}
The math dialect is not only transcendental floating-point functions. It also contains classification predicates and integer bit-counting operations.
45.9.4 Low-Precision Math Before Legalization
func.func @low_precision(%x: f16) -> f16 {
%y = math.exp %x : f16
return %y : f16
}
If the target does not support exp directly on f16, the math-extend-to-supported-types pass can rewrite this through a wider supported type, commonly f32.
45.10 Mental Model
The Math dialect says what mathematical function is intended, not exactly how the machine will compute it.
For beginners, group it this way:
math.sin,math.exp,math.log,math.sqrt, and similar ops are portable elementary functions.math.fma,math.sincos, andmath.clampfexpose compound operations that targets often implement specially.math.isnan,math.isfinite,math.isinf, andmath.isnormalanswer questions about floating-point classes.math.ctlz,math.cttz,math.ctpop,math.absi, andmath.ipowicover integer math that is not ordinary arithmetic.- Transform passes decide whether to keep, combine, expand, approximate, or legalize operations.
- Conversion passes decide which runtime, intrinsic set, or target dialect will implement them.
45.11 Gotchas
Vector and tensor Math operations are elementwise. They do not imply a reduction, map loop, or library call by themselves.
Do not assume every target supports every operation natively. Many Math ops need lowering to runtime calls, expansions, or approximations.
Do not treat math.fma as syntactic sugar for arith.mulf plus arith.addf. FMA is fused and has different numerical behavior.
Fast-math flags affect legality. A pass that is valid under fastmath<contract> or fastmath<afn> may be invalid without those flags.
math.expm1 and math.log1p exist for numerical accuracy. Expanding them to exp(x) - 1 or log(1 + x) can lose accuracy near zero unless the pipeline has explicitly chosen that tradeoff.
math-extend-to-supported-types is a legalization pass, not a precision improvement pass. It allows lowering through a supported type and then truncates back to the original type.
The Math dialect depends on arith, but it is not a replacement for arith. Use each dialect at the right semantic level.
45.12 Source Map
Important local source files:
mlir/include/mlir/Dialect/Math/IR/MathBase.tddefines the dialect, elementwise intent, default rounding note, andarithdependency.mlir/include/mlir/Dialect/Math/IR/MathOps.tddefines the Math operations.mlir/lib/Dialect/Math/IR/MathOps.cppimplements parsing, folding, canonicalization, and related operation behavior.mlir/include/mlir/Dialect/Math/Transforms/Passes.tddeclaresmath-uplift-to-fma,math-extend-to-supported-types,math-expand-ops, andmath-sincos-fusion.mlir/lib/Dialect/Math/Transforms/ExpandOps.cppimplements Math expansion patterns.mlir/lib/Dialect/Math/Transforms/ExtendToSupportedTypes.cppimplements low-precision extension/truncation legalization.mlir/lib/Dialect/Math/Transforms/UpliftToFMA.cppimplements FMA uplift.mlir/lib/Dialect/Math/Transforms/SincosFusion.cppimplements sin/cos fusion.mlir/lib/Dialect/Math/Transforms/PolynomialApproximation.cppimplements polynomial approximation pattern utilities.mlir/include/mlir/Conversion/Passes.tddeclares the Math conversion passes.mlir/lib/Conversion/MathToLLVM/MathToLLVM.cppimplements Math-to-LLVM lowering.mlir/lib/Conversion/MathToLibm/MathToLibm.cppimplements Math-to-libm lowering.mlir/lib/Conversion/ArithAndMathToAPFloat/MathToAPFloat.cppimplements Math-to-APFloat runtime lowering.mlir/lib/Conversion/MathToFuncs/MathToFuncs.cppimplements lowering to generated helper functions.mlir/lib/Conversion/MathToNVVM/MathToNVVM.cppimplements Math-to-CUDA libdevice/NVVM lowering.mlir/lib/Conversion/MathToROCDL/MathToROCDL.cppimplements Math-to-ROCDL lowering.mlir/lib/Conversion/MathToSPIRV/MathToSPIRV.cppimplements Math-to-SPIR-V lowering.mlir/lib/Conversion/MathToXeVM/MathToXeVM.cppimplements Math-to-XeVM and OpenCL-style lowering.mlir/lib/Conversion/MathToEmitC/MathToEmitC.cppimplements Math-to-EmitC pattern lowering.mlir/test/Dialect/Math/contains parser, canonicalization, transform, and approximation tests.mlir/test/Conversion/MathTo*/contains conversion tests for the target lowering families.
Generated operation documentation for this checkout lists these 46 operations:
math.absf
math.absi
math.acos
math.acosh
math.asin
math.asinh
math.atan
math.atan2
math.atanh
math.cbrt
math.ceil
math.clampf
math.copysign
math.cos
math.cosh
math.ctlz
math.ctpop
math.cttz
math.erf
math.erfc
math.exp
math.exp2
math.expm1
math.floor
math.fma
math.fpowi
math.ipowi
math.isfinite
math.isinf
math.isnan
math.isnormal
math.log
math.log10
math.log1p
math.log2
math.powf
math.round
math.roundeven
math.rsqrt
math.sin
math.sincos
math.sinh
math.sqrt
math.tan
math.tanh
math.trunc