[flang-commits] [clang] [flang] [flang][driver] Honor -ffp-contract option ordering (PR #215506)

via flang-commits flang-commits at lists.llvm.org
Tue Aug 11 03:04:48 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang-driver

Author: Bohan (Garth) Lei (garthlei)

<details>
<summary>Changes</summary>

Flang previously processed the last -ffp-contract option before walking the floating-point options in command-line order. Consequently, -ffast-math and -Ofast could overwrite -ffp-contract=off regardless of their relative positions.

Process -ffp-contract in the ordered option loop and remember the last explicit contraction setting. Restore that setting when -fno-fast-math disables the umbrella fast-math options, matching Clang's ordering behavior.

Preserve Flang's existing handling of -ffp-contract=on and add driver tests for option ordering and restoration.

Test: llvm-lit flang/test/Driver/fast-math.f90

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


2 Files Affected:

- (modified) clang/lib/Driver/ToolChains/Flang.cpp (+25-21) 
- (modified) flang/test/Driver/fast-math.f90 (+48) 


``````````diff
diff --git a/clang/lib/Driver/ToolChains/Flang.cpp b/clang/lib/Driver/ToolChains/Flang.cpp
index b2d709afcb4e2..849632258b6ef 100644
--- a/clang/lib/Driver/ToolChains/Flang.cpp
+++ b/clang/lib/Driver/ToolChains/Flang.cpp
@@ -894,6 +894,7 @@ void Flang::addOffloadOptions(Compilation &C, const InputInfoList &Inputs,
 static void addFloatingPointOptions(const Driver &D, const ArgList &Args,
                                     ArgStringList &CmdArgs) {
   StringRef FPContract;
+  StringRef LastSeenFfpContractOption;
   bool HonorINFs = true;
   bool HonorNaNs = true;
   bool ApproxFunc = false;
@@ -904,23 +905,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) {
@@ -983,6 +967,27 @@ static void addFloatingPointOptions(const Driver &D, const ArgList &Args,
     case options::OPT_fno_reciprocal_math:
       ReciprocalMath = false;
       break;
+    case 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;
+        break;
+      }
+
+      LastSeenFfpContractOption = FPContract;
+      break;
+    }
     case options::OPT_Ofast:
       [[fallthrough]];
     case options::OPT_ffast_math:
@@ -1005,10 +1010,9 @@ 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")
-        FPContract = "";
+      // last explicit -ffp-contract value, or to the default if there was no
+      // explicit value.
+      FPContract = LastSeenFfpContractOption;
       setComplexRange(D, A->getSpelling(),
                       LangOptions::ComplexRangeKind::CX_None,
                       LastComplexRangeOption, Range);
diff --git a/flang/test/Driver/fast-math.f90 b/flang/test/Driver/fast-math.f90
index 22e339dc8ace9..59365eeb99c97 100644
--- a/flang/test/Driver/fast-math.f90
+++ b/flang/test/Driver/fast-math.f90
@@ -70,6 +70,54 @@
 ! CHECK-CONTRACT: -fc1
 ! CHECK-CONTRACT-SAME: -ffp-contract=off
 
+! Explicit -ffp-contract options participate in normal command-line ordering.
+! RUN: %flang -ffast-math -ffp-contract=off -fsyntax-only -### %s -o %t 2>&1 \
+! RUN:     | FileCheck --check-prefix=CHECK-FAST-THEN-CONTRACT-OFF \
+! RUN:                 --implicit-check-not=-ffast-math %s
+! CHECK-FAST-THEN-CONTRACT-OFF: -fc1
+! CHECK-FAST-THEN-CONTRACT-OFF-SAME: -ffp-contract=off
+! CHECK-FAST-THEN-CONTRACT-OFF-SAME: -menable-no-infs
+! CHECK-FAST-THEN-CONTRACT-OFF-SAME: -menable-no-nans
+! CHECK-FAST-THEN-CONTRACT-OFF-SAME: -fapprox-func
+! CHECK-FAST-THEN-CONTRACT-OFF-SAME: -fno-signed-zeros
+! CHECK-FAST-THEN-CONTRACT-OFF-SAME: -mreassociate
+! CHECK-FAST-THEN-CONTRACT-OFF-SAME: -freciprocal-math
+
+! RUN: %flang -ffp-contract=off -ffast-math -fsyntax-only -### %s -o %t 2>&1 \
+! RUN:     | FileCheck --check-prefix=CHECK-CONTRACT-OFF-THEN-FAST \
+! RUN:                 --implicit-check-not=-ffp-contract=off %s
+! CHECK-CONTRACT-OFF-THEN-FAST: -fc1
+! CHECK-CONTRACT-OFF-THEN-FAST-SAME: -ffast-math
+
+! -Ofast has the same contraction ordering as -ffast-math.
+! RUN: %flang -Ofast -ffp-contract=off -fsyntax-only -### %s -o %t 2>&1 \
+! RUN:     | FileCheck --check-prefix=CHECK-OFAST-THEN-CONTRACT-OFF %s
+! CHECK-OFAST-THEN-CONTRACT-OFF: -fc1
+! CHECK-OFAST-THEN-CONTRACT-OFF-SAME: -ffp-contract=off
+! CHECK-OFAST-THEN-CONTRACT-OFF-SAME: -menable-no-infs
+! CHECK-OFAST-THEN-CONTRACT-OFF-SAME: -menable-no-nans
+! CHECK-OFAST-THEN-CONTRACT-OFF-SAME: -fapprox-func
+! CHECK-OFAST-THEN-CONTRACT-OFF-SAME: -fno-signed-zeros
+! CHECK-OFAST-THEN-CONTRACT-OFF-SAME: -mreassociate
+! CHECK-OFAST-THEN-CONTRACT-OFF-SAME: -freciprocal-math
+! CHECK-OFAST-THEN-CONTRACT-OFF-SAME: -fstack-arrays
+! CHECK-OFAST-THEN-CONTRACT-OFF-SAME: -O3
+
+! Disabling fast math restores the last explicit contraction setting.
+! RUN: %flang -ffp-contract=off -ffast-math -fno-fast-math \
+! RUN:     -fsyntax-only -### %s -o %t 2>&1 \
+! RUN:     | FileCheck --check-prefix=CHECK-RESTORE-CONTRACT-OFF \
+! RUN:                 --implicit-check-not=-ffast-math %s
+! CHECK-RESTORE-CONTRACT-OFF: -fc1
+! CHECK-RESTORE-CONTRACT-OFF-SAME: -ffp-contract=off
+
+! RUN: %flang -ffp-contract=fast -ffast-math -fno-fast-math \
+! RUN:     -fsyntax-only -### %s -o %t 2>&1 \
+! RUN:     | FileCheck --check-prefix=CHECK-RESTORE-CONTRACT-FAST \
+! RUN:                 --implicit-check-not=-ffast-math %s
+! CHECK-RESTORE-CONTRACT-FAST: -fc1
+! CHECK-RESTORE-CONTRACT-FAST-SAME: -ffp-contract=fast
+
 ! 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/215506


More information about the flang-commits mailing list