1e5dd7070Spatrick //===--- Function.h - Bytecode function for the VM --------------*- C++ -*-===// 2e5dd7070Spatrick // 3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information. 5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6e5dd7070Spatrick // 7e5dd7070Spatrick //===----------------------------------------------------------------------===// 8e5dd7070Spatrick // 9e5dd7070Spatrick // Defines the Function class which holds all bytecode function-specific data. 10e5dd7070Spatrick // 11e5dd7070Spatrick // The scope class which describes local variables is also defined here. 12e5dd7070Spatrick // 13e5dd7070Spatrick //===----------------------------------------------------------------------===// 14e5dd7070Spatrick 15e5dd7070Spatrick #ifndef LLVM_CLANG_AST_INTERP_FUNCTION_H 16e5dd7070Spatrick #define LLVM_CLANG_AST_INTERP_FUNCTION_H 17e5dd7070Spatrick 18e5dd7070Spatrick #include "Pointer.h" 19e5dd7070Spatrick #include "Source.h" 20e5dd7070Spatrick #include "clang/AST/Decl.h" 21e5dd7070Spatrick #include "llvm/Support/raw_ostream.h" 22e5dd7070Spatrick 23e5dd7070Spatrick namespace clang { 24e5dd7070Spatrick namespace interp { 25e5dd7070Spatrick class Program; 26e5dd7070Spatrick class ByteCodeEmitter; 27e5dd7070Spatrick enum PrimType : uint32_t; 28e5dd7070Spatrick 29e5dd7070Spatrick /// Describes a scope block. 30e5dd7070Spatrick /// 31e5dd7070Spatrick /// The block gathers all the descriptors of the locals defined in this block. 32*12c85518Srobert class Scope final { 33e5dd7070Spatrick public: 34e5dd7070Spatrick /// Information about a local's storage. 35e5dd7070Spatrick struct Local { 36e5dd7070Spatrick /// Offset of the local in frame. 37e5dd7070Spatrick unsigned Offset; 38e5dd7070Spatrick /// Descriptor of the local. 39e5dd7070Spatrick Descriptor *Desc; 40e5dd7070Spatrick }; 41e5dd7070Spatrick 42e5dd7070Spatrick using LocalVectorTy = llvm::SmallVector<Local, 8>; 43e5dd7070Spatrick Scope(LocalVectorTy && Descriptors)44e5dd7070Spatrick Scope(LocalVectorTy &&Descriptors) : Descriptors(std::move(Descriptors)) {} 45e5dd7070Spatrick locals()46*12c85518Srobert llvm::iterator_range<LocalVectorTy::const_iterator> locals() const { 47e5dd7070Spatrick return llvm::make_range(Descriptors.begin(), Descriptors.end()); 48e5dd7070Spatrick } 49e5dd7070Spatrick 50e5dd7070Spatrick private: 51e5dd7070Spatrick /// Object descriptors in this block. 52e5dd7070Spatrick LocalVectorTy Descriptors; 53e5dd7070Spatrick }; 54e5dd7070Spatrick 55e5dd7070Spatrick /// Bytecode function. 56e5dd7070Spatrick /// 57e5dd7070Spatrick /// Contains links to the bytecode of the function, as well as metadata 58e5dd7070Spatrick /// describing all arguments and stack-local variables. 59*12c85518Srobert /// 60*12c85518Srobert /// # Calling Convention 61*12c85518Srobert /// 62*12c85518Srobert /// When calling a function, all argument values must be on the stack. 63*12c85518Srobert /// 64*12c85518Srobert /// If the function has a This pointer (i.e. hasThisPointer() returns true, 65*12c85518Srobert /// the argument values need to be preceeded by a Pointer for the This object. 66*12c85518Srobert /// 67*12c85518Srobert /// If the function uses Return Value Optimization, the arguments (and 68*12c85518Srobert /// potentially the This pointer) need to be proceeded by a Pointer pointing 69*12c85518Srobert /// to the location to construct the returned value. 70*12c85518Srobert /// 71*12c85518Srobert /// After the function has been called, it will remove all arguments, 72*12c85518Srobert /// including RVO and This pointer, from the stack. 73*12c85518Srobert /// 74*12c85518Srobert class Function final { 75e5dd7070Spatrick public: 76e5dd7070Spatrick using ParamDescriptor = std::pair<PrimType, Descriptor *>; 77e5dd7070Spatrick 78e5dd7070Spatrick /// Returns the size of the function's local stack. getFrameSize()79e5dd7070Spatrick unsigned getFrameSize() const { return FrameSize; } 80*12c85518Srobert /// Returns the size of the argument stack. getArgSize()81e5dd7070Spatrick unsigned getArgSize() const { return ArgSize; } 82e5dd7070Spatrick 83e5dd7070Spatrick /// Returns a pointer to the start of the code. getCodeBegin()84*12c85518Srobert CodePtr getCodeBegin() const { return Code.data(); } 85e5dd7070Spatrick /// Returns a pointer to the end of the code. getCodeEnd()86*12c85518Srobert CodePtr getCodeEnd() const { return Code.data() + Code.size(); } 87e5dd7070Spatrick 88e5dd7070Spatrick /// Returns the original FunctionDecl. getDecl()89e5dd7070Spatrick const FunctionDecl *getDecl() const { return F; } 90e5dd7070Spatrick 91*12c85518Srobert /// Returns the name of the function decl this code 92*12c85518Srobert /// was generated for. getName()93*12c85518Srobert const std::string getName() const { return F->getNameInfo().getAsString(); } 94*12c85518Srobert 95*12c85518Srobert /// Returns the location. getLoc()96e5dd7070Spatrick SourceLocation getLoc() const { return Loc; } 97e5dd7070Spatrick 98e5dd7070Spatrick /// Returns a parameter descriptor. 99e5dd7070Spatrick ParamDescriptor getParamDescriptor(unsigned Offset) const; 100e5dd7070Spatrick 101e5dd7070Spatrick /// Checks if the first argument is a RVO pointer. hasRVO()102*12c85518Srobert bool hasRVO() const { return HasRVO; } 103e5dd7070Spatrick 104e5dd7070Spatrick /// Range over the scope blocks. 105*12c85518Srobert llvm::iterator_range<llvm::SmallVector<Scope, 2>::const_iterator> scopes()106*12c85518Srobert scopes() const { 107e5dd7070Spatrick return llvm::make_range(Scopes.begin(), Scopes.end()); 108e5dd7070Spatrick } 109e5dd7070Spatrick 110e5dd7070Spatrick /// Range over argument types. 111*12c85518Srobert using arg_reverse_iterator = 112*12c85518Srobert SmallVectorImpl<PrimType>::const_reverse_iterator; args_reverse()113*12c85518Srobert llvm::iterator_range<arg_reverse_iterator> args_reverse() const { 114*12c85518Srobert return llvm::reverse(ParamTypes); 115e5dd7070Spatrick } 116e5dd7070Spatrick 117e5dd7070Spatrick /// Returns a specific scope. getScope(unsigned Idx)118e5dd7070Spatrick Scope &getScope(unsigned Idx) { return Scopes[Idx]; } getScope(unsigned Idx)119*12c85518Srobert const Scope &getScope(unsigned Idx) const { return Scopes[Idx]; } 120e5dd7070Spatrick 121e5dd7070Spatrick /// Returns the source information at a given PC. 122e5dd7070Spatrick SourceInfo getSource(CodePtr PC) const; 123e5dd7070Spatrick 124e5dd7070Spatrick /// Checks if the function is valid to call in constexpr. isConstexpr()125e5dd7070Spatrick bool isConstexpr() const { return IsValid; } 126e5dd7070Spatrick 127e5dd7070Spatrick /// Checks if the function is virtual. 128e5dd7070Spatrick bool isVirtual() const; 129e5dd7070Spatrick 130e5dd7070Spatrick /// Checks if the function is a constructor. isConstructor()131e5dd7070Spatrick bool isConstructor() const { return isa<CXXConstructorDecl>(F); } 132e5dd7070Spatrick 133*12c85518Srobert /// Checks if the function is fully done compiling. isFullyCompiled()134*12c85518Srobert bool isFullyCompiled() const { return IsFullyCompiled; } 135*12c85518Srobert hasThisPointer()136*12c85518Srobert bool hasThisPointer() const { return HasThisPointer; } 137*12c85518Srobert 138*12c85518Srobert // Checks if the funtion already has a body attached. hasBody()139*12c85518Srobert bool hasBody() const { return HasBody; } 140*12c85518Srobert getNumParams()141*12c85518Srobert unsigned getNumParams() const { return ParamTypes.size(); } 142*12c85518Srobert 143e5dd7070Spatrick private: 144e5dd7070Spatrick /// Construct a function representing an actual function. 145e5dd7070Spatrick Function(Program &P, const FunctionDecl *F, unsigned ArgSize, 146e5dd7070Spatrick llvm::SmallVector<PrimType, 8> &&ParamTypes, 147*12c85518Srobert llvm::DenseMap<unsigned, ParamDescriptor> &&Params, 148*12c85518Srobert bool HasThisPointer, bool HasRVO); 149e5dd7070Spatrick 150e5dd7070Spatrick /// Sets the code of a function. setCode(unsigned NewFrameSize,std::vector<char> && NewCode,SourceMap && NewSrcMap,llvm::SmallVector<Scope,2> && NewScopes)151e5dd7070Spatrick void setCode(unsigned NewFrameSize, std::vector<char> &&NewCode, SourceMap &&NewSrcMap, 152e5dd7070Spatrick llvm::SmallVector<Scope, 2> &&NewScopes) { 153e5dd7070Spatrick FrameSize = NewFrameSize; 154e5dd7070Spatrick Code = std::move(NewCode); 155e5dd7070Spatrick SrcMap = std::move(NewSrcMap); 156e5dd7070Spatrick Scopes = std::move(NewScopes); 157e5dd7070Spatrick IsValid = true; 158*12c85518Srobert HasBody = true; 159e5dd7070Spatrick } 160e5dd7070Spatrick setIsFullyCompiled(bool FC)161*12c85518Srobert void setIsFullyCompiled(bool FC) { IsFullyCompiled = FC; } 162*12c85518Srobert 163e5dd7070Spatrick private: 164e5dd7070Spatrick friend class Program; 165e5dd7070Spatrick friend class ByteCodeEmitter; 166e5dd7070Spatrick 167e5dd7070Spatrick /// Program reference. 168e5dd7070Spatrick Program &P; 169e5dd7070Spatrick /// Location of the executed code. 170e5dd7070Spatrick SourceLocation Loc; 171e5dd7070Spatrick /// Declaration this function was compiled from. 172e5dd7070Spatrick const FunctionDecl *F; 173e5dd7070Spatrick /// Local area size: storage + metadata. 174*12c85518Srobert unsigned FrameSize = 0; 175e5dd7070Spatrick /// Size of the argument stack. 176e5dd7070Spatrick unsigned ArgSize; 177e5dd7070Spatrick /// Program code. 178e5dd7070Spatrick std::vector<char> Code; 179e5dd7070Spatrick /// Opcode-to-expression mapping. 180e5dd7070Spatrick SourceMap SrcMap; 181e5dd7070Spatrick /// List of block descriptors. 182e5dd7070Spatrick llvm::SmallVector<Scope, 2> Scopes; 183e5dd7070Spatrick /// List of argument types. 184e5dd7070Spatrick llvm::SmallVector<PrimType, 8> ParamTypes; 185e5dd7070Spatrick /// Map from byte offset to parameter descriptor. 186e5dd7070Spatrick llvm::DenseMap<unsigned, ParamDescriptor> Params; 187e5dd7070Spatrick /// Flag to indicate if the function is valid. 188e5dd7070Spatrick bool IsValid = false; 189*12c85518Srobert /// Flag to indicate if the function is done being 190*12c85518Srobert /// compiled to bytecode. 191*12c85518Srobert bool IsFullyCompiled = false; 192*12c85518Srobert /// Flag indicating if this function takes the this pointer 193*12c85518Srobert /// as the first implicit argument 194*12c85518Srobert bool HasThisPointer = false; 195*12c85518Srobert /// Whether this function has Return Value Optimization, i.e. 196*12c85518Srobert /// the return value is constructed in the caller's stack frame. 197*12c85518Srobert /// This is done for functions that return non-primive values. 198*12c85518Srobert bool HasRVO = false; 199*12c85518Srobert /// If we've already compiled the function's body. 200*12c85518Srobert bool HasBody = false; 201e5dd7070Spatrick 202e5dd7070Spatrick public: 203e5dd7070Spatrick /// Dumps the disassembled bytecode to \c llvm::errs(). 204e5dd7070Spatrick void dump() const; 205e5dd7070Spatrick void dump(llvm::raw_ostream &OS) const; 206e5dd7070Spatrick }; 207e5dd7070Spatrick 208e5dd7070Spatrick } // namespace interp 209e5dd7070Spatrick } // namespace clang 210e5dd7070Spatrick 211e5dd7070Spatrick #endif 212