1e5dd7070Spatrick //===--- ByteCodeExprGen.h - Code generator for expressions -----*- 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 constexpr bytecode compiler. 10e5dd7070Spatrick // 11e5dd7070Spatrick //===----------------------------------------------------------------------===// 12e5dd7070Spatrick 13e5dd7070Spatrick #ifndef LLVM_CLANG_AST_INTERP_BYTECODEEXPRGEN_H 14e5dd7070Spatrick #define LLVM_CLANG_AST_INTERP_BYTECODEEXPRGEN_H 15e5dd7070Spatrick 16e5dd7070Spatrick #include "ByteCodeEmitter.h" 17e5dd7070Spatrick #include "EvalEmitter.h" 18e5dd7070Spatrick #include "Pointer.h" 19e5dd7070Spatrick #include "PrimType.h" 20e5dd7070Spatrick #include "Record.h" 21e5dd7070Spatrick #include "clang/AST/Decl.h" 22e5dd7070Spatrick #include "clang/AST/Expr.h" 23e5dd7070Spatrick #include "clang/AST/StmtVisitor.h" 24ec727ea7Spatrick #include "clang/Basic/TargetInfo.h" 25e5dd7070Spatrick 26e5dd7070Spatrick namespace clang { 27e5dd7070Spatrick class QualType; 28e5dd7070Spatrick 29e5dd7070Spatrick namespace interp { 30e5dd7070Spatrick 31e5dd7070Spatrick template <class Emitter> class LocalScope; 32e5dd7070Spatrick template <class Emitter> class RecordScope; 33e5dd7070Spatrick template <class Emitter> class VariableScope; 34e5dd7070Spatrick template <class Emitter> class DeclScope; 35e5dd7070Spatrick template <class Emitter> class OptionScope; 36*12c85518Srobert template <class Emitter> class ArrayIndexScope; 37e5dd7070Spatrick 38e5dd7070Spatrick /// Compilation context for expressions. 39e5dd7070Spatrick template <class Emitter> 40e5dd7070Spatrick class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>, 41e5dd7070Spatrick public Emitter { 42e5dd7070Spatrick protected: 43e5dd7070Spatrick // Aliases for types defined in the emitter. 44e5dd7070Spatrick using LabelTy = typename Emitter::LabelTy; 45e5dd7070Spatrick using AddrTy = typename Emitter::AddrTy; 46e5dd7070Spatrick 47e5dd7070Spatrick /// Current compilation context. 48e5dd7070Spatrick Context &Ctx; 49e5dd7070Spatrick /// Program to link to. 50e5dd7070Spatrick Program &P; 51e5dd7070Spatrick 52e5dd7070Spatrick public: 53e5dd7070Spatrick /// Initializes the compiler and the backend emitter. 54e5dd7070Spatrick template <typename... Tys> ByteCodeExprGen(Context & Ctx,Program & P,Tys &&...Args)55e5dd7070Spatrick ByteCodeExprGen(Context &Ctx, Program &P, Tys &&... Args) 56e5dd7070Spatrick : Emitter(Ctx, P, Args...), Ctx(Ctx), P(P) {} 57e5dd7070Spatrick 58*12c85518Srobert // Expression visitors - result returned on interp stack. 59e5dd7070Spatrick bool VisitCastExpr(const CastExpr *E); 60e5dd7070Spatrick bool VisitIntegerLiteral(const IntegerLiteral *E); 61e5dd7070Spatrick bool VisitParenExpr(const ParenExpr *E); 62e5dd7070Spatrick bool VisitBinaryOperator(const BinaryOperator *E); 63*12c85518Srobert bool VisitPointerArithBinOp(const BinaryOperator *E); 64*12c85518Srobert bool VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E); 65*12c85518Srobert bool VisitCallExpr(const CallExpr *E); 66*12c85518Srobert bool VisitCXXMemberCallExpr(const CXXMemberCallExpr *E); 67*12c85518Srobert bool VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *E); 68*12c85518Srobert bool VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *E); 69*12c85518Srobert bool VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *E); 70*12c85518Srobert bool VisitCXXThisExpr(const CXXThisExpr *E); 71*12c85518Srobert bool VisitUnaryOperator(const UnaryOperator *E); 72*12c85518Srobert bool VisitDeclRefExpr(const DeclRefExpr *E); 73*12c85518Srobert bool VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E); 74*12c85518Srobert bool VisitSubstNonTypeTemplateParmExpr(const SubstNonTypeTemplateParmExpr *E); 75*12c85518Srobert bool VisitArraySubscriptExpr(const ArraySubscriptExpr *E); 76*12c85518Srobert bool VisitInitListExpr(const InitListExpr *E); 77*12c85518Srobert bool VisitConstantExpr(const ConstantExpr *E); 78*12c85518Srobert bool VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *E); 79*12c85518Srobert bool VisitMemberExpr(const MemberExpr *E); 80*12c85518Srobert bool VisitArrayInitIndexExpr(const ArrayInitIndexExpr *E); 81*12c85518Srobert bool VisitOpaqueValueExpr(const OpaqueValueExpr *E); 82*12c85518Srobert bool VisitAbstractConditionalOperator(const AbstractConditionalOperator *E); 83*12c85518Srobert bool VisitStringLiteral(const StringLiteral *E); 84*12c85518Srobert bool VisitCharacterLiteral(const CharacterLiteral *E); 85*12c85518Srobert bool VisitCompoundAssignOperator(const CompoundAssignOperator *E); 86e5dd7070Spatrick 87e5dd7070Spatrick protected: 88e5dd7070Spatrick bool visitExpr(const Expr *E) override; 89e5dd7070Spatrick bool visitDecl(const VarDecl *VD) override; 90e5dd7070Spatrick 91e5dd7070Spatrick protected: 92e5dd7070Spatrick /// Emits scope cleanup instructions. 93e5dd7070Spatrick void emitCleanup(); 94e5dd7070Spatrick 95e5dd7070Spatrick /// Returns a record type from a record or pointer type. 96e5dd7070Spatrick const RecordType *getRecordTy(QualType Ty); 97e5dd7070Spatrick 98e5dd7070Spatrick /// Returns a record from a record or pointer type. 99e5dd7070Spatrick Record *getRecord(QualType Ty); 100e5dd7070Spatrick Record *getRecord(const RecordDecl *RD); 101e5dd7070Spatrick 102*12c85518Srobert // Returns a function for the given FunctionDecl. 103*12c85518Srobert // If the function does not exist yet, it is compiled. 104*12c85518Srobert const Function *getFunction(const FunctionDecl *FD); 105e5dd7070Spatrick 106e5dd7070Spatrick /// Classifies a type. classify(const Expr * E)107*12c85518Srobert std::optional<PrimType> classify(const Expr *E) const { 108e5dd7070Spatrick return E->isGLValue() ? PT_Ptr : classify(E->getType()); 109e5dd7070Spatrick } classify(QualType Ty)110*12c85518Srobert std::optional<PrimType> classify(QualType Ty) const { 111e5dd7070Spatrick return Ctx.classify(Ty); 112e5dd7070Spatrick } 113e5dd7070Spatrick 114e5dd7070Spatrick /// Classifies a known primitive type classifyPrim(QualType Ty)115e5dd7070Spatrick PrimType classifyPrim(QualType Ty) const { 116e5dd7070Spatrick if (auto T = classify(Ty)) { 117e5dd7070Spatrick return *T; 118e5dd7070Spatrick } 119e5dd7070Spatrick llvm_unreachable("not a primitive type"); 120e5dd7070Spatrick } 121e5dd7070Spatrick 122e5dd7070Spatrick /// Evaluates an expression for side effects and discards the result. 123e5dd7070Spatrick bool discard(const Expr *E); 124e5dd7070Spatrick /// Evaluates an expression and places result on stack. 125e5dd7070Spatrick bool visit(const Expr *E); 126*12c85518Srobert /// Compiles an initializer. 127*12c85518Srobert bool visitInitializer(const Expr *E); 128*12c85518Srobert /// Compiles an array initializer. 129*12c85518Srobert bool visitArrayInitializer(const Expr *Initializer); 130*12c85518Srobert /// Compiles a record initializer. 131*12c85518Srobert bool visitRecordInitializer(const Expr *Initializer); 132*12c85518Srobert /// Creates and initializes a variable from the given decl. 133*12c85518Srobert bool visitVarDecl(const VarDecl *VD); 134e5dd7070Spatrick 135e5dd7070Spatrick /// Visits an expression and converts it to a boolean. 136e5dd7070Spatrick bool visitBool(const Expr *E); 137e5dd7070Spatrick 138e5dd7070Spatrick /// Visits an initializer for a local. visitLocalInitializer(const Expr * Init,unsigned I)139e5dd7070Spatrick bool visitLocalInitializer(const Expr *Init, unsigned I) { 140*12c85518Srobert if (!this->emitGetPtrLocal(I, Init)) 141*12c85518Srobert return false; 142*12c85518Srobert 143*12c85518Srobert if (!visitInitializer(Init)) 144*12c85518Srobert return false; 145*12c85518Srobert 146*12c85518Srobert return this->emitPopPtr(Init); 147e5dd7070Spatrick } 148e5dd7070Spatrick 149e5dd7070Spatrick /// Visits an initializer for a global. visitGlobalInitializer(const Expr * Init,unsigned I)150e5dd7070Spatrick bool visitGlobalInitializer(const Expr *Init, unsigned I) { 151*12c85518Srobert if (!this->emitGetPtrGlobal(I, Init)) 152*12c85518Srobert return false; 153*12c85518Srobert 154*12c85518Srobert if (!visitInitializer(Init)) 155*12c85518Srobert return false; 156*12c85518Srobert 157*12c85518Srobert return this->emitPopPtr(Init); 158e5dd7070Spatrick } 159e5dd7070Spatrick 160e5dd7070Spatrick /// Visits a delegated initializer. visitThisInitializer(const Expr * I)161e5dd7070Spatrick bool visitThisInitializer(const Expr *I) { 162*12c85518Srobert if (!this->emitThis(I)) 163*12c85518Srobert return false; 164*12c85518Srobert 165*12c85518Srobert if (!visitInitializer(I)) 166*12c85518Srobert return false; 167*12c85518Srobert 168*12c85518Srobert return this->emitPopPtr(I); 169e5dd7070Spatrick } 170e5dd7070Spatrick 171e5dd7070Spatrick /// Creates a local primitive value. 172e5dd7070Spatrick unsigned allocateLocalPrimitive(DeclTy &&Decl, PrimType Ty, bool IsMutable, 173e5dd7070Spatrick bool IsExtended = false); 174e5dd7070Spatrick 175e5dd7070Spatrick /// Allocates a space storing a local given its type. 176*12c85518Srobert std::optional<unsigned> allocateLocal(DeclTy &&Decl, bool IsExtended = false); 177e5dd7070Spatrick 178e5dd7070Spatrick private: 179e5dd7070Spatrick friend class VariableScope<Emitter>; 180e5dd7070Spatrick friend class LocalScope<Emitter>; 181e5dd7070Spatrick friend class RecordScope<Emitter>; 182e5dd7070Spatrick friend class DeclScope<Emitter>; 183e5dd7070Spatrick friend class OptionScope<Emitter>; 184*12c85518Srobert friend class ArrayIndexScope<Emitter>; 185e5dd7070Spatrick 186e5dd7070Spatrick /// Emits a zero initializer. 187e5dd7070Spatrick bool visitZeroInitializer(PrimType T, const Expr *E); 188e5dd7070Spatrick 189e5dd7070Spatrick enum class DerefKind { 190e5dd7070Spatrick /// Value is read and pushed to stack. 191e5dd7070Spatrick Read, 192e5dd7070Spatrick /// Direct method generates a value which is written. Returns pointer. 193e5dd7070Spatrick Write, 194e5dd7070Spatrick /// Direct method receives the value, pushes mutated value. Returns pointer. 195e5dd7070Spatrick ReadWrite, 196e5dd7070Spatrick }; 197e5dd7070Spatrick 198e5dd7070Spatrick /// Method to directly load a value. If the value can be fetched directly, 199e5dd7070Spatrick /// the direct handler is called. Otherwise, a pointer is left on the stack 200e5dd7070Spatrick /// and the indirect handler is expected to operate on that. 201e5dd7070Spatrick bool dereference(const Expr *LV, DerefKind AK, 202e5dd7070Spatrick llvm::function_ref<bool(PrimType)> Direct, 203e5dd7070Spatrick llvm::function_ref<bool(PrimType)> Indirect); 204e5dd7070Spatrick bool dereferenceParam(const Expr *LV, PrimType T, const ParmVarDecl *PD, 205e5dd7070Spatrick DerefKind AK, 206e5dd7070Spatrick llvm::function_ref<bool(PrimType)> Direct, 207e5dd7070Spatrick llvm::function_ref<bool(PrimType)> Indirect); 208e5dd7070Spatrick bool dereferenceVar(const Expr *LV, PrimType T, const VarDecl *PD, 209e5dd7070Spatrick DerefKind AK, llvm::function_ref<bool(PrimType)> Direct, 210e5dd7070Spatrick llvm::function_ref<bool(PrimType)> Indirect); 211e5dd7070Spatrick 212*12c85518Srobert /// Emits an APSInt constant. 213*12c85518Srobert bool emitConst(const APSInt &Value, const Expr *E); emitConst(const APInt & Value,const Expr * E)214*12c85518Srobert bool emitConst(const APInt &Value, const Expr *E) { 215*12c85518Srobert return emitConst(static_cast<APSInt>(Value), E); 216e5dd7070Spatrick } 217e5dd7070Spatrick 218*12c85518Srobert /// Emits an integer constant. 219*12c85518Srobert template <typename T> bool emitConst(T Value, const Expr *E); 220e5dd7070Spatrick 221*12c85518Srobert /// Returns the CXXRecordDecl for the type of the given expression, 222*12c85518Srobert /// or nullptr if no such decl exists. getRecordDecl(const Expr * E)223*12c85518Srobert const CXXRecordDecl *getRecordDecl(const Expr *E) const { 224*12c85518Srobert QualType T = E->getType(); 225*12c85518Srobert if (const auto *RD = T->getPointeeCXXRecordDecl()) 226*12c85518Srobert return RD; 227*12c85518Srobert return T->getAsCXXRecordDecl(); 228*12c85518Srobert } 229e5dd7070Spatrick 230*12c85518Srobert /// Returns whether we should create a global variable for the 231*12c85518Srobert /// given VarDecl. shouldBeGloballyIndexed(const VarDecl * VD)232*12c85518Srobert bool shouldBeGloballyIndexed(const VarDecl *VD) const { 233*12c85518Srobert return VD->hasGlobalStorage() || VD->isConstexpr(); 234e5dd7070Spatrick } 235e5dd7070Spatrick 236e5dd7070Spatrick protected: 237e5dd7070Spatrick /// Variable to storage mapping. 238e5dd7070Spatrick llvm::DenseMap<const ValueDecl *, Scope::Local> Locals; 239e5dd7070Spatrick 240e5dd7070Spatrick /// OpaqueValueExpr to location mapping. 241e5dd7070Spatrick llvm::DenseMap<const OpaqueValueExpr *, unsigned> OpaqueExprs; 242e5dd7070Spatrick 243e5dd7070Spatrick /// Current scope. 244e5dd7070Spatrick VariableScope<Emitter> *VarScope = nullptr; 245e5dd7070Spatrick 246*12c85518Srobert /// Current argument index. Needed to emit ArrayInitIndexExpr. 247*12c85518Srobert std::optional<uint64_t> ArrayIndex; 248e5dd7070Spatrick 249e5dd7070Spatrick /// Flag indicating if return value is to be discarded. 250e5dd7070Spatrick bool DiscardResult = false; 251e5dd7070Spatrick }; 252e5dd7070Spatrick 253e5dd7070Spatrick extern template class ByteCodeExprGen<ByteCodeEmitter>; 254e5dd7070Spatrick extern template class ByteCodeExprGen<EvalEmitter>; 255e5dd7070Spatrick 256e5dd7070Spatrick /// Scope chain managing the variable lifetimes. 257e5dd7070Spatrick template <class Emitter> class VariableScope { 258e5dd7070Spatrick public: VariableScope(ByteCodeExprGen<Emitter> * Ctx)259*12c85518Srobert VariableScope(ByteCodeExprGen<Emitter> *Ctx) 260*12c85518Srobert : Ctx(Ctx), Parent(Ctx->VarScope) { 261*12c85518Srobert Ctx->VarScope = this; 262*12c85518Srobert } 263*12c85518Srobert ~VariableScope()264e5dd7070Spatrick virtual ~VariableScope() { Ctx->VarScope = this->Parent; } 265e5dd7070Spatrick add(const Scope::Local & Local,bool IsExtended)266e5dd7070Spatrick void add(const Scope::Local &Local, bool IsExtended) { 267e5dd7070Spatrick if (IsExtended) 268e5dd7070Spatrick this->addExtended(Local); 269e5dd7070Spatrick else 270e5dd7070Spatrick this->addLocal(Local); 271e5dd7070Spatrick } 272e5dd7070Spatrick addLocal(const Scope::Local & Local)273e5dd7070Spatrick virtual void addLocal(const Scope::Local &Local) { 274e5dd7070Spatrick if (this->Parent) 275e5dd7070Spatrick this->Parent->addLocal(Local); 276e5dd7070Spatrick } 277e5dd7070Spatrick addExtended(const Scope::Local & Local)278e5dd7070Spatrick virtual void addExtended(const Scope::Local &Local) { 279e5dd7070Spatrick if (this->Parent) 280e5dd7070Spatrick this->Parent->addExtended(Local); 281e5dd7070Spatrick } 282e5dd7070Spatrick emitDestruction()283e5dd7070Spatrick virtual void emitDestruction() {} 284e5dd7070Spatrick getParent()285e5dd7070Spatrick VariableScope *getParent() { return Parent; } 286e5dd7070Spatrick 287e5dd7070Spatrick protected: 288e5dd7070Spatrick /// ByteCodeExprGen instance. 289e5dd7070Spatrick ByteCodeExprGen<Emitter> *Ctx; 290e5dd7070Spatrick /// Link to the parent scope. 291e5dd7070Spatrick VariableScope *Parent; 292e5dd7070Spatrick }; 293e5dd7070Spatrick 294e5dd7070Spatrick /// Scope for local variables. 295e5dd7070Spatrick /// 296e5dd7070Spatrick /// When the scope is destroyed, instructions are emitted to tear down 297e5dd7070Spatrick /// all variables declared in this scope. 298e5dd7070Spatrick template <class Emitter> class LocalScope : public VariableScope<Emitter> { 299e5dd7070Spatrick public: LocalScope(ByteCodeExprGen<Emitter> * Ctx)300e5dd7070Spatrick LocalScope(ByteCodeExprGen<Emitter> *Ctx) : VariableScope<Emitter>(Ctx) {} 301e5dd7070Spatrick ~LocalScope()302e5dd7070Spatrick ~LocalScope() override { this->emitDestruction(); } 303e5dd7070Spatrick addLocal(const Scope::Local & Local)304e5dd7070Spatrick void addLocal(const Scope::Local &Local) override { 305*12c85518Srobert if (!Idx) { 306e5dd7070Spatrick Idx = this->Ctx->Descriptors.size(); 307e5dd7070Spatrick this->Ctx->Descriptors.emplace_back(); 308e5dd7070Spatrick } 309e5dd7070Spatrick 310e5dd7070Spatrick this->Ctx->Descriptors[*Idx].emplace_back(Local); 311e5dd7070Spatrick } 312e5dd7070Spatrick emitDestruction()313e5dd7070Spatrick void emitDestruction() override { 314*12c85518Srobert if (!Idx) 315e5dd7070Spatrick return; 316e5dd7070Spatrick this->Ctx->emitDestroy(*Idx, SourceInfo{}); 317e5dd7070Spatrick } 318e5dd7070Spatrick 319e5dd7070Spatrick protected: 320e5dd7070Spatrick /// Index of the scope in the chain. 321*12c85518Srobert std::optional<unsigned> Idx; 322e5dd7070Spatrick }; 323e5dd7070Spatrick 324e5dd7070Spatrick /// Scope for storage declared in a compound statement. 325e5dd7070Spatrick template <class Emitter> class BlockScope final : public LocalScope<Emitter> { 326e5dd7070Spatrick public: BlockScope(ByteCodeExprGen<Emitter> * Ctx)327e5dd7070Spatrick BlockScope(ByteCodeExprGen<Emitter> *Ctx) : LocalScope<Emitter>(Ctx) {} 328e5dd7070Spatrick addExtended(const Scope::Local & Local)329e5dd7070Spatrick void addExtended(const Scope::Local &Local) override { 330e5dd7070Spatrick llvm_unreachable("Cannot create temporaries in full scopes"); 331e5dd7070Spatrick } 332e5dd7070Spatrick }; 333e5dd7070Spatrick 334e5dd7070Spatrick /// Expression scope which tracks potentially lifetime extended 335e5dd7070Spatrick /// temporaries which are hoisted to the parent scope on exit. 336e5dd7070Spatrick template <class Emitter> class ExprScope final : public LocalScope<Emitter> { 337e5dd7070Spatrick public: ExprScope(ByteCodeExprGen<Emitter> * Ctx)338e5dd7070Spatrick ExprScope(ByteCodeExprGen<Emitter> *Ctx) : LocalScope<Emitter>(Ctx) {} 339e5dd7070Spatrick addExtended(const Scope::Local & Local)340e5dd7070Spatrick void addExtended(const Scope::Local &Local) override { 341*12c85518Srobert assert(this->Parent); 342e5dd7070Spatrick this->Parent->addLocal(Local); 343e5dd7070Spatrick } 344e5dd7070Spatrick }; 345e5dd7070Spatrick 346*12c85518Srobert template <class Emitter> class ArrayIndexScope final { 347*12c85518Srobert public: ArrayIndexScope(ByteCodeExprGen<Emitter> * Ctx,uint64_t Index)348*12c85518Srobert ArrayIndexScope(ByteCodeExprGen<Emitter> *Ctx, uint64_t Index) : Ctx(Ctx) { 349*12c85518Srobert OldArrayIndex = Ctx->ArrayIndex; 350*12c85518Srobert Ctx->ArrayIndex = Index; 351*12c85518Srobert } 352*12c85518Srobert ~ArrayIndexScope()353*12c85518Srobert ~ArrayIndexScope() { Ctx->ArrayIndex = OldArrayIndex; } 354*12c85518Srobert 355*12c85518Srobert private: 356*12c85518Srobert ByteCodeExprGen<Emitter> *Ctx; 357*12c85518Srobert std::optional<uint64_t> OldArrayIndex; 358*12c85518Srobert }; 359*12c85518Srobert 360e5dd7070Spatrick } // namespace interp 361e5dd7070Spatrick } // namespace clang 362e5dd7070Spatrick 363e5dd7070Spatrick #endif 364