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.

One existing problem is that we can't do much with the values since comparing 
with nans is broken ATM and I don't want to make this patch depend on the 
`__builtin_bit_cast` patch.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D155356

Files:
  clang/lib/AST/Interp/InterpBuiltin.cpp
  clang/test/AST/Interp/builtin-functions.cpp

Index: clang/test/AST/Interp/builtin-functions.cpp
===================================================================
--- clang/test/AST/Interp/builtin-functions.cpp
+++ clang/test/AST/Interp/builtin-functions.cpp
@@ -1,5 +1,8 @@
 // RUN: %clang_cc1 -fexperimental-new-constant-interpreter %s -verify
 // RUN: %clang_cc1 -verify=ref %s -Wno-constant-evaluated
+// RUN: %clang_cc1 -std=c++20 -fexperimental-new-constant-interpreter %s -verify
+// RUN: %clang_cc1 -std=c++20 -verify=ref %s -Wno-constant-evaluated
+
 
 namespace strcmp {
   constexpr char kFoobar[6] = {'f','o','o','b','a','r'};
@@ -34,3 +37,28 @@
                                                                     // ref-error {{not an integral constant}} \
                                                                     // ref-note {{dereferenced one-past-the-end}}
 }
+
+namespace nan {
+  constexpr double NaN1 = __builtin_nan("");
+
+#if __cplusplus >= 202002
+  /// Reading an uninitialized value as part of the argument.
+  constexpr int foo() { // ref-error {{never produces a constant expression}}
+    char f[2];
+    f[0] = '1';
+
+    double d = __builtin_nan(f); // ref-note 2{{subexpression not valid in a constant expression}} \
+                                 // expected-note {{read of uninitialized object}} \
+                                 // expected-note {{in call to '__builtin_nan}}
+    return 1;
+  }
+  static_assert(foo() == 1); // ref-error {{not an integral constant expression}} \
+                             // ref-note {{in call to}} \
+                             // expected-error {{not an integral constant expression}} \
+                             // expected-note {{in call to}}
+#endif
+
+
+  constexpr float Nan2 = __builtin_nans([](){return "0xAE98";}()); // ref-error {{must be initialized by a constant expression}}
+
+}
Index: clang/lib/AST/Interp/InterpBuiltin.cpp
===================================================================
--- clang/lib/AST/Interp/InterpBuiltin.cpp
+++ clang/lib/AST/Interp/InterpBuiltin.cpp
@@ -9,6 +9,7 @@
 #include "Interp.h"
 #include "PrimType.h"
 #include "clang/Basic/Builtins.h"
+#include "clang/Basic/TargetInfo.h"
 
 namespace clang {
 namespace interp {
@@ -57,6 +58,63 @@
   return true;
 }
 
+static bool interp__builtin_nan(InterpState &S, CodePtr OpPC,
+                                const InterpFrame *Frame, const Function *F,
+                                bool Signaling) {
+  const Pointer &Arg = getParam<Pointer>(Frame, 0);
+
+  if (!CheckLoad(S, OpPC, Arg))
+    return false;
+
+  assert(Arg.getFieldDesc()->isPrimitiveArray());
+
+  llvm::APInt Fill;
+  if (Arg.getNumElems() == 0)
+    Fill = llvm::APInt(32, 0);
+  else {
+    // Convert the given string to an integer using StringRef's API.
+    std::string Str;
+
+    for (unsigned I = 0, E = Arg.getNumElems(); I != E; ++I) {
+      const Pointer &Elem = Arg.atIndex(I);
+
+      if (!CheckLoad(S, OpPC, Elem))
+        return false;
+
+      Str += Elem.deref<char>();
+    }
+    StringRef(Str).getAsInteger(0, Fill);
+  }
+
+  const llvm::fltSemantics &TargetSemantics =
+      S.getCtx().getFloatTypeSemantics(F->getDecl()->getReturnType());
+
+  Floating Result;
+  if (S.getCtx().getTargetInfo().isNan2008()) {
+    if (Signaling)
+      Result = Floating(
+          llvm::APFloat::getSNaN(TargetSemantics, /*Negative=*/false, &Fill));
+    else
+      Result = Floating(
+          llvm::APFloat::getQNaN(TargetSemantics, /*Negative=*/false, &Fill));
+  } else {
+    // Prior to IEEE 754-2008, architectures were allowed to choose whether
+    // the first bit of their significand was set for qNaN or sNaN. MIPS chose
+    // a different encoding to what became a standard in 2008, and for pre-
+    // 2008 revisions, MIPS interpreted sNaN-2008 as qNan and qNaN-2008 as
+    // sNaN. This is now known as "legacy NaN" encoding.
+    if (Signaling)
+      Result = Floating(
+          llvm::APFloat::getQNaN(TargetSemantics, /*Negative=*/false, &Fill));
+    else
+      Result = Floating(
+          llvm::APFloat::getSNaN(TargetSemantics, /*Negative=*/false, &Fill));
+  }
+
+  S.Stk.push<Floating>(Result);
+  return true;
+}
+
 bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F) {
   InterpFrame *Frame = S.Current;
   APValue Dummy;
@@ -70,7 +128,24 @@
   case Builtin::BI__builtin_strcmp:
     if (interp__builtin_strcmp(S, OpPC, Frame))
       return Ret<PT_Sint32>(S, OpPC, Dummy);
-    return false;
+    break;
+  case Builtin::BI__builtin_nan:
+  case Builtin::BI__builtin_nanf:
+  case Builtin::BI__builtin_nanl:
+  case Builtin::BI__builtin_nanf16:
+  case Builtin::BI__builtin_nanf128:
+    if (interp__builtin_nan(S, OpPC, Frame, F, /*Signaling=*/false))
+      return Ret<PT_Float>(S, OpPC, Dummy);
+    break;
+  case Builtin::BI__builtin_nans:
+  case Builtin::BI__builtin_nansf:
+  case Builtin::BI__builtin_nansl:
+  case Builtin::BI__builtin_nansf16:
+  case Builtin::BI__builtin_nansf128:
+    if (interp__builtin_nan(S, OpPC, Frame, F, /*Signaling=*/true))
+      return Ret<PT_Float>(S, OpPC, Dummy);
+    break;
+
   default:
     return false;
   }
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to