[clang] [clang][bytecode] Don't create function frames for builtin calls (PR #137607)
Timm Baeder via cfe-commits
cfe-commits at lists.llvm.org
Mon Apr 28 02:43:22 PDT 2025
https://github.com/tbaederr created https://github.com/llvm/llvm-project/pull/137607
They don't have local variables etc. so don't create frames for them.
>From 9ce67008616c3fc8f59f1071fdaede24227cd678 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbaeder at redhat.com>
Date: Mon, 28 Apr 2025 11:40:36 +0200
Subject: [PATCH] [clang][bytecode] Don't create function frames for builtin
calls
They don't have local variables etc. so don't create frames for them.
---
clang/lib/AST/ByteCode/Compiler.cpp | 2 +-
clang/lib/AST/ByteCode/Context.cpp | 6 ++++
clang/lib/AST/ByteCode/Context.h | 7 +++++
clang/lib/AST/ByteCode/Function.cpp | 16 ----------
clang/lib/AST/ByteCode/Function.h | 2 --
clang/lib/AST/ByteCode/Interp.cpp | 33 +--------------------
clang/lib/AST/ByteCode/InterpBuiltin.cpp | 37 ++++++++++++++++++++----
7 files changed, 47 insertions(+), 56 deletions(-)
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index a9610835c81e6..a1b2d13a15fc6 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -4825,7 +4825,7 @@ bool Compiler<Emitter>::VisitBuiltinCallExpr(const CallExpr *E,
return false;
}
- if (!Func->isUnevaluatedBuiltin()) {
+ if (!Context::isUnevaluatedBuiltin(BuiltinID)) {
// Put arguments on the stack.
for (const auto *Arg : E->arguments()) {
if (!this->visit(Arg))
diff --git a/clang/lib/AST/ByteCode/Context.cpp b/clang/lib/AST/ByteCode/Context.cpp
index 431ccfcc821b1..b35b30cc20d81 100644
--- a/clang/lib/AST/ByteCode/Context.cpp
+++ b/clang/lib/AST/ByteCode/Context.cpp
@@ -450,3 +450,9 @@ unsigned Context::collectBaseOffset(const RecordDecl *BaseDecl,
const Record *Context::getRecord(const RecordDecl *D) const {
return P->getOrCreateRecord(D);
}
+
+bool Context::isUnevaluatedBuiltin(unsigned ID) {
+ return ID == Builtin::BI__builtin_classify_type ||
+ ID == Builtin::BI__builtin_os_log_format_buffer_size ||
+ ID == Builtin::BI__builtin_constant_p || ID == Builtin::BI__noop;
+}
diff --git a/clang/lib/AST/ByteCode/Context.h b/clang/lib/AST/ByteCode/Context.h
index 8b542e6474780..5a39f40ef3f11 100644
--- a/clang/lib/AST/ByteCode/Context.h
+++ b/clang/lib/AST/ByteCode/Context.h
@@ -111,6 +111,13 @@ class Context final {
unsigned getEvalID() const { return EvalID; }
+ /// Unevaluated builtins don't get their arguments put on the stack
+ /// automatically. They instead operate on the AST of their Call
+ /// Expression.
+ /// Similar information is available via ASTContext::BuiltinInfo,
+ /// but that is not correct for our use cases.
+ static bool isUnevaluatedBuiltin(unsigned ID);
+
private:
/// Runs a function.
bool Run(State &Parent, const Function *Func);
diff --git a/clang/lib/AST/ByteCode/Function.cpp b/clang/lib/AST/ByteCode/Function.cpp
index 764aa4a851cf4..17f2caa55f503 100644
--- a/clang/lib/AST/ByteCode/Function.cpp
+++ b/clang/lib/AST/ByteCode/Function.cpp
@@ -62,19 +62,3 @@ SourceInfo Function::getSource(CodePtr PC) const {
return SrcMap.back().second;
return It->second;
}
-
-/// Unevaluated builtins don't get their arguments put on the stack
-/// automatically. They instead operate on the AST of their Call
-/// Expression.
-/// Similar information is available via ASTContext::BuiltinInfo,
-/// but that is not correct for our use cases.
-static bool isUnevaluatedBuiltin(unsigned BuiltinID) {
- return BuiltinID == Builtin::BI__builtin_classify_type ||
- BuiltinID == Builtin::BI__builtin_os_log_format_buffer_size ||
- BuiltinID == Builtin::BI__builtin_constant_p ||
- BuiltinID == Builtin::BI__noop;
-}
-
-bool Function::isUnevaluatedBuiltin() const {
- return ::isUnevaluatedBuiltin(BuiltinID);
-}
diff --git a/clang/lib/AST/ByteCode/Function.h b/clang/lib/AST/ByteCode/Function.h
index c114cfe5ba29a..ea3baf6fca4d6 100644
--- a/clang/lib/AST/ByteCode/Function.h
+++ b/clang/lib/AST/ByteCode/Function.h
@@ -202,8 +202,6 @@ class Function final {
bool isBuiltin() const { return getBuiltinID() != 0; }
- bool isUnevaluatedBuiltin() const;
-
unsigned getNumParams() const { return ParamTypes.size(); }
/// Returns the number of parameter this function takes when it's called,
diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp
index 4f94bb5a85192..af9b3bf92ce55 100644
--- a/clang/lib/AST/ByteCode/Interp.cpp
+++ b/clang/lib/AST/ByteCode/Interp.cpp
@@ -251,22 +251,6 @@ void cleanupAfterFunctionCall(InterpState &S, CodePtr OpPC,
assert(S.Current);
assert(Func);
- if (Func->isUnevaluatedBuiltin())
- return;
-
- // Some builtin functions require us to only look at the call site, since
- // the classified parameter types do not match.
- if (unsigned BID = Func->getBuiltinID();
- BID && S.getASTContext().BuiltinInfo.hasCustomTypechecking(BID)) {
- const auto *CE =
- cast<CallExpr>(S.Current->Caller->getExpr(S.Current->getRetPC()));
- for (int32_t I = CE->getNumArgs() - 1; I >= 0; --I) {
- const Expr *A = CE->getArg(I);
- popArg(S, A);
- }
- return;
- }
-
if (S.Current->Caller && Func->isVariadic()) {
// CallExpr we're look for is at the return PC of the current function, i.e.
// in the caller.
@@ -1630,23 +1614,8 @@ bool CallBI(InterpState &S, CodePtr OpPC, const Function *Func,
if (BuiltinID == Builtin::BI__builtin_operator_new &&
S.checkingPotentialConstantExpression())
return false;
- auto NewFrame = std::make_unique<InterpFrame>(S, Func, OpPC);
-
- InterpFrame *FrameBefore = S.Current;
- S.Current = NewFrame.get();
-
- if (InterpretBuiltin(S, OpPC, Func, CE, BuiltinID)) {
- // Release ownership of NewFrame to prevent it from being deleted.
- NewFrame.release(); // Frame was deleted already.
- // Ensure that S.Current is correctly reset to the previous frame.
- assert(S.Current == FrameBefore);
- return true;
- }
- // Interpreting the function failed somehow. Reset to
- // previous state.
- S.Current = FrameBefore;
- return false;
+ return InterpretBuiltin(S, OpPC, Func, CE, BuiltinID);
}
bool CallPtr(InterpState &S, CodePtr OpPC, uint32_t ArgSize,
diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
index f2e11670e8fff..1828ea42398ad 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
@@ -81,14 +81,41 @@ static void assignInteger(Pointer &Dest, PrimType ValueT, const APSInt &Value) {
ValueT, { Dest.deref<T>() = T::from(static_cast<T>(Value)); });
}
+template <PrimType Name, class V = typename PrimConv<Name>::T>
+static bool retBI(InterpState &S, const CallExpr *Call, unsigned BuiltinID) {
+ // The return value of the function is already on the stack.
+ // Remove it, get rid of all the arguments and add it back.
+ const V &Val = S.Stk.pop<V>();
+ if (!Context::isUnevaluatedBuiltin(BuiltinID)) {
+ for (int32_t I = Call->getNumArgs() - 1; I >= 0; --I) {
+ const Expr *A = Call->getArg(I);
+ PrimType Ty = S.getContext().classify(A).value_or(PT_Ptr);
+ TYPE_SWITCH(Ty, S.Stk.discard<T>());
+ }
+ }
+ S.Stk.push<V>(Val);
+ return true;
+}
+
static bool retPrimValue(InterpState &S, CodePtr OpPC,
- std::optional<PrimType> &T) {
- if (!T)
- return RetVoid(S, OpPC);
+ std::optional<PrimType> &T, const CallExpr *Call,
+ unsigned BuiltinID) {
+
+ if (!T) {
+ if (!Context::isUnevaluatedBuiltin(BuiltinID)) {
+ for (int32_t I = Call->getNumArgs() - 1; I >= 0; --I) {
+ const Expr *A = Call->getArg(I);
+ PrimType Ty = S.getContext().classify(A).value_or(PT_Ptr);
+ TYPE_SWITCH(Ty, S.Stk.discard<T>());
+ }
+ }
+
+ return true;
+ }
#define RET_CASE(X) \
case X: \
- return Ret<X>(S, OpPC);
+ return retBI<X>(S, Call, BuiltinID);
switch (*T) {
RET_CASE(PT_Ptr);
RET_CASE(PT_Float);
@@ -2675,7 +2702,7 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
return false;
}
- return retPrimValue(S, OpPC, ReturnT);
+ return retPrimValue(S, OpPC, ReturnT, Call, BuiltinID);
}
bool InterpretOffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E,
More information about the cfe-commits
mailing list