-
Notifications
You must be signed in to change notification settings - Fork 13.5k
[clang] Report erroneous floating point results in _Complex math #90588
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
@llvm/pr-subscribers-clang Author: Timm Baeder (tbaederr) ChangesUse handleFloatFloatBinOp to properly diagnose NaN results and divisions by zero. Fixes #84871 Full diff: https://github.com/llvm/llvm-project/pull/90588.diff 2 Files Affected:
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index f1aa19e4409e15..86fb396fabe2d9 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -15209,11 +15209,21 @@ bool ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
APFloat &ResI = Result.getComplexFloatImag();
if (LHSReal) {
assert(!RHSReal && "Cannot have two real operands for a complex op!");
- ResR = A * C;
- ResI = A * D;
+ ResR = A;
+ ResI = A;
+ // ResR = A * C;
+ // ResI = A * D;
+ if (!handleFloatFloatBinOp(Info, E, ResR, BO_Mul, C) ||
+ !handleFloatFloatBinOp(Info, E, ResI, BO_Mul, D))
+ return false;
} else if (RHSReal) {
- ResR = C * A;
- ResI = C * B;
+ // ResR = C * A;
+ // ResI = C * B;
+ ResR = C;
+ ResI = C;
+ if (!handleFloatFloatBinOp(Info, E, ResR, BO_Mul, A) ||
+ !handleFloatFloatBinOp(Info, E, ResI, BO_Mul, B))
+ return false;
} else {
// In the fully general case, we need to handle NaNs and infinities
// robustly.
@@ -15289,8 +15299,13 @@ bool ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
APFloat &ResR = Result.getComplexFloatReal();
APFloat &ResI = Result.getComplexFloatImag();
if (RHSReal) {
- ResR = A / C;
- ResI = B / C;
+ ResR = A;
+ ResI = B;
+ // ResR = A / C;
+ // ResI = B / C;
+ if (!handleFloatFloatBinOp(Info, E, ResR, BO_Div, C) ||
+ !handleFloatFloatBinOp(Info, E, ResI, BO_Div, C))
+ return false;
} else {
if (LHSReal) {
// No real optimizations we can do here, stub out with zero.
diff --git a/clang/test/SemaCXX/complex-folding.cpp b/clang/test/SemaCXX/complex-folding.cpp
index 054f159e9ce0dd..d3e428f2b75cc2 100644
--- a/clang/test/SemaCXX/complex-folding.cpp
+++ b/clang/test/SemaCXX/complex-folding.cpp
@@ -57,43 +57,58 @@ static_assert(((1.25 + 0.5j) / (0.25 - 0.75j)) == (-0.1 + 1.7j));
static_assert(((1.25 + 0.5j) / 0.25) == (5.0 + 2.0j));
static_assert((1.25 / (0.25 - 0.75j)) == (0.5 + 1.5j));
-// Test that infinities are preserved, don't turn into NaNs, and do form zeros
-// when the divisor.
+
static_assert(__builtin_isinf_sign(__real__((__builtin_inf() + 1.0j) * 1.0)) == 1);
-static_assert(__builtin_isinf_sign(__imag__((1.0 + __builtin_inf() * 1.0j) * 1.0)) == 1);
+static_assert(__builtin_isinf_sign(__imag__((1.0 + __builtin_inf() * 1.0j) * 1.0)) == 1); // expected-error {{static assertion}} \
+ // expected-note {{produces a NaN}}
static_assert(__builtin_isinf_sign(__real__(1.0 * (__builtin_inf() + 1.0j))) == 1);
-static_assert(__builtin_isinf_sign(__imag__(1.0 * (1.0 + __builtin_inf() * 1.0j))) == 1);
-
+static_assert(__builtin_isinf_sign(__imag__(1.0 * (1.0 + __builtin_inf() * 1.0j))) == 1); // expected-error {{static assertion}} \
+ // expected-note {{produces a NaN}}
static_assert(__builtin_isinf_sign(__real__((__builtin_inf() + 1.0j) * (1.0 + 1.0j))) == 1);
static_assert(__builtin_isinf_sign(__real__((1.0 + 1.0j) * (__builtin_inf() + 1.0j))) == 1);
static_assert(__builtin_isinf_sign(__real__((__builtin_inf() + 1.0j) * (__builtin_inf() + 1.0j))) == 1);
-
-static_assert(__builtin_isinf_sign(__real__((1.0 + __builtin_inf() * 1.0j) * (1.0 + 1.0j))) == -1);
-static_assert(__builtin_isinf_sign(__imag__((1.0 + __builtin_inf() * 1.0j) * (1.0 + 1.0j))) == 1);
-static_assert(__builtin_isinf_sign(__real__((1.0 + 1.0j) * (1.0 + __builtin_inf() * 1.0j))) == -1);
-static_assert(__builtin_isinf_sign(__imag__((1.0 + 1.0j) * (1.0 + __builtin_inf() * 1.0j))) == 1);
-
-static_assert(__builtin_isinf_sign(__real__((1.0 + __builtin_inf() * 1.0j) * (1.0 + __builtin_inf() * 1.0j))) == -1);
-static_assert(__builtin_isinf_sign(__real__((__builtin_inf() + __builtin_inf() * 1.0j) * (__builtin_inf() + __builtin_inf() * 1.0j))) == -1);
-
+static_assert(__builtin_isinf_sign(__real__((1.0 + __builtin_inf() * 1.0j) * (1.0 + 1.0j))) == -1); // expected-error {{static assertion}} \
+ // expected-note {{produces a NaN}}
+static_assert(__builtin_isinf_sign(__imag__((1.0 + __builtin_inf() * 1.0j) * (1.0 + 1.0j))) == 1); // expected-error {{static assertion}} \
+ // expected-note {{produces a NaN}}
+static_assert(__builtin_isinf_sign(__real__((1.0 + 1.0j) * (1.0 + __builtin_inf() * 1.0j))) == -1); // expected-error {{static assertion}} \
+ // expected-note {{produces a NaN}}
+static_assert(__builtin_isinf_sign(__imag__((1.0 + 1.0j) * (1.0 + __builtin_inf() * 1.0j))) == 1); // expected-error {{static assertion}} \
+ // expected-note {{produces a NaN}}
+static_assert(__builtin_isinf_sign(__real__((1.0 + __builtin_inf() * 1.0j) * (1.0 + __builtin_inf() * 1.0j))) == -1); // expected-error {{static assertion}} \
+ // expected-note {{produces a NaN}}
+static_assert(__builtin_isinf_sign(__real__((__builtin_inf() + __builtin_inf() * 1.0j) * (__builtin_inf() + __builtin_inf() * 1.0j))) == -1); // expected-error {{static assertion}} \
+ // expected-note {{produces a NaN}}
static_assert(__builtin_isinf_sign(__real__((__builtin_inf() + 1.0j) / (1.0 + 1.0j))) == 1);
-static_assert(__builtin_isinf_sign(__imag__(1.0 + (__builtin_inf() * 1.0j) / (1.0 + 1.0j))) == 1);
-static_assert(__builtin_isinf_sign(__imag__((__builtin_inf() + __builtin_inf() * 1.0j) / (1.0 + 1.0j))) == 1);
+static_assert(__builtin_isinf_sign(__imag__(1.0 + (__builtin_inf() * 1.0j) / (1.0 + 1.0j))) == 1); // expected-error {{static assertion}} \
+ // expected-note {{produces a NaN}}
+static_assert(__builtin_isinf_sign(__imag__((__builtin_inf() + __builtin_inf() * 1.0j) / (1.0 + 1.0j))) == 1); // expected-error {{static assertion}} \
+ // expected-note {{produces a NaN}}
static_assert(__builtin_isinf_sign(__real__((__builtin_inf() + 1.0j) / 1.0)) == 1);
-static_assert(__builtin_isinf_sign(__imag__(1.0 + (__builtin_inf() * 1.0j) / 1.0)) == 1);
-static_assert(__builtin_isinf_sign(__imag__((__builtin_inf() + __builtin_inf() * 1.0j) / 1.0)) == 1);
-
+static_assert(__builtin_isinf_sign(__imag__(1.0 + (__builtin_inf() * 1.0j) / 1.0)) == 1); // expected-error {{static assertion}} \
+ // expected-note {{produces a NaN}}
+static_assert(__builtin_isinf_sign(__imag__((__builtin_inf() + __builtin_inf() * 1.0j) / 1.0)) == 1); // expected-error {{static assertion}} \
+ // expected-note {{produces a NaN}}
static_assert(((1.0 + 1.0j) / (__builtin_inf() + 1.0j)) == (0.0 + 0.0j));
-static_assert(((1.0 + 1.0j) / (1.0 + __builtin_inf() * 1.0j)) == (0.0 + 0.0j));
-static_assert(((1.0 + 1.0j) / (__builtin_inf() + __builtin_inf() * 1.0j)) == (0.0 + 0.0j));
+static_assert(((1.0 + 1.0j) / (1.0 + __builtin_inf() * 1.0j)) == (0.0 + 0.0j)); // expected-error {{static assertion}} \
+ // expected-note {{produces a NaN}}
+static_assert(((1.0 + 1.0j) / (__builtin_inf() + __builtin_inf() * 1.0j)) == (0.0 + 0.0j)); // expected-error {{static assertion}} \
+ // expected-note {{produces a NaN}}
static_assert(((1.0 + 1.0j) / __builtin_inf()) == (0.0 + 0.0j));
-
+static_assert(1.0j / 0.0 == 1); // expected-error {{static assertion}} \
+ // expected-note {{division by zero}}
static_assert(__builtin_isinf_sign(__real__((1.0 + 1.0j) / (0.0 + 0.0j))) == 1);
-static_assert(__builtin_isinf_sign(__real__((1.0 + 1.0j) / 0.0)) == 1);
-
+static_assert(__builtin_isinf_sign(__real__((1.0 + 1.0j) / 0.0)) == 1); // expected-error {{static assertion}} \
+ // expected-note {{division by zero}}
static_assert(__builtin_isinf_sign(__real__((__builtin_inf() + 1.0j) / (0.0 + 0.0j))) == 1);
-static_assert(__builtin_isinf_sign(__imag__((1.0 + __builtin_inf() * 1.0j) / (0.0 + 0.0j))) == 1);
-static_assert(__builtin_isinf_sign(__imag__((__builtin_inf() + __builtin_inf() * 1.0j) / (0.0 + 0.0j))) == 1);
-static_assert(__builtin_isinf_sign(__real__((__builtin_inf() + 1.0j) / 0.0)) == 1);
-static_assert(__builtin_isinf_sign(__imag__((1.0 + __builtin_inf() * 1.0j) / 0.0)) == 1);
-static_assert(__builtin_isinf_sign(__imag__((__builtin_inf() + __builtin_inf() * 1.0j) / 0.0)) == 1);
+static_assert(__builtin_isinf_sign(__imag__((1.0 + __builtin_inf() * 1.0j) / (0.0 + 0.0j))) == 1); // expected-error {{static assertion}} \
+ // expected-note {{produces a NaN}}
+static_assert(__builtin_isinf_sign(__imag__((__builtin_inf() + __builtin_inf() * 1.0j) / (0.0 + 0.0j))) == 1); // expected-error {{static assertion}} \
+ // expected-note {{produces a NaN}}
+static_assert(__builtin_isinf_sign(__real__((__builtin_inf() + 1.0j) / 0.0)) == 1); // expected-error {{static assertion}} \
+ // expected-note {{division by zero}}
+static_assert(__builtin_isinf_sign(__imag__((1.0 + __builtin_inf() * 1.0j) / 0.0)) == 1); // expected-error {{static assertion}} \
+ // expected-note {{produces a NaN}}
+static_assert(__builtin_isinf_sign(__imag__((__builtin_inf() + __builtin_inf() * 1.0j) / 0.0)) == 1); // expected-error {{static assertion}} \
+ // expected-note {{produces a NaN}}
+
|
Ping |
1 similar comment
Ping |
The changes seem reasonable to me, but I'd like to hear from @jcranmer-intel and/or @hubert-reinterpretcast in terms of whether they agree with this direction. |
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.
After banging my head on the desk trying to figure out why the tests were giving such strange results, I realized the issue...
Could you please use __builtin_complex
in the test to construct the complex infinities instead of __builtin_infinity() * 1.0j
?
Use handleFloatFloatBinOp to properly diagnose NaN results and divisions by zero.
Ping |
It seems this review feedback as not been addressed? |
The tests aren't using |
Out of curiosity, why are they not using @jcranmer-intel are you okay with the new approach? |
I started out replacing a lot of those expressions with |
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 unless @jcranmer-intel still has concerns.
…m#90588) Use handleFloatFloatBinOp to properly diagnose NaN results and divisions by zero. Fixes llvm#84871 Signed-off-by: Hafidz Muzakky <[email protected]>
Use handleFloatFloatBinOp to properly diagnose NaN results and divisions by zero.
Fixes #84871