[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