https://github.com/s-watanabe314 created 
https://github.com/llvm/llvm-project/pull/213574

This patch allows overriding the floating point contract settings implied by 
-ffast-math by explicitly specifying -ffp-contract=. The final floating point 
contract mode follows the usual last-flag-wins behavior. In addition, 
-fno-fast-math only cancels the effects of -ffast-math and preserves any 
explicitly specified -ffp-contract= setting.

A warning is emitted when an explicit -ffp-contract= option overrides the 
floating point contract mode implied by -ffast-math.

This behavior is consistent with Clang.

>From 16e3989b586f7d351b3cf2a8b403f9fac49fc72c Mon Sep 17 00:00:00 2001
From: s-watanabe314 <[email protected]>
Date: Tue, 16 Jun 2026 11:52:07 +0900
Subject: [PATCH] [Flang][Driver] Override -ffast-math floating point
 contraction with -ffp-contract=

This patch allows overriding the floating point contract settings
implied by -ffast-math by explicitly specifying -ffp-contract=. The
final floating point contract mode follows the usual last-flag-wins
behavior. In addition, -fno-fast-math only cancels the effects of
-ffast-math and preserves any explicitly specified -ffp-contract=
setting.

A warning is emitted when an explicit -ffp-contract= option overrides
the floating point contract mode implied by -ffast-math.

This behavior is consistent with Clang.
---
 clang/lib/Driver/ToolChains/Flang.cpp | 55 +++++++++++++++++----------
 flang/test/Driver/fast-math.f90       | 27 +++++++++++++
 2 files changed, 62 insertions(+), 20 deletions(-)

