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