[flang-commits] [flang] [flang] Respect math flags during conversions (PR #214311)
via flang-commits
flang-commits at lists.llvm.org
Wed Aug 5 11:51:46 PDT 2026
https://github.com/jon-gibney created https://github.com/llvm/llvm-project/pull/214311
We normally use saturating intrinsics when converting from fp to integers, but when running with -ffast-math we can just use fptosi/fptoui, which avoids generating expensive overflow/NAN checks.
Assisted-by: Claude Opus
>From 8e13402cbbeee8ab3610fa1ca2b9dd4ad477b585 Mon Sep 17 00:00:00 2001
From: Jon Gibney <jonathon.gibney at hpe.com>
Date: Mon, 3 Aug 2026 12:49:45 -0500
Subject: [PATCH] [flang] Respect math flags during conversions
We normally use saturating intrinsics when converting from fp to
integers, but when running with -ffast-math we can just use
fptosi/fptoui, which avoids generating expensive overflow/NAN
checks.
Assisted-by: Claude Opus
---
.../include/flang/Optimizer/CodeGen/CodeGen.h | 2 +
flang/lib/Optimizer/CodeGen/CodeGen.cpp | 36 +++++++++-----
flang/lib/Optimizer/Passes/Pipelines.cpp | 1 +
.../test/Integration/unsafe-fp-conversion.f90 | 47 +++++++++++++++++++
4 files changed, 74 insertions(+), 12 deletions(-)
create mode 100644 flang/test/Integration/unsafe-fp-conversion.f90
diff --git a/flang/include/flang/Optimizer/CodeGen/CodeGen.h b/flang/include/flang/Optimizer/CodeGen/CodeGen.h
index b7a9397edfe6d..283b7226b6e3c 100644
--- a/flang/include/flang/Optimizer/CodeGen/CodeGen.h
+++ b/flang/include/flang/Optimizer/CodeGen/CodeGen.h
@@ -65,6 +65,8 @@ struct FIRToLLVMPassOptions {
// Conversion pass of the MLIR complex dialect.
Fortran::frontend::CodeGenOptions::ComplexRangeKind ComplexRange =
Fortran::frontend::CodeGenOptions::ComplexRangeKind::CX_Full;
+
+ bool unsafeFPConversion = false;
};
/// Convert FIR to the LLVM IR dialect with default options.
diff --git a/flang/lib/Optimizer/CodeGen/CodeGen.cpp b/flang/lib/Optimizer/CodeGen/CodeGen.cpp
index 55c6afee45996..4ebffa0f3797f 100644
--- a/flang/lib/Optimizer/CodeGen/CodeGen.cpp
+++ b/flang/lib/Optimizer/CodeGen/CodeGen.cpp
@@ -1134,19 +1134,31 @@ struct ConvertOpConversion : public fir::FIROpConversion<fir::ConvertOp> {
return mlir::success();
}
if (mlir::isa<mlir::IntegerType>(toTy)) {
- // NOTE: We are checking the fir type here because toTy is an LLVM type
- // which is signless, and we need to use the intrinsic that matches the
- // sign of the output in fir.
- if (toFirTy.isUnsignedInteger()) {
- auto intrinsicName =
- mlir::StringAttr::get(convert.getContext(), "llvm.fptoui.sat");
- rewriter.replaceOpWithNewOp<mlir::LLVM::CallIntrinsicOp>(
- convert, toTy, intrinsicName, op0);
+ if (options.unsafeFPConversion) {
+ // Under unsafe FP math (e.g. -ffast-math), use plain fptosi/fptoui
+ // instead of saturating intrinsics. This avoids expensive
+ // overflow/NAN checking in the generated code.
+ mlir::Value res;
+ if (toFirTy.isUnsignedInteger())
+ res = mlir::LLVM::FPToUIOp::create(rewriter, loc, toTy, op0);
+ else
+ res = mlir::LLVM::FPToSIOp::create(rewriter, loc, toTy, op0);
+ rewriter.replaceOp(convert, res);
} else {
- auto intrinsicName =
- mlir::StringAttr::get(convert.getContext(), "llvm.fptosi.sat");
- rewriter.replaceOpWithNewOp<mlir::LLVM::CallIntrinsicOp>(
- convert, toTy, intrinsicName, op0);
+ // NOTE: We are checking the fir type here because toTy is an LLVM
+ // type which is signless, and we need to use the intrinsic that
+ // matches the sign of the output in fir.
+ if (toFirTy.isUnsignedInteger()) {
+ auto intrinsicName =
+ mlir::StringAttr::get(convert.getContext(), "llvm.fptoui.sat");
+ rewriter.replaceOpWithNewOp<mlir::LLVM::CallIntrinsicOp>(
+ convert, toTy, intrinsicName, op0);
+ } else {
+ auto intrinsicName =
+ mlir::StringAttr::get(convert.getContext(), "llvm.fptosi.sat");
+ rewriter.replaceOpWithNewOp<mlir::LLVM::CallIntrinsicOp>(
+ convert, toTy, intrinsicName, op0);
+ }
}
return mlir::success();
}
diff --git a/flang/lib/Optimizer/Passes/Pipelines.cpp b/flang/lib/Optimizer/Passes/Pipelines.cpp
index 15a342e10fc7f..c866f0a76ccb2 100644
--- a/flang/lib/Optimizer/Passes/Pipelines.cpp
+++ b/flang/lib/Optimizer/Passes/Pipelines.cpp
@@ -112,6 +112,7 @@ getFIRToLLVMPassOptions(const MLIRToLLVMPassPipelineConfig &config) {
options.typeDescriptorsRenamedForAssembly =
!disableCompilerGeneratedNamesConversion;
options.ComplexRange = config.ComplexRange;
+ options.unsafeFPConversion = config.UnsafeFPMath;
return options;
}
diff --git a/flang/test/Integration/unsafe-fp-conversion.f90 b/flang/test/Integration/unsafe-fp-conversion.f90
new file mode 100644
index 0000000000000..ec173584bd5ed
--- /dev/null
+++ b/flang/test/Integration/unsafe-fp-conversion.f90
@@ -0,0 +1,47 @@
+! Test that -ffast-math uses plain fptosi/fptoui for float-to-integer
+! conversions instead of the saturating intrinsics (llvm.fptosi.sat /
+! llvm.fptoui.sat).
+
+! RUN: %flang -O2 -S -emit-llvm %s -o - | FileCheck %s --check-prefix=SAFE
+! RUN: %flang -O2 -ffast-math -S -emit-llvm %s -o - | FileCheck %s --check-prefix=FAST
+
+! SAFE-LABEL: define {{.*}} @float_to_int_
+! SAFE: call i32 @llvm.fptosi.sat.i32.f32
+! SAFE-NOT: fptosi float
+
+! FAST-LABEL: define {{.*}} @float_to_int_
+! FAST: fptosi float
+! FAST-NOT: llvm.fptosi.sat
+
+subroutine float_to_int(x, i)
+ real, intent(in) :: x
+ integer, intent(out) :: i
+ i = x
+end subroutine
+
+! SAFE-LABEL: define {{.*}} @double_to_int_
+! SAFE: call i32 @llvm.fptosi.sat.i32.f64
+! SAFE-NOT: fptosi double
+
+! FAST-LABEL: define {{.*}} @double_to_int_
+! FAST: fptosi double
+! FAST-NOT: llvm.fptosi.sat
+
+subroutine double_to_int(d, i)
+ double precision, intent(in) :: d
+ integer, intent(out) :: i
+ i = d
+end subroutine
+
+! SAFE-LABEL: define {{.*}} @float_to_int8_
+! SAFE: call i64 @llvm.fptosi.sat.i64.f32
+
+! FAST-LABEL: define {{.*}} @float_to_int8_
+! FAST: fptosi float
+! FAST-NOT: llvm.fptosi.sat
+
+subroutine float_to_int8(x, i)
+ real, intent(in) :: x
+ integer(8), intent(out) :: i
+ i = x
+end subroutine
More information about the flang-commits
mailing list