1a7dea167SDimitry Andric //===--- Function.h - Bytecode function for the VM --------------*- C++ -*-===// 2a7dea167SDimitry Andric // 3a7dea167SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4a7dea167SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5a7dea167SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6a7dea167SDimitry Andric // 7a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 8a7dea167SDimitry Andric // 9a7dea167SDimitry Andric // Defines the Function class which holds all bytecode function-specific data. 10a7dea167SDimitry Andric // 11a7dea167SDimitry Andric // The scope class which describes local variables is also defined here. 12a7dea167SDimitry Andric // 13a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 14a7dea167SDimitry Andric 15a7dea167SDimitry Andric #ifndef LLVM_CLANG_AST_INTERP_FUNCTION_H 16a7dea167SDimitry Andric #define LLVM_CLANG_AST_INTERP_FUNCTION_H 17a7dea167SDimitry Andric 185f757f3fSDimitry Andric #include "Descriptor.h" 19*0fca6ea1SDimitry Andric #include "Source.h" 205f757f3fSDimitry Andric #include "clang/AST/ASTLambda.h" 21*0fca6ea1SDimitry Andric #include "clang/AST/Attr.h" 22a7dea167SDimitry Andric #include "clang/AST/Decl.h" 23a7dea167SDimitry Andric #include "llvm/Support/raw_ostream.h" 24a7dea167SDimitry Andric 25a7dea167SDimitry Andric namespace clang { 26a7dea167SDimitry Andric namespace interp { 27a7dea167SDimitry Andric class Program; 28a7dea167SDimitry Andric class ByteCodeEmitter; 295f757f3fSDimitry Andric class Pointer; 30a7dea167SDimitry Andric enum PrimType : uint32_t; 31a7dea167SDimitry Andric 32a7dea167SDimitry Andric /// Describes a scope block. 33a7dea167SDimitry Andric /// 34a7dea167SDimitry Andric /// The block gathers all the descriptors of the locals defined in this block. 35bdd1243dSDimitry Andric class Scope final { 36a7dea167SDimitry Andric public: 37a7dea167SDimitry Andric /// Information about a local's storage. 38a7dea167SDimitry Andric struct Local { 39a7dea167SDimitry Andric /// Offset of the local in frame. 40a7dea167SDimitry Andric unsigned Offset; 41a7dea167SDimitry Andric /// Descriptor of the local. 42a7dea167SDimitry Andric Descriptor *Desc; 43a7dea167SDimitry Andric }; 44a7dea167SDimitry Andric 45a7dea167SDimitry Andric using LocalVectorTy = llvm::SmallVector<Local, 8>; 46a7dea167SDimitry Andric 47a7dea167SDimitry Andric Scope(LocalVectorTy &&Descriptors) : Descriptors(std::move(Descriptors)) {} 48a7dea167SDimitry Andric 49bdd1243dSDimitry Andric llvm::iterator_range<LocalVectorTy::const_iterator> locals() const { 50a7dea167SDimitry Andric return llvm::make_range(Descriptors.begin(), Descriptors.end()); 51a7dea167SDimitry Andric } 52a7dea167SDimitry Andric 53a7dea167SDimitry Andric private: 54a7dea167SDimitry Andric /// Object descriptors in this block. 55a7dea167SDimitry Andric LocalVectorTy Descriptors; 56a7dea167SDimitry Andric }; 57a7dea167SDimitry Andric 58a7dea167SDimitry Andric /// Bytecode function. 59a7dea167SDimitry Andric /// 60a7dea167SDimitry Andric /// Contains links to the bytecode of the function, as well as metadata 61a7dea167SDimitry Andric /// describing all arguments and stack-local variables. 62bdd1243dSDimitry Andric /// 63bdd1243dSDimitry Andric /// # Calling Convention 64bdd1243dSDimitry Andric /// 65bdd1243dSDimitry Andric /// When calling a function, all argument values must be on the stack. 66bdd1243dSDimitry Andric /// 67bdd1243dSDimitry Andric /// If the function has a This pointer (i.e. hasThisPointer() returns true, 68bdd1243dSDimitry Andric /// the argument values need to be preceeded by a Pointer for the This object. 69bdd1243dSDimitry Andric /// 70bdd1243dSDimitry Andric /// If the function uses Return Value Optimization, the arguments (and 715f757f3fSDimitry Andric /// potentially the This pointer) need to be preceeded by a Pointer pointing 72bdd1243dSDimitry Andric /// to the location to construct the returned value. 73bdd1243dSDimitry Andric /// 74bdd1243dSDimitry Andric /// After the function has been called, it will remove all arguments, 75bdd1243dSDimitry Andric /// including RVO and This pointer, from the stack. 76bdd1243dSDimitry Andric /// 77bdd1243dSDimitry Andric class Function final { 78a7dea167SDimitry Andric public: 79a7dea167SDimitry Andric using ParamDescriptor = std::pair<PrimType, Descriptor *>; 80a7dea167SDimitry Andric 81a7dea167SDimitry Andric /// Returns the size of the function's local stack. 82a7dea167SDimitry Andric unsigned getFrameSize() const { return FrameSize; } 83bdd1243dSDimitry Andric /// Returns the size of the argument stack. 84a7dea167SDimitry Andric unsigned getArgSize() const { return ArgSize; } 85a7dea167SDimitry Andric 86a7dea167SDimitry Andric /// Returns a pointer to the start of the code. 87bdd1243dSDimitry Andric CodePtr getCodeBegin() const { return Code.data(); } 88a7dea167SDimitry Andric /// Returns a pointer to the end of the code. 89bdd1243dSDimitry Andric CodePtr getCodeEnd() const { return Code.data() + Code.size(); } 90a7dea167SDimitry Andric 91a7dea167SDimitry Andric /// Returns the original FunctionDecl. 92a7dea167SDimitry Andric const FunctionDecl *getDecl() const { return F; } 93a7dea167SDimitry Andric 94bdd1243dSDimitry Andric /// Returns the name of the function decl this code 95bdd1243dSDimitry Andric /// was generated for. 9606c3fb27SDimitry Andric const std::string getName() const { 9706c3fb27SDimitry Andric if (!F) 9806c3fb27SDimitry Andric return "<<expr>>"; 9906c3fb27SDimitry Andric 10006c3fb27SDimitry Andric return F->getQualifiedNameAsString(); 10106c3fb27SDimitry Andric } 102bdd1243dSDimitry Andric 103349cc55cSDimitry Andric /// Returns the location. 104a7dea167SDimitry Andric SourceLocation getLoc() const { return Loc; } 105a7dea167SDimitry Andric 106a7dea167SDimitry Andric /// Returns a parameter descriptor. 107a7dea167SDimitry Andric ParamDescriptor getParamDescriptor(unsigned Offset) const; 108a7dea167SDimitry Andric 109a7dea167SDimitry Andric /// Checks if the first argument is a RVO pointer. 110bdd1243dSDimitry Andric bool hasRVO() const { return HasRVO; } 111a7dea167SDimitry Andric 112*0fca6ea1SDimitry Andric bool hasNonNullAttr() const { return getDecl()->hasAttr<NonNullAttr>(); } 113*0fca6ea1SDimitry Andric 114a7dea167SDimitry Andric /// Range over the scope blocks. 115bdd1243dSDimitry Andric llvm::iterator_range<llvm::SmallVector<Scope, 2>::const_iterator> 116bdd1243dSDimitry Andric scopes() const { 117a7dea167SDimitry Andric return llvm::make_range(Scopes.begin(), Scopes.end()); 118a7dea167SDimitry Andric } 119a7dea167SDimitry Andric 120a7dea167SDimitry Andric /// Range over argument types. 121bdd1243dSDimitry Andric using arg_reverse_iterator = 122bdd1243dSDimitry Andric SmallVectorImpl<PrimType>::const_reverse_iterator; 123bdd1243dSDimitry Andric llvm::iterator_range<arg_reverse_iterator> args_reverse() const { 124bdd1243dSDimitry Andric return llvm::reverse(ParamTypes); 125a7dea167SDimitry Andric } 126a7dea167SDimitry Andric 127a7dea167SDimitry Andric /// Returns a specific scope. 128a7dea167SDimitry Andric Scope &getScope(unsigned Idx) { return Scopes[Idx]; } 129bdd1243dSDimitry Andric const Scope &getScope(unsigned Idx) const { return Scopes[Idx]; } 130a7dea167SDimitry Andric 131a7dea167SDimitry Andric /// Returns the source information at a given PC. 132a7dea167SDimitry Andric SourceInfo getSource(CodePtr PC) const; 133a7dea167SDimitry Andric 134a7dea167SDimitry Andric /// Checks if the function is valid to call in constexpr. 1355f757f3fSDimitry Andric bool isConstexpr() const { return IsValid || isLambdaStaticInvoker(); } 136a7dea167SDimitry Andric 137a7dea167SDimitry Andric /// Checks if the function is virtual. 138a7dea167SDimitry Andric bool isVirtual() const; 139a7dea167SDimitry Andric 140a7dea167SDimitry Andric /// Checks if the function is a constructor. 141a7dea167SDimitry Andric bool isConstructor() const { return isa<CXXConstructorDecl>(F); } 14206c3fb27SDimitry Andric /// Checks if the function is a destructor. 14306c3fb27SDimitry Andric bool isDestructor() const { return isa<CXXDestructorDecl>(F); } 14406c3fb27SDimitry Andric 14506c3fb27SDimitry Andric /// Returns the parent record decl, if any. 14606c3fb27SDimitry Andric const CXXRecordDecl *getParentDecl() const { 14706c3fb27SDimitry Andric if (const auto *MD = dyn_cast<CXXMethodDecl>(F)) 14806c3fb27SDimitry Andric return MD->getParent(); 14906c3fb27SDimitry Andric return nullptr; 15006c3fb27SDimitry Andric } 151a7dea167SDimitry Andric 1525f757f3fSDimitry Andric /// Returns whether this function is a lambda static invoker, 1535f757f3fSDimitry Andric /// which we generate custom byte code for. 1545f757f3fSDimitry Andric bool isLambdaStaticInvoker() const { 1555f757f3fSDimitry Andric if (const auto *MD = dyn_cast<CXXMethodDecl>(F)) 1565f757f3fSDimitry Andric return MD->isLambdaStaticInvoker(); 1575f757f3fSDimitry Andric return false; 1585f757f3fSDimitry Andric } 1595f757f3fSDimitry Andric 1605f757f3fSDimitry Andric /// Returns whether this function is the call operator 1615f757f3fSDimitry Andric /// of a lambda record decl. 1625f757f3fSDimitry Andric bool isLambdaCallOperator() const { 1635f757f3fSDimitry Andric if (const auto *MD = dyn_cast<CXXMethodDecl>(F)) 1645f757f3fSDimitry Andric return clang::isLambdaCallOperator(MD); 1655f757f3fSDimitry Andric return false; 1665f757f3fSDimitry Andric } 1675f757f3fSDimitry Andric 168bdd1243dSDimitry Andric /// Checks if the function is fully done compiling. 169bdd1243dSDimitry Andric bool isFullyCompiled() const { return IsFullyCompiled; } 170bdd1243dSDimitry Andric 171bdd1243dSDimitry Andric bool hasThisPointer() const { return HasThisPointer; } 172bdd1243dSDimitry Andric 17306c3fb27SDimitry Andric /// Checks if the function already has a body attached. 174bdd1243dSDimitry Andric bool hasBody() const { return HasBody; } 175bdd1243dSDimitry Andric 1765f757f3fSDimitry Andric /// Checks if the function is defined. 1775f757f3fSDimitry Andric bool isDefined() const { return Defined; } 1785f757f3fSDimitry Andric 1795f757f3fSDimitry Andric bool isVariadic() const { return Variadic; } 1805f757f3fSDimitry Andric 18106c3fb27SDimitry Andric unsigned getBuiltinID() const { return F->getBuiltinID(); } 18206c3fb27SDimitry Andric 1835f757f3fSDimitry Andric bool isBuiltin() const { return F->getBuiltinID() != 0; } 1845f757f3fSDimitry Andric 1855f757f3fSDimitry Andric bool isUnevaluatedBuiltin() const { return IsUnevaluatedBuiltin; } 1865f757f3fSDimitry Andric 187bdd1243dSDimitry Andric unsigned getNumParams() const { return ParamTypes.size(); } 188bdd1243dSDimitry Andric 189*0fca6ea1SDimitry Andric /// Returns the number of parameter this function takes when it's called, 190*0fca6ea1SDimitry Andric /// i.e excluding the instance pointer and the RVO pointer. 191*0fca6ea1SDimitry Andric unsigned getNumWrittenParams() const { 192*0fca6ea1SDimitry Andric assert(getNumParams() >= (unsigned)(hasThisPointer() + hasRVO())); 193*0fca6ea1SDimitry Andric return getNumParams() - hasThisPointer() - hasRVO(); 194*0fca6ea1SDimitry Andric } 195*0fca6ea1SDimitry Andric unsigned getWrittenArgSize() const { 196*0fca6ea1SDimitry Andric return ArgSize - (align(primSize(PT_Ptr)) * (hasThisPointer() + hasRVO())); 197*0fca6ea1SDimitry Andric } 198*0fca6ea1SDimitry Andric 199*0fca6ea1SDimitry Andric bool isThisPointerExplicit() const { 200*0fca6ea1SDimitry Andric if (const auto *MD = dyn_cast<CXXMethodDecl>(F)) 201*0fca6ea1SDimitry Andric return MD->isExplicitObjectMemberFunction(); 202*0fca6ea1SDimitry Andric return false; 203*0fca6ea1SDimitry Andric } 204*0fca6ea1SDimitry Andric 20506c3fb27SDimitry Andric unsigned getParamOffset(unsigned ParamIndex) const { 20606c3fb27SDimitry Andric return ParamOffsets[ParamIndex]; 20706c3fb27SDimitry Andric } 20806c3fb27SDimitry Andric 209a7dea167SDimitry Andric private: 210a7dea167SDimitry Andric /// Construct a function representing an actual function. 211a7dea167SDimitry Andric Function(Program &P, const FunctionDecl *F, unsigned ArgSize, 21206c3fb27SDimitry Andric llvm::SmallVectorImpl<PrimType> &&ParamTypes, 213bdd1243dSDimitry Andric llvm::DenseMap<unsigned, ParamDescriptor> &&Params, 21406c3fb27SDimitry Andric llvm::SmallVectorImpl<unsigned> &&ParamOffsets, bool HasThisPointer, 2155f757f3fSDimitry Andric bool HasRVO, bool UnevaluatedBuiltin); 216a7dea167SDimitry Andric 217a7dea167SDimitry Andric /// Sets the code of a function. 21806c3fb27SDimitry Andric void setCode(unsigned NewFrameSize, std::vector<std::byte> &&NewCode, 21906c3fb27SDimitry Andric SourceMap &&NewSrcMap, llvm::SmallVector<Scope, 2> &&NewScopes, 22006c3fb27SDimitry Andric bool NewHasBody) { 221a7dea167SDimitry Andric FrameSize = NewFrameSize; 222a7dea167SDimitry Andric Code = std::move(NewCode); 223a7dea167SDimitry Andric SrcMap = std::move(NewSrcMap); 224a7dea167SDimitry Andric Scopes = std::move(NewScopes); 225a7dea167SDimitry Andric IsValid = true; 22606c3fb27SDimitry Andric HasBody = NewHasBody; 227a7dea167SDimitry Andric } 228a7dea167SDimitry Andric 229bdd1243dSDimitry Andric void setIsFullyCompiled(bool FC) { IsFullyCompiled = FC; } 2305f757f3fSDimitry Andric void setDefined(bool D) { Defined = D; } 231bdd1243dSDimitry Andric 232a7dea167SDimitry Andric private: 233a7dea167SDimitry Andric friend class Program; 234a7dea167SDimitry Andric friend class ByteCodeEmitter; 235a7dea167SDimitry Andric 236a7dea167SDimitry Andric /// Program reference. 237a7dea167SDimitry Andric Program &P; 238a7dea167SDimitry Andric /// Location of the executed code. 239a7dea167SDimitry Andric SourceLocation Loc; 240a7dea167SDimitry Andric /// Declaration this function was compiled from. 241a7dea167SDimitry Andric const FunctionDecl *F; 242a7dea167SDimitry Andric /// Local area size: storage + metadata. 243bdd1243dSDimitry Andric unsigned FrameSize = 0; 244a7dea167SDimitry Andric /// Size of the argument stack. 245a7dea167SDimitry Andric unsigned ArgSize; 246a7dea167SDimitry Andric /// Program code. 24706c3fb27SDimitry Andric std::vector<std::byte> Code; 248a7dea167SDimitry Andric /// Opcode-to-expression mapping. 249a7dea167SDimitry Andric SourceMap SrcMap; 250a7dea167SDimitry Andric /// List of block descriptors. 251a7dea167SDimitry Andric llvm::SmallVector<Scope, 2> Scopes; 252a7dea167SDimitry Andric /// List of argument types. 253a7dea167SDimitry Andric llvm::SmallVector<PrimType, 8> ParamTypes; 254a7dea167SDimitry Andric /// Map from byte offset to parameter descriptor. 255a7dea167SDimitry Andric llvm::DenseMap<unsigned, ParamDescriptor> Params; 25606c3fb27SDimitry Andric /// List of parameter offsets. 25706c3fb27SDimitry Andric llvm::SmallVector<unsigned, 8> ParamOffsets; 258a7dea167SDimitry Andric /// Flag to indicate if the function is valid. 259a7dea167SDimitry Andric bool IsValid = false; 260bdd1243dSDimitry Andric /// Flag to indicate if the function is done being 261bdd1243dSDimitry Andric /// compiled to bytecode. 262bdd1243dSDimitry Andric bool IsFullyCompiled = false; 263bdd1243dSDimitry Andric /// Flag indicating if this function takes the this pointer 264bdd1243dSDimitry Andric /// as the first implicit argument 265bdd1243dSDimitry Andric bool HasThisPointer = false; 266bdd1243dSDimitry Andric /// Whether this function has Return Value Optimization, i.e. 267bdd1243dSDimitry Andric /// the return value is constructed in the caller's stack frame. 268bdd1243dSDimitry Andric /// This is done for functions that return non-primive values. 269bdd1243dSDimitry Andric bool HasRVO = false; 270bdd1243dSDimitry Andric /// If we've already compiled the function's body. 271bdd1243dSDimitry Andric bool HasBody = false; 2725f757f3fSDimitry Andric bool Defined = false; 2735f757f3fSDimitry Andric bool Variadic = false; 2745f757f3fSDimitry Andric bool IsUnevaluatedBuiltin = false; 275a7dea167SDimitry Andric 276a7dea167SDimitry Andric public: 277a7dea167SDimitry Andric /// Dumps the disassembled bytecode to \c llvm::errs(). 278a7dea167SDimitry Andric void dump() const; 279a7dea167SDimitry Andric void dump(llvm::raw_ostream &OS) const; 280a7dea167SDimitry Andric }; 281a7dea167SDimitry Andric 282a7dea167SDimitry Andric } // namespace interp 283a7dea167SDimitry Andric } // namespace clang 284a7dea167SDimitry Andric 285a7dea167SDimitry Andric #endif 286