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.

I was wondering how to best implement builtin function calls, but I don't think 
actually generating bytecode for them makes much sense.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D134958

Files:
  clang/lib/AST/CMakeLists.txt
  clang/lib/AST/Interp/ByteCodeExprGen.cpp
  clang/lib/AST/Interp/Interp.h
  clang/lib/AST/Interp/InterpBuiltin.cpp
  clang/lib/AST/Interp/Opcodes.td
  clang/test/AST/Interp/builtins.cpp

Index: clang/test/AST/Interp/builtins.cpp
===================================================================
--- /dev/null
+++ clang/test/AST/Interp/builtins.cpp
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify %s
+// RUN: %clang_cc1 -verify=ref %s
+
+// expected-no-diagnostics
+// ref-no-diagnostics
+
+
+static_assert(__builtin_clz(10) == 28, "");
Index: clang/lib/AST/Interp/Opcodes.td
===================================================================
--- clang/lib/AST/Interp/Opcodes.td
+++ clang/lib/AST/Interp/Opcodes.td
@@ -169,6 +169,13 @@
   let HasCustomEval = 1;
 }
 
+/// Call a builtin function.
+def CallBI : Opcode {
+  let Args = [ArgUint32];
+  let Types = [];
+  let ChangesPC = 1;
+}
+
 //===----------------------------------------------------------------------===//
 // Frame management
 //===----------------------------------------------------------------------===//
Index: clang/lib/AST/Interp/InterpBuiltin.cpp
===================================================================
--- /dev/null
+++ clang/lib/AST/Interp/InterpBuiltin.cpp
@@ -0,0 +1,23 @@
+//===----- InterpBuiltin.cpp - Interpret builtin functions ------*- 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 "Integral.h"
+#include "InterpState.h"
+
+namespace clang {
+namespace interp {
+
+bool InterpretBuiltinClz(InterpState &S) {
+  auto Arg = S.Stk.pop<Integral<32, false>>();
+  auto Result = Arg.countLeadingZeros();
+  S.Stk.push<Integral<32, true>>(Integral<32, true>::from(Result));
+  return true;
+}
+
+} // namespace interp
+} // namespace clang
Index: clang/lib/AST/Interp/Interp.h
===================================================================
--- clang/lib/AST/Interp/Interp.h
+++ clang/lib/AST/Interp/Interp.h
@@ -25,6 +25,7 @@
 #include "clang/AST/ASTDiagnostic.h"
 #include "clang/AST/CXXInheritance.h"
 #include "clang/AST/Expr.h"
+#include "clang/Basic/TargetBuiltins.h"
 #include "llvm/ADT/APFloat.h"
 #include "llvm/ADT/APSInt.h"
 #include "llvm/Support/Endian.h"
@@ -91,6 +92,10 @@
 /// Checks if a method is pure virtual.
 bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD);
 
+/// Prototypes for evaluation of builtin functions.
+/// Implemented in InterpBuiltin.cpp
+bool InterpretBuiltinClz(InterpState &S);
+
 template <typename T> inline bool IsTrue(const T &V) { return !V.isZero(); }
 
 //===----------------------------------------------------------------------===//
@@ -1090,6 +1095,16 @@
   return true;
 }
 
+inline bool CallBI(InterpState &S, CodePtr OpPC, uint32_t ID) {
+  switch (ID) {
+  case Builtin::BI__builtin_clz:
+    return InterpretBuiltinClz(S);
+
+  default:
+    return false;
+  }
+}
+
 //===----------------------------------------------------------------------===//
 // Read opcode arguments
 //===----------------------------------------------------------------------===//
Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp
===================================================================
--- clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -943,42 +943,56 @@
 
 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)) {
-    const Function *Func = getFunction(FuncDecl);
-    if (!Func)
-      return false;
-    // If the function is being compiled right now, this is a recursive call.
-    // In that case, the function can't be valid yet, even though it will be
-    // later.
-    // If the function is already fully compiled but not constexpr, it was
-    // found to be faulty earlier on, so bail out.
-    if (Func->isFullyCompiled() && !Func->isConstexpr())
-      return false;
-
+    unsigned BuiltinID = E->getBuiltinCallee();
     QualType ReturnType = E->getCallReturnType(Ctx.getASTContext());
     Optional<PrimType> T = classify(ReturnType);
-    // Put arguments on the stack.
-    for (const auto *Arg : E->arguments()) {
-      if (!this->visit(Arg))
+
+    if (BuiltinID != 0) {
+      assert(*T);
+      FuncDecl->dump();
+
+      // Put arguments on the stack.
+      for (const auto *Arg : E->arguments()) {
+        if (!this->visit(Arg))
+          return false;
+      }
+      return this->emitCallBI(BuiltinID, E);
+
+    } else {
+      const Function *Func = getFunction(FuncDecl);
+
+      if (!Func)
+        return false;
+      // If the function is being compiled right now, this is a recursive call.
+      // In that case, the function can't be valid yet, even though it will be
+      // later.
+      // If the function is already fully compiled but not constexpr, it was
+      // found to be faulty earlier on, so bail out.
+      if (Func->isFullyCompiled() && !Func->isConstexpr())
         return false;
-    }
 
-    // Primitive return value, just call it.
-    if (T)
-      return this->emitCall(*T, Func, E);
+      // Put arguments on the stack.
+      for (const auto *Arg : E->arguments()) {
+        if (!this->visit(Arg))
+          return false;
+      }
 
-    // Void Return value, easy.
-    if (ReturnType->isVoidType())
-      return this->emitCallVoid(Func, E);
+      // Primitive return value, just call it.
+      if (T)
+        return this->emitCall(*T, Func, E);
 
-    // Non-primitive return value with Return Value Optimization,
-    // we already have a pointer on the stack to write the result into.
-    // TODO: Is this always the case?
-    if (Func->hasRVO())
-      return this->emitCallVoid(Func, E);
+      // Void Return value, easy.
+      if (ReturnType->isVoidType())
+        return this->emitCallVoid(Func, E);
+
+      // Non-primitive return value with Return Value Optimization,
+      // we already have a pointer on the stack to write the result into.
+      // TODO: Is this always the case?
+      if (Func->hasRVO())
+        return this->emitCallVoid(Func, E);
+    }
   } else {
     assert(false && "We don't support non-FunctionDecl callees right now.");
   }
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/Interp.cpp
+  Interp/InterpBuiltin.cpp
   Interp/InterpBlock.cpp
   Interp/InterpFrame.cpp
   Interp/InterpStack.cpp
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to