Path: blob/main/contrib/llvm-project/clang/lib/AST/Interp/Compiler.h
35292 views
//===--- Compiler.h - Code generator for expressions -----*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// Defines the constexpr bytecode compiler.9//10//===----------------------------------------------------------------------===//1112#ifndef LLVM_CLANG_AST_INTERP_BYTECODEEXPRGEN_H13#define LLVM_CLANG_AST_INTERP_BYTECODEEXPRGEN_H1415#include "ByteCodeEmitter.h"16#include "EvalEmitter.h"17#include "Pointer.h"18#include "PrimType.h"19#include "Record.h"20#include "clang/AST/Decl.h"21#include "clang/AST/Expr.h"22#include "clang/AST/StmtVisitor.h"23#include "clang/Basic/TargetInfo.h"2425namespace clang {26class QualType;2728namespace interp {2930template <class Emitter> class LocalScope;31template <class Emitter> class DestructorScope;32template <class Emitter> class VariableScope;33template <class Emitter> class DeclScope;34template <class Emitter> class InitLinkScope;35template <class Emitter> class InitStackScope;36template <class Emitter> class OptionScope;37template <class Emitter> class ArrayIndexScope;38template <class Emitter> class SourceLocScope;39template <class Emitter> class LoopScope;40template <class Emitter> class LabelScope;41template <class Emitter> class SwitchScope;42template <class Emitter> class StmtExprScope;4344template <class Emitter> class Compiler;45struct InitLink {46public:47enum {48K_This = 0,49K_Field = 1,50K_Temp = 2,51K_Decl = 3,52};5354static InitLink This() { return InitLink{K_This}; }55static InitLink Field(unsigned Offset) {56InitLink IL{K_Field};57IL.Offset = Offset;58return IL;59}60static InitLink Temp(unsigned Offset) {61InitLink IL{K_Temp};62IL.Offset = Offset;63return IL;64}65static InitLink Decl(const ValueDecl *D) {66InitLink IL{K_Decl};67IL.D = D;68return IL;69}7071InitLink(uint8_t Kind) : Kind(Kind) {}72template <class Emitter>73bool emit(Compiler<Emitter> *Ctx, const Expr *E) const;7475uint32_t Kind;76union {77unsigned Offset;78const ValueDecl *D;79};80};8182/// State encapsulating if a the variable creation has been successful,83/// unsuccessful, or no variable has been created at all.84struct VarCreationState {85std::optional<bool> S = std::nullopt;86VarCreationState() = default;87VarCreationState(bool b) : S(b) {}88static VarCreationState NotCreated() { return VarCreationState(); }8990operator bool() const { return S && *S; }91bool notCreated() const { return !S; }92};9394/// Compilation context for expressions.95template <class Emitter>96class Compiler : public ConstStmtVisitor<Compiler<Emitter>, bool>,97public Emitter {98protected:99// Aliases for types defined in the emitter.100using LabelTy = typename Emitter::LabelTy;101using AddrTy = typename Emitter::AddrTy;102using OptLabelTy = std::optional<LabelTy>;103using CaseMap = llvm::DenseMap<const SwitchCase *, LabelTy>;104105/// Current compilation context.106Context &Ctx;107/// Program to link to.108Program &P;109110public:111/// Initializes the compiler and the backend emitter.112template <typename... Tys>113Compiler(Context &Ctx, Program &P, Tys &&...Args)114: Emitter(Ctx, P, Args...), Ctx(Ctx), P(P) {}115116// Expressions.117bool VisitCastExpr(const CastExpr *E);118bool VisitIntegerLiteral(const IntegerLiteral *E);119bool VisitFloatingLiteral(const FloatingLiteral *E);120bool VisitImaginaryLiteral(const ImaginaryLiteral *E);121bool VisitParenExpr(const ParenExpr *E);122bool VisitBinaryOperator(const BinaryOperator *E);123bool VisitLogicalBinOp(const BinaryOperator *E);124bool VisitPointerArithBinOp(const BinaryOperator *E);125bool VisitComplexBinOp(const BinaryOperator *E);126bool VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E);127bool VisitCallExpr(const CallExpr *E);128bool VisitBuiltinCallExpr(const CallExpr *E);129bool VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *E);130bool VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *E);131bool VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *E);132bool VisitGNUNullExpr(const GNUNullExpr *E);133bool VisitCXXThisExpr(const CXXThisExpr *E);134bool VisitUnaryOperator(const UnaryOperator *E);135bool VisitComplexUnaryOperator(const UnaryOperator *E);136bool VisitDeclRefExpr(const DeclRefExpr *E);137bool VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E);138bool VisitSubstNonTypeTemplateParmExpr(const SubstNonTypeTemplateParmExpr *E);139bool VisitArraySubscriptExpr(const ArraySubscriptExpr *E);140bool VisitInitListExpr(const InitListExpr *E);141bool VisitCXXParenListInitExpr(const CXXParenListInitExpr *E);142bool VisitConstantExpr(const ConstantExpr *E);143bool VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *E);144bool VisitMemberExpr(const MemberExpr *E);145bool VisitArrayInitIndexExpr(const ArrayInitIndexExpr *E);146bool VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E);147bool VisitOpaqueValueExpr(const OpaqueValueExpr *E);148bool VisitAbstractConditionalOperator(const AbstractConditionalOperator *E);149bool VisitStringLiteral(const StringLiteral *E);150bool VisitObjCStringLiteral(const ObjCStringLiteral *E);151bool VisitObjCEncodeExpr(const ObjCEncodeExpr *E);152bool VisitSYCLUniqueStableNameExpr(const SYCLUniqueStableNameExpr *E);153bool VisitCharacterLiteral(const CharacterLiteral *E);154bool VisitCompoundAssignOperator(const CompoundAssignOperator *E);155bool VisitFloatCompoundAssignOperator(const CompoundAssignOperator *E);156bool VisitPointerCompoundAssignOperator(const CompoundAssignOperator *E);157bool VisitExprWithCleanups(const ExprWithCleanups *E);158bool VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *E);159bool VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *E);160bool VisitCompoundLiteralExpr(const CompoundLiteralExpr *E);161bool VisitTypeTraitExpr(const TypeTraitExpr *E);162bool VisitArrayTypeTraitExpr(const ArrayTypeTraitExpr *E);163bool VisitLambdaExpr(const LambdaExpr *E);164bool VisitPredefinedExpr(const PredefinedExpr *E);165bool VisitCXXThrowExpr(const CXXThrowExpr *E);166bool VisitCXXReinterpretCastExpr(const CXXReinterpretCastExpr *E);167bool VisitCXXNoexceptExpr(const CXXNoexceptExpr *E);168bool VisitCXXConstructExpr(const CXXConstructExpr *E);169bool VisitSourceLocExpr(const SourceLocExpr *E);170bool VisitOffsetOfExpr(const OffsetOfExpr *E);171bool VisitCXXScalarValueInitExpr(const CXXScalarValueInitExpr *E);172bool VisitSizeOfPackExpr(const SizeOfPackExpr *E);173bool VisitGenericSelectionExpr(const GenericSelectionExpr *E);174bool VisitChooseExpr(const ChooseExpr *E);175bool VisitEmbedExpr(const EmbedExpr *E);176bool VisitObjCBoolLiteralExpr(const ObjCBoolLiteralExpr *E);177bool VisitCXXInheritedCtorInitExpr(const CXXInheritedCtorInitExpr *E);178bool VisitExpressionTraitExpr(const ExpressionTraitExpr *E);179bool VisitCXXUuidofExpr(const CXXUuidofExpr *E);180bool VisitRequiresExpr(const RequiresExpr *E);181bool VisitConceptSpecializationExpr(const ConceptSpecializationExpr *E);182bool VisitCXXRewrittenBinaryOperator(const CXXRewrittenBinaryOperator *E);183bool VisitPseudoObjectExpr(const PseudoObjectExpr *E);184bool VisitPackIndexingExpr(const PackIndexingExpr *E);185bool VisitRecoveryExpr(const RecoveryExpr *E);186bool VisitAddrLabelExpr(const AddrLabelExpr *E);187bool VisitConvertVectorExpr(const ConvertVectorExpr *E);188bool VisitShuffleVectorExpr(const ShuffleVectorExpr *E);189bool VisitExtVectorElementExpr(const ExtVectorElementExpr *E);190bool VisitObjCBoxedExpr(const ObjCBoxedExpr *E);191bool VisitCXXStdInitializerListExpr(const CXXStdInitializerListExpr *E);192bool VisitStmtExpr(const StmtExpr *E);193bool VisitCXXNewExpr(const CXXNewExpr *E);194bool VisitCXXDeleteExpr(const CXXDeleteExpr *E);195196// Statements.197bool visitCompoundStmt(const CompoundStmt *S);198bool visitLoopBody(const Stmt *S);199bool visitDeclStmt(const DeclStmt *DS);200bool visitReturnStmt(const ReturnStmt *RS);201bool visitIfStmt(const IfStmt *IS);202bool visitWhileStmt(const WhileStmt *S);203bool visitDoStmt(const DoStmt *S);204bool visitForStmt(const ForStmt *S);205bool visitCXXForRangeStmt(const CXXForRangeStmt *S);206bool visitBreakStmt(const BreakStmt *S);207bool visitContinueStmt(const ContinueStmt *S);208bool visitSwitchStmt(const SwitchStmt *S);209bool visitCaseStmt(const CaseStmt *S);210bool visitDefaultStmt(const DefaultStmt *S);211bool visitAttributedStmt(const AttributedStmt *S);212bool visitCXXTryStmt(const CXXTryStmt *S);213214protected:215bool visitStmt(const Stmt *S);216bool visitExpr(const Expr *E) override;217bool visitFunc(const FunctionDecl *F) override;218219bool visitDeclAndReturn(const VarDecl *VD, bool ConstantContext) override;220221protected:222/// Emits scope cleanup instructions.223void emitCleanup();224225/// Returns a record type from a record or pointer type.226const RecordType *getRecordTy(QualType Ty);227228/// Returns a record from a record or pointer type.229Record *getRecord(QualType Ty);230Record *getRecord(const RecordDecl *RD);231232/// Returns a function for the given FunctionDecl.233/// If the function does not exist yet, it is compiled.234const Function *getFunction(const FunctionDecl *FD);235236std::optional<PrimType> classify(const Expr *E) const {237return Ctx.classify(E);238}239std::optional<PrimType> classify(QualType Ty) const {240return Ctx.classify(Ty);241}242243/// Classifies a known primitive type.244PrimType classifyPrim(QualType Ty) const {245if (auto T = classify(Ty)) {246return *T;247}248llvm_unreachable("not a primitive type");249}250/// Classifies a known primitive expression.251PrimType classifyPrim(const Expr *E) const {252if (auto T = classify(E))253return *T;254llvm_unreachable("not a primitive type");255}256257/// Evaluates an expression and places the result on the stack. If the258/// expression is of composite type, a local variable will be created259/// and a pointer to said variable will be placed on the stack.260bool visit(const Expr *E);261/// Compiles an initializer. This is like visit() but it will never262/// create a variable and instead rely on a variable already having263/// been created. visitInitializer() then relies on a pointer to this264/// variable being on top of the stack.265bool visitInitializer(const Expr *E);266/// Evaluates an expression for side effects and discards the result.267bool discard(const Expr *E);268/// Just pass evaluation on to \p E. This leaves all the parsing flags269/// intact.270bool delegate(const Expr *E);271/// Creates and initializes a variable from the given decl.272VarCreationState visitVarDecl(const VarDecl *VD, bool Toplevel = false);273VarCreationState visitDecl(const VarDecl *VD);274/// Visit an APValue.275bool visitAPValue(const APValue &Val, PrimType ValType, const Expr *E);276bool visitAPValueInitializer(const APValue &Val, const Expr *E);277/// Visit the given decl as if we have a reference to it.278bool visitDeclRef(const ValueDecl *D, const Expr *E);279280/// Visits an expression and converts it to a boolean.281bool visitBool(const Expr *E);282283bool visitInitList(ArrayRef<const Expr *> Inits, const Expr *ArrayFiller,284const Expr *E);285bool visitArrayElemInit(unsigned ElemIndex, const Expr *Init);286287/// Creates a local primitive value.288unsigned allocateLocalPrimitive(DeclTy &&Decl, PrimType Ty, bool IsConst,289bool IsExtended = false);290291/// Allocates a space storing a local given its type.292std::optional<unsigned>293allocateLocal(DeclTy &&Decl, const ValueDecl *ExtendingDecl = nullptr);294295private:296friend class VariableScope<Emitter>;297friend class LocalScope<Emitter>;298friend class DestructorScope<Emitter>;299friend class DeclScope<Emitter>;300friend class InitLinkScope<Emitter>;301friend class InitStackScope<Emitter>;302friend class OptionScope<Emitter>;303friend class ArrayIndexScope<Emitter>;304friend class SourceLocScope<Emitter>;305friend struct InitLink;306friend class LoopScope<Emitter>;307friend class LabelScope<Emitter>;308friend class SwitchScope<Emitter>;309friend class StmtExprScope<Emitter>;310311/// Emits a zero initializer.312bool visitZeroInitializer(PrimType T, QualType QT, const Expr *E);313bool visitZeroRecordInitializer(const Record *R, const Expr *E);314315/// Emits an APSInt constant.316bool emitConst(const llvm::APSInt &Value, PrimType Ty, const Expr *E);317bool emitConst(const llvm::APSInt &Value, const Expr *E);318bool emitConst(const llvm::APInt &Value, const Expr *E) {319return emitConst(static_cast<llvm::APSInt>(Value), E);320}321322/// Emits an integer constant.323template <typename T> bool emitConst(T Value, PrimType Ty, const Expr *E);324template <typename T> bool emitConst(T Value, const Expr *E);325326llvm::RoundingMode getRoundingMode(const Expr *E) const {327FPOptions FPO = E->getFPFeaturesInEffect(Ctx.getLangOpts());328329if (FPO.getRoundingMode() == llvm::RoundingMode::Dynamic)330return llvm::RoundingMode::NearestTiesToEven;331332return FPO.getRoundingMode();333}334335bool emitPrimCast(PrimType FromT, PrimType ToT, QualType ToQT, const Expr *E);336PrimType classifyComplexElementType(QualType T) const {337assert(T->isAnyComplexType());338339QualType ElemType = T->getAs<ComplexType>()->getElementType();340341return *this->classify(ElemType);342}343344bool emitComplexReal(const Expr *SubExpr);345bool emitComplexBoolCast(const Expr *E);346bool emitComplexComparison(const Expr *LHS, const Expr *RHS,347const BinaryOperator *E);348349bool emitRecordDestruction(const Record *R);350bool emitDestruction(const Descriptor *Desc);351unsigned collectBaseOffset(const QualType BaseType,352const QualType DerivedType);353bool emitLambdaStaticInvokerBody(const CXXMethodDecl *MD);354355protected:356/// Variable to storage mapping.357llvm::DenseMap<const ValueDecl *, Scope::Local> Locals;358359/// OpaqueValueExpr to location mapping.360llvm::DenseMap<const OpaqueValueExpr *, unsigned> OpaqueExprs;361362/// Current scope.363VariableScope<Emitter> *VarScope = nullptr;364365/// Current argument index. Needed to emit ArrayInitIndexExpr.366std::optional<uint64_t> ArrayIndex;367368/// DefaultInit- or DefaultArgExpr, needed for SourceLocExpr.369const Expr *SourceLocDefaultExpr = nullptr;370371/// Flag indicating if return value is to be discarded.372bool DiscardResult = false;373374bool InStmtExpr = false;375376/// Flag inidicating if we're initializing an already created377/// variable. This is set in visitInitializer().378bool Initializing = false;379const ValueDecl *InitializingDecl = nullptr;380381llvm::SmallVector<InitLink> InitStack;382bool InitStackActive = false;383384/// Flag indicating if we're initializing a global variable.385bool GlobalDecl = false;386387/// Type of the expression returned by the function.388std::optional<PrimType> ReturnType;389390/// Switch case mapping.391CaseMap CaseLabels;392393/// Point to break to.394OptLabelTy BreakLabel;395/// Point to continue to.396OptLabelTy ContinueLabel;397/// Default case label.398OptLabelTy DefaultLabel;399};400401extern template class Compiler<ByteCodeEmitter>;402extern template class Compiler<EvalEmitter>;403404/// Scope chain managing the variable lifetimes.405template <class Emitter> class VariableScope {406public:407VariableScope(Compiler<Emitter> *Ctx, const ValueDecl *VD)408: Ctx(Ctx), Parent(Ctx->VarScope), ValDecl(VD) {409Ctx->VarScope = this;410}411412virtual ~VariableScope() { Ctx->VarScope = this->Parent; }413414void add(const Scope::Local &Local, bool IsExtended) {415if (IsExtended)416this->addExtended(Local);417else418this->addLocal(Local);419}420421virtual void addLocal(const Scope::Local &Local) {422if (this->Parent)423this->Parent->addLocal(Local);424}425426virtual void addExtended(const Scope::Local &Local) {427if (this->Parent)428this->Parent->addExtended(Local);429}430431void addExtended(const Scope::Local &Local, const ValueDecl *ExtendingDecl) {432// Walk up the chain of scopes until we find the one for ExtendingDecl.433// If there is no such scope, attach it to the parent one.434VariableScope *P = this;435while (P) {436if (P->ValDecl == ExtendingDecl) {437P->addLocal(Local);438return;439}440P = P->Parent;441if (!P)442break;443}444445// Use the parent scope.446addExtended(Local);447}448449virtual void emitDestruction() {}450virtual bool emitDestructors() { return true; }451VariableScope *getParent() const { return Parent; }452453protected:454/// Compiler instance.455Compiler<Emitter> *Ctx;456/// Link to the parent scope.457VariableScope *Parent;458const ValueDecl *ValDecl = nullptr;459};460461/// Generic scope for local variables.462template <class Emitter> class LocalScope : public VariableScope<Emitter> {463public:464LocalScope(Compiler<Emitter> *Ctx) : VariableScope<Emitter>(Ctx, nullptr) {}465LocalScope(Compiler<Emitter> *Ctx, const ValueDecl *VD)466: VariableScope<Emitter>(Ctx, VD) {}467468/// Emit a Destroy op for this scope.469~LocalScope() override {470if (!Idx)471return;472this->Ctx->emitDestroy(*Idx, SourceInfo{});473removeStoredOpaqueValues();474}475476/// Overriden to support explicit destruction.477void emitDestruction() override { destroyLocals(); }478479/// Explicit destruction of local variables.480bool destroyLocals() {481if (!Idx)482return true;483484bool Success = this->emitDestructors();485this->Ctx->emitDestroy(*Idx, SourceInfo{});486removeStoredOpaqueValues();487this->Idx = std::nullopt;488return Success;489}490491void addLocal(const Scope::Local &Local) override {492if (!Idx) {493Idx = this->Ctx->Descriptors.size();494this->Ctx->Descriptors.emplace_back();495}496497this->Ctx->Descriptors[*Idx].emplace_back(Local);498}499500bool emitDestructors() override {501if (!Idx)502return true;503// Emit destructor calls for local variables of record504// type with a destructor.505for (Scope::Local &Local : this->Ctx->Descriptors[*Idx]) {506if (!Local.Desc->isPrimitive() && !Local.Desc->isPrimitiveArray()) {507if (!this->Ctx->emitGetPtrLocal(Local.Offset, SourceInfo{}))508return false;509510if (!this->Ctx->emitDestruction(Local.Desc))511return false;512513if (!this->Ctx->emitPopPtr(SourceInfo{}))514return false;515removeIfStoredOpaqueValue(Local);516}517}518return true;519}520521void removeStoredOpaqueValues() {522if (!Idx)523return;524525for (const Scope::Local &Local : this->Ctx->Descriptors[*Idx]) {526removeIfStoredOpaqueValue(Local);527}528}529530void removeIfStoredOpaqueValue(const Scope::Local &Local) {531if (const auto *OVE =532llvm::dyn_cast_if_present<OpaqueValueExpr>(Local.Desc->asExpr())) {533if (auto It = this->Ctx->OpaqueExprs.find(OVE);534It != this->Ctx->OpaqueExprs.end())535this->Ctx->OpaqueExprs.erase(It);536};537}538539/// Index of the scope in the chain.540std::optional<unsigned> Idx;541};542543/// Emits the destructors of the variables of \param OtherScope544/// when this scope is destroyed. Does not create a Scope in the bytecode at545/// all, this is just a RAII object to emit destructors.546template <class Emitter> class DestructorScope final {547public:548DestructorScope(LocalScope<Emitter> &OtherScope) : OtherScope(OtherScope) {}549550~DestructorScope() { OtherScope.emitDestructors(); }551552private:553LocalScope<Emitter> &OtherScope;554};555556/// Scope for storage declared in a compound statement.557template <class Emitter> class BlockScope final : public LocalScope<Emitter> {558public:559BlockScope(Compiler<Emitter> *Ctx) : LocalScope<Emitter>(Ctx) {}560561void addExtended(const Scope::Local &Local) override {562// If we to this point, just add the variable as a normal local563// variable. It will be destroyed at the end of the block just564// like all others.565this->addLocal(Local);566}567};568569template <class Emitter> class ArrayIndexScope final {570public:571ArrayIndexScope(Compiler<Emitter> *Ctx, uint64_t Index) : Ctx(Ctx) {572OldArrayIndex = Ctx->ArrayIndex;573Ctx->ArrayIndex = Index;574}575576~ArrayIndexScope() { Ctx->ArrayIndex = OldArrayIndex; }577578private:579Compiler<Emitter> *Ctx;580std::optional<uint64_t> OldArrayIndex;581};582583template <class Emitter> class SourceLocScope final {584public:585SourceLocScope(Compiler<Emitter> *Ctx, const Expr *DefaultExpr) : Ctx(Ctx) {586assert(DefaultExpr);587// We only switch if the current SourceLocDefaultExpr is null.588if (!Ctx->SourceLocDefaultExpr) {589Enabled = true;590Ctx->SourceLocDefaultExpr = DefaultExpr;591}592}593594~SourceLocScope() {595if (Enabled)596Ctx->SourceLocDefaultExpr = nullptr;597}598599private:600Compiler<Emitter> *Ctx;601bool Enabled = false;602};603604template <class Emitter> class InitLinkScope final {605public:606InitLinkScope(Compiler<Emitter> *Ctx, InitLink &&Link) : Ctx(Ctx) {607Ctx->InitStack.push_back(std::move(Link));608}609610~InitLinkScope() { this->Ctx->InitStack.pop_back(); }611612private:613Compiler<Emitter> *Ctx;614};615616template <class Emitter> class InitStackScope final {617public:618InitStackScope(Compiler<Emitter> *Ctx, bool Active)619: Ctx(Ctx), OldValue(Ctx->InitStackActive) {620Ctx->InitStackActive = Active;621}622623~InitStackScope() { this->Ctx->InitStackActive = OldValue; }624625private:626Compiler<Emitter> *Ctx;627bool OldValue;628};629630} // namespace interp631} // namespace clang632633#endif634635636