[PATCH] D156506: [clang][Interp] Check floating results for NaNs

2023-09-11 Thread Timm Bäder via Phabricator via cfe-commits
This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
Closed by commit rG4b5fe9c42d94: [clang][Interp] Check floating results for 
NaNs (authored by tbaeder).

Changed prior to commit:
  https://reviews.llvm.org/D156506?vs=545023&id=556407#toc

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D156506/new/

https://reviews.llvm.org/D156506

Files:
  clang/lib/AST/Interp/Interp.cpp
  clang/lib/AST/Interp/Interp.h
  clang/test/AST/Interp/floats.cpp

Index: clang/test/AST/Interp/floats.cpp
===
--- clang/test/AST/Interp/floats.cpp
+++ clang/test/AST/Interp/floats.cpp
@@ -202,3 +202,18 @@
   static_assert(!(inf < nan), "");
   static_assert(!(inf > nan), "");
 }
+
+namespace nan {
+  constexpr double nan = __builtin_nan("");
+  static_assert(nan);
+
+  constexpr double D1 = 1 + nan; // ref-error {{must be initialized by a constant expression}} \
+ // ref-note {{produces a NaN}} \
+ // expected-error {{must be initialized by a constant expression}} \
+ // expected-note {{produces a NaN}}
+
+  constexpr double D2 = __builtin_inf() / __builtin_inf(); // ref-error {{must be initialized by a constant expression}} \
+   // ref-note {{produces a NaN}} \
+   // expected-error {{must be initialized by a constant expression}} \
+   // expected-note {{produces a NaN}}
+}
Index: clang/lib/AST/Interp/Interp.h
===
--- clang/lib/AST/Interp/Interp.h
+++ clang/lib/AST/Interp/Interp.h
@@ -172,7 +172,8 @@
 
 /// Checks if the result of a floating-point operation is valid
 /// in the current context.
-bool CheckFloatResult(InterpState &S, CodePtr OpPC, APFloat::opStatus Status);
+bool CheckFloatResult(InterpState &S, CodePtr OpPC, const Floating &Result,
+  APFloat::opStatus Status);
 
 /// Interpreter entry point.
 bool Interpret(InterpState &S, APValue &Result);
@@ -304,7 +305,7 @@
   Floating Result;
   auto Status = Floating::add(LHS, RHS, RM, &Result);
   S.Stk.push(Result);
-  return CheckFloatResult(S, OpPC, Status);
+  return CheckFloatResult(S, OpPC, Result, Status);
 }
 
 template ::T>
@@ -322,7 +323,7 @@
   Floating Result;
   auto Status = Floating::sub(LHS, RHS, RM, &Result);
   S.Stk.push(Result);
-  return CheckFloatResult(S, OpPC, Status);
+  return CheckFloatResult(S, OpPC, Result, Status);
 }
 
 template ::T>
@@ -340,7 +341,7 @@
   Floating Result;
   auto Status = Floating::mul(LHS, RHS, RM, &Result);
   S.Stk.push(Result);
-  return CheckFloatResult(S, OpPC, Status);
+  return CheckFloatResult(S, OpPC, Result, Status);
 }
 /// 1) Pops the RHS from the stack.
 /// 2) Pops the LHS from the stack.
@@ -443,7 +444,7 @@
   Floating Result;
   auto Status = Floating::div(LHS, RHS, RM, &Result);
   S.Stk.push(Result);
-  return CheckFloatResult(S, OpPC, Status);
+  return CheckFloatResult(S, OpPC, Result, Status);
 }
 
 //===--===//
@@ -622,7 +623,7 @@
 
   Ptr.deref() = Result;
 
-  return CheckFloatResult(S, OpPC, Status);
+  return CheckFloatResult(S, OpPC, Result, Status);
 }
 
 inline bool Incf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
@@ -1525,7 +1526,7 @@
   auto Status = Floating::fromIntegral(FromAP, *Sem, RM, Result);
   S.Stk.push(Result);
 
-  return CheckFloatResult(S, OpPC, Status);
+  return CheckFloatResult(S, OpPC, Result, Status);
 }
 
 template ::T>
@@ -1550,7 +1551,7 @@
 }
 
 S.Stk.push(T(Result));
-return CheckFloatResult(S, OpPC, Status);
+return CheckFloatResult(S, OpPC, F, Status);
   }
 }
 
Index: clang/lib/AST/Interp/Interp.cpp
===
--- clang/lib/AST/Interp/Interp.cpp
+++ clang/lib/AST/Interp/Interp.cpp
@@ -495,13 +495,25 @@
   return false;
 }
 
