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 26 namespace clang { 27 class QualType; 28 29 namespace interp { 30 31 template <class Emitter> class LocalScope; 32 template <class Emitter> class DestructorScope; 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 template <class Emitter> class ArrayIndexScope; 38 39 /// Compilation context for expressions. 40 template <class Emitter> 41 class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>, 42 public Emitter { 43 protected: 44 // Aliases for types defined in the emitter. 45 using LabelTy = typename Emitter::LabelTy; 46 using AddrTy = typename Emitter::AddrTy; 47 48 /// Current compilation context. 49 Context &Ctx; 50 /// Program to link to. 51 Program &P; 52 53 public: 54 /// Initializes the compiler and the backend emitter. 55 template <typename... Tys> 56 ByteCodeExprGen(Context &Ctx, Program &P, Tys &&... Args) 57 : Emitter(Ctx, P, Args...), Ctx(Ctx), P(P) {} 58 59 // Expression visitors - result returned on interp stack. 60 bool VisitCastExpr(const CastExpr *E); 61 bool VisitIntegerLiteral(const IntegerLiteral *E); 62 bool VisitFloatingLiteral(const FloatingLiteral *E); 63 bool VisitParenExpr(const ParenExpr *E); 64 bool VisitBinaryOperator(const BinaryOperator *E); 65 bool VisitLogicalBinOp(const BinaryOperator *E); 66 bool VisitPointerArithBinOp(const BinaryOperator *E); 67 bool VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E); 68 bool VisitCallExpr(const CallExpr *E); 69 bool VisitBuiltinCallExpr(const CallExpr *E); 70 bool VisitCXXMemberCallExpr(const CXXMemberCallExpr *E); 71 bool VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *E); 72 bool VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *E); 73 bool VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *E); 74 bool VisitCXXThisExpr(const CXXThisExpr *E); 75 bool VisitUnaryOperator(const UnaryOperator *E); 76 bool VisitDeclRefExpr(const DeclRefExpr *E); 77 bool VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E); 78 bool VisitSubstNonTypeTemplateParmExpr(const SubstNonTypeTemplateParmExpr *E); 79 bool VisitArraySubscriptExpr(const ArraySubscriptExpr *E); 80 bool VisitInitListExpr(const InitListExpr *E); 81 bool VisitConstantExpr(const ConstantExpr *E); 82 bool VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *E); 83 bool VisitMemberExpr(const MemberExpr *E); 84 bool VisitArrayInitIndexExpr(const ArrayInitIndexExpr *E); 85 bool VisitOpaqueValueExpr(const OpaqueValueExpr *E); 86 bool VisitAbstractConditionalOperator(const AbstractConditionalOperator *E); 87 bool VisitStringLiteral(const StringLiteral *E); 88 bool VisitCharacterLiteral(const CharacterLiteral *E); 89 bool VisitCompoundAssignOperator(const CompoundAssignOperator *E); 90 bool VisitFloatCompoundAssignOperator(const CompoundAssignOperator *E); 91 bool VisitPointerCompoundAssignOperator(const CompoundAssignOperator *E); 92 bool VisitExprWithCleanups(const ExprWithCleanups *E); 93 bool VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *E); 94 bool VisitCompoundLiteralExpr(const CompoundLiteralExpr *E); 95 bool VisitTypeTraitExpr(const TypeTraitExpr *E); 96 bool VisitLambdaExpr(const LambdaExpr *E); 97 bool VisitPredefinedExpr(const PredefinedExpr *E); 98 99 protected: 100 bool visitExpr(const Expr *E) override; 101 bool visitDecl(const VarDecl *VD) override; 102 103 protected: 104 /// Emits scope cleanup instructions. 105 void emitCleanup(); 106 107 /// Returns a record type from a record or pointer type. 108 const RecordType *getRecordTy(QualType Ty); 109 110 /// Returns a record from a record or pointer type. 111 Record *getRecord(QualType Ty); 112 Record *getRecord(const RecordDecl *RD); 113 114 // Returns a function for the given FunctionDecl. 115 // If the function does not exist yet, it is compiled. 116 const Function *getFunction(const FunctionDecl *FD); 117 118 /// Classifies a type. 119 std::optional<PrimType> classify(const Expr *E) const { 120 return E->isGLValue() ? PT_Ptr : classify(E->getType()); 121 } 122 std::optional<PrimType> classify(QualType Ty) const { 123 return Ctx.classify(Ty); 124 } 125 126 /// Classifies a known primitive type 127 PrimType classifyPrim(QualType Ty) const { 128 if (auto T = classify(Ty)) { 129 return *T; 130 } 131 llvm_unreachable("not a primitive type"); 132 } 133 134 /// Evaluates an expression for side effects and discards the result. 135 bool discard(const Expr *E); 136 /// Evaluates an expression and places result on stack. 137 bool visit(const Expr *E); 138 /// Compiles an initializer. 139 bool visitInitializer(const Expr *E); 140 /// Compiles an array initializer. 141 bool visitArrayInitializer(const Expr *Initializer); 142 /// Compiles a record initializer. 143 bool visitRecordInitializer(const Expr *Initializer); 144 /// Creates and initializes a variable from the given decl. 145 bool visitVarDecl(const VarDecl *VD); 146 147 /// Visits an expression and converts it to a boolean. 148 bool visitBool(const Expr *E); 149 150 /// Visits an initializer for a local. 151 bool visitLocalInitializer(const Expr *Init, unsigned I) { 152 if (!this->emitGetPtrLocal(I, Init)) 153 return false; 154 155 if (!visitInitializer(Init)) 156 return false; 157 158 return this->emitPopPtr(Init); 159 } 160 161 /// Visits an initializer for a global. 162 bool visitGlobalInitializer(const Expr *Init, unsigned I) { 163 if (!this->emitGetPtrGlobal(I, Init)) 164 return false; 165 166 if (!visitInitializer(Init)) 167 return false; 168 169 if ((Init->getType()->isArrayType() || Init->getType()->isRecordType()) && 170 !this->emitCheckGlobalCtor(Init)) 171 return false; 172 173 return this->emitPopPtr(Init); 174 } 175 176 /// Visits a delegated initializer. 177 bool visitThisInitializer(const Expr *I) { 178 if (!this->emitThis(I)) 179 return false; 180 181 if (!visitInitializer(I)) 182 return false; 183 184 return this->emitPopPtr(I); 185 } 186 187 bool visitConditional(const AbstractConditionalOperator *E, 188 llvm::function_ref<bool(const Expr *)> V); 189 190 /// Creates a local primitive value. 191 unsigned allocateLocalPrimitive(DeclTy &&Decl, PrimType Ty, bool IsConst, 192 bool IsExtended = false); 193 194 /// Allocates a space storing a local given its type. 195 std::optional<unsigned> allocateLocal(DeclTy &&Decl, bool IsExtended = false); 196 197 private: 198 friend class VariableScope<Emitter>; 199 friend class LocalScope<Emitter>; 200 friend class DestructorScope<Emitter>; 201 friend class RecordScope<Emitter>; 202 friend class DeclScope<Emitter>; 203 friend class OptionScope<Emitter>; 204 friend class ArrayIndexScope<Emitter>; 205 206 /// Emits a zero initializer. 207 bool visitZeroInitializer(QualType QT, const Expr *E); 208 209 enum class DerefKind { 210 /// Value is read and pushed to stack. 211 Read, 212 /// Direct method generates a value which is written. Returns pointer. 213 Write, 214 /// Direct method receives the value, pushes mutated value. Returns pointer. 215 ReadWrite, 216 }; 217 218 /// Method to directly load a value. If the value can be fetched directly, 219 /// the direct handler is called. Otherwise, a pointer is left on the stack 220 /// and the indirect handler is expected to operate on that. 221 bool dereference(const Expr *LV, DerefKind AK, 222 llvm::function_ref<bool(PrimType)> Direct, 223 llvm::function_ref<bool(PrimType)> Indirect); 224 bool dereferenceParam(const Expr *LV, PrimType T, const ParmVarDecl *PD, 225 DerefKind AK, 226 llvm::function_ref<bool(PrimType)> Direct, 227 llvm::function_ref<bool(PrimType)> Indirect); 228 bool dereferenceVar(const Expr *LV, PrimType T, const VarDecl *PD, 229 DerefKind AK, llvm::function_ref<bool(PrimType)> Direct, 230 llvm::function_ref<bool(PrimType)> Indirect); 231 232 /// Emits an APSInt constant. 233 bool emitConst(const llvm::APSInt &Value, const Expr *E); 234 bool emitConst(const llvm::APInt &Value, const Expr *E) { 235 return emitConst(static_cast<llvm::APSInt>(Value), E); 236 } 237 238 /// Emits an integer constant. 239 template <typename T> bool emitConst(T Value, const Expr *E); 240 241 /// Returns the CXXRecordDecl for the type of the given expression, 242 /// or nullptr if no such decl exists. 243 const CXXRecordDecl *getRecordDecl(const Expr *E) const { 244 QualType T = E->getType(); 245 if (const auto *RD = T->getPointeeCXXRecordDecl()) 246 return RD; 247 return T->getAsCXXRecordDecl(); 248 } 249 250 llvm::RoundingMode getRoundingMode(const Expr *E) const { 251 FPOptions FPO = E->getFPFeaturesInEffect(Ctx.getLangOpts()); 252 253 if (FPO.getRoundingMode() == llvm::RoundingMode::Dynamic) 254 return llvm::RoundingMode::NearestTiesToEven; 255 256 return FPO.getRoundingMode(); 257 } 258 259 bool emitRecordDestruction(const Descriptor *Desc); 260 bool emitDerivedToBaseCasts(const RecordType *DerivedType, 261 const RecordType *BaseType, const Expr *E); 262 263 protected: 264 /// Variable to storage mapping. 265 llvm::DenseMap<const ValueDecl *, Scope::Local> Locals; 266 267 /// OpaqueValueExpr to location mapping. 268 llvm::DenseMap<const OpaqueValueExpr *, unsigned> OpaqueExprs; 269 270 /// Current scope. 271 VariableScope<Emitter> *VarScope = nullptr; 272 273 /// Current argument index. Needed to emit ArrayInitIndexExpr. 274 std::optional<uint64_t> ArrayIndex; 275 276 /// Flag indicating if return value is to be discarded. 277 bool DiscardResult = false; 278 }; 279 280 extern template class ByteCodeExprGen<ByteCodeEmitter>; 281 extern template class ByteCodeExprGen<EvalEmitter>; 282 283 /// Scope chain managing the variable lifetimes. 284 template <class Emitter> class VariableScope { 285 public: 286 VariableScope(ByteCodeExprGen<Emitter> *Ctx) 287 : Ctx(Ctx), Parent(Ctx->VarScope) { 288 Ctx->VarScope = this; 289 } 290 291 virtual ~VariableScope() { Ctx->VarScope = this->Parent; } 292 293 void add(const Scope::Local &Local, bool IsExtended) { 294 if (IsExtended) 295 this->addExtended(Local); 296 else 297 this->addLocal(Local); 298 } 299 300 virtual void addLocal(const Scope::Local &Local) { 301 if (this->Parent) 302 this->Parent->addLocal(Local); 303 } 304 305 virtual void addExtended(const Scope::Local &Local) { 306 if (this->Parent) 307 this->Parent->addExtended(Local); 308 } 309 310 virtual void emitDestruction() {} 311 virtual void emitDestructors() {} 312 VariableScope *getParent() const { return Parent; } 313 314 protected: 315 /// ByteCodeExprGen instance. 316 ByteCodeExprGen<Emitter> *Ctx; 317 /// Link to the parent scope. 318 VariableScope *Parent; 319 }; 320 321 /// Generic scope for local variables. 322 template <class Emitter> class LocalScope : public VariableScope<Emitter> { 323 public: 324 LocalScope(ByteCodeExprGen<Emitter> *Ctx) : VariableScope<Emitter>(Ctx) {} 325 326 /// Emit a Destroy op for this scope. 327 ~LocalScope() override { 328 if (!Idx) 329 return; 330 this->Ctx->emitDestroy(*Idx, SourceInfo{}); 331 } 332 333 /// Overriden to support explicit destruction. 334 void emitDestruction() override { 335 if (!Idx) 336 return; 337 this->emitDestructors(); 338 this->Ctx->emitDestroy(*Idx, SourceInfo{}); 339 this->Idx = std::nullopt; 340 } 341 342 void addLocal(const Scope::Local &Local) override { 343 if (!Idx) { 344 Idx = this->Ctx->Descriptors.size(); 345 this->Ctx->Descriptors.emplace_back(); 346 } 347 348 this->Ctx->Descriptors[*Idx].emplace_back(Local); 349 } 350 351 void emitDestructors() override { 352 if (!Idx) 353 return; 354 // Emit destructor calls for local variables of record 355 // type with a destructor. 356 for (Scope::Local &Local : this->Ctx->Descriptors[*Idx]) { 357 if (!Local.Desc->isPrimitive() && !Local.Desc->isPrimitiveArray()) { 358 this->Ctx->emitGetPtrLocal(Local.Offset, SourceInfo{}); 359 this->Ctx->emitRecordDestruction(Local.Desc); 360 } 361 } 362 } 363 364 /// Index of the scope in the chain. 365 std::optional<unsigned> Idx; 366 }; 367 368 /// Emits the destructors of the variables of \param OtherScope 369 /// when this scope is destroyed. Does not create a Scope in the bytecode at 370 /// all, this is just a RAII object to emit destructors. 371 template <class Emitter> class DestructorScope final { 372 public: 373 DestructorScope(LocalScope<Emitter> &OtherScope) : OtherScope(OtherScope) {} 374 375 ~DestructorScope() { OtherScope.emitDestructors(); } 376 377 private: 378 LocalScope<Emitter> &OtherScope; 379 }; 380 381 /// Like a regular LocalScope, except that the destructors of all local 382 /// variables are automatically emitted when the AutoScope is destroyed. 383 template <class Emitter> class AutoScope : public LocalScope<Emitter> { 384 public: 385 AutoScope(ByteCodeExprGen<Emitter> *Ctx) 386 : LocalScope<Emitter>(Ctx), DS(*this) {} 387 388 private: 389 DestructorScope<Emitter> DS; 390 }; 391 392 /// Scope for storage declared in a compound statement. 393 template <class Emitter> class BlockScope final : public AutoScope<Emitter> { 394 public: 395 BlockScope(ByteCodeExprGen<Emitter> *Ctx) : AutoScope<Emitter>(Ctx) {} 396 397 void addExtended(const Scope::Local &Local) override { 398 // If we to this point, just add the variable as a normal local 399 // variable. It will be destroyed at the end of the block just 400 // like all others. 401 this->addLocal(Local); 402 } 403 }; 404 405 /// Expression scope which tracks potentially lifetime extended 406 /// temporaries which are hoisted to the parent scope on exit. 407 template <class Emitter> class ExprScope final : public AutoScope<Emitter> { 408 public: 409 ExprScope(ByteCodeExprGen<Emitter> *Ctx) : AutoScope<Emitter>(Ctx) {} 410 411 void addExtended(const Scope::Local &Local) override { 412 if (this->Parent) 413 this->Parent->addLocal(Local); 414 } 415 }; 416 417 template <class Emitter> class ArrayIndexScope final { 418 public: 419 ArrayIndexScope(ByteCodeExprGen<Emitter> *Ctx, uint64_t Index) : Ctx(Ctx) { 420 OldArrayIndex = Ctx->ArrayIndex; 421 Ctx->ArrayIndex = Index; 422 } 423 424 ~ArrayIndexScope() { Ctx->ArrayIndex = OldArrayIndex; } 425 426 private: 427 ByteCodeExprGen<Emitter> *Ctx; 428 std::optional<uint64_t> OldArrayIndex; 429 }; 430 431 } // namespace interp 432 } // namespace clang 433 434 #endif 435