1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432 |
- //===--- ByteCodeExprGen.cpp - Code generator for expressions ---*- C++ -*-===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- #include "ByteCodeExprGen.h"
- #include "ByteCodeEmitter.h"
- #include "ByteCodeGenError.h"
- #include "ByteCodeStmtGen.h"
- #include "Context.h"
- #include "Function.h"
- #include "PrimType.h"
- #include "Program.h"
- #include "State.h"
- using namespace clang;
- using namespace clang::interp;
- using APSInt = llvm::APSInt;
- namespace clang {
- namespace interp {
- /// Scope used to handle temporaries in toplevel variable declarations.
- template <class Emitter> class DeclScope final : public LocalScope<Emitter> {
- public:
- DeclScope(ByteCodeExprGen<Emitter> *Ctx, const VarDecl *VD)
- : LocalScope<Emitter>(Ctx), Scope(Ctx->P, VD) {}
- void addExtended(const Scope::Local &Local) override {
- return this->addLocal(Local);
- }
- private:
- Program::DeclScope Scope;
- };
- /// Scope used to handle initialization methods.
- template <class Emitter> class OptionScope {
- public:
- /// Root constructor, compiling or discarding primitives.
- OptionScope(ByteCodeExprGen<Emitter> *Ctx, bool NewDiscardResult)
- : Ctx(Ctx), OldDiscardResult(Ctx->DiscardResult) {
- Ctx->DiscardResult = NewDiscardResult;
- }
- ~OptionScope() { Ctx->DiscardResult = OldDiscardResult; }
- private:
- /// Parent context.
- ByteCodeExprGen<Emitter> *Ctx;
- /// Old discard flag to restore.
- bool OldDiscardResult;
- };
- } // namespace interp
- } // namespace clang
- template <class Emitter>
- bool ByteCodeExprGen<Emitter>::VisitCastExpr(const CastExpr *CE) {
- auto *SubExpr = CE->getSubExpr();
- switch (CE->getCastKind()) {
- case CK_LValueToRValue: {
- return dereference(
- CE->getSubExpr(), DerefKind::Read,
- [](PrimType) {
- // Value loaded - nothing to do here.
- return true;
- },
- [this, CE](PrimType T) {
- // Pointer on stack - dereference it.
- if (!this->emitLoadPop(T, CE))
- return false;
- return DiscardResult ? this->emitPop(T, CE) : true;
- });
- }
- case CK_UncheckedDerivedToBase:
- case CK_DerivedToBase: {
- if (!this->visit(SubExpr))
- return false;
- const CXXRecordDecl *FromDecl = getRecordDecl(SubExpr);
- assert(FromDecl);
- const CXXRecordDecl *ToDecl = getRecordDecl(CE);
- assert(ToDecl);
- const Record *R = getRecord(FromDecl);
- const Record::Base *ToBase = R->getBase(ToDecl);
- assert(ToBase);
- return this->emitGetPtrBase(ToBase->Offset, CE);
- }
- case CK_ArrayToPointerDecay:
- case CK_AtomicToNonAtomic:
- case CK_ConstructorConversion:
- case CK_FunctionToPointerDecay:
- case CK_NonAtomicToAtomic:
- case CK_NoOp:
- case CK_UserDefinedConversion:
- case CK_NullToPointer:
- return this->visit(SubExpr);
- case CK_IntegralToBoolean:
- case CK_IntegralCast: {
- std::optional<PrimType> FromT = classify(SubExpr->getType());
- std::optional<PrimType> ToT = classify(CE->getType());
- if (!FromT || !ToT)
- return false;
- if (!this->visit(SubExpr))
- return false;
- // TODO: Emit this only if FromT != ToT.
- return this->emitCast(*FromT, *ToT, CE);
- }
- case CK_ToVoid:
- return discard(SubExpr);
- default:
- assert(false && "Cast not implemented");
- }
- llvm_unreachable("Unhandled clang::CastKind enum");
- }
- template <class Emitter>
- bool ByteCodeExprGen<Emitter>::VisitIntegerLiteral(const IntegerLiteral *LE) {
- if (DiscardResult)
- return true;
- return this->emitConst(LE->getValue(), LE);
- }
- template <class Emitter>
- bool ByteCodeExprGen<Emitter>::VisitParenExpr(const ParenExpr *PE) {
- return this->visit(PE->getSubExpr());
- }
- template <class Emitter>
- bool ByteCodeExprGen<Emitter>::VisitBinaryOperator(const BinaryOperator *BO) {
- const Expr *LHS = BO->getLHS();
- const Expr *RHS = BO->getRHS();
- // Deal with operations which have composite or void types.
- switch (BO->getOpcode()) {
- case BO_Comma:
- if (!discard(LHS))
- return false;
- if (!this->visit(RHS))
- return false;
- return true;
- default:
- break;
- }
- // Typecheck the args.
- std::optional<PrimType> LT = classify(LHS->getType());
- std::optional<PrimType> RT = classify(RHS->getType());
- std::optional<PrimType> T = classify(BO->getType());
- if (!LT || !RT || !T) {
- return this->bail(BO);
- }
- auto Discard = [this, T, BO](bool Result) {
- if (!Result)
- return false;
- return DiscardResult ? this->emitPop(*T, BO) : true;
- };
- // Pointer arithmetic special case.
- if (BO->getOpcode() == BO_Add || BO->getOpcode() == BO_Sub) {
- if (*T == PT_Ptr || (*LT == PT_Ptr && *RT == PT_Ptr))
- return this->VisitPointerArithBinOp(BO);
- }
- if (!visit(LHS) || !visit(RHS))
- return false;
- switch (BO->getOpcode()) {
- case BO_EQ:
- return Discard(this->emitEQ(*LT, BO));
- case BO_NE:
- return Discard(this->emitNE(*LT, BO));
- case BO_LT:
- return Discard(this->emitLT(*LT, BO));
- case BO_LE:
- return Discard(this->emitLE(*LT, BO));
- case BO_GT:
- return Discard(this->emitGT(*LT, BO));
- case BO_GE:
- return Discard(this->emitGE(*LT, BO));
- case BO_Sub:
- return Discard(this->emitSub(*T, BO));
- case BO_Add:
- return Discard(this->emitAdd(*T, BO));
- case BO_Mul:
- return Discard(this->emitMul(*T, BO));
- case BO_Rem:
- return Discard(this->emitRem(*T, BO));
- case BO_Div:
- return Discard(this->emitDiv(*T, BO));
- case BO_Assign:
- if (DiscardResult)
- return this->emitStorePop(*T, BO);
- return this->emitStore(*T, BO);
- case BO_And:
- return Discard(this->emitBitAnd(*T, BO));
- case BO_Or:
- return Discard(this->emitBitOr(*T, BO));
- case BO_Shl:
- return Discard(this->emitShl(*LT, *RT, BO));
- case BO_Shr:
- return Discard(this->emitShr(*LT, *RT, BO));
- case BO_Xor:
- return Discard(this->emitBitXor(*T, BO));
- case BO_LAnd:
- case BO_LOr:
- default:
- return this->bail(BO);
- }
- llvm_unreachable("Unhandled binary op");
- }
- /// Perform addition/subtraction of a pointer and an integer or
- /// subtraction of two pointers.
- template <class Emitter>
- bool ByteCodeExprGen<Emitter>::VisitPointerArithBinOp(const BinaryOperator *E) {
- BinaryOperatorKind Op = E->getOpcode();
- const Expr *LHS = E->getLHS();
- const Expr *RHS = E->getRHS();
- if ((Op != BO_Add && Op != BO_Sub) ||
- (!LHS->getType()->isPointerType() && !RHS->getType()->isPointerType()))
- return false;
- std::optional<PrimType> LT = classify(LHS);
- std::optional<PrimType> RT = classify(RHS);
- if (!LT || !RT)
- return false;
- if (LHS->getType()->isPointerType() && RHS->getType()->isPointerType()) {
- if (Op != BO_Sub)
- return false;
- assert(E->getType()->isIntegerType());
- if (!visit(RHS) || !visit(LHS))
- return false;
- return this->emitSubPtr(classifyPrim(E->getType()), E);
- }
- PrimType OffsetType;
- if (LHS->getType()->isIntegerType()) {
- if (!visit(RHS) || !visit(LHS))
- return false;
- OffsetType = *LT;
- } else if (RHS->getType()->isIntegerType()) {
- if (!visit(LHS) || !visit(RHS))
- return false;
- OffsetType = *RT;
- } else {
- return false;
- }
- if (Op == BO_Add)
- return this->emitAddOffset(OffsetType, E);
- else if (Op == BO_Sub)
- return this->emitSubOffset(OffsetType, E);
- return this->bail(E);
- }
- template <class Emitter>
- bool ByteCodeExprGen<Emitter>::VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E) {
- if (std::optional<PrimType> T = classify(E))
- return this->emitZero(*T, E);
- return false;
- }
- template <class Emitter>
- bool ByteCodeExprGen<Emitter>::VisitArraySubscriptExpr(
- const ArraySubscriptExpr *E) {
- const Expr *Base = E->getBase();
- const Expr *Index = E->getIdx();
- PrimType IndexT = classifyPrim(Index->getType());
- // Take pointer of LHS, add offset from RHS, narrow result.
- // What's left on the stack after this is a pointer.
- if (!this->visit(Base))
- return false;
- if (!this->visit(Index))
- return false;
- if (!this->emitAddOffset(IndexT, E))
- return false;
- if (!this->emitNarrowPtr(E))
- return false;
- if (DiscardResult)
- return this->emitPopPtr(E);
- return true;
- }
- template <class Emitter>
- bool ByteCodeExprGen<Emitter>::VisitInitListExpr(const InitListExpr *E) {
- for (const Expr *Init : E->inits()) {
- if (!this->visit(Init))
- return false;
- }
- return true;
- }
- template <class Emitter>
- bool ByteCodeExprGen<Emitter>::VisitSubstNonTypeTemplateParmExpr(
- const SubstNonTypeTemplateParmExpr *E) {
- return this->visit(E->getReplacement());
- }
- template <class Emitter>
- bool ByteCodeExprGen<Emitter>::VisitConstantExpr(const ConstantExpr *E) {
- // TODO: Check if the ConstantExpr already has a value set and if so,
- // use that instead of evaluating it again.
- return this->visit(E->getSubExpr());
- }
- static CharUnits AlignOfType(QualType T, const ASTContext &ASTCtx,
- UnaryExprOrTypeTrait Kind) {
- bool AlignOfReturnsPreferred =
- ASTCtx.getLangOpts().getClangABICompat() <= LangOptions::ClangABI::Ver7;
- // C++ [expr.alignof]p3:
- // When alignof is applied to a reference type, the result is the
- // alignment of the referenced type.
- if (const auto *Ref = T->getAs<ReferenceType>())
- T = Ref->getPointeeType();
- // __alignof is defined to return the preferred alignment.
- // Before 8, clang returned the preferred alignment for alignof and
- // _Alignof as well.
- if (Kind == UETT_PreferredAlignOf || AlignOfReturnsPreferred)
- return ASTCtx.toCharUnitsFromBits(ASTCtx.getPreferredTypeAlign(T));
- return ASTCtx.getTypeAlignInChars(T);
- }
- template <class Emitter>
- bool ByteCodeExprGen<Emitter>::VisitUnaryExprOrTypeTraitExpr(
- const UnaryExprOrTypeTraitExpr *E) {
- UnaryExprOrTypeTrait Kind = E->getKind();
- ASTContext &ASTCtx = Ctx.getASTContext();
- if (Kind == UETT_SizeOf) {
- QualType ArgType = E->getTypeOfArgument();
- CharUnits Size;
- if (ArgType->isVoidType() || ArgType->isFunctionType())
- Size = CharUnits::One();
- else {
- if (ArgType->isDependentType() || !ArgType->isConstantSizeType())
- return false;
- Size = ASTCtx.getTypeSizeInChars(ArgType);
- }
- return this->emitConst(Size.getQuantity(), E);
- }
- if (Kind == UETT_AlignOf || Kind == UETT_PreferredAlignOf) {
- CharUnits Size;
- if (E->isArgumentType()) {
- QualType ArgType = E->getTypeOfArgument();
- Size = AlignOfType(ArgType, ASTCtx, Kind);
- } else {
- // Argument is an expression, not a type.
- const Expr *Arg = E->getArgumentExpr()->IgnoreParens();
- // The kinds of expressions that we have special-case logic here for
- // should be kept up to date with the special checks for those
- // expressions in Sema.
- // alignof decl is always accepted, even if it doesn't make sense: we
- // default to 1 in those cases.
- if (const auto *DRE = dyn_cast<DeclRefExpr>(Arg))
- Size = ASTCtx.getDeclAlign(DRE->getDecl(),
- /*RefAsPointee*/ true);
- else if (const auto *ME = dyn_cast<MemberExpr>(Arg))
- Size = ASTCtx.getDeclAlign(ME->getMemberDecl(),
- /*RefAsPointee*/ true);
- else
- Size = AlignOfType(Arg->getType(), ASTCtx, Kind);
- }
- return this->emitConst(Size.getQuantity(), E);
- }
- return false;
- }
- template <class Emitter>
- bool ByteCodeExprGen<Emitter>::VisitMemberExpr(const MemberExpr *E) {
- if (DiscardResult)
- return true;
- // 'Base.Member'
- const Expr *Base = E->getBase();
- const ValueDecl *Member = E->getMemberDecl();
- if (!this->visit(Base))
- return false;
- // Base above gives us a pointer on the stack.
- // TODO: Implement non-FieldDecl members.
- if (const auto *FD = dyn_cast<FieldDecl>(Member)) {
- const RecordDecl *RD = FD->getParent();
- const Record *R = getRecord(RD);
- const Record::Field *F = R->getField(FD);
- // Leave a pointer to the field on the stack.
- if (F->Decl->getType()->isReferenceType())
- return this->emitGetFieldPop(PT_Ptr, F->Offset, E);
- return this->emitGetPtrField(F->Offset, E);
- }
- return false;
- }
- template <class Emitter>
- bool ByteCodeExprGen<Emitter>::VisitArrayInitIndexExpr(
- const ArrayInitIndexExpr *E) {
- // ArrayIndex might not be set if a ArrayInitIndexExpr is being evaluated
- // stand-alone, e.g. via EvaluateAsInt().
- if (!ArrayIndex)
- return false;
- return this->emitConst(*ArrayIndex, E);
- }
- template <class Emitter>
- bool ByteCodeExprGen<Emitter>::VisitOpaqueValueExpr(const OpaqueValueExpr *E) {
- return this->visit(E->getSourceExpr());
- }
- template <class Emitter>
- bool ByteCodeExprGen<Emitter>::VisitAbstractConditionalOperator(
- const AbstractConditionalOperator *E) {
- const Expr *Condition = E->getCond();
- const Expr *TrueExpr = E->getTrueExpr();
- const Expr *FalseExpr = E->getFalseExpr();
- LabelTy LabelEnd = this->getLabel(); // Label after the operator.
- LabelTy LabelFalse = this->getLabel(); // Label for the false expr.
- if (!this->visit(Condition))
- return false;
- if (!this->jumpFalse(LabelFalse))
- return false;
- if (!this->visit(TrueExpr))
- return false;
- if (!this->jump(LabelEnd))
- return false;
- this->emitLabel(LabelFalse);
- if (!this->visit(FalseExpr))
- return false;
- this->fallthrough(LabelEnd);
- this->emitLabel(LabelEnd);
- return true;
- }
- template <class Emitter>
- bool ByteCodeExprGen<Emitter>::VisitStringLiteral(const StringLiteral *E) {
- unsigned StringIndex = P.createGlobalString(E);
- return this->emitGetPtrGlobal(StringIndex, E);
- }
- template <class Emitter>
- bool ByteCodeExprGen<Emitter>::VisitCharacterLiteral(
- const CharacterLiteral *E) {
- return this->emitConst(E->getValue(), E);
- }
- template <class Emitter>
- bool ByteCodeExprGen<Emitter>::VisitCompoundAssignOperator(
- const CompoundAssignOperator *E) {
- const Expr *LHS = E->getLHS();
- const Expr *RHS = E->getRHS();
- std::optional<PrimType> LT = classify(E->getLHS()->getType());
- std::optional<PrimType> RT = classify(E->getRHS()->getType());
- if (!LT || !RT)
- return false;
- assert(!E->getType()->isPointerType() &&
- "Support pointer arithmethic in compound assignment operators");
- // Get LHS pointer, load its value and get RHS value.
- if (!visit(LHS))
- return false;
- if (!this->emitLoad(*LT, E))
- return false;
- if (!visit(RHS))
- return false;
- // Perform operation.
- switch (E->getOpcode()) {
- case BO_AddAssign:
- if (!this->emitAdd(*LT, E))
- return false;
- break;
- case BO_SubAssign:
- if (!this->emitSub(*LT, E))
- return false;
- break;
- case BO_MulAssign:
- case BO_DivAssign:
- case BO_RemAssign:
- case BO_ShlAssign:
- if (!this->emitShl(*LT, *RT, E))
- return false;
- break;
- case BO_ShrAssign:
- if (!this->emitShr(*LT, *RT, E))
- return false;
- break;
- case BO_AndAssign:
- case BO_XorAssign:
- case BO_OrAssign:
- default:
- llvm_unreachable("Unimplemented compound assign operator");
- }
- // And store the result in LHS.
- if (DiscardResult)
- return this->emitStorePop(*LT, E);
- return this->emitStore(*LT, E);
- }
- template <class Emitter> bool ByteCodeExprGen<Emitter>::discard(const Expr *E) {
- OptionScope<Emitter> Scope(this, /*NewDiscardResult=*/true);
- return this->Visit(E);
- }
- template <class Emitter>
- bool ByteCodeExprGen<Emitter>::visit(const Expr *E) {
- OptionScope<Emitter> Scope(this, /*NewDiscardResult=*/false);
- return this->Visit(E);
- }
- template <class Emitter>
- bool ByteCodeExprGen<Emitter>::visitBool(const Expr *E) {
- if (std::optional<PrimType> T = classify(E->getType())) {
- return visit(E);
- } else {
- return this->bail(E);
- }
- }
- template <class Emitter>
- bool ByteCodeExprGen<Emitter>::visitZeroInitializer(PrimType T, const Expr *E) {
- switch (T) {
- case PT_Bool:
- return this->emitZeroBool(E);
- case PT_Sint8:
- return this->emitZeroSint8(E);
- case PT_Uint8:
- return this->emitZeroUint8(E);
- case PT_Sint16:
- return this->emitZeroSint16(E);
- case PT_Uint16:
- return this->emitZeroUint16(E);
- case PT_Sint32:
- return this->emitZeroSint32(E);
- case PT_Uint32:
- return this->emitZeroUint32(E);
- case PT_Sint64:
- return this->emitZeroSint64(E);
- case PT_Uint64:
- return this->emitZeroUint64(E);
- case PT_Ptr:
- return this->emitNullPtr(E);
- }
- llvm_unreachable("unknown primitive type");
- }
- template <class Emitter>
- bool ByteCodeExprGen<Emitter>::dereference(
- const Expr *LV, DerefKind AK, llvm::function_ref<bool(PrimType)> Direct,
- llvm::function_ref<bool(PrimType)> Indirect) {
- if (std::optional<PrimType> T = classify(LV->getType())) {
- if (!LV->refersToBitField()) {
- // Only primitive, non bit-field types can be dereferenced directly.
- if (auto *DE = dyn_cast<DeclRefExpr>(LV)) {
- if (!DE->getDecl()->getType()->isReferenceType()) {
- if (auto *PD = dyn_cast<ParmVarDecl>(DE->getDecl()))
- return dereferenceParam(LV, *T, PD, AK, Direct, Indirect);
- if (auto *VD = dyn_cast<VarDecl>(DE->getDecl()))
- return dereferenceVar(LV, *T, VD, AK, Direct, Indirect);
- }
- }
- }
- if (!visit(LV))
- return false;
- return Indirect(*T);
- }
- return false;
- }
- template <class Emitter>
- bool ByteCodeExprGen<Emitter>::dereferenceParam(
- const Expr *LV, PrimType T, const ParmVarDecl *PD, DerefKind AK,
- llvm::function_ref<bool(PrimType)> Direct,
- llvm::function_ref<bool(PrimType)> Indirect) {
- auto It = this->Params.find(PD);
- if (It != this->Params.end()) {
- unsigned Idx = It->second;
- switch (AK) {
- case DerefKind::Read:
- return DiscardResult ? true : this->emitGetParam(T, Idx, LV);
- case DerefKind::Write:
- if (!Direct(T))
- return false;
- if (!this->emitSetParam(T, Idx, LV))
- return false;
- return DiscardResult ? true : this->emitGetPtrParam(Idx, LV);
- case DerefKind::ReadWrite:
- if (!this->emitGetParam(T, Idx, LV))
- return false;
- if (!Direct(T))
- return false;
- if (!this->emitSetParam(T, Idx, LV))
- return false;
- return DiscardResult ? true : this->emitGetPtrParam(Idx, LV);
- }
- return true;
- }
- // If the param is a pointer, we can dereference a dummy value.
- if (!DiscardResult && T == PT_Ptr && AK == DerefKind::Read) {
- if (auto Idx = P.getOrCreateDummy(PD))
- return this->emitGetPtrGlobal(*Idx, PD);
- return false;
- }
- // Value cannot be produced - try to emit pointer and do stuff with it.
- return visit(LV) && Indirect(T);
- }
- template <class Emitter>
- bool ByteCodeExprGen<Emitter>::dereferenceVar(
- const Expr *LV, PrimType T, const VarDecl *VD, DerefKind AK,
- llvm::function_ref<bool(PrimType)> Direct,
- llvm::function_ref<bool(PrimType)> Indirect) {
- auto It = Locals.find(VD);
- if (It != Locals.end()) {
- const auto &L = It->second;
- switch (AK) {
- case DerefKind::Read:
- if (!this->emitGetLocal(T, L.Offset, LV))
- return false;
- return DiscardResult ? this->emitPop(T, LV) : true;
- case DerefKind::Write:
- if (!Direct(T))
- return false;
- if (!this->emitSetLocal(T, L.Offset, LV))
- return false;
- return DiscardResult ? true : this->emitGetPtrLocal(L.Offset, LV);
- case DerefKind::ReadWrite:
- if (!this->emitGetLocal(T, L.Offset, LV))
- return false;
- if (!Direct(T))
- return false;
- if (!this->emitSetLocal(T, L.Offset, LV))
- return false;
- return DiscardResult ? true : this->emitGetPtrLocal(L.Offset, LV);
- }
- } else if (auto Idx = P.getGlobal(VD)) {
- switch (AK) {
- case DerefKind::Read:
- if (!this->emitGetGlobal(T, *Idx, LV))
- return false;
- return DiscardResult ? this->emitPop(T, LV) : true;
- case DerefKind::Write:
- if (!Direct(T))
- return false;
- if (!this->emitSetGlobal(T, *Idx, LV))
- return false;
- return DiscardResult ? true : this->emitGetPtrGlobal(*Idx, LV);
- case DerefKind::ReadWrite:
- if (!this->emitGetGlobal(T, *Idx, LV))
- return false;
- if (!Direct(T))
- return false;
- if (!this->emitSetGlobal(T, *Idx, LV))
- return false;
- return DiscardResult ? true : this->emitGetPtrGlobal(*Idx, LV);
- }
- }
- // If the declaration is a constant value, emit it here even
- // though the declaration was not evaluated in the current scope.
- // The access mode can only be read in this case.
- if (!DiscardResult && AK == DerefKind::Read) {
- if (VD->hasLocalStorage() && VD->hasInit() && !VD->isConstexpr()) {
- QualType VT = VD->getType();
- if (VT.isConstQualified() && VT->isFundamentalType())
- return this->visit(VD->getInit());
- }
- }
- // Value cannot be produced - try to emit pointer.
- return visit(LV) && Indirect(T);
- }
- template <class Emitter>
- template <typename T>
- bool ByteCodeExprGen<Emitter>::emitConst(T Value, const Expr *E) {
- switch (classifyPrim(E->getType())) {
- case PT_Sint8:
- return this->emitConstSint8(Value, E);
- case PT_Uint8:
- return this->emitConstUint8(Value, E);
- case PT_Sint16:
- return this->emitConstSint16(Value, E);
- case PT_Uint16:
- return this->emitConstUint16(Value, E);
- case PT_Sint32:
- return this->emitConstSint32(Value, E);
- case PT_Uint32:
- return this->emitConstUint32(Value, E);
- case PT_Sint64:
- return this->emitConstSint64(Value, E);
- case PT_Uint64:
- return this->emitConstUint64(Value, E);
- case PT_Bool:
- return this->emitConstBool(Value, E);
- case PT_Ptr:
- llvm_unreachable("Invalid integral type");
- break;
- }
- llvm_unreachable("unknown primitive type");
- }
- template <class Emitter>
- bool ByteCodeExprGen<Emitter>::emitConst(const APSInt &Value, const Expr *E) {
- if (Value.isSigned())
- return this->emitConst(Value.getSExtValue(), E);
- return this->emitConst(Value.getZExtValue(), E);
- }
- template <class Emitter>
- unsigned ByteCodeExprGen<Emitter>::allocateLocalPrimitive(DeclTy &&Src,
- PrimType Ty,
- bool IsConst,
- bool IsExtended) {
- // Make sure we don't accidentally register the same decl twice.
- if (const auto *VD =
- dyn_cast_if_present<ValueDecl>(Src.dyn_cast<const Decl *>())) {
- assert(!P.getGlobal(VD));
- assert(Locals.find(VD) == Locals.end());
- }
- // FIXME: There are cases where Src.is<Expr*>() is wrong, e.g.
- // (int){12} in C. Consider using Expr::isTemporaryObject() instead
- // or isa<MaterializeTemporaryExpr>().
- Descriptor *D = P.createDescriptor(Src, Ty, Descriptor::InlineDescMD, IsConst,
- Src.is<const Expr *>());
- Scope::Local Local = this->createLocal(D);
- if (auto *VD = dyn_cast_or_null<ValueDecl>(Src.dyn_cast<const Decl *>()))
- Locals.insert({VD, Local});
- VarScope->add(Local, IsExtended);
- return Local.Offset;
- }
- template <class Emitter>
- std::optional<unsigned>
- ByteCodeExprGen<Emitter>::allocateLocal(DeclTy &&Src, bool IsExtended) {
- // Make sure we don't accidentally register the same decl twice.
- if (const auto *VD =
- dyn_cast_if_present<ValueDecl>(Src.dyn_cast<const Decl *>())) {
- assert(!P.getGlobal(VD));
- assert(Locals.find(VD) == Locals.end());
- }
- QualType Ty;
- const ValueDecl *Key = nullptr;
- const Expr *Init = nullptr;
- bool IsTemporary = false;
- if (auto *VD = dyn_cast_if_present<ValueDecl>(Src.dyn_cast<const Decl *>())) {
- Key = VD;
- Ty = VD->getType();
- if (const auto *VarD = dyn_cast<VarDecl>(VD))
- Init = VarD->getInit();
- }
- if (auto *E = Src.dyn_cast<const Expr *>()) {
- IsTemporary = true;
- Ty = E->getType();
- }
- Descriptor *D = P.createDescriptor(
- Src, Ty.getTypePtr(), Descriptor::InlineDescMD, Ty.isConstQualified(),
- IsTemporary, /*IsMutable=*/false, Init);
- if (!D)
- return {};
- Scope::Local Local = this->createLocal(D);
- if (Key)
- Locals.insert({Key, Local});
- VarScope->add(Local, IsExtended);
- return Local.Offset;
- }
- // NB: When calling this function, we have a pointer to the
- // array-to-initialize on the stack.
- template <class Emitter>
- bool ByteCodeExprGen<Emitter>::visitArrayInitializer(const Expr *Initializer) {
- assert(Initializer->getType()->isArrayType());
- // TODO: Fillers?
- if (const auto *InitList = dyn_cast<InitListExpr>(Initializer)) {
- unsigned ElementIndex = 0;
- for (const Expr *Init : InitList->inits()) {
- if (std::optional<PrimType> T = classify(Init->getType())) {
- // Visit the primitive element like normal.
- if (!this->emitDupPtr(Init))
- return false;
- if (!this->visit(Init))
- return false;
- if (!this->emitInitElem(*T, ElementIndex, Init))
- return false;
- } else {
- // Advance the pointer currently on the stack to the given
- // dimension and narrow().
- if (!this->emitDupPtr(Init))
- return false;
- if (!this->emitConstUint32(ElementIndex, Init))
- return false;
- if (!this->emitAddOffsetUint32(Init))
- return false;
- if (!this->emitNarrowPtr(Init))
- return false;
- if (!visitInitializer(Init))
- return false;
- }
- if (!this->emitPopPtr(Init))
- return false;
- ++ElementIndex;
- }
- return true;
- } else if (const auto *DIE = dyn_cast<CXXDefaultInitExpr>(Initializer)) {
- return this->visitInitializer(DIE->getExpr());
- } else if (const auto *AILE = dyn_cast<ArrayInitLoopExpr>(Initializer)) {
- // TODO: This compiles to quite a lot of bytecode if the array is larger.
- // Investigate compiling this to a loop, or at least try to use
- // the AILE's Common expr.
- const Expr *SubExpr = AILE->getSubExpr();
- size_t Size = AILE->getArraySize().getZExtValue();
- std::optional<PrimType> ElemT = classify(SubExpr->getType());
- // So, every iteration, we execute an assignment here
- // where the LHS is on the stack (the target array)
- // and the RHS is our SubExpr.
- for (size_t I = 0; I != Size; ++I) {
- ArrayIndexScope<Emitter> IndexScope(this, I);
- if (!this->emitDupPtr(SubExpr)) // LHS
- return false;
- if (ElemT) {
- if (!this->visit(SubExpr))
- return false;
- if (!this->emitInitElem(*ElemT, I, Initializer))
- return false;
- } else {
- // Narrow to our array element and recurse into visitInitializer()
- if (!this->emitConstUint64(I, SubExpr))
- return false;
- if (!this->emitAddOffsetUint64(SubExpr))
- return false;
- if (!this->emitNarrowPtr(SubExpr))
- return false;
- if (!visitInitializer(SubExpr))
- return false;
- }
- if (!this->emitPopPtr(Initializer))
- return false;
- }
- return true;
- } else if (const auto *IVIE = dyn_cast<ImplicitValueInitExpr>(Initializer)) {
- const ArrayType *AT = IVIE->getType()->getAsArrayTypeUnsafe();
- assert(AT);
- const auto *CAT = cast<ConstantArrayType>(AT);
- size_t NumElems = CAT->getSize().getZExtValue();
- if (std::optional<PrimType> ElemT = classify(CAT->getElementType())) {
- // TODO(perf): For int and bool types, we can probably just skip this
- // since we memset our Block*s to 0 and so we have the desired value
- // without this.
- for (size_t I = 0; I != NumElems; ++I) {
- if (!this->emitZero(*ElemT, Initializer))
- return false;
- if (!this->emitInitElem(*ElemT, I, Initializer))
- return false;
- }
- } else {
- assert(false && "default initializer for non-primitive type");
- }
- return true;
- } else if (const auto *Ctor = dyn_cast<CXXConstructExpr>(Initializer)) {
- const ConstantArrayType *CAT =
- Ctx.getASTContext().getAsConstantArrayType(Ctor->getType());
- assert(CAT);
- size_t NumElems = CAT->getSize().getZExtValue();
- const Function *Func = getFunction(Ctor->getConstructor());
- if (!Func || !Func->isConstexpr())
- return false;
- // FIXME(perf): We're calling the constructor once per array element here,
- // in the old intepreter we had a special-case for trivial constructors.
- for (size_t I = 0; I != NumElems; ++I) {
- if (!this->emitDupPtr(Initializer))
- return false;
- if (!this->emitConstUint64(I, Initializer))
- return false;
- if (!this->emitAddOffsetUint64(Initializer))
- return false;
- if (!this->emitNarrowPtr(Initializer))
- return false;
- // Constructor arguments.
- for (const auto *Arg : Ctor->arguments()) {
- if (!this->visit(Arg))
- return false;
- }
- if (!this->emitCall(Func, Initializer))
- return false;
- }
- return true;
- }
- assert(false && "Unknown expression for array initialization");
- return false;
- }
- template <class Emitter>
- bool ByteCodeExprGen<Emitter>::visitRecordInitializer(const Expr *Initializer) {
- Initializer = Initializer->IgnoreParenImpCasts();
- assert(Initializer->getType()->isRecordType());
- if (const auto CtorExpr = dyn_cast<CXXConstructExpr>(Initializer)) {
- const Function *Func = getFunction(CtorExpr->getConstructor());
- if (!Func || !Func->isConstexpr())
- return false;
- // The This pointer is already on the stack because this is an initializer,
- // but we need to dup() so the call() below has its own copy.
- if (!this->emitDupPtr(Initializer))
- return false;
- // Constructor arguments.
- for (const auto *Arg : CtorExpr->arguments()) {
- if (!this->visit(Arg))
- return false;
- }
- return this->emitCall(Func, Initializer);
- } else if (const auto *InitList = dyn_cast<InitListExpr>(Initializer)) {
- const Record *R = getRecord(InitList->getType());
- unsigned InitIndex = 0;
- for (const Expr *Init : InitList->inits()) {
- const Record::Field *FieldToInit = R->getField(InitIndex);
- if (!this->emitDupPtr(Initializer))
- return false;
- if (std::optional<PrimType> T = classify(Init)) {
- if (!this->visit(Init))
- return false;
- if (!this->emitInitField(*T, FieldToInit->Offset, Initializer))
- return false;
- if (!this->emitPopPtr(Initializer))
- return false;
- } else {
- // Non-primitive case. Get a pointer to the field-to-initialize
- // on the stack and recurse into visitInitializer().
- if (!this->emitGetPtrField(FieldToInit->Offset, Init))
- return false;
- if (!this->visitInitializer(Init))
- return false;
- if (!this->emitPopPtr(Initializer))
- return false;
- }
- ++InitIndex;
- }
- return true;
- } else if (const CallExpr *CE = dyn_cast<CallExpr>(Initializer)) {
- // RVO functions expect a pointer to initialize on the stack.
- // Dup our existing pointer so it has its own copy to use.
- if (!this->emitDupPtr(Initializer))
- return false;
- return this->VisitCallExpr(CE);
- } else if (const auto *DIE = dyn_cast<CXXDefaultInitExpr>(Initializer)) {
- return this->visitInitializer(DIE->getExpr());
- }
- return false;
- }
- template <class Emitter>
- bool ByteCodeExprGen<Emitter>::visitInitializer(const Expr *Initializer) {
- QualType InitializerType = Initializer->getType();
- if (InitializerType->isArrayType())
- return visitArrayInitializer(Initializer);
- if (InitializerType->isRecordType())
- return visitRecordInitializer(Initializer);
- // Otherwise, visit the expression like normal.
- return this->visit(Initializer);
- }
- template <class Emitter>
- const RecordType *ByteCodeExprGen<Emitter>::getRecordTy(QualType Ty) {
- if (const PointerType *PT = dyn_cast<PointerType>(Ty))
- return PT->getPointeeType()->getAs<RecordType>();
- else
- return Ty->getAs<RecordType>();
- }
- template <class Emitter>
- Record *ByteCodeExprGen<Emitter>::getRecord(QualType Ty) {
- if (auto *RecordTy = getRecordTy(Ty)) {
- return getRecord(RecordTy->getDecl());
- }
- return nullptr;
- }
- template <class Emitter>
- Record *ByteCodeExprGen<Emitter>::getRecord(const RecordDecl *RD) {
- return P.getOrCreateRecord(RD);
- }
- template <class Emitter>
- const Function *ByteCodeExprGen<Emitter>::getFunction(const FunctionDecl *FD) {
- assert(FD);
- const Function *Func = P.getFunction(FD);
- bool IsBeingCompiled = Func && !Func->isFullyCompiled();
- bool WasNotDefined = Func && !Func->hasBody();
- if (IsBeingCompiled)
- return Func;
- if (!Func || WasNotDefined) {
- if (auto R = ByteCodeStmtGen<ByteCodeEmitter>(Ctx, P).compileFunc(FD))
- Func = *R;
- else {
- llvm::consumeError(R.takeError());
- return nullptr;
- }
- }
- return Func;
- }
- template <class Emitter>
- bool ByteCodeExprGen<Emitter>::visitExpr(const Expr *Exp) {
- ExprScope<Emitter> RootScope(this);
- if (!visit(Exp))
- return false;
- if (std::optional<PrimType> T = classify(Exp))
- return this->emitRet(*T, Exp);
- else
- return this->emitRetValue(Exp);
- }
- /// Toplevel visitDecl().
- /// We get here from evaluateAsInitializer().
- /// We need to evaluate the initializer and return its value.
- template <class Emitter>
- bool ByteCodeExprGen<Emitter>::visitDecl(const VarDecl *VD) {
- std::optional<PrimType> VarT = classify(VD->getType());
- // Create and initialize the variable.
- if (!this->visitVarDecl(VD))
- return false;
- // Get a pointer to the variable
- if (shouldBeGloballyIndexed(VD)) {
- auto GlobalIndex = P.getGlobal(VD);
- assert(GlobalIndex); // visitVarDecl() didn't return false.
- if (!this->emitGetPtrGlobal(*GlobalIndex, VD))
- return false;
- } else {
- auto Local = Locals.find(VD);
- assert(Local != Locals.end()); // Same here.
- if (!this->emitGetPtrLocal(Local->second.Offset, VD))
- return false;
- }
- // Return the value
- if (VarT) {
- if (!this->emitLoadPop(*VarT, VD))
- return false;
- return this->emitRet(*VarT, VD);
- }
- return this->emitRetValue(VD);
- }
- template <class Emitter>
- bool ByteCodeExprGen<Emitter>::visitVarDecl(const VarDecl *VD) {
- const Expr *Init = VD->getInit();
- std::optional<PrimType> VarT = classify(VD->getType());
- if (shouldBeGloballyIndexed(VD)) {
- std::optional<unsigned> GlobalIndex = P.getOrCreateGlobal(VD, Init);
- if (!GlobalIndex)
- return this->bail(VD);
- assert(Init);
- {
- DeclScope<Emitter> LocalScope(this, VD);
- if (VarT) {
- if (!this->visit(Init))
- return false;
- return this->emitInitGlobal(*VarT, *GlobalIndex, VD);
- }
- return this->visitGlobalInitializer(Init, *GlobalIndex);
- }
- } else {
- VariableScope<Emitter> LocalScope(this);
- if (VarT) {
- unsigned Offset = this->allocateLocalPrimitive(
- VD, *VarT, VD->getType().isConstQualified());
- if (Init) {
- // Compile the initializer in its own scope.
- ExprScope<Emitter> Scope(this);
- if (!this->visit(Init))
- return false;
- return this->emitSetLocal(*VarT, Offset, VD);
- }
- } else {
- if (std::optional<unsigned> Offset = this->allocateLocal(VD)) {
- if (Init)
- return this->visitLocalInitializer(Init, *Offset);
- }
- }
- return true;
- }
- return false;
- }
- template <class Emitter>
- bool ByteCodeExprGen<Emitter>::VisitCallExpr(const CallExpr *E) {
- assert(!E->getBuiltinCallee() && "Builtin functions aren't supported yet");
- const Decl *Callee = E->getCalleeDecl();
- if (const auto *FuncDecl = dyn_cast_or_null<FunctionDecl>(Callee)) {
- const Function *Func = getFunction(FuncDecl);
- if (!Func)
- return false;
- // If the function is being compiled right now, this is a recursive call.
- // In that case, the function can't be valid yet, even though it will be
- // later.
- // If the function is already fully compiled but not constexpr, it was
- // found to be faulty earlier on, so bail out.
- if (Func->isFullyCompiled() && !Func->isConstexpr())
- return false;
- QualType ReturnType = E->getCallReturnType(Ctx.getASTContext());
- std::optional<PrimType> T = classify(ReturnType);
- if (Func->hasRVO() && DiscardResult) {
- // If we need to discard the return value but the function returns its
- // value via an RVO pointer, we need to create one such pointer just
- // for this call.
- if (std::optional<unsigned> LocalIndex = allocateLocal(E)) {
- if (!this->emitGetPtrLocal(*LocalIndex, E))
- return false;
- }
- }
- // Put arguments on the stack.
- for (const auto *Arg : E->arguments()) {
- if (!this->visit(Arg))
- return false;
- }
- // In any case call the function. The return value will end up on the stack and
- // if the function has RVO, we already have the pointer on the stack to write
- // the result into.
- if (!this->emitCall(Func, E))
- return false;
- if (DiscardResult && !ReturnType->isVoidType() && T)
- return this->emitPop(*T, E);
- return true;
- } else {
- assert(false && "We don't support non-FunctionDecl callees right now.");
- }
- return false;
- }
- template <class Emitter>
- bool ByteCodeExprGen<Emitter>::VisitCXXMemberCallExpr(
- const CXXMemberCallExpr *E) {
- // Get a This pointer on the stack.
- if (!this->visit(E->getImplicitObjectArgument()))
- return false;
- return VisitCallExpr(E);
- }
- template <class Emitter>
- bool ByteCodeExprGen<Emitter>::VisitCXXDefaultInitExpr(
- const CXXDefaultInitExpr *E) {
- return this->visit(E->getExpr());
- }
- template <class Emitter>
- bool ByteCodeExprGen<Emitter>::VisitCXXDefaultArgExpr(
- const CXXDefaultArgExpr *E) {
- return this->visit(E->getExpr());
- }
- template <class Emitter>
- bool ByteCodeExprGen<Emitter>::VisitCXXBoolLiteralExpr(
- const CXXBoolLiteralExpr *E) {
- if (DiscardResult)
- return true;
- return this->emitConstBool(E->getValue(), E);
- }
- template <class Emitter>
- bool ByteCodeExprGen<Emitter>::VisitCXXNullPtrLiteralExpr(
- const CXXNullPtrLiteralExpr *E) {
- if (DiscardResult)
- return true;
- return this->emitNullPtr(E);
- }
- template <class Emitter>
- bool ByteCodeExprGen<Emitter>::VisitCXXThisExpr(const CXXThisExpr *E) {
- if (DiscardResult)
- return true;
- return this->emitThis(E);
- }
- template <class Emitter>
- bool ByteCodeExprGen<Emitter>::VisitUnaryOperator(const UnaryOperator *E) {
- const Expr *SubExpr = E->getSubExpr();
- std::optional<PrimType> T = classify(SubExpr->getType());
- // TODO: Support pointers for inc/dec operators.
- switch (E->getOpcode()) {
- case UO_PostInc: { // x++
- if (!this->visit(SubExpr))
- return false;
- return DiscardResult ? this->emitIncPop(*T, E) : this->emitInc(*T, E);
- }
- case UO_PostDec: { // x--
- if (!this->visit(SubExpr))
- return false;
- return DiscardResult ? this->emitDecPop(*T, E) : this->emitDec(*T, E);
- }
- case UO_PreInc: { // ++x
- if (!this->visit(SubExpr))
- return false;
- // Post-inc and pre-inc are the same if the value is to be discarded.
- if (DiscardResult)
- return this->emitIncPop(*T, E);
- this->emitLoad(*T, E);
- this->emitConst(1, E);
- this->emitAdd(*T, E);
- return this->emitStore(*T, E);
- }
- case UO_PreDec: { // --x
- if (!this->visit(SubExpr))
- return false;
- // Post-dec and pre-dec are the same if the value is to be discarded.
- if (DiscardResult)
- return this->emitDecPop(*T, E);
- this->emitLoad(*T, E);
- this->emitConst(1, E);
- this->emitSub(*T, E);
- return this->emitStore(*T, E);
- }
- case UO_LNot: // !x
- if (!this->visit(SubExpr))
- return false;
- // The Inv doesn't change anything, so skip it if we don't need the result.
- return DiscardResult ? this->emitPop(*T, E) : this->emitInvBool(E);
- case UO_Minus: // -x
- if (!this->visit(SubExpr))
- return false;
- return DiscardResult ? this->emitPop(*T, E) : this->emitNeg(*T, E);
- case UO_Plus: // +x
- if (!this->visit(SubExpr)) // noop
- return false;
- return DiscardResult ? this->emitPop(*T, E) : true;
- case UO_AddrOf: // &x
- // We should already have a pointer when we get here.
- if (!this->visit(SubExpr))
- return false;
- return DiscardResult ? this->emitPop(*T, E) : true;
- case UO_Deref: // *x
- return dereference(
- SubExpr, DerefKind::Read,
- [](PrimType) {
- llvm_unreachable("Dereferencing requires a pointer");
- return false;
- },
- [this, E](PrimType T) {
- return DiscardResult ? this->emitPop(T, E) : true;
- });
- case UO_Not: // ~x
- if (!this->visit(SubExpr))
- return false;
- return DiscardResult ? this->emitPop(*T, E) : this->emitComp(*T, E);
- case UO_Real: // __real x
- case UO_Imag: // __imag x
- case UO_Extension:
- case UO_Coawait:
- assert(false && "Unhandled opcode");
- }
- return false;
- }
- template <class Emitter>
- bool ByteCodeExprGen<Emitter>::VisitDeclRefExpr(const DeclRefExpr *E) {
- const auto *Decl = E->getDecl();
- // References are implemented via pointers, so when we see a DeclRefExpr
- // pointing to a reference, we need to get its value directly (i.e. the
- // pointer to the actual value) instead of a pointer to the pointer to the
- // value.
- bool IsReference = Decl->getType()->isReferenceType();
- if (auto It = Locals.find(Decl); It != Locals.end()) {
- const unsigned Offset = It->second.Offset;
- if (IsReference)
- return this->emitGetLocal(PT_Ptr, Offset, E);
- return this->emitGetPtrLocal(Offset, E);
- } else if (auto GlobalIndex = P.getGlobal(Decl)) {
- if (IsReference)
- return this->emitGetGlobal(PT_Ptr, *GlobalIndex, E);
- return this->emitGetPtrGlobal(*GlobalIndex, E);
- } else if (const auto *PVD = dyn_cast<ParmVarDecl>(Decl)) {
- if (auto It = this->Params.find(PVD); It != this->Params.end()) {
- if (IsReference)
- return this->emitGetParam(PT_Ptr, It->second, E);
- return this->emitGetPtrParam(It->second, E);
- }
- } else if (const auto *ECD = dyn_cast<EnumConstantDecl>(Decl)) {
- return this->emitConst(ECD->getInitVal(), E);
- }
- return false;
- }
- template <class Emitter>
- void ByteCodeExprGen<Emitter>::emitCleanup() {
- for (VariableScope<Emitter> *C = VarScope; C; C = C->getParent())
- C->emitDestruction();
- }
- namespace clang {
- namespace interp {
- template class ByteCodeExprGen<ByteCodeEmitter>;
- template class ByteCodeExprGen<EvalEmitter>;
- } // namespace interp
- } // namespace clang
|