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