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