-bool CheckFloatResult(InterpState &S, CodePtr OpPC, APFloat::opStatus Status) {
+bool CheckFloatResult(InterpState &S, CodePtr OpPC, const Floating &Result,
+  APFloat::opStatus Status) {
+  const SourceInfo &E = S.Current->getSource(OpPC);
+
+  // [expr.pre]p4:
+  //   If during the evaluation of an expression, the result is not
+  //   mathematically defined [...], the behavior is undefined.
+  // FIXME: C++ rules require us to not conform to IEEE 754 here.
+  if (Result.isNan()) {
+S.CCEDiag(E, diag::note_constexpr_float_arithmetic)
+<< /*NaN=*/true << S.Current->getRange(OpPC);
+return S.noteUndefinedBehavior();
+  }
+
   // In a constant context, assume that any dynamic rounding mode or FP
   // exception state matches the default fl

[PATCH] D156506: [clang][Interp] Check floating results for NaNs

2023-09-04 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder added a comment.

I thought this review wasn't clear at all on what's supposed to happen but 
since https://reviews.llvm.org/D157072 is going nowhere, I'll just push this 
one in the next few days.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D156506/new/

https://reviews.llvm.org/D156506

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D156506: [clang][Interp] Check floating results for NaNs

2023-08-03 Thread Joshua Cranmer via Phabricator via cfe-commits
jcranmer-intel added inline comments.



Comment at: clang/lib/AST/Interp/Interp.cpp:503
+  //   If during the evaluation of an expression, the result is not
+  //   mathematically defined [...], the behavior is undefined.
+  // FIXME: C++ rules require us to not conform to IEEE 754 here.

tbaeder wrote:
> @jcranmer-intel Doesn't this comment (which I've coped from 
> `ExprConstant.cpp`) contradict what you said about not checking the result?
Immediately following that in the specification is this:
> [Note 3: Treatment of division by zero, forming a remainder using a zero 
> divisor, and all floating-point exceptions varies among machines, and is 
> sometimes adjustable by a library function. — end note]

The current C++ specification is rather clear about its unclarity on 
floating-point. Also note that IEEE 754 defines floating-point data as 
consisting of {-inf, ..., -0} union {+0, ..., +inf} union {NaN}. So NaN is 
arguable to be a well-defined mathematical result, if you consider that 
floating-point types don't model real numbers but an approximation of real 
numbers (just as unsigned integers model not integers but integers mod 2^N).


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D156506/new/

https://reviews.llvm.org/D156506

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D156506: [clang][Interp] Check floating results for NaNs

2023-08-03 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder added inline comments.



Comment at: clang/lib/AST/Interp/Interp.cpp:503
+  //   If during the evaluation of an expression, the result is not
+  //   mathematically defined [...], the behavior is undefined.
+  // FIXME: C++ rules require us to not conform to IEEE 754 here.

@jcranmer-intel Doesn't this comment (which I've coped from `ExprConstant.cpp`) 
contradict what you said about not checking the result?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D156506/new/

https://reviews.llvm.org/D156506

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D156506: [clang][Interp] Check floating results for NaNs

2023-08-02 Thread Joshua Cranmer via Phabricator via cfe-commits
jcranmer-intel added a comment.

You definitely don't want these rules to apply to all qNaNs. It's when an input 
operand is an sNaN for many operations. Note that the result of an operation 
with an sNaN as input (and FP result type) is a qNaN output, and the only times 
that you get an sNaN output are the times when you never signal (I think), so 
checking the result type is incorrect.




Comment at: clang/lib/AST/Interp/Interp.cpp:534-539
   if ((Status & APFloat::opStatus::opInvalidOp) &&
   FPO.getExceptionMode() != LangOptions::FPE_Ignore) {
 // There is no usefully definable result.
 S.FFDiag(E);
 return false;
   }

A further note is that sNaNs signal `FE_INVALID` when used, so sNaN should 
generally fall into this if statement in particular.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D156506/new/

https://reviews.llvm.org/D156506

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D156506: [clang][Interp] Check floating results for NaNs

2023-08-02 Thread Aaron Ballman via Phabricator via cfe-commits
aaron.ballman accepted this revision.
aaron.ballman added a subscriber: jcranmer-intel.
aaron.ballman added a comment.
This revision is now accepted and ready to land.

> This does not handle the builtin functions yet, since I'm not sure if I 
> should check for all nans or only signaling ones yet.

I think it's only signaling ones, but CC @jcranmer-intel for a better-informed 
answer.

The changes here LGTM though.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D156506/new/

https://reviews.llvm.org/D156506

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D156506: [clang][Interp] Check floating results for NaNs

2023-07-27 Thread Timm Bäder via Phabricator via cfe-commits
tbaeder created this revision.
tbaeder added reviewers: aaron.ballman, erichkeane, shafik, cor3ntin.
Herald added a project: All.
tbaeder requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

This does not handle the builtin functions yet, since I'm not sure if I should 
check for all nans or only signaling ones yet.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D156506

Files:
  clang/lib/AST/Interp/Interp.cpp
  clang/lib/AST/Interp/Interp.h
  clang/test/AST/Interp/floats.cpp

