[Mlir-commits] [mlir] [mlir][math] Add opt-in f64 round expansion (PR #230408)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Fri Oct 9 01:57:22 PDT 2026
https://github.com/sriramshastry updated https://github.com/llvm/llvm-project/pull/230408
>From 30cb0e23650f7f3f8a87cf2d5dd108dfc8da4d53 Mon Sep 17 00:00:00 2001
From: Sriram Shastry <sriramshastry at gmail.com>
Date: Fri, 9 Oct 2026 08:36:15 +0000
Subject: [PATCH] [mlir][math] Add opt-in f64 round expansion
Signed-off-by: Sriram Shastry <sriramshastry at gmail.com>
---
.../mlir/Dialect/Math/Transforms/Passes.td | 12 +-
.../lib/Dialect/Math/Transforms/ExpandOps.cpp | 62 +++++
.../Conversion/MathToLLVM/math-to-llvm.mlir | 33 +++
mlir/test/Dialect/Math/expand-math.mlir | 51 +++++
.../Dialect/Math/round-f64-expansion.mlir | 211 ++++++++++++++++++
5 files changed, 368 insertions(+), 1 deletion(-)
create mode 100644 mlir/test/Dialect/Math/round-f64-expansion.mlir
diff --git a/mlir/include/mlir/Dialect/Math/Transforms/Passes.td b/mlir/include/mlir/Dialect/Math/Transforms/Passes.td
index 56ba4d05caa5a2..1095a7e07c7c1e 100644
--- a/mlir/include/mlir/Dialect/Math/Transforms/Passes.td
+++ b/mlir/include/mlir/Dialect/Math/Transforms/Passes.td
@@ -51,6 +51,14 @@ def MathExpandOpsPass : Pass<"math-expand-ops"> {
to be subsequently lowered through these. For example, hyperbolic functions
are transformed into their expanded form containing only `exp` functions.
+ f64 `math.round` expansion is disabled by default. Set `expand-round-f64`
+ to enable its integer software expansion when `round` is selected by `ops`.
+ This includes Round operations generated by RoundEven expansion. Default
+ behavior, f32 lowering and direct LLVM conversion are unchanged. Prefer
+ direct LLVM lowering when native rounding instructions are available;
+ expansion assumes the default floating-point environment and does not
+ preserve observable exception flags or traps.
+
The `ops` parameter can be used to apply only a subset of all the
available expansions, these must correspond to the operation mnemonic.
For example, `ops=sinh,acosh` will expand only `math.sinh` and
@@ -60,7 +68,9 @@ def MathExpandOpsPass : Pass<"math-expand-ops"> {
let dependentDialects = ["arith::ArithDialect", "mlir::tensor::TensorDialect"];
let options = [
ListOption<"opMnemonics", "ops", "std::string",
- "Operations to expand.">
+ "Operations to expand.">,
+ Option<"expandRoundF64", "expand-round-f64", "bool", "false",
+ "Enable f64 round expansion when round is selected">
];
}
diff --git a/mlir/lib/Dialect/Math/Transforms/ExpandOps.cpp b/mlir/lib/Dialect/Math/Transforms/ExpandOps.cpp
index 41816abf073398..c6d70b565b17f0 100644
--- a/mlir/lib/Dialect/Math/Transforms/ExpandOps.cpp
+++ b/mlir/lib/Dialect/Math/Transforms/ExpandOps.cpp
@@ -518,6 +518,65 @@ static LogicalResult convertExp2fOp(math::Exp2Op op,
return success();
}
+static LogicalResult convertRoundF64Op(math::RoundOp op,
+ PatternRewriter &rewriter) {
+ Location loc = op.getLoc();
+ ImplicitLocOpBuilder b(loc, rewriter);
+ Value operand = op.getOperand();
+ Type opType = operand.getType();
+ Type opEType = getElementTypeOrSelf(opType);
+
+ if (!opEType.isF64() || isUnrankedShaped(opType))
+ return failure();
+
+ Type intType = b.getI64Type();
+ if (auto shapedType = dyn_cast<ShapedType>(opType))
+ intType = shapedType.clone(intType);
+
+ auto intConst = [&](int64_t value) {
+ return createIntConst(loc, intType, value, b, operand);
+ };
+
+ Value zero = intConst(0);
+ Value one = intConst(1);
+ Value allOnes = intConst(-1);
+ Value cFractionBits = intConst(52);
+ Value cBias = intConst(1023);
+ Value cRoundShiftBase = intConst(51);
+ Value cShiftMask = intConst(63);
+ Value magnitudeMask = intConst(0x7fffffffffffffffLL);
+ Value halfBits = intConst(0x3fe0000000000000LL);
+ Value oneBits = intConst(0x3ff0000000000000LL);
+
+ Value bits = arith::BitcastOp::create(b, intType, operand);
+ Value magnitude = arith::AndIOp::create(b, bits, magnitudeMask);
+ Value sign = arith::XOrIOp::create(b, bits, magnitude);
+ Value exponentField = arith::ShRUIOp::create(b, magnitude, cFractionBits);
+ Value exponent = arith::SubIOp::create(b, exponentField, cBias);
+ Value roundShift = arith::SubIOp::create(b, cRoundShiftBase, exponent);
+ roundShift = arith::AndIOp::create(b, roundShift, cShiftMask);
+ Value roundBit = arith::ShLIOp::create(b, one, roundShift);
+ Value mask =
+ arith::SubIOp::create(b, arith::ShLIOp::create(b, roundBit, one), one);
+ Value invertedMask = arith::XOrIOp::create(b, mask, allOnes);
+ Value incremented = arith::AddIOp::create(b, magnitude, roundBit);
+ Value roundedMagnitude = arith::AndIOp::create(b, incremented, invertedMask);
+ Value atLeastHalf =
+ arith::CmpIOp::create(b, arith::CmpIPredicate::uge, magnitude, halfBits);
+ Value smallMagnitude = arith::SelectOp::create(b, atLeastHalf, oneBits, zero);
+ Value isSmall =
+ arith::CmpIOp::create(b, arith::CmpIPredicate::slt, exponent, zero);
+ Value resultMagnitude =
+ arith::SelectOp::create(b, isSmall, smallMagnitude, roundedMagnitude);
+ Value isLarge = arith::CmpIOp::create(b, arith::CmpIPredicate::sge, exponent,
+ cFractionBits);
+ resultMagnitude =
+ arith::SelectOp::create(b, isLarge, magnitude, resultMagnitude);
+ Value resultBits = arith::OrIOp::create(b, resultMagnitude, sign);
+ rewriter.replaceOp(op, arith::BitcastOp::create(b, opType, resultBits));
+ return success();
+}
+
static LogicalResult convertRoundOp(math::RoundOp op,
PatternRewriter &rewriter) {
Location loc = op.getLoc();
@@ -860,6 +919,9 @@ struct MathExpandOpsPass final
SmallVector<StringRef> mnemonics =
llvm::to_vector_of<StringRef>(opMnemonics);
math::populateExpansionPatterns(patterns, mnemonics);
+ if (expandRoundF64 &&
+ (mnemonics.empty() || llvm::count(mnemonics, "round") > 0))
+ patterns.add(convertRoundF64Op);
if (failed(applyPatternsGreedily(getOperation(), std::move(patterns))))
return signalPassFailure();
}
diff --git a/mlir/test/Conversion/MathToLLVM/math-to-llvm.mlir b/mlir/test/Conversion/MathToLLVM/math-to-llvm.mlir
index 3dd9d74ba7043e..4dacba6c78085a 100644
--- a/mlir/test/Conversion/MathToLLVM/math-to-llvm.mlir
+++ b/mlir/test/Conversion/MathToLLVM/math-to-llvm.mlir
@@ -654,6 +654,39 @@ func.func @round(%arg0 : f32) {
// -----
+// CHECK-LABEL: func @round_f64(
+// CHECK-SAME: %[[ARG:.*]]: f64
+func.func @round_f64(%arg: f64) -> f64 {
+ // CHECK: %[[RESULT:.*]] = llvm.intr.round(%[[ARG]]) : (f64) -> f64
+ // CHECK: return %[[RESULT]]
+ %result = math.round %arg : f64
+ return %result : f64
+}
+
+// -----
+
+// CHECK-LABEL: func @round_vector_f64(
+// CHECK-SAME: %[[ARG:.*]]: vector<2xf64>
+func.func @round_vector_f64(%arg: vector<2xf64>) -> vector<2xf64> {
+ // CHECK: %[[RESULT:.*]] = llvm.intr.round(%[[ARG]]) : (vector<2xf64>) -> vector<2xf64>
+ // CHECK: return %[[RESULT]]
+ %result = math.round %arg : vector<2xf64>
+ return %result : vector<2xf64>
+}
+
+// -----
+
+// CHECK-LABEL: func @round_scalable_f64(
+// CHECK-SAME: %[[ARG:.*]]: vector<[2]xf64>
+func.func @round_scalable_f64(%arg: vector<[2]xf64>) -> vector<[2]xf64> {
+ // CHECK: %[[RESULT:.*]] = llvm.intr.round(%[[ARG]]) : (vector<[2]xf64>) -> vector<[2]xf64>
+ // CHECK: return %[[RESULT]]
+ %result = math.round %arg : vector<[2]xf64>
+ return %result : vector<[2]xf64>
+}
+
+// -----
+
// CHECK-LABEL: func @roundeven(
// CHECK-SAME: f32
func.func @roundeven(%arg0 : f32) {
diff --git a/mlir/test/Dialect/Math/expand-math.mlir b/mlir/test/Dialect/Math/expand-math.mlir
index 84b0bb0aa314ae..dcd4bfedf79a5f 100644
--- a/mlir/test/Dialect/Math/expand-math.mlir
+++ b/mlir/test/Dialect/Math/expand-math.mlir
@@ -1,5 +1,6 @@
// RUN: mlir-opt %s --split-input-file -math-expand-ops | FileCheck %s
// RUN: mlir-opt %s --split-input-file -math-expand-ops=ops=tanh,tan | FileCheck %s --check-prefix=CHECK-FILTER
+// RUN: mlir-opt %s --split-input-file -math-expand-ops=expand-round-f64=true | FileCheck %s --check-prefix=F64
// CHECK-LABEL: func @tanh
func.func @tanh(%arg: f32) -> f32 {
@@ -254,6 +255,52 @@ func.func @roundf_func(%a: f32) -> f32 {
// -----
+// CHECK-LABEL: func @round_f64_dynamic_tensor
+// CHECK: math.round
+// CHECK: return
+// F64-LABEL: func @round_f64_dynamic_tensor
+// F64: tensor.dim
+// F64: tensor.splat
+// F64: arith.bitcast %{{.*}} : tensor<?xf64> to tensor<?xi64>
+// F64: arith.andi
+// F64: arith.shli
+// F64-NOT: math.round
+// F64-NOT: scf.if
+// F64: return
+func.func @round_f64_dynamic_tensor(%arg: tensor<?xf64>) -> tensor<?xf64> {
+ %result = math.round %arg : tensor<?xf64>
+ return %result : tensor<?xf64>
+}
+
+// -----
+
+// CHECK-LABEL: func @round_f64_tensor
+// CHECK: math.round
+// CHECK: return
+// F64-LABEL: func @round_f64_tensor
+// F64: arith.bitcast %{{.*}} : tensor<2xf64> to tensor<2xi64>
+// F64: arith.shli
+// F64-NOT: math.round
+// F64-NOT: scf.if
+// F64: return
+func.func @round_f64_tensor(%arg: tensor<2xf64>) -> tensor<2xf64> {
+ %result = math.round %arg : tensor<2xf64>
+ return %result : tensor<2xf64>
+}
+
+// -----
+
+// CHECK-LABEL: func @round_f64_unranked
+// CHECK: math.round
+// F64-LABEL: func @round_f64_unranked
+// F64: math.round
+func.func @round_f64_unranked(%arg: tensor<*xf64>) -> tensor<*xf64> {
+ %result = math.round %arg : tensor<*xf64>
+ return %result : tensor<*xf64>
+}
+
+// -----
+
// CHECK-LABEL: func @powf_func
// CHECK-SAME: (%[[ARG0:.+]]: f64, %[[ARG1:.+]]: f64) -> f64
func.func @powf_func(%a: f64, %b: f64) -> f64 {
@@ -353,6 +400,10 @@ func.func @powf_func_three(%a: f64) -> f64{
// -----
// CHECK-LABEL: func.func @roundeven64
+// F64-LABEL: func.func @roundeven64
+// F64: arith.bitcast %{{.*}} : i64 to f64
+// F64-NOT: math.round
+// F64: return
func.func @roundeven64(%arg: f64) -> f64 {
%res = math.roundeven %arg : f64
return %res : f64
diff --git a/mlir/test/Dialect/Math/round-f64-expansion.mlir b/mlir/test/Dialect/Math/round-f64-expansion.mlir
new file mode 100644
index 00000000000000..6593e98bd8d9f4
--- /dev/null
+++ b/mlir/test/Dialect/Math/round-f64-expansion.mlir
@@ -0,0 +1,211 @@
+// RUN: mlir-opt %s -math-expand-ops | FileCheck %s --check-prefix=DEFAULT
+// RUN: mlir-opt %s -math-expand-ops=expand-round-f64=false | FileCheck %s --check-prefix=DEFAULT
+// RUN: mlir-opt %s -math-expand-ops="ops=roundeven expand-round-f64=true" | FileCheck %s --check-prefix=DEFAULT
+// RUN: mlir-opt %s -math-expand-ops="ops=round expand-round-f64=true" | FileCheck %s --check-prefix=ROUND-ONLY
+// RUN: mlir-opt %s -math-expand-ops=expand-round-f64=true | FileCheck %s --check-prefix=CHECK --enable-var-scope --implicit-check-not=scf.if --implicit-check-not=math.round
+// RUN: mlir-opt %s -math-expand-ops=expand-round-f64=true -inline -canonicalize | FileCheck %s --check-prefix=VALUES --enable-var-scope
+// RUN: mlir-opt %s -pass-pipeline='builtin.module(func.func(math-expand-ops{expand-round-f64=true},convert-math-to-llvm,convert-arith-to-llvm),convert-vector-to-llvm,convert-func-to-llvm,reconcile-unrealized-casts)' | FileCheck %s --check-prefix=LLVM --enable-var-scope --implicit-check-not=scf.if --implicit-check-not=llvm.cond_br
+
+// DEFAULT-LABEL: func.func @round_f64(
+// DEFAULT: math.round
+// ROUND-ONLY-LABEL: func.func @round_f64(
+// ROUND-ONLY: arith.shli
+// ROUND-ONLY-NOT: math.round
+// ROUND-ONLY: return
+// CHECK-LABEL: func.func @round_f64(
+// CHECK-DAG: %[[MASK:.*]] = arith.constant 63 : i64
+// CHECK: %[[SHIFT:.*]] = arith.andi %{{.*}}, %[[MASK]] : i64
+// CHECK: arith.shli %{{.*}}, %[[SHIFT]] : i64
+// CHECK: arith.select
+// CHECK: arith.bitcast %{{.*}} : i64 to f64
+// LLVM-LABEL: llvm.func @round_f64(
+// LLVM: llvm.shl
+// LLVM: llvm.select
+func.func @round_f64(%value: f64) -> f64 {
+ %result = math.round %value : f64
+ return %result : f64
+}
+
+// DEFAULT-LABEL: func.func @round_vector_f64(
+// DEFAULT: math.round
+// ROUND-ONLY-LABEL: func.func @round_vector_f64(
+// ROUND-ONLY: arith.shli
+// ROUND-ONLY-NOT: math.round
+// ROUND-ONLY: return
+// CHECK-LABEL: func.func @round_vector_f64(
+// CHECK-DAG: %[[MASK:.*]] = arith.constant dense<63> : vector<2xi64>
+// CHECK: %[[SHIFT:.*]] = arith.andi %{{.*}}, %[[MASK]] : vector<2xi64>
+// CHECK: arith.shli %{{.*}}, %[[SHIFT]] : vector<2xi64>
+// LLVM-LABEL: llvm.func @round_vector_f64(
+// LLVM: llvm.shl
+// LLVM: llvm.select
+func.func @round_vector_f64(%value: vector<2xf64>) -> vector<2xf64> {
+ %result = math.round %value : vector<2xf64>
+ return %result : vector<2xf64>
+}
+
+// DEFAULT-LABEL: func.func @round_scalable_f64(
+// DEFAULT: math.round
+// ROUND-ONLY-LABEL: func.func @round_scalable_f64(
+// ROUND-ONLY: arith.shli
+// ROUND-ONLY-NOT: math.round
+// ROUND-ONLY: return
+// CHECK-LABEL: func.func @round_scalable_f64(
+// CHECK-DAG: %[[MASK:.*]] = arith.constant dense<63> : vector<[2]xi64>
+// CHECK: %[[SHIFT:.*]] = arith.andi %{{.*}}, %[[MASK]] : vector<[2]xi64>
+// CHECK: arith.shli %{{.*}}, %[[SHIFT]] : vector<[2]xi64>
+// LLVM-LABEL: llvm.func @round_scalable_f64(
+// LLVM: llvm.shl
+// LLVM: llvm.select
+func.func @round_scalable_f64(%value: vector<[2]xf64>) -> vector<[2]xf64> {
+ %result = math.round %value : vector<[2]xf64>
+ return %result : vector<[2]xf64>
+}
+
+// LLVM-LABEL: llvm.func @masked_f64(
+// LLVM-SAME: %[[CHOOSE:[^ :]+]]: i1
+// LLVM: llvm.select %[[CHOOSE]],
+// LLVM: llvm.return
+func.func @masked_f64(%choose: i1, %value: f64) -> f64 {
+ %rounded = math.round %value : f64
+ %zero = arith.constant 0.0 : f64
+ %result = arith.select %choose, %rounded, %zero : f64
+ return %result : f64
+}
+
+// LLVM-LABEL: llvm.func @masked_vector_f64(
+// LLVM-SAME: %[[CHOOSE:[^ :]+]]: i1
+// LLVM: llvm.select %[[CHOOSE]],
+// LLVM: llvm.return
+func.func @masked_vector_f64(%choose: i1, %value: vector<2xf64>) -> vector<2xf64> {
+ %rounded = math.round %value : vector<2xf64>
+ %zero = arith.constant dense<0.0> : vector<2xf64>
+ %result = arith.select %choose, %rounded, %zero : vector<2xf64>
+ return %result : vector<2xf64>
+}
+
+// LLVM-LABEL: llvm.func @masked_scalable_f64(
+// LLVM-SAME: %[[CHOOSE:[^ :]+]]: i1
+// LLVM: llvm.select %[[CHOOSE]],
+// LLVM: llvm.return
+func.func @masked_scalable_f64(%choose: i1, %value: vector<[2]xf64>) -> vector<[2]xf64> {
+ %rounded = math.round %value : vector<[2]xf64>
+ %zero = arith.constant dense<0.0> : vector<[2]xf64>
+ %result = arith.select %choose, %rounded, %zero : vector<[2]xf64>
+ return %result : vector<[2]xf64>
+}
+
+// VALUES-LABEL: func.func @half_neighbors(
+// VALUES: %[[EXPECTED:.*]] = arith.constant dense<[0, 4607182418800017408]> : vector<2xi64>
+// VALUES-NEXT: return %[[EXPECTED]] : vector<2xi64>
+func.func @half_neighbors() -> vector<2xi64> {
+ %input = arith.constant dense<[4602678819172646911, 4602678819172646912]> : vector<2xi64>
+ %value = arith.bitcast %input : vector<2xi64> to vector<2xf64>
+ %rounded = func.call @round_vector_f64(%value) : (vector<2xf64>) -> vector<2xf64>
+ %result = arith.bitcast %rounded : vector<2xf64> to vector<2xi64>
+ return %result : vector<2xi64>
+}
+
+// VALUES-LABEL: func.func @ties(
+// VALUES: %[[EXPECTED:.*]] = arith.constant dense<[4611686018427387904, -4609434218613702656]> : vector<2xi64>
+// VALUES-NEXT: return %[[EXPECTED]] : vector<2xi64>
+func.func @ties() -> vector<2xi64> {
+ %input = arith.constant dense<[4609434218613702656, -4610560118520545280]> : vector<2xi64>
+ %value = arith.bitcast %input : vector<2xi64> to vector<2xf64>
+ %rounded = func.call @round_vector_f64(%value) : (vector<2xf64>) -> vector<2xf64>
+ %result = arith.bitcast %rounded : vector<2xf64> to vector<2xi64>
+ return %result : vector<2xi64>
+}
+
+// VALUES-LABEL: func.func @signed_subnormals(
+// VALUES: %[[EXPECTED:.*]] = arith.constant dense<[0, -9223372036854775808]> : vector<2xi64>
+// VALUES-NEXT: return %[[EXPECTED]] : vector<2xi64>
+func.func @signed_subnormals() -> vector<2xi64> {
+ %input = arith.constant dense<[1, -9223372036854775807]> : vector<2xi64>
+ %value = arith.bitcast %input : vector<2xi64> to vector<2xf64>
+ %rounded = func.call @round_vector_f64(%value) : (vector<2xf64>) -> vector<2xf64>
+ %result = arith.bitcast %rounded : vector<2xf64> to vector<2xi64>
+ return %result : vector<2xi64>
+}
+
+// VALUES-LABEL: func.func @large_boundary(
+// VALUES: %[[EXPECTED:.*]] = arith.constant dense<[4841369599423283200, 4841369599423283201]> : vector<2xi64>
+// VALUES-NEXT: return %[[EXPECTED]] : vector<2xi64>
+func.func @large_boundary() -> vector<2xi64> {
+ %input = arith.constant dense<[4841369599423283199, 4841369599423283201]> : vector<2xi64>
+ %value = arith.bitcast %input : vector<2xi64> to vector<2xf64>
+ %rounded = func.call @round_vector_f64(%value) : (vector<2xf64>) -> vector<2xf64>
+ %result = arith.bitcast %rounded : vector<2xf64> to vector<2xi64>
+ return %result : vector<2xi64>
+}
+
+// VALUES-LABEL: func.func @special_values(
+// VALUES: %[[EXPECTED:.*]] = arith.constant dense<[9218868437227405312, 9221120237041095220]> : vector<2xi64>
+// VALUES-NEXT: return %[[EXPECTED]] : vector<2xi64>
+func.func @special_values() -> vector<2xi64> {
+ %input = arith.constant dense<[9218868437227405312, 9221120237041095220]> : vector<2xi64>
+ %value = arith.bitcast %input : vector<2xi64> to vector<2xf64>
+ %rounded = func.call @round_vector_f64(%value) : (vector<2xf64>) -> vector<2xf64>
+ %result = arith.bitcast %rounded : vector<2xf64> to vector<2xi64>
+ return %result : vector<2xi64>
+}
+
+// VALUES-LABEL: func.func @negative_zero(
+// VALUES: %[[EXPECTED:.*]] = arith.constant -9223372036854775808 : i64
+// VALUES-NEXT: return %[[EXPECTED]] : i64
+func.func @negative_zero() -> i64 {
+ %input = arith.constant -9223372036854775808 : i64
+ %value = arith.bitcast %input : i64 to f64
+ %rounded = func.call @round_f64(%value) : (f64) -> f64
+ %result = arith.bitcast %rounded : f64 to i64
+ return %result : i64
+}
+
+// VALUES-LABEL: func.func @negative_infinity(
+// VALUES: %[[EXPECTED:.*]] = arith.constant -4503599627370496 : i64
+// VALUES-NEXT: return %[[EXPECTED]] : i64
+func.func @negative_infinity() -> i64 {
+ %input = arith.constant -4503599627370496 : i64
+ %value = arith.bitcast %input : i64 to f64
+ %rounded = func.call @round_f64(%value) : (f64) -> f64
+ %result = arith.bitcast %rounded : f64 to i64
+ return %result : i64
+}
+
+// VALUES-LABEL: func.func @signaling_nan(
+// VALUES: %[[EXPECTED:.*]] = arith.constant 9218868437227405313 : i64
+// VALUES-NEXT: return %[[EXPECTED]] : i64
+func.func @signaling_nan() -> i64 {
+ %input = arith.constant 9218868437227405313 : i64
+ %value = arith.bitcast %input : i64 to f64
+ %rounded = func.call @round_f64(%value) : (f64) -> f64
+ %result = arith.bitcast %rounded : f64 to i64
+ return %result : i64
+}
+
+// DEFAULT-LABEL: func.func @roundeven_f64(
+// ROUND-ONLY-LABEL: func.func @roundeven_f64(
+// ROUND-ONLY: math.roundeven
+// DEFAULT: math.round
+// DEFAULT-NOT: math.roundeven
+// DEFAULT: return
+// CHECK-LABEL: func.func @roundeven_f64(
+// CHECK: arith.shli
+// CHECK: return
+// LLVM-LABEL: llvm.func @roundeven_f64(
+// LLVM: llvm.shl
+// LLVM: llvm.return
+func.func @roundeven_f64(%value: f64) -> f64 {
+ %result = math.roundeven %value : f64
+ return %result : f64
+}
+
+// VALUES-LABEL: func.func @even_tie(
+// VALUES: %[[EXPECTED:.*]] = arith.constant 4611686018427387904 : i64
+// VALUES-NEXT: return %[[EXPECTED]] : i64
+func.func @even_tie() -> i64 {
+ %value = arith.constant 2.5 : f64
+ %rounded = func.call @roundeven_f64(%value) : (f64) -> f64
+ %result = arith.bitcast %rounded : f64 to i64
+ return %result : i64
+}
More information about the Mlir-commits
mailing list