brintos

brintos / llvm-project-archived public Read only

0
0
Text · 10.2 KiB · 8c309c9 Raw
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