[clang] [flang] [Flang][Driver] Override -ffast-math floating point contraction with -ffp-contract= (PR #213574)

via cfe-commits cfe-commits at lists.llvm.org
Sun Aug 2 18:18:46 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang-driver

Author: Shunsuke Watanabe (s-watanabe314)

<details>
<summary>Changes</summary>

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.

---
Full diff: https://github.com/llvm/llvm-project/pull/213574.diff


2 Files Affected:

- (modified) clang/lib/Driver/ToolChains/Flang.cpp (+35-20) 
- (modified) flang/test/Driver/fast-math.f90 (+27) 


``````````diff
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{{.*}}

``````````

</details>


https://github.com/llvm/llvm-project/pull/213574


More information about the cfe-commits mailing list