[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