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> ByteCodeExprGen(Context & Ctx,Program & P,Tys &&...Args)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. getIntWidth(QualType Ty)91 unsigned getIntWidth(QualType Ty) { 92 auto &ASTContext = Ctx.getASTContext(); 93 return ASTContext.getIntWidth(Ty); 94 } 95 96 /// Returns the value of CHAR_BIT. getCharBit()97 unsigned getCharBit() const { 98 auto &ASTContext = Ctx.getASTContext(); 99 return ASTContext.getTargetInfo().getCharWidth(); 100 } 101 102 /// Classifies a type. classify(const Expr * E)103 llvm::Optional<PrimType> classify(const Expr *E) const { 104 return E->isGLValue() ? PT_Ptr : classify(E->getType()); 105 } classify(QualType Ty)106 llvm::Optional<PrimType> classify(QualType Ty) const { 107 return Ctx.classify(Ty); 108 } 109 110 /// Checks if a pointer needs adjustment. needsAdjust(QualType Ty)111 bool needsAdjust(QualType Ty) const { 112 return true; 113 } 114 115 /// Classifies a known primitive type classifyPrim(QualType Ty)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. visitLocalInitializer(const Expr * Init,unsigned I)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. visitGlobalInitializer(const Expr * Init,unsigned I)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. visitThisInitializer(const Expr * I)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. emitConst(const Expr * E,T Value)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. emitInitFn()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: ~VariableScope()243 virtual ~VariableScope() { Ctx->VarScope = this->Parent; } 244 add(const Scope::Local & Local,bool IsExtended)245 void add(const Scope::Local &Local, bool IsExtended) { 246 if (IsExtended) 247 this->addExtended(Local); 248 else 249 this->addLocal(Local); 250 } 251 addLocal(const Scope::Local & Local)252 virtual void addLocal(const Scope::Local &Local) { 253 if (this->Parent) 254 this->Parent->addLocal(Local); 255 } 256 addExtended(const Scope::Local & Local)257 virtual void addExtended(const Scope::Local &Local) { 258 if (this->Parent) 259 this->Parent->addExtended(Local); 260 } 261 emitDestruction()262 virtual void emitDestruction() {} 263 getParent()264 VariableScope *getParent() { return Parent; } 265 266 protected: VariableScope(ByteCodeExprGen<Emitter> * Ctx)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: LocalScope(ByteCodeExprGen<Emitter> * Ctx)284 LocalScope(ByteCodeExprGen<Emitter> *Ctx) : VariableScope<Emitter>(Ctx) {} 285 ~LocalScope()286 ~LocalScope() override { this->emitDestruction(); } 287 addLocal(const Scope::Local & Local)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 emitDestruction()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: BlockScope(ByteCodeExprGen<Emitter> * Ctx)311 BlockScope(ByteCodeExprGen<Emitter> *Ctx) : LocalScope<Emitter>(Ctx) {} 312 addExtended(const Scope::Local & Local)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: ExprScope(ByteCodeExprGen<Emitter> * Ctx)322 ExprScope(ByteCodeExprGen<Emitter> *Ctx) : LocalScope<Emitter>(Ctx) {} 323 addExtended(const Scope::Local & Local)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