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