[Mlir-commits] [mlir] [mlir][arith] Add `arith.fptofp` op (PR #188041)
Matthias Springer
llvmlistbot at llvm.org
Mon Mar 23 06:44:56 PDT 2026
https://github.com/matthias-springer created https://github.com/llvm/llvm-project/pull/188041
There are multiple FP types with the same bitwidth. Neither `extf` nor `truncf` can be used in that case. Add a new `arith.fptofp` op that can be used in such cases. The op is modeled after `arith.truncf`. Also add a lowering to LLVM.
Assisted-by: claude-4.6-opus-high
>From 9f464e76a28a9c1f9ffc3af304876fac46e69888 Mon Sep 17 00:00:00 2001
From: Matthias Springer <me at m-sp.org>
Date: Mon, 23 Mar 2026 13:42:54 +0000
Subject: [PATCH] [mlir][arith] Add `arith.fptofp` op
---
.../include/mlir/Dialect/Arith/IR/ArithOps.td | 34 +++++
.../Conversion/ArithToLLVM/ArithToLLVM.cpp | 70 +++++++++++
mlir/lib/Dialect/Arith/IR/ArithOps.cpp | 44 +++++++
.../Conversion/ArithToLLVM/arith-to-llvm.mlir | 116 ++++++++++++++++++
mlir/test/Dialect/Arith/canonicalize.mlir | 11 ++
mlir/test/Dialect/Arith/invalid.mlir | 40 ++++++
mlir/test/Dialect/Arith/ops.mlir | 80 ++++++++++++
7 files changed, 395 insertions(+)
diff --git a/mlir/include/mlir/Dialect/Arith/IR/ArithOps.td b/mlir/include/mlir/Dialect/Arith/IR/ArithOps.td
index 4b830c05bf585..06ff3f9eeac44 100644
--- a/mlir/include/mlir/Dialect/Arith/IR/ArithOps.td
+++ b/mlir/include/mlir/Dialect/Arith/IR/ArithOps.td
@@ -1425,6 +1425,40 @@ def Arith_TruncFOp :
attr-dict `:` type($in) `to` type($out) }];
}
+//===----------------------------------------------------------------------===//
+// FPToFPOp
+//===----------------------------------------------------------------------===//
+
+def Arith_FPToFPOp :
+ Arith_Op<"fptofp",
+ [Pure, SameOperandsAndResultShape, SameInputOutputTensorDims,
+ DeclareOpInterfaceMethods<ArithRoundingModeInterface>,
+ DeclareOpInterfaceMethods<ArithFastMathInterface>,
+ DeclareOpInterfaceMethods<CastOpInterface>]>,
+ Arguments<(ins FloatLike:$in,
+ OptionalAttr<Arith_RoundingModeAttr>:$roundingmode,
+ OptionalAttr<Arith_FastMathAttr>:$fastmath)>,
+ Results<(outs FloatLike:$out)> {
+ let summary = "cast between floating-point types";
+ let description = [{
+ Cast a floating-point value to a different floating-point type. Unlike
+ `arith.extf` and `arith.truncf`, this operation supports arbitrary
+ conversions between floating-point types, including conversions between
+ types of the same bitwidth but different semantics (e.g., f16 to bf16).
+
+ The source and destination element types must be different. If the value
+ cannot be exactly represented, it is rounded using the provided rounding
+ mode or the default one if no rounding mode is provided. When operating
+ on vectors, casts elementwise.
+ }];
+
+ let hasFolder = 1;
+ let hasVerifier = 1;
+ let assemblyFormat = [{ $in ($roundingmode^)?
+ (`fastmath` `` $fastmath^)?
+ attr-dict `:` type($in) `to` type($out) }];
+}
+
//===----------------------------------------------------------------------===//
// Scaling TruncFOp
//===----------------------------------------------------------------------===//
diff --git a/mlir/lib/Conversion/ArithToLLVM/ArithToLLVM.cpp b/mlir/lib/Conversion/ArithToLLVM/ArithToLLVM.cpp
index e7f561e8a4d67..a6fe481304c06 100644
--- a/mlir/lib/Conversion/ArithToLLVM/ArithToLLVM.cpp
+++ b/mlir/lib/Conversion/ArithToLLVM/ArithToLLVM.cpp
@@ -262,6 +262,75 @@ struct CmpFOpLowering : public ConvertOpToLLVMPattern<arith::CmpFOp> {
ConversionPatternRewriter &rewriter) const override;
};
+/// Lower arith.fptofp to the appropriate LLVM op(s).
+///
+/// - If src is wider than dst: llvm.fptrunc
+/// - If src is narrower than dst: llvm.fpext
+/// - bf16 <-> f16: llvm.fpext to f32, then llvm.fptrunc to dst.
+/// - Other FP types: not supported by the LLVM dialect.
+struct FPToFPOpLowering : public ConvertOpToLLVMPattern<arith::FPToFPOp> {
+ using ConvertOpToLLVMPattern::ConvertOpToLLVMPattern;
+
+ LogicalResult
+ matchAndRewrite(arith::FPToFPOp op, OpAdaptor adaptor,
+ ConversionPatternRewriter &rewriter) const override {
+ if (LLVM::detail::opHasUnsupportedFloatingPointTypes(op,
+ *getTypeConverter()))
+ return rewriter.notifyMatchFailure(op, "unsupported floating point type");
+
+ auto srcFloat = cast<FloatType>(getElementTypeOrSelf(op.getIn().getType()));
+ auto dstFloat = cast<FloatType>(getElementTypeOrSelf(op.getType()));
+
+ Type convertedType = getTypeConverter()->convertType(op.getType());
+ if (!convertedType)
+ return rewriter.notifyMatchFailure(op, "failed to convert result type");
+
+ Value input = adaptor.getIn();
+ Location loc = op.getLoc();
+ Type operandType = input.getType();
+
+ if (!isa<LLVM::LLVMArrayType>(operandType)) {
+ rewriter.replaceOp(op, emitConversion(rewriter, loc, input, convertedType,
+ srcFloat, dstFloat));
+ return success();
+ }
+
+ if (!isa<VectorType>(op.getType()))
+ return rewriter.notifyMatchFailure(op, "expected vector result type");
+
+ return LLVM::detail::handleMultidimensionalVectors(
+ op.getOperation(), adaptor.getOperands(), *getTypeConverter(),
+ [&](Type llvm1DVectorTy, ValueRange operands) -> Value {
+ return emitConversion(rewriter, loc, operands.front(), llvm1DVectorTy,
+ srcFloat, dstFloat);
+ },
+ rewriter);
+ }
+
+private:
+ static Value emitConversion(ConversionPatternRewriter &rewriter, Location loc,
+ Value input, Type targetType, FloatType srcFloat,
+ FloatType dstFloat) {
+ unsigned srcWidth = srcFloat.getWidth();
+ unsigned dstWidth = dstFloat.getWidth();
+ if (srcWidth > dstWidth)
+ return LLVM::FPTruncOp::create(rewriter, loc, targetType, input);
+ if (srcWidth < dstWidth)
+ return LLVM::FPExtOp::create(rewriter, loc, targetType, input);
+
+ // Same width, different semantics: bf16 <-> f16
+ assert((srcFloat.isBF16() && dstFloat.isF16() ||
+ srcFloat.isF16() && dstFloat.isBF16()) &&
+ "only bf16 <-> f16 conversions are supported");
+ Type f32Scalar = Float32Type::get(rewriter.getContext());
+ Type f32Ty = f32Scalar;
+ if (auto vecTy = dyn_cast<VectorType>(targetType))
+ f32Ty = VectorType::get(vecTy.getShape(), f32Scalar);
+ Value ext = LLVM::FPExtOp::create(rewriter, loc, f32Ty, input);
+ return LLVM::FPTruncOp::create(rewriter, loc, targetType, ext);
+ }
+};
+
struct SelectOpOneToNLowering : public ConvertOpToLLVMPattern<arith::SelectOp> {
using ConvertOpToLLVMPattern::ConvertOpToLLVMPattern;
using Adaptor = ConvertOpToLLVMPattern<arith::SelectOp>::OneToNOpAdaptor;
@@ -642,6 +711,7 @@ void mlir::arith::populateArithToLLVMConversionPatterns(
ExtFOpLowering,
ExtSIOpLowering,
ExtUIOpLowering,
+ FPToFPOpLowering,
FPToSIOpLowering,
FPToUIOpLowering,
IndexCastOpSILowering,
diff --git a/mlir/lib/Dialect/Arith/IR/ArithOps.cpp b/mlir/lib/Dialect/Arith/IR/ArithOps.cpp
index 155edc5070a9d..774eeb03536be 100644
--- a/mlir/lib/Dialect/Arith/IR/ArithOps.cpp
+++ b/mlir/lib/Dialect/Arith/IR/ArithOps.cpp
@@ -1699,6 +1699,50 @@ LogicalResult arith::TruncFOp::verify() {
return verifyTruncateOp<FloatType>(*this);
}
+//===----------------------------------------------------------------------===//
+// FPToFPOp
+//===----------------------------------------------------------------------===//
+
+OpFoldResult arith::FPToFPOp::fold(FoldAdaptor adaptor) {
+ auto resElemType = cast<FloatType>(getElementTypeOrSelf(getType()));
+ const llvm::fltSemantics &targetSemantics = resElemType.getFloatSemantics();
+ return constFoldCastOp<FloatAttr, FloatAttr>(
+ adaptor.getOperands(), getType(),
+ [this, &targetSemantics](const APFloat &a, bool &castStatus) {
+ RoundingMode roundingMode =
+ getRoundingmode().value_or(RoundingMode::to_nearest_even);
+ llvm::RoundingMode llvmRoundingMode =
+ convertArithRoundingModeToLLVMIR(roundingMode);
+ FailureOr<APFloat> result =
+ convertFloatValue(a, targetSemantics, llvmRoundingMode);
+ if (failed(result)) {
+ castStatus = false;
+ return a;
+ }
+ return *result;
+ });
+}
+
+bool arith::FPToFPOp::areCastCompatible(TypeRange inputs, TypeRange outputs) {
+ if (!areValidCastInputsAndOutputs(inputs, outputs))
+ return false;
+ auto srcType = getTypeIfLike<FloatType>(inputs.front());
+ auto dstType = getTypeIfLike<FloatType>(outputs.front());
+ if (!srcType || !dstType)
+ return false;
+ return srcType != dstType;
+}
+
+LogicalResult arith::FPToFPOp::verify() {
+ Type srcType = getElementTypeOrSelf(getIn().getType());
+ Type dstType = getElementTypeOrSelf(getType());
+ if (srcType == dstType)
+ return emitError("result element type ")
+ << dstType << " must be different from operand element type "
+ << srcType;
+ return success();
+}
+
//===----------------------------------------------------------------------===//
// ScalingTruncFOp
//===----------------------------------------------------------------------===//
diff --git a/mlir/test/Conversion/ArithToLLVM/arith-to-llvm.mlir b/mlir/test/Conversion/ArithToLLVM/arith-to-llvm.mlir
index 47069906fa110..5c43639442338 100644
--- a/mlir/test/Conversion/ArithToLLVM/arith-to-llvm.mlir
+++ b/mlir/test/Conversion/ArithToLLVM/arith-to-llvm.mlir
@@ -838,3 +838,119 @@ func.func @supported_fp_type(%arg0: f32, %arg1: vector<4xf32>, %arg2: vector<4x8
%3 = arith.cmpf oeq, %arg0, %arg3 : f32
return
}
+
+// -----
+
+// CHECK-LABEL: func @fptofp_ext(
+// CHECK-SAME: %[[ARG0:.*]]: f16, %[[ARG1:.*]]: f32)
+func.func @fptofp_ext(%arg0 : f16, %arg1 : f32) {
+// CHECK-NEXT: = llvm.fpext %[[ARG0]] : f16 to f32
+ %0 = arith.fptofp %arg0 : f16 to f32
+// CHECK-NEXT: = llvm.fpext %[[ARG0]] : f16 to f64
+ %1 = arith.fptofp %arg0 : f16 to f64
+// CHECK-NEXT: = llvm.fpext %[[ARG1]] : f32 to f64
+ %2 = arith.fptofp %arg1 : f32 to f64
+ return
+}
+
+// -----
+
+// CHECK-LABEL: func @fptofp_trunc(
+// CHECK-SAME: %[[ARG0:.*]]: f32, %[[ARG1:.*]]: f64)
+func.func @fptofp_trunc(%arg0 : f32, %arg1 : f64) {
+// CHECK-NEXT: = llvm.fptrunc %[[ARG0]] : f32 to f16
+ %0 = arith.fptofp %arg0 : f32 to f16
+// CHECK-NEXT: = llvm.fptrunc %[[ARG1]] : f64 to f16
+ %1 = arith.fptofp %arg1 : f64 to f16
+// CHECK-NEXT: = llvm.fptrunc %[[ARG1]] : f64 to f32
+ %2 = arith.fptofp %arg1 : f64 to f32
+ return
+}
+
+// -----
+
+// bf16 <-> f16: same width, different semantics. Lowered via f32.
+// CHECK-LABEL: func @fptofp_same_width(
+// CHECK-SAME: %[[ARG0:.*]]: bf16, %[[ARG1:.*]]: f16)
+func.func @fptofp_same_width(%arg0 : bf16, %arg1 : f16) {
+// CHECK-NEXT: %[[EXT0:.*]] = llvm.fpext %[[ARG0]] : bf16 to f32
+// CHECK-NEXT: = llvm.fptrunc %[[EXT0]] : f32 to f16
+ %0 = arith.fptofp %arg0 : bf16 to f16
+// CHECK-NEXT: %[[EXT1:.*]] = llvm.fpext %[[ARG1]] : f16 to f32
+// CHECK-NEXT: = llvm.fptrunc %[[EXT1]] : f32 to bf16
+ %1 = arith.fptofp %arg1 : f16 to bf16
+ return
+}
+
+// -----
+
+// CHECK-LABEL: func @fptofp_ext_vector(
+// CHECK-SAME: %[[ARG0:.*]]: vector<2xf16>, %[[ARG1:.*]]: vector<2xf32>)
+func.func @fptofp_ext_vector(%arg0 : vector<2xf16>, %arg1 : vector<2xf32>) {
+// CHECK-NEXT: = llvm.fpext %[[ARG0]] : vector<2xf16> to vector<2xf32>
+ %0 = arith.fptofp %arg0 : vector<2xf16> to vector<2xf32>
+// CHECK-NEXT: = llvm.fpext %[[ARG0]] : vector<2xf16> to vector<2xf64>
+ %1 = arith.fptofp %arg0 : vector<2xf16> to vector<2xf64>
+// CHECK-NEXT: = llvm.fpext %[[ARG1]] : vector<2xf32> to vector<2xf64>
+ %2 = arith.fptofp %arg1 : vector<2xf32> to vector<2xf64>
+ return
+}
+
+// -----
+
+// CHECK-LABEL: func @fptofp_trunc_vector(
+// CHECK-SAME: %[[ARG0:.*]]: vector<2xf32>, %[[ARG1:.*]]: vector<2xf64>)
+func.func @fptofp_trunc_vector(%arg0 : vector<2xf32>, %arg1 : vector<2xf64>) {
+// CHECK-NEXT: = llvm.fptrunc %[[ARG0]] : vector<2xf32> to vector<2xf16>
+ %0 = arith.fptofp %arg0 : vector<2xf32> to vector<2xf16>
+// CHECK-NEXT: = llvm.fptrunc %[[ARG1]] : vector<2xf64> to vector<2xf16>
+ %1 = arith.fptofp %arg1 : vector<2xf64> to vector<2xf16>
+// CHECK-NEXT: = llvm.fptrunc %[[ARG1]] : vector<2xf64> to vector<2xf32>
+ %2 = arith.fptofp %arg1 : vector<2xf64> to vector<2xf32>
+ return
+}
+
+// -----
+
+// CHECK-LABEL: func @fptofp_same_width_vector(
+// CHECK-SAME: %[[ARG0:.*]]: vector<2xbf16>, %[[ARG1:.*]]: vector<2xf16>)
+func.func @fptofp_same_width_vector(%arg0 : vector<2xbf16>, %arg1 : vector<2xf16>) {
+// CHECK-NEXT: %[[EXT0:.*]] = llvm.fpext %[[ARG0]] : vector<2xbf16> to vector<2xf32>
+// CHECK-NEXT: = llvm.fptrunc %[[EXT0]] : vector<2xf32> to vector<2xf16>
+ %0 = arith.fptofp %arg0 : vector<2xbf16> to vector<2xf16>
+// CHECK-NEXT: %[[EXT1:.*]] = llvm.fpext %[[ARG1]] : vector<2xf16> to vector<2xf32>
+// CHECK-NEXT: = llvm.fptrunc %[[EXT1]] : vector<2xf32> to vector<2xbf16>
+ %1 = arith.fptofp %arg1 : vector<2xf16> to vector<2xbf16>
+ return
+}
+
+// -----
+
+// Multi-dimensional vectors are unrolled.
+// CHECK-LABEL: @fptofp_ext_multidim_vector
+func.func @fptofp_ext_multidim_vector(%arg0 : vector<2x3xf16>) {
+// CHECK-COUNT-2: llvm.fpext %{{.*}} : vector<3xf16> to vector<3xf32>
+ %0 = arith.fptofp %arg0 : vector<2x3xf16> to vector<2x3xf32>
+ return
+}
+
+// -----
+
+// CHECK-LABEL: @fptofp_trunc_multidim_vector
+func.func @fptofp_trunc_multidim_vector(%arg0 : vector<2x3xf64>) {
+// CHECK-COUNT-2: llvm.fptrunc %{{.*}} : vector<3xf64> to vector<3xf32>
+ %0 = arith.fptofp %arg0 : vector<2x3xf64> to vector<2x3xf32>
+ return
+}
+
+// -----
+
+// CHECK-LABEL: @fptofp_same_width_multidim_vector
+func.func @fptofp_same_width_multidim_vector(%arg0 : vector<2x3xbf16>) {
+// CHECK: llvm.fpext %{{.*}} : vector<3xbf16> to vector<3xf32>
+// CHECK: llvm.fptrunc %{{.*}} : vector<3xf32> to vector<3xf16>
+// CHECK: llvm.fpext %{{.*}} : vector<3xbf16> to vector<3xf32>
+// CHECK: llvm.fptrunc %{{.*}} : vector<3xf32> to vector<3xf16>
+ %0 = arith.fptofp %arg0 : vector<2x3xbf16> to vector<2x3xf16>
+ return
+}
diff --git a/mlir/test/Dialect/Arith/canonicalize.mlir b/mlir/test/Dialect/Arith/canonicalize.mlir
index 643e4e076e7c6..5d3bc34636669 100644
--- a/mlir/test/Dialect/Arith/canonicalize.mlir
+++ b/mlir/test/Dialect/Arith/canonicalize.mlir
@@ -3553,3 +3553,14 @@ func.func @truncf_neg_inf_to_finite_only_no_fold() -> f4E2M1FN {
return %result : f4E2M1FN
}
+// -----
+
+// CHECK-LABEL: @fptofp_fold_f8
+// CHECK: %[[C:.*]] = arith.constant 2.000000e+00 : f8E5M2
+// CHECK: return %[[C]]
+func.func @fptofp_fold_f8() -> f8E5M2 {
+ %c = arith.constant 2.0 : f8E4M3FN
+ %result = arith.fptofp %c : f8E4M3FN to f8E5M2
+ return %result : f8E5M2
+}
+
diff --git a/mlir/test/Dialect/Arith/invalid.mlir b/mlir/test/Dialect/Arith/invalid.mlir
index 0ea614e0d4b97..722d36d6448be 100644
--- a/mlir/test/Dialect/Arith/invalid.mlir
+++ b/mlir/test/Dialect/Arith/invalid.mlir
@@ -1016,3 +1016,43 @@ func.func @index_castui_i0(%a: i0) -> index {
%0 = arith.index_castui %a : i0 to index
return %0 : index
}
+
+// -----
+
+func.func @fptofp_same_type(%arg0 : f32) {
+ // expected-error @+1 {{are cast incompatible}}
+ %0 = arith.fptofp %arg0 : f32 to f32
+ return
+}
+
+// -----
+
+func.func @fptofp_same_type_vec(%arg0 : vector<2xf16>) {
+ // expected-error @+1 {{are cast incompatible}}
+ %0 = arith.fptofp %arg0 : vector<2xf16> to vector<2xf16>
+ return
+}
+
+// -----
+
+func.func @fptofp_shape_mismatch(%arg0 : vector<2xf16>) {
+ // expected-error @+1 {{op requires the same shape for all operands and results}}
+ %0 = arith.fptofp %arg0 : vector<2xf16> to vector<3xf32>
+ return
+}
+
+// -----
+
+func.func @fptofp_int_input(%arg0 : i32) {
+ // expected-error @+1 {{op operand #0 must be floating-point-like, but got 'i32'}}
+ %0 = arith.fptofp %arg0 : i32 to f32
+ return
+}
+
+// -----
+
+func.func @fptofp_int_output(%arg0 : f32) {
+ // expected-error @+1 {{op result #0 must be floating-point-like, but got 'i32'}}
+ %0 = arith.fptofp %arg0 : f32 to i32
+ return
+}
diff --git a/mlir/test/Dialect/Arith/ops.mlir b/mlir/test/Dialect/Arith/ops.mlir
index 9765db69d6dd5..97a359357819f 100644
--- a/mlir/test/Dialect/Arith/ops.mlir
+++ b/mlir/test/Dialect/Arith/ops.mlir
@@ -1228,3 +1228,83 @@ func.func @intflags_func(%arg0: i64, %arg1: i64) {
%4 = arith.trunci %arg0 overflow<nsw, nuw> : i64 to i32
return
}
+
+// CHECK-LABEL: func @test_fptofp(
+// CHECK-SAME: %[[ARG0:.*]]: f16
+func.func @test_fptofp(%arg0 : f16) -> f32 {
+ // CHECK: arith.fptofp %[[ARG0]] : f16 to f32
+ %0 = arith.fptofp %arg0 : f16 to f32
+ return %0 : f32
+}
+
+// CHECK-LABEL: func @test_fptofp_bf16_to_f16(
+// CHECK-SAME: %[[ARG0:.*]]: bf16
+func.func @test_fptofp_bf16_to_f16(%arg0 : bf16) -> f16 {
+ // CHECK: arith.fptofp %[[ARG0]] : bf16 to f16
+ %0 = arith.fptofp %arg0 : bf16 to f16
+ return %0 : f16
+}
+
+// CHECK-LABEL: func @test_fptofp_vector(
+// CHECK-SAME: %[[ARG0:.*]]: vector<8xf16>
+func.func @test_fptofp_vector(%arg0 : vector<8xf16>) -> vector<8xf32> {
+ // CHECK: arith.fptofp %[[ARG0]] : vector<8xf16> to vector<8xf32>
+ %0 = arith.fptofp %arg0 : vector<8xf16> to vector<8xf32>
+ return %0 : vector<8xf32>
+}
+
+// CHECK-LABEL: func @test_fptofp_scalable_vector(
+// CHECK-SAME: %[[ARG0:.*]]: vector<[8]xf16>
+func.func @test_fptofp_scalable_vector(%arg0 : vector<[8]xf16>) -> vector<[8]xf32> {
+ // CHECK: arith.fptofp %[[ARG0]] : vector<[8]xf16> to vector<[8]xf32>
+ %0 = arith.fptofp %arg0 : vector<[8]xf16> to vector<[8]xf32>
+ return %0 : vector<[8]xf32>
+}
+
+// CHECK-LABEL: func @test_fptofp_tensor(
+// CHECK-SAME: %[[ARG0:.*]]: tensor<8x8xf32>
+func.func @test_fptofp_tensor(%arg0 : tensor<8x8xf32>) -> tensor<8x8xf64> {
+ // CHECK: arith.fptofp %[[ARG0]] : tensor<8x8xf32> to tensor<8x8xf64>
+ %0 = arith.fptofp %arg0 : tensor<8x8xf32> to tensor<8x8xf64>
+ return %0 : tensor<8x8xf64>
+}
+
+// CHECK-LABEL: func @test_fptofp_tensor_encoding(
+// CHECK-SAME: %[[ARG0:.*]]: tensor<8x8xf32, "foo">
+func.func @test_fptofp_tensor_encoding(%arg0 : tensor<8x8xf32, "foo">) -> tensor<8x8xf64, "foo"> {
+ // CHECK: arith.fptofp %[[ARG0]] : tensor<8x8xf32, "foo"> to tensor<8x8xf64, "foo">
+ %0 = arith.fptofp %arg0 : tensor<8x8xf32, "foo"> to tensor<8x8xf64, "foo">
+ return %0 : tensor<8x8xf64, "foo">
+}
+
+// CHECK-LABEL: func @test_fptofp_rounding_mode(
+// CHECK-SAME: %[[ARG0:.*]]: f64
+func.func @test_fptofp_rounding_mode(%arg0 : f64) -> (f32, f32, f32, f32, f32) {
+ // CHECK: arith.fptofp %[[ARG0]] to_nearest_even : f64 to f32
+ %0 = arith.fptofp %arg0 to_nearest_even : f64 to f32
+ // CHECK: arith.fptofp %[[ARG0]] downward : f64 to f32
+ %1 = arith.fptofp %arg0 downward : f64 to f32
+ // CHECK: arith.fptofp %[[ARG0]] upward : f64 to f32
+ %2 = arith.fptofp %arg0 upward : f64 to f32
+ // CHECK: arith.fptofp %[[ARG0]] toward_zero : f64 to f32
+ %3 = arith.fptofp %arg0 toward_zero : f64 to f32
+ // CHECK: arith.fptofp %[[ARG0]] to_nearest_away : f64 to f32
+ %4 = arith.fptofp %arg0 to_nearest_away : f64 to f32
+ return %0, %1, %2, %3, %4 : f32, f32, f32, f32, f32
+}
+
+// CHECK-LABEL: func @test_fptofp_fastmath(
+// CHECK-SAME: %[[ARG0:.*]]: f32
+func.func @test_fptofp_fastmath(%arg0 : f32) -> f64 {
+ // CHECK: arith.fptofp %[[ARG0]] fastmath<nnan> : f32 to f64
+ %0 = arith.fptofp %arg0 fastmath<nnan> : f32 to f64
+ return %0 : f64
+}
+
+// CHECK-LABEL: func @test_fptofp_rounding_mode_and_fastmath(
+// CHECK-SAME: %[[ARG0:.*]]: f64
+func.func @test_fptofp_rounding_mode_and_fastmath(%arg0 : f64) -> f32 {
+ // CHECK: arith.fptofp %[[ARG0]] to_nearest_even fastmath<nnan> : f64 to f32
+ %0 = arith.fptofp %arg0 to_nearest_even fastmath<nnan> : f64 to f32
+ return %0 : f32
+}
More information about the Mlir-commits
mailing list