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