diff --git a/clang/lib/Driver/ToolChains/Flang.cpp 
b/clang/lib/Driver/ToolChains/Flang.cpp
index 650148de1374a..5ad2b5540aa42 100644
--- a/clang/lib/Driver/ToolChains/Flang.cpp
+++ b/clang/lib/Driver/ToolChains/Flang.cpp
@@ -797,6 +797,8 @@ void Flang::addOffloadOptions(Compilation &C, const 
InputInfoList &Inputs,
 static void addFloatingPointOptions(const Driver &D, const ArgList &Args,
                                     ArgStringList &CmdArgs) {
   StringRef FPContract;
+  StringRef LastSeenFfpContractOption;
+  StringRef LastFpContractOverrideOption;
   bool HonorINFs = true;
   bool HonorNaNs = true;
   bool ApproxFunc = false;
@@ -807,23 +809,6 @@ static void addFloatingPointOptions(const Driver &D, const 
ArgList &Args,
   StringRef LastComplexRangeOption;
   LangOptions::ComplexRangeKind Range = LangOptions::ComplexRangeKind::CX_None;
 
-  if (const Arg *A = Args.getLastArg(options::OPT_ffp_contract)) {
-    const StringRef Val = A->getValue();
-    if (Val == "fast" || Val == "off") {
-      FPContract = Val;
-    } else if (Val == "on") {
-      // Warn instead of error because users might have makefiles written for
-      // gfortran (which accepts -ffp-contract=on)
-      D.Diag(diag::warn_drv_unsupported_option_for_flang)
-          << Val << A->getOption().getName() << "off";
-      FPContract = "off";
-    } else
-      // Clang's "fast-honor-pragmas" option is not supported because it is
-      // non-standard
-      D.Diag(diag::err_drv_unsupported_option_argument)
-          << A->getSpelling() << Val;
-  }
-
   for (const Arg *A : Args) {
     auto optId = A->getOption().getID();
     switch (optId) {
@@ -886,6 +871,32 @@ static void addFloatingPointOptions(const Driver &D, const 
ArgList &Args,
     case options::OPT_fno_reciprocal_math:
       ReciprocalMath = false;
       break;
+    case options::OPT_ffp_contract: {
+      StringRef Val = A->getValue();
+      if (Val == "fast" || Val == "off") {
+        if (Val != FPContract && LastFpContractOverrideOption != "") {
+          D.Diag(clang::diag::warn_drv_overriding_option)
+              << LastFpContractOverrideOption
+              << Args.MakeArgString("-ffp-contract=" + Val);
+        }
+        FPContract = Val;
+        LastSeenFfpContractOption = Val;
+      } else if (Val == "on") {
+        // Warn instead of error because users might have makefiles written for
+        // gfortran (which accepts -ffp-contract=on)
+        D.Diag(diag::warn_drv_unsupported_option_for_flang)
+            << Val << A->getOption().getName() << "off";
+        FPContract = "off";
+        LastSeenFfpContractOption = "off";
+      } else {
+        // Clang's "fast-honor-pragmas" option is not supported because it is
+        // non-standard
+        D.Diag(diag::err_drv_unsupported_option_argument)
+            << A->getSpelling() << Val;
+      }
+      LastFpContractOverrideOption = "";
+      break;
+    }
     case options::OPT_Ofast:
       [[fallthrough]];
     case options::OPT_ffast_math:
@@ -896,6 +907,7 @@ static void addFloatingPointOptions(const Driver &D, const 
ArgList &Args,
       ApproxFunc = true;
       SignedZeros = false;
       FPContract = "fast";
+      LastFpContractOverrideOption = "-ffast-math";
       setComplexRange(D, A->getSpelling(),
                       LangOptions::ComplexRangeKind::CX_Basic,
                       LastComplexRangeOption, Range);
@@ -908,9 +920,12 @@ static void addFloatingPointOptions(const Driver &D, const 
ArgList &Args,
       ApproxFunc = false;
       SignedZeros = true;
       // -fno-fast-math should undo -ffast-math so I return FPContract to the
-      // default. It is important to check it is "fast" (the default) so that
-      // --ffp-contract=off -fno-fast-math --> -ffp-contract=off
-      if (FPContract == "fast")
+      // default. If -ffp-contract= was explicitly specified, restore the
+      // user-requested value from LastSeenFfpContractOption so that
+      // -ffp-contract=off -fno-fast-math --> -ffp-contract=off
+      if (LastSeenFfpContractOption != "")
+        FPContract = LastSeenFfpContractOption;
+      else
         FPContract = "";
       setComplexRange(D, A->getSpelling(),
                       LangOptions::ComplexRangeKind::CX_None,
diff --git a/flang/test/Driver/fast-math.f90 b/flang/test/Driver/fast-math.f90
index 22e339dc8ace9..3a6a48c98ab0c 100644
--- a/flang/test/Driver/fast-math.f90
+++ b/flang/test/Driver/fast-math.f90
@@ -64,12 +64,39 @@
 ! CHECK-TO-COMPS-SAME: -mreassociate
 ! CHECK-TO-COMPS-SAME: -freciprocal-math
 
+! Check if -ffast-math component flags can be disabled
+! RUN: %flang -ffast-math \
+! RUN:      -ffp-contract=off \
+! RUN:      -fhonor-infinities \
+! RUN:      -fhonor-nans \
+! RUN:      -fno-approx-func \
+! RUN:      -fsigned-zeros \
+! RUN:      -fno-associative-math \
+! RUN:      -fno-reciprocal-math \
+! RUN:      -fsyntax-only -### %s -o %t 2>&1 \
+! RUN:      | FileCheck --check-prefix=CHECK-TO-COMPS-DIS %s
+! CHECK-TO-COMPS-DIS: warning: overriding '-ffast-math' option with 
'-ffp-contract=off' [-Woverriding-option]
+! CHECK-TO-COMPS-DIS: -fc1
+! CHECK-TO-COMPS-DIS-SAME: -ffp-contract=off
+! CHECK-TO-COMPS-DIS-NOT: -menable-no-infs
+! CHECK-TO-COMPS-DIS-NOT: -menable-no-nans
+! CHECK-TO-COMPS-DIS-NOT: -fapprox-func
+! CHECK-TO-COMPS-DIS-NOT: -fno-signed-zeros
+! CHECK-TO-COMPS-DIS-NOT: -mreassociate
+! CHECK-TO-COMPS-DIS-NOT: -freciprocal-math
+
 ! Check that -fno-fast-math doesn't clobber -ffp-contract
 ! RUN: %flang -ffp-contract=off -fno-fast-math -fsyntax-only -### %s -o %t 
2>&1 \
 ! RUN:     | FileCheck --check-prefix=CHECK-CONTRACT %s
 ! CHECK-CONTRACT: -fc1
 ! CHECK-CONTRACT-SAME: -ffp-contract=off
 
+! Check that -fno-fast-math only disables -ffast-math.
+! RUN: %flang -ffp-contract=off -ffast-math -fno-fast-math -fsyntax-only -### 
%s -o %t 2>&1 \
+! RUN:     | FileCheck --check-prefix=CHECK-CONTRACT-NOFAST %s
+! CHECK-CONTRACT-NOFAST: -fc1
+! CHECK-CONTRACT-NOFAST-SAME: -ffp-contract=off
+
 ! Check that -ffast-math causes us to link to crtfastmath.o
 ! UNSUPPORTED: system-windows
 ! UNSUPPORTED: target=powerpc{{.*}}

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to