Author: Timm Baeder Date: 2025-04-28T13:11:15+02:00 New Revision: e086d7b1464ad091ae849cb907f8647c8439cb66
URL: https://github.com/llvm/llvm-project/commit/e086d7b1464ad091ae849cb907f8647c8439cb66 DIFF: https://github.com/llvm/llvm-project/commit/e086d7b1464ad091ae849cb907f8647c8439cb66.diff LOG: [clang][bytecode] Don't create function frames for builtin calls (#137607) They don't have local variables etc. so don't create frames for them. Added: Modified: clang/lib/AST/ByteCode/Compiler.cpp clang/lib/AST/ByteCode/Context.cpp clang/lib/AST/ByteCode/Context.h clang/lib/AST/ByteCode/Function.cpp clang/lib/AST/ByteCode/Function.h clang/lib/AST/ByteCode/Interp.cpp clang/lib/AST/ByteCode/InterpBuiltin.cpp Removed: ################################################################################ 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..8779adf0d9c6b 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); @@ -147,17 +174,16 @@ static bool interp__builtin_is_constant_evaluated(InterpState &S, CodePtr OpPC, // The one above that, potentially the one for std::is_constant_evaluated(). if (S.inConstantContext() && !S.checkingPotentialConstantExpression() && S.getEvalStatus().Diag && - (Depth == 1 || (Depth == 2 && isStdCall(Caller->getCallee())))) { - if (Caller->Caller && isStdCall(Caller->getCallee())) { - const Expr *E = Caller->Caller->getExpr(Caller->getRetPC()); + (Depth == 0 || (Depth == 1 && isStdCall(Frame->getCallee())))) { + if (Caller && isStdCall(Frame->getCallee())) { + const Expr *E = Caller->getExpr(Caller->getRetPC()); S.report(E->getExprLoc(), diag::warn_is_constant_evaluated_always_true_constexpr) << "std::is_constant_evaluated" << E->getSourceRange(); } else { - const Expr *E = Frame->Caller->getExpr(Frame->getRetPC()); - S.report(E->getExprLoc(), + S.report(Call->getExprLoc(), diag::warn_is_constant_evaluated_always_true_constexpr) - << "__builtin_is_constant_evaluated" << E->getSourceRange(); + << "__builtin_is_constant_evaluated" << Call->getSourceRange(); } } @@ -2675,7 +2701,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, _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits