diff options
Diffstat (limited to 'clang/lib/AST/Interp/ByteCodeExprGen.h')
| -rw-r--r-- | clang/lib/AST/Interp/ByteCodeExprGen.h | 331 | 
1 files changed, 331 insertions, 0 deletions
diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.h b/clang/lib/AST/Interp/ByteCodeExprGen.h new file mode 100644 index 000000000000..1d0e34fc991f --- /dev/null +++ b/clang/lib/AST/Interp/ByteCodeExprGen.h @@ -0,0 +1,331 @@ +//===--- ByteCodeExprGen.h - Code generator for expressions -----*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Defines the constexpr bytecode compiler. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_INTERP_BYTECODEEXPRGEN_H +#define LLVM_CLANG_AST_INTERP_BYTECODEEXPRGEN_H + +#include "ByteCodeEmitter.h" +#include "EvalEmitter.h" +#include "Pointer.h" +#include "PrimType.h" +#include "Record.h" +#include "clang/AST/Decl.h" +#include "clang/AST/Expr.h" +#include "clang/AST/StmtVisitor.h" +#include "llvm/ADT/Optional.h" + +namespace clang { +class QualType; + +namespace interp { +class Function; +class State; + +template <class Emitter> class LocalScope; +template <class Emitter> class RecordScope; +template <class Emitter> class VariableScope; +template <class Emitter> class DeclScope; +template <class Emitter> class OptionScope; + +/// Compilation context for expressions. +template <class Emitter> +class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>, +                        public Emitter { +protected: +  // Emitters for opcodes of various arities. +  using NullaryFn = bool (ByteCodeExprGen::*)(const SourceInfo &); +  using UnaryFn = bool (ByteCodeExprGen::*)(PrimType, const SourceInfo &); +  using BinaryFn = bool (ByteCodeExprGen::*)(PrimType, PrimType, +                                             const SourceInfo &); + +  // Aliases for types defined in the emitter. +  using LabelTy = typename Emitter::LabelTy; +  using AddrTy = typename Emitter::AddrTy; + +  // Reference to a function generating the pointer of an initialized object.s +  using InitFnRef = std::function<bool()>; + +  /// Current compilation context. +  Context &Ctx; +  /// Program to link to. +  Program &P; + +public: +  /// Initializes the compiler and the backend emitter. +  template <typename... Tys> +  ByteCodeExprGen(Context &Ctx, Program &P, Tys &&... Args) +      : Emitter(Ctx, P, Args...), Ctx(Ctx), P(P) {} + +  // Expression visitors - result returned on stack. +  bool VisitCastExpr(const CastExpr *E); +  bool VisitIntegerLiteral(const IntegerLiteral *E); +  bool VisitParenExpr(const ParenExpr *E); +  bool VisitBinaryOperator(const BinaryOperator *E); + +protected: +  bool visitExpr(const Expr *E) override; +  bool visitDecl(const VarDecl *VD) override; + +protected: +  /// Emits scope cleanup instructions. +  void emitCleanup(); + +  /// Returns a record type from a record or pointer type. +  const RecordType *getRecordTy(QualType Ty); + +  /// Returns a record from a record or pointer type. +  Record *getRecord(QualType Ty); +  Record *getRecord(const RecordDecl *RD); + +  /// Returns the size int bits of an integer. +  unsigned getIntWidth(QualType Ty) { +    auto &ASTContext = Ctx.getASTContext(); +    return ASTContext.getIntWidth(Ty); +  } + +  /// Returns the value of CHAR_BIT. +  unsigned getCharBit() const { +    auto &ASTContext = Ctx.getASTContext(); +    return ASTContext.getTargetInfo().getCharWidth(); +  } + +  /// Classifies a type. +  llvm::Optional<PrimType> classify(const Expr *E) const { +    return E->isGLValue() ? PT_Ptr : classify(E->getType()); +  } +  llvm::Optional<PrimType> classify(QualType Ty) const { +    return Ctx.classify(Ty); +  } + +  /// Checks if a pointer needs adjustment. +  bool needsAdjust(QualType Ty) const { +    return true; +  } + +  /// Classifies a known primitive type +  PrimType classifyPrim(QualType Ty) const { +    if (auto T = classify(Ty)) { +      return *T; +    } +    llvm_unreachable("not a primitive type"); +  } + +  /// Evaluates an expression for side effects and discards the result. +  bool discard(const Expr *E); +  /// Evaluates an expression and places result on stack. +  bool visit(const Expr *E); +  /// Compiles an initializer for a local. +  bool visitInitializer(const Expr *E, InitFnRef GenPtr); + +  /// Visits an expression and converts it to a boolean. +  bool visitBool(const Expr *E); + +  /// Visits an initializer for a local. +  bool visitLocalInitializer(const Expr *Init, unsigned I) { +    return visitInitializer(Init, [this, I, Init] { +      return this->emitGetPtrLocal(I, Init); +    }); +  } + +  /// Visits an initializer for a global. +  bool visitGlobalInitializer(const Expr *Init, unsigned I) { +    return visitInitializer(Init, [this, I, Init] { +      return this->emitGetPtrGlobal(I, Init); +    }); +  } + +  /// Visits a delegated initializer. +  bool visitThisInitializer(const Expr *I) { +    return visitInitializer(I, [this, I] { return this->emitThis(I); }); +  } + +  /// Creates a local primitive value. +  unsigned allocateLocalPrimitive(DeclTy &&Decl, PrimType Ty, bool IsMutable, +                                  bool IsExtended = false); + +  /// Allocates a space storing a local given its type. +  llvm::Optional<unsigned> allocateLocal(DeclTy &&Decl, +                                         bool IsExtended = false); + +private: +  friend class VariableScope<Emitter>; +  friend class LocalScope<Emitter>; +  friend class RecordScope<Emitter>; +  friend class DeclScope<Emitter>; +  friend class OptionScope<Emitter>; + +  /// Emits a zero initializer. +  bool visitZeroInitializer(PrimType T, const Expr *E); + +  enum class DerefKind { +    /// Value is read and pushed to stack. +    Read, +    /// Direct method generates a value which is written. Returns pointer. +    Write, +    /// Direct method receives the value, pushes mutated value. Returns pointer. +    ReadWrite, +  }; + +  /// Method to directly load a value. If the value can be fetched directly, +  /// the direct handler is called. Otherwise, a pointer is left on the stack +  /// and the indirect handler is expected to operate on that. +  bool dereference(const Expr *LV, DerefKind AK, +                   llvm::function_ref<bool(PrimType)> Direct, +                   llvm::function_ref<bool(PrimType)> Indirect); +  bool dereferenceParam(const Expr *LV, PrimType T, const ParmVarDecl *PD, +                        DerefKind AK, +                        llvm::function_ref<bool(PrimType)> Direct, +                        llvm::function_ref<bool(PrimType)> Indirect); +  bool dereferenceVar(const Expr *LV, PrimType T, const VarDecl *PD, +                      DerefKind AK, llvm::function_ref<bool(PrimType)> Direct, +                      llvm::function_ref<bool(PrimType)> Indirect); + +  /// Emits an APInt constant. +  bool emitConst(PrimType T, unsigned NumBits, const llvm::APInt &Value, +                 const Expr *E); + +  /// Emits an integer constant. +  template <typename T> bool emitConst(const Expr *E, T Value) { +    QualType Ty = E->getType(); +    unsigned NumBits = getIntWidth(Ty); +    APInt WrappedValue(NumBits, Value, std::is_signed<T>::value); +    return emitConst(*Ctx.classify(Ty), NumBits, WrappedValue, E); +  } + +  /// Returns a pointer to a variable declaration. +  bool getPtrVarDecl(const VarDecl *VD, const Expr *E); + +  /// Returns the index of a global. +  llvm::Optional<unsigned> getGlobalIdx(const VarDecl *VD); + +  /// Emits the initialized pointer. +  bool emitInitFn() { +    assert(InitFn && "missing initializer"); +    return (*InitFn)(); +  } + +protected: +  /// Variable to storage mapping. +  llvm::DenseMap<const ValueDecl *, Scope::Local> Locals; + +  /// OpaqueValueExpr to location mapping. +  llvm::DenseMap<const OpaqueValueExpr *, unsigned> OpaqueExprs; + +  /// Current scope. +  VariableScope<Emitter> *VarScope = nullptr; + +  /// Current argument index. +  llvm::Optional<uint64_t> ArrayIndex; + +  /// Flag indicating if return value is to be discarded. +  bool DiscardResult = false; + +  /// Expression being initialized. +  llvm::Optional<InitFnRef> InitFn = {}; +}; + +extern template class ByteCodeExprGen<ByteCodeEmitter>; +extern template class ByteCodeExprGen<EvalEmitter>; + +/// Scope chain managing the variable lifetimes. +template <class Emitter> class VariableScope { +public: +  virtual ~VariableScope() { Ctx->VarScope = this->Parent; } + +  void add(const Scope::Local &Local, bool IsExtended) { +    if (IsExtended) +      this->addExtended(Local); +    else +      this->addLocal(Local); +  } + +  virtual void addLocal(const Scope::Local &Local) { +    if (this->Parent) +      this->Parent->addLocal(Local); +  } + +  virtual void addExtended(const Scope::Local &Local) { +    if (this->Parent) +      this->Parent->addExtended(Local); +  } + +  virtual void emitDestruction() {} + +  VariableScope *getParent() { return Parent; } + +protected: +  VariableScope(ByteCodeExprGen<Emitter> *Ctx) +      : Ctx(Ctx), Parent(Ctx->VarScope) { +    Ctx->VarScope = this; +  } + +  /// ByteCodeExprGen instance. +  ByteCodeExprGen<Emitter> *Ctx; +  /// Link to the parent scope. +  VariableScope *Parent; +}; + +/// Scope for local variables. +/// +/// When the scope is destroyed, instructions are emitted to tear down +/// all variables declared in this scope. +template <class Emitter> class LocalScope : public VariableScope<Emitter> { +public: +  LocalScope(ByteCodeExprGen<Emitter> *Ctx) : VariableScope<Emitter>(Ctx) {} + +  ~LocalScope() override { this->emitDestruction(); } + +  void addLocal(const Scope::Local &Local) override { +    if (!Idx.hasValue()) { +      Idx = this->Ctx->Descriptors.size(); +      this->Ctx->Descriptors.emplace_back(); +    } + +    this->Ctx->Descriptors[*Idx].emplace_back(Local); +  } + +  void emitDestruction() override { +    if (!Idx.hasValue()) +      return; +    this->Ctx->emitDestroy(*Idx, SourceInfo{}); +  } + +protected: +  /// Index of the scope in the chain. +  Optional<unsigned> Idx; +}; + +/// Scope for storage declared in a compound statement. +template <class Emitter> class BlockScope final : public LocalScope<Emitter> { +public: +  BlockScope(ByteCodeExprGen<Emitter> *Ctx) : LocalScope<Emitter>(Ctx) {} + +  void addExtended(const Scope::Local &Local) override { +    llvm_unreachable("Cannot create temporaries in full scopes"); +  } +}; + +/// Expression scope which tracks potentially lifetime extended +/// temporaries which are hoisted to the parent scope on exit. +template <class Emitter> class ExprScope final : public LocalScope<Emitter> { +public: +  ExprScope(ByteCodeExprGen<Emitter> *Ctx) : LocalScope<Emitter>(Ctx) {} + +  void addExtended(const Scope::Local &Local) override { +    this->Parent->addLocal(Local); +  } +}; + +} // namespace interp +} // namespace clang + +#endif  | 
