-
Notifications
You must be signed in to change notification settings - Fork 14.3k
Remove FiniteMathOnly and use only NoHonorINFs and NoHonorNANs. #97342
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
the values of HonorINFs and HonorNANs.
if (!LO.NoHonorInfs || !LO.NoHonorInfs) | ||
assert(!LO.FiniteMathOnly && "FiniteMathOnly implies NoHonorInfs"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about:
assert((LO.FiniteMathOnly == (LO.NoHonorInfs && LO.NoHonorNans)) && "inf/nan inconsistent internal state");
to make it more clear that the state has to be sane no matter which options are set? Also, this corrects the duplicate condition in your if
statement.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With this condition, this command line will assert:
clang.exe -Xclang -menable-no-infs -Xclang -menable-no-nans foo.c
FiniteMathonly
is 0
by default.
Do we want that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That sounds like a logic bug to me -- if infs and nans are disabled, then it's definitely finite math only mode. If infs OR nans are disabled... I think it's also finite math only mode.
Ideally, I think we should get rid of the internal notion of FiniteMathOnly
and replace it with the honor infs/nans flags explicitly so we don't get into these sort of situations to begin with. We'd still have to answer how to define __FINITE_MATH_ONLY__
, but that seems doable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is quite a bit of LIT tests that have that "logic bug" then. They are using -Xclang -menable-no-infs -Xclang -menable-no-nan
without the -ffinite-math-only
option.
Getting rid of FiniteMathOnly
is fine by me.
FiniteMathOnly = !HonorINFs && !HonorNaNs
which would mean -menable-no-infs -menable-non-nans
. I would think using one or the other of these options could still mean that input values may be either INF or NAN or we can produce them, in which case we wouldn't be in finite math mode.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is quite a bit of LIT tests that have that "logic bug" then. They are using -Xclang -menable-no-infs -Xclang -menable-no-nan without the -ffinite-math-only option.
I didn't mean the logic bug was on the user end; I meant that our internal state has the logic bug because !FiniteMathOnly
implies that infinities are supported and so it logically conflicts with !HonorInfs
.
Getting rid of FiniteMathOnly is fine by me.
FiniteMathOnly = !HonorINFs && !HonorNaNs which would mean -menable-no-infs -menable-non-nans. I would think using one or the other of these options could still mean that input values may be either INF or NAN or we can produce them, in which case we wouldn't be in finite math mode.
I can see the logic there and I think that's defensible, but because FiniteMathOnly
determines the value __FINITE_MATH_ONLY__
expands to, we should probably see how that flag is being used in the wild to see whether folks expect it to be 1
or 0
when infinity is enabled but NAN is disabled (for example).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with Aaron that we should get rid of the internal state that combines these two modes. I expect we'll only want to define __FINITE_MATH_ONLY__
when we aren't honoring either. You could create code that made incorrect assumptions either way, but the state described by the symbol is that we aren't honoring either.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The way I see it, nnan and ninf collectively define four modes for math: full types, no-nan, finite-math (nnan + ninf), and the extremely questionable (to me at least) ninf-without-nnan. I don't think FiniteMathOnly
as a concept independent of the nnan/ninf flags makes much sense.
There is perhaps room for disagreement as to whether __FINITE_MATH_ONLY__
should be nnan || ninf
or nnan && ninf
; I lean towards && myself. Looking at sourcegraph, there seems to be essentially three uses of these macros: two to indicate that they don't care about min(NaN) results, and one to avoid using fpclassify.
✅ With the latest revision this PR passed the C/C++ code formatter. |
@llvm/pr-subscribers-clang @llvm/pr-subscribers-clang-driver Author: Zahira Ammarguellat (zahiraam) ChangesFull diff: https://github.com/llvm/llvm-project/pull/97342.diff 6 Files Affected:
diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h
index 91f1c2f2e6239..e1adcb3a95f18 100644
--- a/clang/include/clang/Basic/LangOptions.h
+++ b/clang/include/clang/Basic/LangOptions.h
@@ -816,6 +816,11 @@ class FPOptions {
setAllowFPReassociate(LO.AllowFPReassoc);
setNoHonorNaNs(LO.NoHonorNaNs);
setNoHonorInfs(LO.NoHonorInfs);
+ // Ensure that if FiniteMathOnly is enabled, NoHonorNaNs and NoHonorInfs are
+ // also enabled. This is because FiniteMathOnly mode assumes no NaNs or Infs
+ // are present in computations.
+ assert((LO.FiniteMathOnly == (LO.NoHonorInfs && LO.NoHonorNaNs)) &&
+ "inf/nan inconsistent internal state");
setNoSignedZero(LO.NoSignedZero);
setAllowReciprocal(LO.AllowRecip);
setAllowApproxFunc(LO.ApproxFunc);
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index aa285c39f14b4..65257e3c4c9d9 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -3295,7 +3295,17 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
}
// Handle __FINITE_MATH_ONLY__ similarly.
- if (!HonorINFs && !HonorNaNs)
+ bool InfValues, NanValues = true;
+ auto processArg = [&](const auto *Arg) {
+ if (StringRef(Arg->getValue()) == "-menable-no-nans")
+ NanValues = false;
+ if (StringRef(Arg->getValue()) == "-menable-no-infs")
+ InfValues = false;
+ };
+ for (auto *Arg : Args.filtered(options::OPT_Xclang)) {
+ processArg(Arg);
+ }
+ if ((!HonorINFs && !HonorNaNs) || (!NanValues && !InfValues))
CmdArgs.push_back("-ffinite-math-only");
if (const Arg *A = Args.getLastArg(options::OPT_mfpmath_EQ)) {
diff --git a/clang/lib/Frontend/InitPreprocessor.cpp b/clang/lib/Frontend/InitPreprocessor.cpp
index 5e52555c6fee9..e7e02e9ddf96e 100644
--- a/clang/lib/Frontend/InitPreprocessor.cpp
+++ b/clang/lib/Frontend/InitPreprocessor.cpp
@@ -1311,7 +1311,7 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
if (!LangOpts.MathErrno)
Builder.defineMacro("__NO_MATH_ERRNO__");
- if (LangOpts.FastMath || LangOpts.FiniteMathOnly)
+ if (LangOpts.FastMath || (LangOpts.NoHonorInfs && LangOpts.NoHonorNaNs))
Builder.defineMacro("__FINITE_MATH_ONLY__", "1");
else
Builder.defineMacro("__FINITE_MATH_ONLY__", "0");
diff --git a/clang/test/CodeGen/fp-floatcontrol-stack.cpp b/clang/test/CodeGen/fp-floatcontrol-stack.cpp
index 090da25d21207..237c9d4f9a37e 100644
--- a/clang/test/CodeGen/fp-floatcontrol-stack.cpp
+++ b/clang/test/CodeGen/fp-floatcontrol-stack.cpp
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -triple x86_64-linux-gnu -ffp-contract=on -DDEFAULT=1 -emit-llvm -o - %s | FileCheck --check-prefix=CHECK-DDEFAULT %s
// RUN: %clang_cc1 -triple x86_64-linux-gnu -ffp-contract=on -DEBSTRICT=1 -ffp-exception-behavior=strict -emit-llvm -o - %s | FileCheck --check-prefix=CHECK-DEBSTRICT %s
// RUN: %clang_cc1 -triple x86_64-linux-gnu -DFAST=1 -ffast-math -ffp-contract=fast -emit-llvm -o - %s | FileCheck --check-prefix=CHECK-FAST %s
-// RUN: %clang_cc1 -triple x86_64-linux-gnu -ffp-contract=on -DNOHONOR=1 -menable-no-infs -menable-no-nans -emit-llvm -o - %s | FileCheck --check-prefix=CHECK-NOHONOR %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -ffp-contract=on -DNOHONOR=1 -ffinite-math-only -menable-no-infs -menable-no-nans -emit-llvm -o - %s | FileCheck --check-prefix=CHECK-NOHONOR %s
#define FUN(n) \
(float z) { return n * z + n; }
diff --git a/clang/test/Sema/warn-infinity-nan-disabled-lnx.cpp b/clang/test/Sema/warn-infinity-nan-disabled-lnx.cpp
index 03a432e05851d..cb719c3a519da 100644
--- a/clang/test/Sema/warn-infinity-nan-disabled-lnx.cpp
+++ b/clang/test/Sema/warn-infinity-nan-disabled-lnx.cpp
@@ -1,10 +1,11 @@
// RUN: %clang_cc1 -x c++ -verify=no-inf-no-nan \
-// RUN: -triple powerpc64le-unknown-unknown %s -menable-no-infs \
-// RUN: -menable-no-nans -std=c++23
+// RUN: -triple powerpc64le-unknown-unknown %s \
+// RUN: -ffinite-math-only -std=c++23
// RUN: %clang_cc1 -x c++ -verify=no-inf-no-nan \
-// RUN: -triple powerpc64le-unknown-unknown %s -menable-no-infs \
-// RUN: -menable-no-nans -funsafe-math-optimizations -std=c++23
+// RUN: -triple powerpc64le-unknown-unknown %s \
+// RUN: -ffinite-math-only -funsafe-math-optimizations \
+// RUN: -std=c++23
// RUN: %clang_cc1 -x c++ -verify=no-fast -triple powerpc64le-unknown-unknown \
// RUN: %s -std=c++23
diff --git a/clang/test/Sema/warn-infinity-nan-disabled-win.cpp b/clang/test/Sema/warn-infinity-nan-disabled-win.cpp
index 51f9d325619ba..4bf3355926634 100644
--- a/clang/test/Sema/warn-infinity-nan-disabled-win.cpp
+++ b/clang/test/Sema/warn-infinity-nan-disabled-win.cpp
@@ -2,12 +2,12 @@
// on Windows the NAN macro is defined using INFINITY. See below.
// RUN: %clang_cc1 -x c++ -verify=no-inf-no-nan \
-// RUN: -triple powerpc64le-unknown-unknown %s -menable-no-infs \
-// RUN: -menable-no-nans -std=c++23
+// RUN: -triple powerpc64le-unknown-unknown %s -ffinite-math-only -std=c++23
// RUN: %clang_cc1 -x c++ -verify=no-inf-no-nan \
-// RUN: -triple powerpc64le-unknown-unknown %s -menable-no-infs \
-// RUN: -menable-no-nans -funsafe-math-optimizations -std=c++23
+// RUN: -triple powerpc64le-unknown-unknown %s \
+// RUN: -ffinite-math-only -funsafe-math-optimizations \
+// RUN: -std=c++23
// RUN: %clang_cc1 -x c++ -verify=no-fast -triple powerpc64le-unknown-unknown \
// RUN: %s -std=c++23
|
// Ensure that if FiniteMathOnly is enabled, NoHonorNaNs and NoHonorInfs are | ||
// also enabled. This is because FiniteMathOnly mode assumes no NaNs or Infs | ||
// are present in computations. | ||
assert((LO.FiniteMathOnly == (LO.NoHonorInfs && LO.NoHonorNaNs)) && |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The FiniteMathOnly
variable should be removed from LangOptions
entirely at this point; the plan is to only rely on NoHonorInfs
and NoHonorNans
instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is no need for the assertion then. I suppose CLFiniteMathOnly
should be removed too, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Correct, that assertion can go away (don't forget to update the PR title and summary accordingly as well).
I suppose CLFiniteMathOnly should be removed too, right?
CC @AnastasiaStulova as OpenCL code owner.
I think CLFiniteMathOnly
is a combination of NoHonorInfs
, NoHonorNaNs
, and OpenCL
language mode. However, I don't see CLFiniteMathOnly
being used by anything when I grep over the source. We set the flag from Options.td via marshaling, but we don't seem to ever check the value of the LangOpt anywhere. So it seems like CLFiniteMathOnly
can be removed and maybe -cl-finite-math-only
could be deprecated and eventually removed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Btw this option is defined in OpenCL spec so it would be better to keep this at least as a driver option.
https://registry.khronos.org/OpenCL/specs/3.0-unified/html/OpenCL_API.html#optimization-options
I think mapping it to NoHonorInfs
, NoHonorNaNs
frontend options seems reasonable.
Can the description of this change be elaborated to describe what the intension is.
Tagging @svenvh for any additional feedback.
But mapping
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@AnastasiaStulova thanks for the review.
The driver option -cl-finite-math-only
can still be used.
Updated the PR's description.
@@ -3295,7 +3295,17 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, | |||
} | |||
|
|||
// Handle __FINITE_MATH_ONLY__ similarly. | |||
if (!HonorINFs && !HonorNaNs) | |||
bool InfValues, NanValues = true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
InfValues
isn't initialized here
for (auto *Arg : Args.filtered(options::OPT_Xclang)) { | ||
processArg(Arg); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for (auto *Arg : Args.filtered(options::OPT_Xclang)) { | |
processArg(Arg); | |
} | |
for (auto *Arg : Args.filtered(options::OPT_Xclang)) | |
processArg(Arg); |
clang/lib/Basic/LangOptions.cpp
Outdated
NoHonorNaNs = 0; | ||
NoHonorInfs = 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we don't need this code at all because LangOptions.def
defines both of these with a default value of 0 anyway, so the x macros above should already do this automatically, right?
for (auto *Arg : Args.filtered(options::OPT_Xclang)) | ||
processArg(Arg); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of filtering all arguments to cc1 and looping over all of them, can we use Args.getLastArg()
? And can we skip that processing if we already know we're doing to pass -ffinite-math-only
because of (!HonorINFs && !HonorNaNs)
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't use Args.getLastArg()
with arguments to Xclang
. Args.filtered()
needs to be used.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you thinking of something like this?
// Handle __FINITE_MATH_ONLY__ similarly.
if (!HonorINFs && !HonorNaNs)
CmdArgs.push_back("-ffinite-math-only");
else {
bool InfValues = true;
bool NanValues = true;
auto processArg = [&](const auto *Arg) {
if (StringRef(Arg->getValue()) == "-menable-no-nans")
NanValues = false;
if (StringRef(Arg->getValue()) == "-menable-no-infs")
InfValues = false;
};
for (auto *Arg : Args.filtered(options::OPT_Xclang))
processArg(Arg);
if (!NanValues && !InfValues)
CmdArgs.push_back("-ffinite-math-only");
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That could work, I was thinking along these lines:
// Explanation of why we need to do this dance goes here.
auto NaNsAndInfs = [&] {
bool InfValues = true;
bool NanValues = true;
auto processArg = [&](const auto *Arg) {
if (StringRef(Arg->getValue()) == "-menable-no-nans")
NanValues = false;
if (StringRef(Arg->getValue()) == "-menable-no-infs")
InfValues = false;
};
for (auto *Arg : Args.filtered(options::OPT_Xclang))
processArg(Arg);
return InfValues && NanValues;
};
if ((!HonorINFs && !HonorNaNs) || !NaNsAndInfs())
CmdArgs.push_back("-ffinite-math-only");
I leave it to driver folks to say what they'd prefer if they have a strong preference.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mdtoguchi WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No strong preference - singular addition of -ffinite-math-only
is easier to maintain.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see. I could write something like this as a compromise?
bool shouldAddFiniteMathOnly = false;
if (!HonorINFs && !HonorNaNs) {
shouldAddFiniteMathOnly = true;
} else {
bool InfValues = true;
bool NanValues = true;
for (const auto *Arg : Args.filtered(options::OPT_Xclang)) {
StringRef ArgValue = Arg->getValue();
if (ArgValue == "-menable-no-nans")
NanValues = false;
else if (ArgValue == "-menable-no-infs")
InfValues = false;
}
if (!NanValues && !InfValues)
shouldAddFiniteMathOnly = true;
}
if (shouldAddFiniteMathOnly) {
CmdArgs.push_back("-ffinite-math-only");
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd be okay with that approach.
Opts.FastMath || Opts.FiniteMathOnly || Opts.UnsafeFPMath || | ||
Opts.AllowFPReassoc || Opts.NoHonorNaNs || Opts.NoHonorInfs || | ||
Opts.NoSignedZero || Opts.AllowRecip || Opts.ApproxFunc; | ||
Opts.FastMath || (Opts.NoHonorInfs && Opts.NoHonorNaNs) || |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given that NoHonorInfs and NoHonorNaNs are both individually checked below, you don't need this entry here.
Ping @AnastasiaStulova for OpenCL feedback (this PR impacts an OpenCL command line option). |
f85506e
to
50b2a87
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changes LGTM, I've added @MaskRay and @jansvoboda11 in case they can help answer the OpenCL questions, as it seems @AnastasiaStulova may be unavailable at the moment.
If we don't hear back from anyone in the next two days, I think it's fine to land.
Currently
__FINITE_MATH_ONLY__
is set whenFiniteMathOnly
. AndFiniteMathOnly
is set whenNoHonorInfs
&&NoHonorNans
is true. But what happens one of the latter flags is false?To avoid potential inconsistencies, the internal option
FiniteMathOnly
is removed option and the macro__FINITE_MATH_ONLY__
is set whenNoHonorInfs
&&NoHonorNans
.