[flang-commits] [clang] [flang] [flang][driver] Honor -ffp-contract option ordering (PR #215506)
Bohan Lei via flang-commits
flang-commits at lists.llvm.org
Tue Aug 11 03:04:05 PDT 2026
https://github.com/garthlei created https://github.com/llvm/llvm-project/pull/215506
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
>From 971d05d243e9e7b15f798178cda7c9cdd320b482 Mon Sep 17 00:00:00 2001
From: Bohan Lei <garthlei at linux.alibaba.com>
Date: Tue, 11 Aug 2026 17:58:30 +0800
Subject: [PATCH] [flang][driver] Honor -ffp-contract option ordering
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
---
clang/lib/Driver/ToolChains/Flang.cpp | 46 +++++++++++++------------
flang/test/Driver/fast-math.f90 | 48 +++++++++++++++++++++++++++
2 files changed, 73 insertions(+), 21 deletions(-)
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{{.*}}
More information about the flang-commits
mailing list