323 lines · c
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-exception6//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_H16#define LLVM_CLANG_AST_INTERP_FUNCTION_H17 18#include "Descriptor.h"19#include "Source.h"20#include "clang/AST/Attr.h"21#include "clang/AST/Decl.h"22#include "clang/AST/DeclCXX.h"23#include "llvm/ADT/PointerUnion.h"24#include "llvm/Support/raw_ostream.h"25 26namespace clang {27namespace interp {28class Program;29class ByteCodeEmitter;30class Pointer;31enum PrimType : uint8_t;32 33/// Describes a scope block.34///35/// The block gathers all the descriptors of the locals defined in this block.36class Scope final {37public:38 /// Information about a local's storage.39 struct Local {40 /// Offset of the local in frame.41 unsigned Offset;42 /// Descriptor of the local.43 Descriptor *Desc;44 /// If the cleanup for this local should be emitted.45 bool EnabledByDefault = true;46 };47 48 using LocalVectorTy = llvm::SmallVector<Local, 8>;49 50 Scope(LocalVectorTy &&Descriptors) : Descriptors(std::move(Descriptors)) {}51 52 llvm::iterator_range<LocalVectorTy::const_iterator> locals() const {53 return llvm::make_range(Descriptors.begin(), Descriptors.end());54 }55 56 llvm::iterator_range<LocalVectorTy::const_reverse_iterator>57 locals_reverse() const {58 return llvm::reverse(Descriptors);59 }60 61private:62 /// Object descriptors in this block.63 LocalVectorTy Descriptors;64};65 66using FunctionDeclTy =67 llvm::PointerUnion<const FunctionDecl *, const BlockExpr *>;68 69/// Bytecode function.70///71/// Contains links to the bytecode of the function, as well as metadata72/// describing all arguments and stack-local variables.73///74/// # Calling Convention75///76/// When calling a function, all argument values must be on the stack.77///78/// If the function has a This pointer (i.e. hasThisPointer() returns true,79/// the argument values need to be preceeded by a Pointer for the This object.80///81/// If the function uses Return Value Optimization, the arguments (and82/// potentially the This pointer) need to be preceeded by a Pointer pointing83/// to the location to construct the returned value.84///85/// After the function has been called, it will remove all arguments,86/// including RVO and This pointer, from the stack.87///88class Function final {89public:90 enum class FunctionKind {91 Normal,92 Ctor,93 Dtor,94 LambdaStaticInvoker,95 LambdaCallOperator,96 CopyOrMoveOperator,97 };98 using ParamDescriptor = std::pair<PrimType, Descriptor *>;99 100 /// Returns the size of the function's local stack.101 unsigned getFrameSize() const { return FrameSize; }102 /// Returns the size of the argument stack.103 unsigned getArgSize() const { return ArgSize; }104 105 /// Returns a pointer to the start of the code.106 CodePtr getCodeBegin() const { return Code.data(); }107 /// Returns a pointer to the end of the code.108 CodePtr getCodeEnd() const { return Code.data() + Code.size(); }109 110 /// Returns the original FunctionDecl.111 const FunctionDecl *getDecl() const {112 return dyn_cast<const FunctionDecl *>(Source);113 }114 const BlockExpr *getExpr() const {115 return dyn_cast<const BlockExpr *>(Source);116 }117 118 /// Returns the name of the function decl this code119 /// was generated for.120 std::string getName() const {121 if (!Source || !getDecl())122 return "<<expr>>";123 124 return getDecl()->getQualifiedNameAsString();125 }126 127 /// Returns a parameter descriptor.128 ParamDescriptor getParamDescriptor(unsigned Offset) const;129 130 /// Checks if the first argument is a RVO pointer.131 bool hasRVO() const { return HasRVO; }132 133 bool hasNonNullAttr() const { return getDecl()->hasAttr<NonNullAttr>(); }134 135 /// Range over the scope blocks.136 llvm::iterator_range<llvm::SmallVector<Scope, 2>::const_iterator>137 scopes() const {138 return llvm::make_range(Scopes.begin(), Scopes.end());139 }140 141 /// Range over argument types.142 using arg_reverse_iterator =143 SmallVectorImpl<PrimType>::const_reverse_iterator;144 llvm::iterator_range<arg_reverse_iterator> args_reverse() const {145 return llvm::reverse(ParamTypes);146 }147 148 /// Returns a specific scope.149 Scope &getScope(unsigned Idx) { return Scopes[Idx]; }150 const Scope &getScope(unsigned Idx) const { return Scopes[Idx]; }151 152 /// Returns the source information at a given PC.153 SourceInfo getSource(CodePtr PC) const;154 155 /// Checks if the function is valid to call.156 bool isValid() const { return IsValid || isLambdaStaticInvoker(); }157 158 /// Checks if the function is virtual.159 bool isVirtual() const { return Virtual; };160 bool isImmediate() const { return Immediate; }161 bool isConstexpr() const { return Constexpr; }162 163 /// Checks if the function is a constructor.164 bool isConstructor() const { return Kind == FunctionKind::Ctor; }165 /// Checks if the function is a destructor.166 bool isDestructor() const { return Kind == FunctionKind::Dtor; }167 /// Checks if the function is copy or move operator.168 bool isCopyOrMoveOperator() const {169 return Kind == FunctionKind::CopyOrMoveOperator;170 }171 172 /// Returns whether this function is a lambda static invoker,173 /// which we generate custom byte code for.174 bool isLambdaStaticInvoker() const {175 return Kind == FunctionKind::LambdaStaticInvoker;176 }177 178 /// Returns whether this function is the call operator179 /// of a lambda record decl.180 bool isLambdaCallOperator() const {181 return Kind == FunctionKind::LambdaCallOperator;182 }183 184 /// Returns the parent record decl, if any.185 const CXXRecordDecl *getParentDecl() const {186 if (const auto *MD = dyn_cast_if_present<CXXMethodDecl>(187 dyn_cast<const FunctionDecl *>(Source)))188 return MD->getParent();189 return nullptr;190 }191 192 /// Checks if the function is fully done compiling.193 bool isFullyCompiled() const { return IsFullyCompiled; }194 195 bool hasThisPointer() const { return HasThisPointer; }196 197 /// Checks if the function already has a body attached.198 bool hasBody() const { return HasBody; }199 200 /// Checks if the function is defined.201 bool isDefined() const { return Defined; }202 203 bool isVariadic() const { return Variadic; }204 205 unsigned getNumParams() const { return ParamTypes.size(); }206 207 /// Returns the number of parameter this function takes when it's called,208 /// i.e excluding the instance pointer and the RVO pointer.209 unsigned getNumWrittenParams() const {210 assert(getNumParams() >= (unsigned)(hasThisPointer() + hasRVO()));211 return getNumParams() - hasThisPointer() - hasRVO();212 }213 unsigned getWrittenArgSize() const {214 return ArgSize - (align(primSize(PT_Ptr)) * (hasThisPointer() + hasRVO()));215 }216 217 bool isThisPointerExplicit() const {218 if (const auto *MD = dyn_cast_if_present<CXXMethodDecl>(219 dyn_cast<const FunctionDecl *>(Source)))220 return MD->isExplicitObjectMemberFunction();221 return false;222 }223 224 unsigned getParamOffset(unsigned ParamIndex) const {225 return ParamOffsets[ParamIndex];226 }227 228 PrimType getParamType(unsigned ParamIndex) const {229 return ParamTypes[ParamIndex];230 }231 232private:233 /// Construct a function representing an actual function.234 Function(Program &P, FunctionDeclTy Source, unsigned ArgSize,235 llvm::SmallVectorImpl<PrimType> &&ParamTypes,236 llvm::DenseMap<unsigned, ParamDescriptor> &&Params,237 llvm::SmallVectorImpl<unsigned> &&ParamOffsets, bool HasThisPointer,238 bool HasRVO, bool IsLambdaStaticInvoker);239 240 /// Sets the code of a function.241 void setCode(FunctionDeclTy Source, unsigned NewFrameSize,242 llvm::SmallVector<std::byte> &&NewCode, SourceMap &&NewSrcMap,243 llvm::SmallVector<Scope, 2> &&NewScopes, bool NewHasBody) {244 this->Source = Source;245 FrameSize = NewFrameSize;246 Code = std::move(NewCode);247 SrcMap = std::move(NewSrcMap);248 Scopes = std::move(NewScopes);249 IsValid = true;250 HasBody = NewHasBody;251 }252 253 void setIsFullyCompiled(bool FC) { IsFullyCompiled = FC; }254 void setDefined(bool D) { Defined = D; }255 256private:257 friend class Program;258 friend class ByteCodeEmitter;259 friend class Context;260 261 /// Program reference.262 Program &P;263 /// Function Kind.264 FunctionKind Kind;265 /// Declaration this function was compiled from.266 FunctionDeclTy Source;267 /// Local area size: storage + metadata.268 unsigned FrameSize = 0;269 /// Size of the argument stack.270 unsigned ArgSize;271 /// Program code.272 llvm::SmallVector<std::byte> Code;273 /// Opcode-to-expression mapping.274 SourceMap SrcMap;275 /// List of block descriptors.276 llvm::SmallVector<Scope, 2> Scopes;277 /// List of argument types.278 llvm::SmallVector<PrimType, 8> ParamTypes;279 /// Map from byte offset to parameter descriptor.280 llvm::DenseMap<unsigned, ParamDescriptor> Params;281 /// List of parameter offsets.282 llvm::SmallVector<unsigned, 8> ParamOffsets;283 /// Flag to indicate if the function is valid.284 LLVM_PREFERRED_TYPE(bool)285 unsigned IsValid : 1;286 /// Flag to indicate if the function is done being287 /// compiled to bytecode.288 LLVM_PREFERRED_TYPE(bool)289 unsigned IsFullyCompiled : 1;290 /// Flag indicating if this function takes the this pointer291 /// as the first implicit argument292 LLVM_PREFERRED_TYPE(bool)293 unsigned HasThisPointer : 1;294 /// Whether this function has Return Value Optimization, i.e.295 /// the return value is constructed in the caller's stack frame.296 /// This is done for functions that return non-primive values.297 LLVM_PREFERRED_TYPE(bool)298 unsigned HasRVO : 1;299 /// If we've already compiled the function's body.300 LLVM_PREFERRED_TYPE(bool)301 unsigned HasBody : 1;302 LLVM_PREFERRED_TYPE(bool)303 unsigned Defined : 1;304 LLVM_PREFERRED_TYPE(bool)305 unsigned Variadic : 1;306 LLVM_PREFERRED_TYPE(bool)307 unsigned Virtual : 1;308 LLVM_PREFERRED_TYPE(bool)309 unsigned Immediate : 1;310 LLVM_PREFERRED_TYPE(bool)311 unsigned Constexpr : 1;312 313public:314 /// Dumps the disassembled bytecode to \c llvm::errs().315 void dump() const;316 void dump(llvm::raw_ostream &OS) const;317};318 319} // namespace interp320} // namespace clang321 322#endif323