Home | History | Annotate | Line # | Download | only in Interp
      1 //===--- ByteCodeExprGen.h - Code generator for expressions -----*- 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 constexpr bytecode compiler.
     10 //
     11 //===----------------------------------------------------------------------===//
     12 
     13 #ifndef LLVM_CLANG_AST_INTERP_BYTECODEEXPRGEN_H
     14 #define LLVM_CLANG_AST_INTERP_BYTECODEEXPRGEN_H
     15 
     16 #include "ByteCodeEmitter.h"
     17 #include "EvalEmitter.h"
     18 #include "Pointer.h"
     19 #include "PrimType.h"
     20 #include "Record.h"
     21 #include "clang/AST/Decl.h"
     22 #include "clang/AST/Expr.h"
     23 #include "clang/AST/StmtVisitor.h"
     24 #include "clang/Basic/TargetInfo.h"
     25 #include "llvm/ADT/Optional.h"
     26 
     27 namespace clang {
     28 class QualType;
     29 
     30 namespace interp {
     31 class Function;
     32 class State;
     33 
     34 template <class Emitter> class LocalScope;
     35 template <class Emitter> class RecordScope;
     36 template <class Emitter> class VariableScope;
     37 template <class Emitter> class DeclScope;
     38 template <class Emitter> class OptionScope;
     39 
     40 /// Compilation context for expressions.
     41 template <class Emitter>
     42 class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
     43                         public Emitter {
     44 protected:
     45   // Emitters for opcodes of various arities.
     46   using NullaryFn = bool (ByteCodeExprGen::*)(const SourceInfo &);
     47   using UnaryFn = bool (ByteCodeExprGen::*)(PrimType, const SourceInfo &);
     48   using BinaryFn = bool (ByteCodeExprGen::*)(PrimType, PrimType,
     49                                              const SourceInfo &);
     50 
     51   // Aliases for types defined in the emitter.
     52   using LabelTy = typename Emitter::LabelTy;
     53   using AddrTy = typename Emitter::AddrTy;
     54 
     55   // Reference to a function generating the pointer of an initialized object.s
     56   using InitFnRef = std::function<bool()>;
     57 
     58   /// Current compilation context.
     59   Context &Ctx;
     60   /// Program to link to.
     61   Program &P;
     62 
     63 public:
     64   /// Initializes the compiler and the backend emitter.
     65   template <typename... Tys>
     66   ByteCodeExprGen(Context &Ctx, Program &P, Tys &&... Args)
     67       : Emitter(Ctx, P, Args...), Ctx(Ctx), P(P) {}
     68 
     69   // Expression visitors - result returned on stack.
     70   bool VisitCastExpr(const CastExpr *E);
     71   bool VisitIntegerLiteral(const IntegerLiteral *E);
     72   bool VisitParenExpr(const ParenExpr *E);
     73   bool VisitBinaryOperator(const BinaryOperator *E);
     74 
     75 protected:
     76   bool visitExpr(const Expr *E) override;
     77   bool visitDecl(const VarDecl *VD) override;
     78 
     79 protected:
     80   /// Emits scope cleanup instructions.
     81   void emitCleanup();
     82 
     83   /// Returns a record type from a record or pointer type.
     84   const RecordType *getRecordTy(QualType Ty);
     85 
     86   /// Returns a record from a record or pointer type.
     87   Record *getRecord(QualType Ty);
     88   Record *getRecord(const RecordDecl *RD);
     89 
     90   /// Returns the size int bits of an integer.
     91   unsigned getIntWidth(QualType Ty) {
     92     auto &ASTContext = Ctx.getASTContext();
     93     return ASTContext.getIntWidth(Ty);
     94   }
     95 
     96   /// Returns the value of CHAR_BIT.
     97   unsigned getCharBit() const {
     98     auto &ASTContext = Ctx.getASTContext();
     99     return ASTContext.getTargetInfo().getCharWidth();
    100   }
    101 
    102   /// Classifies a type.
    103   llvm::Optional<PrimType> classify(const Expr *E) const {
    104     return E->isGLValue() ? PT_Ptr : classify(E->getType());
    105   }
    106   llvm::Optional<PrimType> classify(QualType Ty) const {
    107     return Ctx.classify(Ty);
    108   }
    109 
    110   /// Checks if a pointer needs adjustment.
    111   bool needsAdjust(QualType Ty) const {
    112     return true;
    113   }
    114 
    115   /// Classifies a known primitive type
    116   PrimType classifyPrim(QualType Ty) const {
    117     if (auto T = classify(Ty)) {
    118       return *T;
    119     }
    120     llvm_unreachable("not a primitive type");
    121   }
    122 
    123   /// Evaluates an expression for side effects and discards the result.
    124   bool discard(const Expr *E);
    125   /// Evaluates an expression and places result on stack.
    126   bool visit(const Expr *E);
    127   /// Compiles an initializer for a local.
    128   bool visitInitializer(const Expr *E, InitFnRef GenPtr);
    129 
    130   /// Visits an expression and converts it to a boolean.
    131   bool visitBool(const Expr *E);
    132 
    133   /// Visits an initializer for a local.
    134   bool visitLocalInitializer(const Expr *Init, unsigned I) {
    135     return visitInitializer(Init, [this, I, Init] {
    136       return this->emitGetPtrLocal(I, Init);
    137     });
    138   }
    139 
    140   /// Visits an initializer for a global.
    141   bool visitGlobalInitializer(const Expr *Init, unsigned I) {
    142     return visitInitializer(Init, [this, I, Init] {
    143       return this->emitGetPtrGlobal(I, Init);
    144     });
    145   }
    146 
    147   /// Visits a delegated initializer.
    148   bool visitThisInitializer(const Expr *I) {
    149     return visitInitializer(I, [this, I] { return this->emitThis(I); });
    150   }
    151 
    152   /// Creates a local primitive value.
    153   unsigned allocateLocalPrimitive(DeclTy &&Decl, PrimType Ty, bool IsMutable,
    154                                   bool IsExtended = false);
    155 
    156   /// Allocates a space storing a local given its type.
    157   llvm::Optional<unsigned> allocateLocal(DeclTy &&Decl,
    158                                          bool IsExtended = false);
    159 
    160 private:
    161   friend class VariableScope<Emitter>;
    162   friend class LocalScope<Emitter>;
    163   friend class RecordScope<Emitter>;
    164   friend class DeclScope<Emitter>;
    165   friend class OptionScope<Emitter>;
    166 
    167   /// Emits a zero initializer.
    168   bool visitZeroInitializer(PrimType T, const Expr *E);
    169 
    170   enum class DerefKind {
    171     /// Value is read and pushed to stack.
    172     Read,
    173     /// Direct method generates a value which is written. Returns pointer.
    174     Write,
    175     /// Direct method receives the value, pushes mutated value. Returns pointer.
    176     ReadWrite,
    177   };
    178 
    179   /// Method to directly load a value. If the value can be fetched directly,
    180   /// the direct handler is called. Otherwise, a pointer is left on the stack
    181   /// and the indirect handler is expected to operate on that.
    182   bool dereference(const Expr *LV, DerefKind AK,
    183                    llvm::function_ref<bool(PrimType)> Direct,
    184                    llvm::function_ref<bool(PrimType)> Indirect);
    185   bool dereferenceParam(const Expr *LV, PrimType T, const ParmVarDecl *PD,
    186                         DerefKind AK,
    187                         llvm::function_ref<bool(PrimType)> Direct,
    188                         llvm::function_ref<bool(PrimType)> Indirect);
    189   bool dereferenceVar(const Expr *LV, PrimType T, const VarDecl *PD,
    190                       DerefKind AK, llvm::function_ref<bool(PrimType)> Direct,
    191                       llvm::function_ref<bool(PrimType)> Indirect);
    192 
    193   /// Emits an APInt constant.
    194   bool emitConst(PrimType T, unsigned NumBits, const llvm::APInt &Value,
    195                  const Expr *E);
    196 
    197   /// Emits an integer constant.
    198   template <typename T> bool emitConst(const Expr *E, T Value) {
    199     QualType Ty = E->getType();
    200     unsigned NumBits = getIntWidth(Ty);
    201     APInt WrappedValue(NumBits, Value, std::is_signed<T>::value);
    202     return emitConst(*Ctx.classify(Ty), NumBits, WrappedValue, E);
    203   }
    204 
    205   /// Returns a pointer to a variable declaration.
    206   bool getPtrVarDecl(const VarDecl *VD, const Expr *E);
    207 
    208   /// Returns the index of a global.
    209   llvm::Optional<unsigned> getGlobalIdx(const VarDecl *VD);
    210 
    211   /// Emits the initialized pointer.
    212   bool emitInitFn() {
    213     assert(InitFn && "missing initializer");
    214     return (*InitFn)();
    215   }
    216 
    217 protected:
    218   /// Variable to storage mapping.
    219   llvm::DenseMap<const ValueDecl *, Scope::Local> Locals;
    220 
    221   /// OpaqueValueExpr to location mapping.
    222   llvm::DenseMap<const OpaqueValueExpr *, unsigned> OpaqueExprs;
    223 
    224   /// Current scope.
    225   VariableScope<Emitter> *VarScope = nullptr;
    226 
    227   /// Current argument index.
    228   llvm::Optional<uint64_t> ArrayIndex;
    229 
    230   /// Flag indicating if return value is to be discarded.
    231   bool DiscardResult = false;
    232 
    233   /// Expression being initialized.
    234   llvm::Optional<InitFnRef> InitFn = {};
    235 };
    236 
    237 extern template class ByteCodeExprGen<ByteCodeEmitter>;
    238 extern template class ByteCodeExprGen<EvalEmitter>;
    239 
    240 /// Scope chain managing the variable lifetimes.
    241 template <class Emitter> class VariableScope {
    242 public:
    243   virtual ~VariableScope() { Ctx->VarScope = this->Parent; }
    244 
    245   void add(const Scope::Local &Local, bool IsExtended) {
    246     if (IsExtended)
    247       this->addExtended(Local);
    248     else
    249       this->addLocal(Local);
    250   }
    251 
    252   virtual void addLocal(const Scope::Local &Local) {
    253     if (this->Parent)
    254       this->Parent->addLocal(Local);
    255   }
    256 
    257   virtual void addExtended(const Scope::Local &Local) {
    258     if (this->Parent)
    259       this->Parent->addExtended(Local);
    260   }
    261 
    262   virtual void emitDestruction() {}
    263 
    264   VariableScope *getParent() { return Parent; }
    265 
    266 protected:
    267   VariableScope(ByteCodeExprGen<Emitter> *Ctx)
    268       : Ctx(Ctx), Parent(Ctx->VarScope) {
    269     Ctx->VarScope = this;
    270   }
    271 
    272   /// ByteCodeExprGen instance.
    273   ByteCodeExprGen<Emitter> *Ctx;
    274   /// Link to the parent scope.
    275   VariableScope *Parent;
    276 };
    277 
    278 /// Scope for local variables.
    279 ///
    280 /// When the scope is destroyed, instructions are emitted to tear down
    281 /// all variables declared in this scope.
    282 template <class Emitter> class LocalScope : public VariableScope<Emitter> {
    283 public:
    284   LocalScope(ByteCodeExprGen<Emitter> *Ctx) : VariableScope<Emitter>(Ctx) {}
    285 
    286   ~LocalScope() override { this->emitDestruction(); }
    287 
    288   void addLocal(const Scope::Local &Local) override {
    289     if (!Idx.hasValue()) {
    290       Idx = this->Ctx->Descriptors.size();
    291       this->Ctx->Descriptors.emplace_back();
    292     }
    293 
    294     this->Ctx->Descriptors[*Idx].emplace_back(Local);
    295   }
    296 
    297   void emitDestruction() override {
    298     if (!Idx.hasValue())
    299       return;
    300     this->Ctx->emitDestroy(*Idx, SourceInfo{});
    301   }
    302 
    303 protected:
    304   /// Index of the scope in the chain.
    305   Optional<unsigned> Idx;
    306 };
    307 
    308 /// Scope for storage declared in a compound statement.
    309 template <class Emitter> class BlockScope final : public LocalScope<Emitter> {
    310 public:
    311   BlockScope(ByteCodeExprGen<Emitter> *Ctx) : LocalScope<Emitter>(Ctx) {}
    312 
    313   void addExtended(const Scope::Local &Local) override {
    314     llvm_unreachable("Cannot create temporaries in full scopes");
    315   }
    316 };
    317 
    318 /// Expression scope which tracks potentially lifetime extended
    319 /// temporaries which are hoisted to the parent scope on exit.
    320 template <class Emitter> class ExprScope final : public LocalScope<Emitter> {
    321 public:
    322   ExprScope(ByteCodeExprGen<Emitter> *Ctx) : LocalScope<Emitter>(Ctx) {}
    323 
    324   void addExtended(const Scope::Local &Local) override {
    325     this->Parent->addLocal(Local);
    326   }
    327 };
    328 
    329 } // namespace interp
    330 } // namespace clang
    331 
    332 #endif
    333