[clang] a7a4463 - [clang][Interp] Start implementing builtin functions

Timm Bäder via cfe-commits cfe-commits at lists.llvm.org
Wed Jan 25 05:08:17 PST 2023


Author: Timm Bäder
Date: 2023-01-25T14:08:03+01:00
New Revision: a7a4463acbe10d1b5c9eadcd6cb94790caad86e4

URL: https://github.com/llvm/llvm-project/commit/a7a4463acbe10d1b5c9eadcd6cb94790caad86e4
DIFF: https://github.com/llvm/llvm-project/commit/a7a4463acbe10d1b5c9eadcd6cb94790caad86e4.diff

LOG: [clang][Interp] Start implementing builtin functions

Differential Revision: https://reviews.llvm.org/D137487

Added: 
    clang/lib/AST/Interp/InterpBuiltin.cpp
    clang/test/AST/Interp/builtins.cpp

Modified: 
    clang/lib/AST/CMakeLists.txt
    clang/lib/AST/Interp/ByteCodeExprGen.cpp
    clang/lib/AST/Interp/ByteCodeExprGen.h
    clang/lib/AST/Interp/Function.h
    clang/lib/AST/Interp/Interp.h
    clang/lib/AST/Interp/Opcodes.td

Removed: 
    


################################################################################
diff  --git a/clang/lib/AST/CMakeLists.txt b/clang/lib/AST/CMakeLists.txt
index 40a5d6694f83..e4c1008fe34b 100644
--- a/clang/lib/AST/CMakeLists.txt
+++ b/clang/lib/AST/CMakeLists.txt
@@ -73,6 +73,7 @@ add_clang_library(clangAST
   Interp/EvalEmitter.cpp
   Interp/Frame.cpp
   Interp/Function.cpp
+  Interp/InterpBuiltin.cpp
   Interp/Interp.cpp
   Interp/InterpBlock.cpp
   Interp/InterpFrame.cpp

diff  --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
index d28b89381b87..2581c1c36da2 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -1240,9 +1240,35 @@ bool ByteCodeExprGen<Emitter>::visitVarDecl(const VarDecl *VD) {
   return false;
 }
 
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitBuiltinCallExpr(const CallExpr *E) {
+  const Function *Func = getFunction(E->getDirectCallee());
+  if (!Func)
+    return false;
+
+  // Put arguments on the stack.
+  for (const auto *Arg : E->arguments()) {
+    if (!this->visit(Arg))
+      return false;
+  }
+
+  if (!this->emitCallBI(Func, E))
+    return false;
+
+  if (DiscardResult) {
+    QualType ReturnType = E->getCallReturnType(Ctx.getASTContext());
+    PrimType T = classifyPrim(ReturnType);
+
+    return this->emitPop(T, E);
+  }
+
+  return true;
+}
+
 template <class Emitter>
 bool ByteCodeExprGen<Emitter>::VisitCallExpr(const CallExpr *E) {
-  assert(!E->getBuiltinCallee() && "Builtin functions aren't supported yet");
+  if (E->getBuiltinCallee())
+    return VisitBuiltinCallExpr(E);
 
   const Decl *Callee = E->getCalleeDecl();
   if (const auto *FuncDecl = dyn_cast_or_null<FunctionDecl>(Callee)) {
@@ -1276,9 +1302,9 @@ bool ByteCodeExprGen<Emitter>::VisitCallExpr(const CallExpr *E) {
         return false;
     }
 
-    // In any case call the function. The return value will end up on the stack and
-    // if the function has RVO, we already have the pointer on the stack to write
-    // the result into.
+    // In any case call the function. The return value will end up on the stack
+    // and if the function has RVO, we already have the pointer on the stack to
+    // write the result into.
     if (!this->emitCall(Func, E))
       return false;
 

diff  --git a/clang/lib/AST/Interp/ByteCodeExprGen.h b/clang/lib/AST/Interp/ByteCodeExprGen.h
index c7fcc59e5a60..7af61695864c 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.h
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.h
@@ -63,6 +63,7 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
   bool VisitPointerArithBinOp(const BinaryOperator *E);
   bool VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E);
   bool VisitCallExpr(const CallExpr *E);
+  bool VisitBuiltinCallExpr(const CallExpr *E);
   bool VisitCXXMemberCallExpr(const CXXMemberCallExpr *E);
   bool VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *E);
   bool VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *E);

diff  --git a/clang/lib/AST/Interp/Function.h b/clang/lib/AST/Interp/Function.h
index 5b2a77f1a12d..434c3f7b0def 100644
--- a/clang/lib/AST/Interp/Function.h
+++ b/clang/lib/AST/Interp/Function.h
@@ -138,6 +138,8 @@ class Function final {
   // 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:

diff  --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h
index 9433652f1526..7ee823ef130a 100644
--- a/clang/lib/AST/Interp/Interp.h
+++ b/clang/lib/AST/Interp/Interp.h
@@ -140,6 +140,8 @@ bool CheckDivRem(InterpState &S, CodePtr OpPC, const T &LHS, const T &RHS) {
 /// Interpreter entry point.
 bool Interpret(InterpState &S, APValue &Result);
 
+bool InterpretBuiltin(InterpState &S, CodePtr PC, unsigned BuiltinID);
+
 enum class ArithOp { Add, Sub };
 
 //===----------------------------------------------------------------------===//
@@ -1320,6 +1322,20 @@ inline bool Call(InterpState &S, CodePtr &PC, const Function *Func) {
   return false;
 }
 
+inline bool CallBI(InterpState &S, CodePtr &PC, const Function *Func) {
+  auto NewFrame = std::make_unique<InterpFrame>(S, Func, PC);
+
+  InterpFrame *FrameBefore = S.Current;
+  S.Current = NewFrame.get();
+
+  if (InterpretBuiltin(S, PC, Func->getBuiltinID())) {
+    NewFrame.release();
+    return true;
+  }
+  S.Current = FrameBefore;
+  return false;
+}
+
 //===----------------------------------------------------------------------===//
 // Read opcode arguments
 //===----------------------------------------------------------------------===//

diff  --git a/clang/lib/AST/Interp/InterpBuiltin.cpp b/clang/lib/AST/Interp/InterpBuiltin.cpp
new file mode 100644
index 000000000000..8e6b83fe50ae
--- /dev/null
+++ b/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

diff  --git a/clang/lib/AST/Interp/Opcodes.td b/clang/lib/AST/Interp/Opcodes.td
index 07facb6a6024..64582980b7e8 100644
--- a/clang/lib/AST/Interp/Opcodes.td
+++ b/clang/lib/AST/Interp/Opcodes.td
@@ -164,6 +164,12 @@ def Call : Opcode {
   let ChangesPC = 1;
 }
 
+def CallBI : Opcode {
+  let Args = [ArgFunction];
+  let Types = [];
+  let ChangesPC = 1;
+}
+
 //===----------------------------------------------------------------------===//
 // Frame management
 //===----------------------------------------------------------------------===//

diff  --git a/clang/test/AST/Interp/builtins.cpp b/clang/test/AST/Interp/builtins.cpp
new file mode 100644
index 000000000000..535686f9c482
--- /dev/null
+++ b/clang/test/AST/Interp/builtins.cpp
@@ -0,0 +1,24 @@
+// 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 %s -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
+}


        


More information about the cfe-commits mailing list