Index: clang/test/AST/Interp/floats.cpp
===
--- clang/test/AST/Interp/floats.cpp
+++ clang/test/AST/Interp/floats.cpp
@@ -161,3 +161,18 @@
   static_assert(!(inf < nan), "");
   static_assert(!(inf > nan), "");
 }
+
+namespace nan {
+  constexpr double nan = __builtin_nan("");
+  static_assert(nan);
+
+  constexpr double D1 = 1 + nan; // ref-error {{must be initialized by a constant expression}} \
+ // ref-note {{produces a NaN}} \
+ // expected-error {{must be initialized by a constant expression}} \
+ // expected-note {{produces a NaN}}
+
+  constexpr double D2 = __builtin_inf() / __builtin_inf(); // ref-error {{must be initialized by a constant expression}} \
+   // ref-note {{produces a NaN}} \
+   // expected-error {{must be initialized by a constant expression}} \
+   // expected-note {{produces a NaN}}
+}
Index: clang/lib/AST/Interp/Interp.h
===
--- clang/lib/AST/Interp/Interp.h
+++ clang/lib/AST/Interp/Interp.h
@@ -171,7 +171,8 @@
 
 /// Checks if the result is a floating-point operation is valid
 /// in the current context.
-bool CheckFloatResult(InterpState &S, CodePtr OpPC, APFloat::opStatus Status);
+bool CheckFloatResult(InterpState &S, CodePtr OpPC, const Floating &Result,
+  APFloat::opStatus Status);
 
 bool CheckBitcast(InterpState &S, CodePtr OpPC, unsigned IndeterminateBits,
   bool TargetIsUCharOrByte);
@@ -316,7 +317,7 @@
   Floating Result;
   auto Status = Floating::add(LHS, RHS, RM, &Result);
   S.Stk.push(Result);
-  return CheckFloatResult(S, OpPC, Status);
+  return CheckFloatResult(S, OpPC, Result, Status);
 }
 
 template ::T>
@@ -334,7 +335,7 @@
   Floating Result;
   auto Status = Floating::sub(LHS, RHS, RM, &Result);
   S.Stk.push(Result);
-  return CheckFloatResult(S, OpPC, Status);
+  return CheckFloatResult(S, OpPC, Result, Status);
 }
 
 template ::T>
@@ -352,7 +353,7 @@
   Floating Result;
   auto Status = Floating::mul(LHS, RHS, RM, &Result);
   S.Stk.push(Result);
-  return CheckFloatResult(S, OpPC, Status);
+  return CheckFloatResult(S, OpPC, Result, Status);
 }
 /// 1) Pops the RHS from the stack.
 /// 2) Pops the LHS from the stack.
@@ -455,7 +456,7 @@
   Floating Result;
   auto Status = Floating::div(LHS, RHS, RM, &Result);
   S.Stk.push(Result);
-  return CheckFloatResult(S, OpPC, Status);
+  return CheckFloatResult(S, OpPC, Result, Status);
 }
 
 //===--===//
@@ -632,7 +633,7 @@
 
   Ptr.deref() = Result;
 
-  return CheckFloatResult(S, OpPC, Status);
+  return CheckFloatResult(S, OpPC, Result, Status);
 }
 
 inline bool Incf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
@@ -1586,7 +1587,7 @@
   auto Status = Floating::fromIntegral(FromAP, *Sem, RM, Result);
   S.Stk.push(Result);
 
-  return CheckFloatResult(S, OpPC, Status);
+  return CheckFloatResult(S, OpPC, Result, Status);
 }
 
 template ::T>
@@ -1611,7 +1612,7 @@
 }
 
 S.Stk.push(T(Result));
-return CheckFloatResult(S, OpPC, Status);
+return CheckFloatResult(S, OpPC, F, Status);
   }
 }
 
Index: clang/lib/AST/Interp/Interp.cpp
===
--- clang/lib/AST/Interp/Interp.cpp
+++ clang/lib/AST/Interp/Interp.cpp
@@ -494,13 +494,25 @@
   return false;
 }
 
-bool CheckFloatResult(InterpState &S, CodePtr OpPC, APFloat::opStatus Status) {
+bool CheckFloatResult(InterpState &S, CodePtr OpPC, const Floating &Result,
+  APFloat::opStatus Status) {
+  const SourceInfo &E = S.Current->getSource(OpPC);
+
+  // [expr.pre]p4:
+  //   If during the evaluation of an expression, the result is not
+  //   mathematically defined [...], the behavior is undefined.
+  // FIXME: C++ rules require us to not conform to IEEE 754 here.
+  if (Result.isNan()) {
+S.CCEDiag(E, diag::note_constexpr_float_arithmetic)
+<< /*NaN=*/true << S.Current->getRange(OpPC);
+return S.noteUndefinedBehavior();
+  }
+
   // In a constant context, assume that any dynamic rounding mode or FP
   // exception