[clang] [clang][Driver] Restore -cl-fast-relaxed-math fast-math cascade at cc1 level (PR #211768)

Wenju He via cfe-commits cfe-commits at lists.llvm.org
Fri Jul 24 03:54:57 PDT 2026


https://github.com/wenju-he created https://github.com/llvm/llvm-project/pull/211768

b630323 dropped the cc1-level ImpliedByAnyOf<[cl_fast_relaxed_math]> on fast_math to let -fhonor-nans/-fhonor-infinities override -cl-fast-relaxed-math via the Driver. This broke our downstream test that talks to cc1/CompilerInvocation directly: a bare -cl-fast-relaxed-math no longer implied nnan/ninf/nofpclass, silently degrading to plain contract.

Restore the cc1-level implication so -cl-fast-relaxed-math alone gives the full fast-math cascade again, and give -menable-no-nans/ -menable-no-infs real CC1Option negation flags (-mno-enable-no-nans/ -mno-enable-no-infs). The Driver now emits the negation flag when -fhonor-nans/-fhonor-infinities is combined with -cl-fast-relaxed-math, explicitly cancelling just the implied NaN or Inf assumption without suppressing the rest of the cascade.

>From 152618ca703ffb290e7b0796af0f06431a9b013b Mon Sep 17 00:00:00 2001
From: Wenju He <wenju.he at intel.com>
Date: Fri, 24 Jul 2026 12:49:14 +0200
Subject: [PATCH] [clang][Driver] Restore -cl-fast-relaxed-math fast-math
 cascade at cc1 level

b630323 dropped the cc1-level ImpliedByAnyOf<[cl_fast_relaxed_math]> on
fast_math to let -fhonor-nans/-fhonor-infinities override
-cl-fast-relaxed-math via the Driver. This broke our downstream test that
talks to cc1/CompilerInvocation directly: a bare -cl-fast-relaxed-math no
longer implied nnan/ninf/nofpclass, silently degrading to plain contract.

Restore the cc1-level implication so -cl-fast-relaxed-math alone gives
the full fast-math cascade again, and give -menable-no-nans/
-menable-no-infs real CC1Option negation flags (-mno-enable-no-nans/
-mno-enable-no-infs). The Driver now emits the negation flag when
-fhonor-nans/-fhonor-infinities is combined with -cl-fast-relaxed-math,
explicitly cancelling just the implied NaN or Inf assumption without
suppressing the rest of the cascade.

Co-Authored-By: Claude Sonnet 5 <noreply at anthropic.com>
---
 clang/include/clang/Options/Options.td     | 21 ++++++++++++++-------
 clang/lib/Driver/ToolChains/Clang.cpp      | 12 ++++++++++++
 clang/test/CodeGenOpenCL/relaxed-fpmath.cl | 10 ++++++++++
 clang/test/Driver/opencl.cl                | 10 +++++++---
 4 files changed, 43 insertions(+), 10 deletions(-)

diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td
index 41848b18f2e1b..82ba02e262b0c 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -2507,7 +2507,8 @@ def ffp_exception_behavior_EQ : Joined<["-"], "ffp-exception-behavior=">, Group<
 defm fast_math : BoolFOption<"fast-math",
   LangOpts<"FastMath">, Default<hlsl.KeyPath>,
   PosFlag<SetTrue, [], [ClangOption, CC1Option, FC1Option, FlangOption],
-          "Allow aggressive, lossy floating-point optimizations">,
+          "Allow aggressive, lossy floating-point optimizations",
+          [cl_fast_relaxed_math.KeyPath]>,
   NegFlag<SetFalse, [], [ClangOption, CC1Option, FC1Option, FlangOption]>>;
 defm math_errno : BoolFOption<"math-errno",
   LangOpts<"MathErrno">, DefaultFalse,
@@ -8773,12 +8774,18 @@ let Visibility = [CC1Option, FC1Option] in {
 def mreassociate : Flag<["-"], "mreassociate">,
   HelpText<"Allow reassociation transformations for floating-point instructions">,
   MarshallingInfoFlag<LangOpts<"AllowFPReassoc">>, ImpliedByAnyOf<[funsafe_math_optimizations.KeyPath]>;
-def menable_no_nans : Flag<["-"], "menable-no-nans">,
-  HelpText<"Allow optimization to assume there are no NaNs.">,
-  MarshallingInfoFlag<LangOpts<"NoHonorNaNs">>, ImpliedByAnyOf<[ffast_math.KeyPath]>;
-def menable_no_infs : Flag<["-"], "menable-no-infs">,
-  HelpText<"Allow optimization to assume there are no infinities.">,
-  MarshallingInfoFlag<LangOpts<"NoHonorInfs">>, ImpliedByAnyOf<[ffast_math.KeyPath]>;
+defm enable_no_nans : BoolMOption<"enable-no-nans",
+  LangOpts<"NoHonorNaNs">, DefaultFalse,
+  PosFlag<SetTrue, [], [CC1Option, FC1Option],
+          "Allow optimization to assume there are no NaNs.",
+          [ffast_math.KeyPath]>,
+  NegFlag<SetFalse, [], [CC1Option, FC1Option]>>;
+defm enable_no_infs : BoolMOption<"enable-no-infs",
+  LangOpts<"NoHonorInfs">, DefaultFalse,
+  PosFlag<SetTrue, [], [CC1Option, FC1Option],
+          "Allow optimization to assume there are no infinities.",
+          [ffast_math.KeyPath]>,
+  NegFlag<SetFalse, [], [CC1Option, FC1Option]>>;
 
 def pic_level : Separate<["-"], "pic-level">,
   HelpText<"Value for __PIC__">,
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 660e61d7c5de3..d27d019c88c71 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -3386,11 +3386,23 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
     A->claim();
   }
 
+  // -cl-fast-relaxed-math implies -ffast-math at the cc1 level (so that
+  // callers talking to cc1 directly, e.g. via CompilerInvocation, get the
+  // full fast-math cascade from a bare -cl-fast-relaxed-math). When the
+  // Driver determines NaNs/Infs should still be honored (because
+  // -fhonor-nans/-fhonor-infinities overrode -cl-fast-relaxed-math), it must
+  // explicitly cancel that cc1-level implication.
+  bool NeedsHonorOverride = Args.hasArg(options::OPT_cl_fast_relaxed_math);
+
   if (!HonorINFs)
     CmdArgs.push_back("-menable-no-infs");
+  else if (NeedsHonorOverride)
+    CmdArgs.push_back("-mno-enable-no-infs");
 
   if (!HonorNaNs)
     CmdArgs.push_back("-menable-no-nans");
+  else if (NeedsHonorOverride)
+    CmdArgs.push_back("-mno-enable-no-nans");
 
   if (ApproxFunc)
     CmdArgs.push_back("-fapprox-func");
diff --git a/clang/test/CodeGenOpenCL/relaxed-fpmath.cl b/clang/test/CodeGenOpenCL/relaxed-fpmath.cl
index e875a6c9d1ad8..44fc9513b5498 100644
--- a/clang/test/CodeGenOpenCL/relaxed-fpmath.cl
+++ b/clang/test/CodeGenOpenCL/relaxed-fpmath.cl
@@ -5,6 +5,14 @@
 // RUN: %clang_cc1 %s -emit-llvm -cl-mad-enable -o - | FileCheck %s -check-prefix=MAD
 // RUN: %clang_cc1 %s -emit-llvm -cl-no-signed-zeros -o - | FileCheck %s -check-prefix=NOSIGNED
 
+// -cl-fast-relaxed-math alone implies -ffast-math at the cc1 level, so both
+// -menable-no-nans and -menable-no-infs are implied.
+// RUN: %clang_cc1 %s -emit-llvm -cl-fast-relaxed-math -o - | FileCheck %s -check-prefix=FAST
+// A caller (e.g. a cc1-direct invocation) can cancel just one side of the
+// implied fast-math NaN/Inf assumptions via the negation flags.
+// RUN: %clang_cc1 %s -emit-llvm -cl-fast-relaxed-math -mno-enable-no-nans -o - | FileCheck %s -check-prefix=NONAN
+// RUN: %clang_cc1 %s -emit-llvm -cl-fast-relaxed-math -mno-enable-no-infs -o - | FileCheck %s -check-prefix=NOINF
+
 // Check the fp options are correct with PCH.
 // RUN: %clang_cc1 %s -DGEN_PCH=1 -finclude-default-header -triple spir-unknown-unknown -emit-pch -o %t.pch
 // RUN: %clang_cc1 %s -include-pch %t.pch -fno-validate-pch -emit-llvm -o - | FileCheck %s -check-prefix=NORMAL
@@ -25,6 +33,8 @@ float spscalardiv(float a, float b) {
   // UNSAFE: fdiv reassoc nsz arcp contract afn float
   // MAD: fdiv float
   // NOSIGNED: fdiv nsz float
+  // NONAN: fdiv reassoc ninf nsz arcp contract afn float
+  // NOINF: fdiv reassoc nnan nsz arcp contract afn float
   return a / b;
 }
 // CHECK: attributes
diff --git a/clang/test/Driver/opencl.cl b/clang/test/Driver/opencl.cl
index 8024c27f69f69..3110fb3f0bd77 100644
--- a/clang/test/Driver/opencl.cl
+++ b/clang/test/Driver/opencl.cl
@@ -12,9 +12,9 @@
 // RUN: %clang -S -### -cl-finite-math-only %s 2>&1 | FileCheck --check-prefix=CHECK-FINITE-MATH-ONLY %s
 // RUN: %clang -S -### -cl-kernel-arg-info %s 2>&1 | FileCheck --check-prefix=CHECK-KERNEL-ARG-INFO %s
 // RUN: %clang -S -### -cl-unsafe-math-optimizations %s 2>&1 | FileCheck --check-prefix=CHECK-UNSAFE-MATH-OPT %s
-// RUN: %clang -S -### -cl-fast-relaxed-math %s 2>&1 | FileCheck --check-prefix=CHECK-FAST-RELAXED-MATH %s
-// RUN: %clang -S -### -cl-fast-relaxed-math -fhonor-nans %s 2>&1 | FileCheck --check-prefixes=CHECK-FAST-RELAXED-MATH,NO-NNAN %s
-// RUN: %clang -S -### -cl-fast-relaxed-math -fhonor-infinities %s 2>&1 | FileCheck --check-prefixes=CHECK-FAST-RELAXED-MATH,NO-NINF %s
+// RUN: %clang -S -### -cl-fast-relaxed-math %s 2>&1 | FileCheck --check-prefixes=CHECK-FAST-RELAXED-MATH,NO-MNO-ENABLE %s
+// RUN: %clang -S -### -cl-fast-relaxed-math -fhonor-nans %s 2>&1 | FileCheck --check-prefixes=CHECK-FAST-RELAXED-MATH,NO-NNAN,YES-NO-ENABLE-NNAN %s
+// RUN: %clang -S -### -cl-fast-relaxed-math -fhonor-infinities %s 2>&1 | FileCheck --check-prefixes=CHECK-FAST-RELAXED-MATH,NO-NINF,YES-NO-ENABLE-NINF %s
 // RUN: %clang -S -### -cl-mad-enable %s 2>&1 | FileCheck --check-prefix=CHECK-MAD-ENABLE %s
 // RUN: %clang -S -### -cl-no-signed-zeros %s 2>&1 | FileCheck --check-prefix=CHECK-NO-SIGNED-ZEROS %s
 // RUN: %clang -S -### -cl-denorms-are-zero %s 2>&1 | FileCheck --check-prefix=CHECK-DENORMS-ARE-ZERO %s
@@ -47,6 +47,10 @@
 // CHECK-NO-SIGNED-ZEROS: "-cc1" {{.*}} "-cl-no-signed-zeros"
 // NO-NNAN-NOT: "menable-no-nans"
 // NO-NINF-NOT: "menable-no-infs"
+// YES-NO-ENABLE-NNAN: "-mno-enable-no-nans"
+// YES-NO-ENABLE-NINF: "-mno-enable-no-infs"
+// NO-MNO-ENABLE-NOT: "-mno-enable-no-nans"
+// NO-MNO-ENABLE-NOT: "-mno-enable-no-infs"
 
 // This is not forwarded
 // CHECK-DENORMS-ARE-ZERO-NOT: "-cl-denorms-are-zero"



More information about the cfe-commits mailing list