tbaeder created this revision.
tbaeder added reviewers: aaron.ballman, erichkeane, tahonermann, shafik.
Herald added a project: All.
tbaeder requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Another try at this.

This time, only implement `__builtin_is_constant_evaluated()`.

Unfortunately I can't just use 
`clang/test/SemaCXX/builtin-is-constant-evaluated.cpp`  because there are some 
other unsupported expressions in there.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D137487

Files:
  clang/lib/AST/CMakeLists.txt
  clang/lib/AST/Interp/ByteCodeExprGen.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/AST/Interp/builtins.cpp

Index: clang/test/AST/Interp/builtins.cpp
===================================================================
--- /dev/null
+++ clang/test/AST/Interp/builtins.cpp
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -fexperimental-new-constant-interpreter %s -verify
+// RUN: %clang_cc1 -fexperimental-new-constant-interpreter %s -S -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -verify=ref %s -Wno-constant-evaluated
+// RUN: %clang_cc1 -verify=ref %s -Wno-constant-evaluated
+// RUN: %clang_cc1 -verify=ref %s -Wno-constant-evaluated -S -emit-llvm -o - | FileCheck %s
+
+// expected-no-diagnostics
+// ref-no-diagnostics
+
+using size_t = decltype(sizeof(int));
+
+namespace std {
+inline constexpr bool is_constant_evaluated() noexcept {
+  return __builtin_is_constant_evaluated();
+}
+} // namespace std
+
+constexpr bool b = std::is_constant_evaluated();
+static_assert(b, "");
+static_assert(std::is_constant_evaluated() , "");
+
+
+bool is_this_constant() {
+  return __builtin_is_constant_evaluated(); // CHECK: ret i1 false
+}
Index: clang/lib/AST/Interp/InterpBuiltin.cpp
===================================================================
--- /dev/null
+++ clang/lib/AST/Interp/InterpBuiltin.cpp
@@ -0,0 +1,51 @@
+//===--- InterpBuiltin.cpp - Interpreter for the constexpr VM ---*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+#include "Boolean.h"
+#include "Interp.h"
+#include "PrimType.h"
+#include "clang/Basic/Builtins.h"
+
+namespace clang {
+namespace interp {
+
+/// This is a slightly simplified version of the Ret() we have in Interp.cpp
+/// If they end up diverging in the future, we should get rid of the code
+/// duplication.
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+static bool Ret(InterpState &S, CodePtr &PC) {
+  S.CallStackDepth--;
+  const T &Ret = S.Stk.pop<T>();
+
+  assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame");
+  if (!S.checkingPotentialConstantExpression())
+    S.Current->popArgs();
+
+  InterpFrame *Caller = S.Current->Caller;
+  assert(Caller);
+
+  PC = S.Current->getRetPC();
+  delete S.Current;
+  S.Current = Caller;
+  S.Stk.push<T>(Ret);
+
+  return true;
+}
+
+bool InterpretBuiltin(InterpState &S, CodePtr PC, unsigned BuiltinID) {
+  switch (BuiltinID) {
+  case Builtin::BI__builtin_is_constant_evaluated:
+    S.Stk.push<Boolean>(Boolean::from(S.inConstantContext()));
+    Ret<PT_Bool>(S, PC);
+    return true;
+  }
+
+  return false;
+}
+
+} // namespace interp
+} // namespace clang
Index: clang/lib/AST/Interp/Interp.h
===================================================================
--- clang/lib/AST/Interp/Interp.h
+++ clang/lib/AST/Interp/Interp.h
@@ -110,6 +110,8 @@
 /// Interpreter entry point.
 bool Interpret(InterpState &S, APValue &Result);
 
+bool InterpretBuiltin(InterpState &S, CodePtr PC, unsigned BuiltinID);
+
 enum class ArithOp { Add, Sub };
 
 //===----------------------------------------------------------------------===//
@@ -1349,21 +1351,29 @@
   InterpFrame *FrameBefore = S.Current;
   S.Current = NewFrame.get();
 
-  APValue CallResult;
-  // Note that we cannot assert(CallResult.hasValue()) here since
-  // Ret() above only sets the APValue if the curent frame doesn't
-  // have a caller set.
-  if (Interpret(S, CallResult)) {
-    NewFrame.release(); // Frame was delete'd already.
-    assert(S.Current == FrameBefore);
-
-    // For constructors, check that all fields have been initialized.
-    if (Func->isConstructor()) {
-      if (!CheckCtorCall(S, PC, ThisPtr))
-        return false;
+  // Evaluate builtin functions directly.
+  if (unsigned BID = Func->getBuiltinID()) {
+    if (InterpretBuiltin(S, PC, BID)) {
+      NewFrame.release();
+      return true;
     }
+  } else {
+    APValue CallResult;
+    // Note that we cannot assert(CallResult.hasValue()) here since
+    // Ret() above only sets the APValue if the curent frame doesn't
+    // have a caller set.
+    if (Interpret(S, CallResult)) {
+      NewFrame.release(); // Frame was delete'd already.
+      assert(S.Current == FrameBefore);
+
+      // For constructors, check that all fields have been initialized.
+      if (Func->isConstructor()) {
+        if (!CheckCtorCall(S, PC, ThisPtr))
+          return false;
+      }
 
-    return true;
+      return true;
+    }
   }
 
   // Interpreting the function failed somehow. Reset to
Index: clang/lib/AST/Interp/Interp.cpp
===================================================================
--- clang/lib/AST/Interp/Interp.cpp
+++ clang/lib/AST/Interp/Interp.cpp
@@ -349,6 +349,11 @@
     }
   }
 
+  // Builtin functions are always fine, provided we implement them, which
+  // we will check later.
+  if (F->getBuiltinID())
+    return true;
+
   if (!F->isConstexpr()) {
     const SourceLocation &Loc = S.Current->getLocation(OpPC);
     if (S.getLangOpts().CPlusPlus11) {
Index: clang/lib/AST/Interp/Function.h
===================================================================
--- clang/lib/AST/Interp/Function.h
+++ clang/lib/AST/Interp/Function.h
@@ -138,6 +138,8 @@
   // Checks if the funtion already has a body attached.
   bool hasBody() const { return HasBody; }
 
+  unsigned getBuiltinID() const { return F->getBuiltinID(); }
+
   unsigned getNumParams() const { return ParamTypes.size(); }
 
 private:
Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp
===================================================================
--- clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -1370,10 +1370,8 @@
 
 template <class Emitter>
 bool ByteCodeExprGen<Emitter>::VisitCallExpr(const CallExpr *E) {
-  assert(!E->getBuiltinCallee() && "Builtin functions aren't supported yet");
-
   const Decl *Callee = E->getCalleeDecl();
-  if (const auto *FuncDecl = dyn_cast_or_null<FunctionDecl>(Callee)) {
+  if (const auto *FuncDecl = dyn_cast_if_present<FunctionDecl>(Callee)) {
     const Function *Func = getFunction(FuncDecl);
     if (!Func)
       return false;
Index: clang/lib/AST/CMakeLists.txt
===================================================================
--- clang/lib/AST/CMakeLists.txt
+++ clang/lib/AST/CMakeLists.txt
@@ -73,6 +73,7 @@
   Interp/Frame.cpp
   Interp/Function.cpp
   Interp/Floating.cpp
+  Interp/InterpBuiltin.cpp
   Interp/Interp.cpp
   Interp/InterpBlock.cpp
   Interp/InterpFrame.cpp
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to