Author: Timm Baeder Date: 2026-01-30T10:07:23+01:00 New Revision: afb2e4f2e2b04a34522376e6bbf39237499c745b
URL: https://github.com/llvm/llvm-project/commit/afb2e4f2e2b04a34522376e6bbf39237499c745b DIFF: https://github.com/llvm/llvm-project/commit/afb2e4f2e2b04a34522376e6bbf39237499c745b.diff LOG: [clang][bytecode] Clean up `interp::Function` parameter handling (#178621) Replace the multiple data structures with a vector + a map holding all `ParamDescriptor`s. Update docs. Added: Modified: clang/lib/AST/ByteCode/ByteCodeEmitter.cpp clang/lib/AST/ByteCode/Context.cpp clang/lib/AST/ByteCode/Function.cpp clang/lib/AST/ByteCode/Function.h clang/lib/AST/ByteCode/Interp.cpp clang/lib/AST/ByteCode/InterpFrame.cpp Removed: ################################################################################ diff --git a/clang/lib/AST/ByteCode/ByteCodeEmitter.cpp b/clang/lib/AST/ByteCode/ByteCodeEmitter.cpp index 5dc6eca582ad9..35821085ff49b 100644 --- a/clang/lib/AST/ByteCode/ByteCodeEmitter.cpp +++ b/clang/lib/AST/ByteCode/ByteCodeEmitter.cpp @@ -32,15 +32,15 @@ void ByteCodeEmitter::compileFunc(const FunctionDecl *FuncDecl, return; // Set up lambda captures. - if (const auto *MD = dyn_cast<CXXMethodDecl>(FuncDecl); - MD && isLambdaCallOperator(MD)) { + if (Func->isLambdaCallOperator()) { // Set up lambda capture to closure record field mapping. - const Record *R = P.getOrCreateRecord(MD->getParent()); + const CXXRecordDecl *ParentDecl = Func->getParentDecl(); + const Record *R = P.getOrCreateRecord(ParentDecl); assert(R); llvm::DenseMap<const ValueDecl *, FieldDecl *> LC; FieldDecl *LTC; - MD->getParent()->getCaptureFields(LC, LTC); + ParentDecl->getCaptureFields(LC, LTC); for (auto Cap : LC) { unsigned Offset = R->getField(Cap.second)->Offset; @@ -59,12 +59,13 @@ void ByteCodeEmitter::compileFunc(const FunctionDecl *FuncDecl, unsigned ParamIndex = 0; unsigned Drop = Func->hasRVO() + (Func->hasThisPointer() && !Func->isThisPointerExplicit()); - for (auto ParamOffset : llvm::drop_begin(Func->ParamOffsets, Drop)) { - const ParmVarDecl *PD = FuncDecl->parameters()[ParamIndex]; + + for (const auto &ParamDesc : llvm::drop_begin(Func->ParamDescriptors, Drop)) { + const ParmVarDecl *PD = FuncDecl->getParamDecl(ParamIndex); if (PD->isInvalidDecl()) IsValid = false; - OptPrimType T = Ctx.classify(PD->getType()); - this->Params.insert({PD, {ParamOffset, T != std::nullopt}}); + this->Params.insert( + {PD, {ParamDesc.Offset, Ctx.canClassify(PD->getType())}}); ++ParamIndex; } diff --git a/clang/lib/AST/ByteCode/Context.cpp b/clang/lib/AST/ByteCode/Context.cpp index 5d5816eb02cd2..d6fdf581baaec 100644 --- a/clang/lib/AST/ByteCode/Context.cpp +++ b/clang/lib/AST/ByteCode/Context.cpp @@ -520,9 +520,7 @@ const Function *Context::getOrCreateFunction(const FunctionDecl *FuncDecl) { } // Set up argument indices. unsigned ParamOffset = 0; - SmallVector<PrimType, 8> ParamTypes; - SmallVector<unsigned, 8> ParamOffsets; - llvm::DenseMap<unsigned, Function::ParamDescriptor> ParamDescriptors; + llvm::SmallVector<Function::ParamDescriptor> ParamDescriptors; // If the return is not a primitive, a pointer to the storage where the // value is initialized in is passed as the first argument. See 'RVO' @@ -531,8 +529,7 @@ const Function *Context::getOrCreateFunction(const FunctionDecl *FuncDecl) { bool HasRVO = false; if (!Ty->isVoidType() && !canClassify(Ty)) { HasRVO = true; - ParamTypes.push_back(PT_Ptr); - ParamOffsets.push_back(ParamOffset); + ParamDescriptors.emplace_back(nullptr, ParamOffset, PT_Ptr); ParamOffset += align(primSize(PT_Ptr)); } @@ -544,8 +541,7 @@ const Function *Context::getOrCreateFunction(const FunctionDecl *FuncDecl) { if (!IsLambdaStaticInvoker) { HasThisPointer = MD->isInstance(); if (MD->isImplicitObjectMemberFunction()) { - ParamTypes.push_back(PT_Ptr); - ParamOffsets.push_back(ParamOffset); + ParamDescriptors.emplace_back(nullptr, ParamOffset, PT_Ptr); ParamOffset += align(primSize(PT_Ptr)); } } @@ -584,18 +580,15 @@ const Function *Context::getOrCreateFunction(const FunctionDecl *FuncDecl) { Descriptor *Desc = P->createDescriptor(PD, PT, nullptr, std::nullopt, IsConst, /*IsTemporary=*/false, /*IsMutable=*/false, IsVolatile); - - ParamDescriptors.insert({ParamOffset, {PT, Desc}}); - ParamOffsets.push_back(ParamOffset); + ParamDescriptors.emplace_back(Desc, ParamOffset, PT); ParamOffset += align(primSize(PT)); - ParamTypes.push_back(PT); } // Create a handle over the emitted code. assert(!P->getFunction(FuncDecl)); - const Function *Func = P->createFunction( - FuncDecl, ParamOffset, std::move(ParamTypes), std::move(ParamDescriptors), - std::move(ParamOffsets), HasThisPointer, HasRVO, IsLambdaStaticInvoker); + const Function *Func = + P->createFunction(FuncDecl, ParamOffset, std::move(ParamDescriptors), + HasThisPointer, HasRVO, IsLambdaStaticInvoker); return Func; } @@ -603,9 +596,7 @@ const Function *Context::getOrCreateObjCBlock(const BlockExpr *E) { const BlockDecl *BD = E->getBlockDecl(); // Set up argument indices. unsigned ParamOffset = 0; - SmallVector<PrimType, 8> ParamTypes; - SmallVector<unsigned, 8> ParamOffsets; - llvm::DenseMap<unsigned, Function::ParamDescriptor> ParamDescriptors; + llvm::SmallVector<Function::ParamDescriptor> ParamDescriptors; // Assign descriptors to all parameters. // Composite objects are lowered to pointers. @@ -618,10 +609,8 @@ const Function *Context::getOrCreateObjCBlock(const BlockExpr *E) { Descriptor *Desc = P->createDescriptor(PD, PT, nullptr, std::nullopt, IsConst, /*IsTemporary=*/false, /*IsMutable=*/false, IsVolatile); - ParamDescriptors.insert({ParamOffset, {PT, Desc}}); - ParamOffsets.push_back(ParamOffset); + ParamDescriptors.emplace_back(Desc, ParamOffset, PT); ParamOffset += align(primSize(PT)); - ParamTypes.push_back(PT); } if (BD->hasCaptures()) @@ -629,8 +618,7 @@ const Function *Context::getOrCreateObjCBlock(const BlockExpr *E) { // Create a handle over the emitted code. Function *Func = - P->createFunction(E, ParamOffset, std::move(ParamTypes), - std::move(ParamDescriptors), std::move(ParamOffsets), + P->createFunction(E, ParamOffset, std::move(ParamDescriptors), /*HasThisPointer=*/false, /*HasRVO=*/false, /*IsLambdaStaticInvoker=*/false); @@ -638,6 +626,7 @@ const Function *Context::getOrCreateObjCBlock(const BlockExpr *E) { Func->setDefined(true); // We don't compile the BlockDecl code at all right now. Func->setIsFullyCompiled(true); + return Func; } diff --git a/clang/lib/AST/ByteCode/Function.cpp b/clang/lib/AST/ByteCode/Function.cpp index 4c7872b19dcdf..56d08a64d1024 100644 --- a/clang/lib/AST/ByteCode/Function.cpp +++ b/clang/lib/AST/ByteCode/Function.cpp @@ -16,15 +16,17 @@ using namespace clang; using namespace clang::interp; Function::Function(Program &P, FunctionDeclTy Source, unsigned ArgSize, - llvm::SmallVectorImpl<PrimType> &&ParamTypes, - llvm::DenseMap<unsigned, ParamDescriptor> &&Params, - llvm::SmallVectorImpl<unsigned> &&ParamOffsets, + llvm::SmallVectorImpl<ParamDescriptor> &&ParamDescriptors, bool HasThisPointer, bool HasRVO, bool IsLambdaStaticInvoker) : P(P), Kind(FunctionKind::Normal), Source(Source), ArgSize(ArgSize), - ParamTypes(std::move(ParamTypes)), Params(std::move(Params)), - ParamOffsets(std::move(ParamOffsets)), IsValid(false), + ParamDescriptors(std::move(ParamDescriptors)), IsValid(false), IsFullyCompiled(false), HasThisPointer(HasThisPointer), HasRVO(HasRVO), HasBody(false), Defined(false) { + for (ParamDescriptor PD : this->ParamDescriptors) { + Params.insert({PD.Offset, PD}); + } + assert(Params.size() == this->ParamDescriptors.size()); + if (const auto *F = dyn_cast<const FunctionDecl *>(Source)) { Variadic = F->isVariadic(); Immediate = F->isImmediateFunction(); diff --git a/clang/lib/AST/ByteCode/Function.h b/clang/lib/AST/ByteCode/Function.h index a086682d4ce21..544172b7e0c26 100644 --- a/clang/lib/AST/ByteCode/Function.h +++ b/clang/lib/AST/ByteCode/Function.h @@ -85,6 +85,17 @@ using FunctionDeclTy = /// After the function has been called, it will remove all arguments, /// including RVO and This pointer, from the stack. /// +/// The parameters saved in a clang::intepr::Function include both the +/// instance pointer as well as the RVO pointer. +/// +/// \verbatim +/// Stack position when calling ─────┐ +/// this Function │ +/// ▼ +/// ┌─────┬──────┬────────┬────────┬─────┬────────────────────┐ +/// │ RVO │ This │ Param1 │ Param2 │ ... │ │ +/// └─────┴──────┴────────┴────────┴─────┴────────────────────┘ +/// \endverbatim class Function final { public: enum class FunctionKind { @@ -95,7 +106,14 @@ class Function final { LambdaCallOperator, CopyOrMoveOperator, }; - using ParamDescriptor = std::pair<PrimType, Descriptor *>; + + struct ParamDescriptor { + const Descriptor *Desc; + unsigned Offset; + PrimType T; + ParamDescriptor(const Descriptor *Desc, unsigned Offset, PrimType T) + : Desc(Desc), Offset(Offset), T(T) {} + }; /// Returns the size of the function's local stack. unsigned getFrameSize() const { return FrameSize; } @@ -140,9 +158,9 @@ class Function final { /// Range over argument types. using arg_reverse_iterator = - SmallVectorImpl<PrimType>::const_reverse_iterator; + SmallVectorImpl<ParamDescriptor>::const_reverse_iterator; llvm::iterator_range<arg_reverse_iterator> args_reverse() const { - return llvm::reverse(ParamTypes); + return llvm::reverse(ParamDescriptors); } /// Returns a specific scope. @@ -202,7 +220,7 @@ class Function final { bool isVariadic() const { return Variadic; } - unsigned getNumParams() const { return ParamTypes.size(); } + unsigned getNumParams() const { return ParamDescriptors.size(); } /// Returns the number of parameter this function takes when it's called, /// i.e excluding the instance pointer and the RVO pointer. @@ -222,20 +240,18 @@ class Function final { } unsigned getParamOffset(unsigned ParamIndex) const { - return ParamOffsets[ParamIndex]; + return ParamDescriptors[ParamIndex].Offset; } PrimType getParamType(unsigned ParamIndex) const { - return ParamTypes[ParamIndex]; + return ParamDescriptors[ParamIndex].T; } private: /// Construct a function representing an actual function. Function(Program &P, FunctionDeclTy Source, unsigned ArgSize, - llvm::SmallVectorImpl<PrimType> &&ParamTypes, - llvm::DenseMap<unsigned, ParamDescriptor> &&Params, - llvm::SmallVectorImpl<unsigned> &&ParamOffsets, bool HasThisPointer, - bool HasRVO, bool IsLambdaStaticInvoker); + llvm::SmallVectorImpl<ParamDescriptor> &&ParamDescriptors, + bool HasThisPointer, bool HasRVO, bool IsLambdaStaticInvoker); /// Sets the code of a function. void setCode(FunctionDeclTy Source, unsigned NewFrameSize, @@ -275,12 +291,10 @@ class Function final { SourceMap SrcMap; /// List of block descriptors. llvm::SmallVector<Scope, 2> Scopes; - /// List of argument types. - llvm::SmallVector<PrimType, 8> ParamTypes; - /// Map from byte offset to parameter descriptor. + /// List of all parameters, including RVO and instance pointer. + llvm::SmallVector<ParamDescriptor> ParamDescriptors; + /// Map from Parameter offset to parameter descriptor. llvm::DenseMap<unsigned, ParamDescriptor> Params; - /// List of parameter offsets. - llvm::SmallVector<unsigned, 8> ParamOffsets; /// Flag to indicate if the function is valid. LLVM_PREFERRED_TYPE(bool) unsigned IsValid : 1; diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp index 2a495a475c378..d095e6f862fc5 100644 --- a/clang/lib/AST/ByteCode/Interp.cpp +++ b/clang/lib/AST/ByteCode/Interp.cpp @@ -296,8 +296,8 @@ void cleanupAfterFunctionCall(InterpState &S, CodePtr OpPC, // And in any case, remove the fixed parameters (the non-variadic ones) // at the end. - for (PrimType Ty : Func->args_reverse()) - TYPE_SWITCH(Ty, S.Stk.discard<T>()); + for (const Function::ParamDescriptor &PDesc : Func->args_reverse()) + TYPE_SWITCH(PDesc.T, S.Stk.discard<T>()); } bool isConstexprUnknown(const Pointer &P) { diff --git a/clang/lib/AST/ByteCode/InterpFrame.cpp b/clang/lib/AST/ByteCode/InterpFrame.cpp index ef70d9526c194..3c185a0ad661a 100644 --- a/clang/lib/AST/ByteCode/InterpFrame.cpp +++ b/clang/lib/AST/ByteCode/InterpFrame.cpp @@ -252,14 +252,14 @@ Pointer InterpFrame::getParamPointer(unsigned Off) { assert(!isBottomFrame()); // Allocate memory to store the parameter and the block metadata. - const auto &Desc = Func->getParamDescriptor(Off); - size_t BlockSize = sizeof(Block) + Desc.second->getAllocSize(); + const auto &PDesc = Func->getParamDescriptor(Off); + size_t BlockSize = sizeof(Block) + PDesc.Desc->getAllocSize(); auto Memory = std::make_unique<char[]>(BlockSize); - auto *B = new (Memory.get()) Block(S.Ctx.getEvalID(), Desc.second); + auto *B = new (Memory.get()) Block(S.Ctx.getEvalID(), PDesc.Desc); B->invokeCtor(); // Copy the initial value. - TYPE_SWITCH(Desc.first, new (B->data()) T(stackRef<T>(Off))); + TYPE_SWITCH(PDesc.T, new (B->data()) T(stackRef<T>(Off))); // Record the param. Params.insert({Off, std::move(Memory)}); _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
