tbaeder updated this revision to Diff 540760.
tbaeder marked an inline comment as done.

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

https://reviews.llvm.org/D155369

Files:
  clang/lib/AST/Interp/Function.cpp
  clang/lib/AST/Interp/Function.h
  clang/lib/AST/Interp/Interp.cpp
  clang/lib/AST/Interp/Interp.h
  clang/lib/AST/Interp/InterpBuiltin.cpp
  clang/test/Sema/constant-builtins-fmin.cpp

Index: clang/test/Sema/constant-builtins-fmin.cpp
===================================================================
--- clang/test/Sema/constant-builtins-fmin.cpp
+++ clang/test/Sema/constant-builtins-fmin.cpp
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 -std=c++17 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++17 -fsyntax-only -verify -fexperimental-new-constant-interpreter %s
 // expected-no-diagnostics
 
 constexpr double NaN = __builtin_nan("");
Index: clang/lib/AST/Interp/InterpBuiltin.cpp
===================================================================
--- clang/lib/AST/Interp/InterpBuiltin.cpp
+++ clang/lib/AST/Interp/InterpBuiltin.cpp
@@ -158,6 +158,20 @@
   return true;
 }
 
+/// Defined as __builtin_isnan(...), to accommodate the fact that it can
+/// take a float, double, long double, etc.
+/// But for us, that's all a Floating anyway.
+static bool interp__builtin_isnan(InterpState &S, CodePtr OpPC,
+                                  const InterpFrame *Frame, const Function *F) {
+  // FIXME: We are not going through getParam() here, because the function
+  // doesn't have any parameters. Wait for a pattern to emerge and maybe
+  // refactor this into a different function that checks things are valid.
+  const Floating &Arg = S.Stk.peek<Floating>();
+
+  S.Stk.push<Integral<32, true>>(Integral<32, true>::from(Arg.isNan()));
+  return true;
+}
+
 bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F) {
   InterpFrame *Frame = S.Current;
   APValue Dummy;
@@ -213,6 +227,11 @@
       return Ret<PT_Float>(S, OpPC, Dummy);
     break;
 
+  case Builtin::BI__builtin_isnan:
+    if (interp__builtin_isnan(S, OpPC, Frame, F))
+      return Ret<PT_Sint32>(S, OpPC, Dummy);
+    break;
+
   default:
     return false;
   }
Index: clang/lib/AST/Interp/Interp.h
===================================================================
--- clang/lib/AST/Interp/Interp.h
+++ clang/lib/AST/Interp/Interp.h
@@ -200,6 +200,9 @@
 // Returning values
 //===----------------------------------------------------------------------===//
 
+/// Pop arguments of builtins defined as func-name(...).
+bool popBuiltinArgs(InterpState &S, CodePtr OpPC);
+
 template <PrimType Name, class T = typename PrimConv<Name>::T>
 bool Ret(InterpState &S, CodePtr &PC, APValue &Result) {
   const T &Ret = S.Stk.pop<T>();
@@ -216,8 +219,16 @@
   }
 
   assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame");
-  if (!S.checkingPotentialConstantExpression() || S.Current->Caller)
-    S.Current->popArgs();
+  if (!S.checkingPotentialConstantExpression() || S.Current->Caller) {
+    // Certain builtin functions are declared as func-name(...), so the
+    // parameters are checked in Sema and only available through the CallExpr.
+    // The interp::Function we create for them has 0 parameters, so we need to
+    // remove them from the stack by checking the CallExpr.
+    if (S.Current && S.Current->getFunction()->needsRuntimeArgPop(S.getCtx()))
+      popBuiltinArgs(S, PC);
+    else
+      S.Current->popArgs();
+  }
 
   if (InterpFrame *Caller = S.Current->Caller) {
     PC = S.Current->getRetPC();
Index: clang/lib/AST/Interp/Interp.cpp
===================================================================
--- clang/lib/AST/Interp/Interp.cpp
+++ clang/lib/AST/Interp/Interp.cpp
@@ -122,6 +122,18 @@
 namespace clang {
 namespace interp {
 
+bool popBuiltinArgs(InterpState &S, CodePtr OpPC) {
+  assert(S.Current && S.Current->getFunction()->needsRuntimeArgPop(S.getCtx()));
+  const Expr *E = S.Current->getExpr(OpPC);
+  assert(isa<CallExpr>(E));
+  const CallExpr *CE = cast<CallExpr>(E);
+  for (const auto *A : llvm::reverse(CE->arguments())) {
+    PrimType Ty = S.getContext().classify(A->getType()).value_or(PT_Ptr);
+    TYPE_SWITCH(Ty, S.Stk.discard<T>());
+  }
+  return true;
+}
+
 bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
   if (!Ptr.isExtern())
     return true;
Index: clang/lib/AST/Interp/Function.h
===================================================================
--- clang/lib/AST/Interp/Function.h
+++ clang/lib/AST/Interp/Function.h
@@ -171,6 +171,12 @@
 
   unsigned getBuiltinID() const { return F->getBuiltinID(); }
 
+  bool isBuiltin() const { return F->getBuiltinID() != 0; }
+
+  /// Does this function need its arguments to be classified at runtime
+  /// rather than at bytecode-compile-time?
+  bool needsRuntimeArgPop(const ASTContext &Ctx) const;
+
   unsigned getNumParams() const { return ParamTypes.size(); }
 
   unsigned getParamOffset(unsigned ParamIndex) const {
Index: clang/lib/AST/Interp/Function.cpp
===================================================================
--- clang/lib/AST/Interp/Function.cpp
+++ clang/lib/AST/Interp/Function.cpp
@@ -7,10 +7,11 @@
 //===----------------------------------------------------------------------===//
 
 #include "Function.h"
-#include "Program.h"
 #include "Opcode.h"
+#include "Program.h"
 #include "clang/AST/Decl.h"
 #include "clang/AST/DeclCXX.h"
+#include "clang/Basic/Builtins.h"
 
 using namespace clang;
 using namespace clang::interp;
@@ -47,3 +48,9 @@
     return M->isVirtual();
   return false;
 }
+
+bool Function::needsRuntimeArgPop(const ASTContext &Ctx) const {
+  if (!isBuiltin())
+    return false;
+  return Ctx.BuiltinInfo.hasCustomTypechecking(getBuiltinID());
+}
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to