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>().
template <class Emitter>
std::optional<unsigned>
ByteCodeExprGen<Emitter>::allocateLocal(DeclTy &&Src, bool IsExtended) {
- QualType Ty;
+ // 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;
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 (std::optional<unsigned> I = P.createGlobal(VD, Init)) {
- if (std::optional<PrimType> T = classify(VD->getType())) {
- {
- // Primitive declarations - compute the value and set it.
- DeclScope<Emitter> LocalScope(this, VD);
- if (!visit(Init))
+ 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;
- // If the declaration is global, save the value for later use.
- if (!this->emitDup(*T, VD))
- return false;
- if (!this->emitInitGlobal(*T, *I, VD))
- return false;
- return this->emitRet(*T, VD);
+ return this->emitSetLocal(*VarT, Offset, VD);
+ }
} else {
- {
- // Composite declarations - allocate storage and initialize it.
- DeclScope<Emitter> LocalScope(this, VD);
- if (!visitGlobalInitializer(Init, *I))
- return false;
+ if (std::optional<unsigned> Offset = this->allocateLocal(VD)) {
+ if (Init)
+ return this->visitLocalInitializer(Init, *Offset);
}
-
- // Return a pointer to the global.
- if (!this->emitGetPtrGlobal(*I, VD))
- return false;
- return this->emitRetValue(VD);
}
+ return true;
}
- return this->bail(VD);
+ return false;
}
template <class Emitter>
bool visitArrayInitializer(const Expr *Initializer);
/// Compiles a record initializer.
bool visitRecordInitializer(const Expr *Initializer);
+ /// Creates and initializes a variable from the given decl.
+ bool visitVarDecl(const VarDecl *VD);
/// Visits an expression and converts it to a boolean.
bool visitBool(const Expr *E);
return T->getAsCXXRecordDecl();
}
+ /// Returns whether we should create a global variable for the
+ /// given VarDecl.
+ bool shouldBeGloballyIndexed(const VarDecl *VD) const {
+ return VD->hasGlobalStorage() || VD->isConstexpr();
+ }
+
protected:
/// Variable to storage mapping.
llvm::DenseMap<const ValueDecl *, Scope::Local> Locals;
/// Scope chain managing the variable lifetimes.
template <class Emitter> class VariableScope {
public:
+ VariableScope(ByteCodeExprGen<Emitter> *Ctx)
+ : Ctx(Ctx), Parent(Ctx->VarScope) {
+ Ctx->VarScope = this;
+ }
+
virtual ~VariableScope() { Ctx->VarScope = this->Parent; }
void add(const Scope::Local &Local, bool IsExtended) {
VariableScope *getParent() { return Parent; }
protected:
- VariableScope(ByteCodeExprGen<Emitter> *Ctx)
- : Ctx(Ctx), Parent(Ctx->VarScope) {
- Ctx->VarScope = this;
- }
-
/// ByteCodeExprGen instance.
ByteCodeExprGen<Emitter> *Ctx;
/// Link to the parent scope.
for (auto *D : DS->decls()) {
// Variable declarator.
if (auto *VD = dyn_cast<VarDecl>(D)) {
- if (!visitVarDecl(VD))
+ if (!this->visitVarDecl(VD))
return false;
continue;
}
return this->jump(*ContinueLabel);
}
-template <class Emitter>
-bool ByteCodeStmtGen<Emitter>::visitVarDecl(const VarDecl *VD) {
- if (!VD->hasLocalStorage()) {
- // No code generation required.
- return true;
- }
-
- // Integers, pointers, primitives.
- if (std::optional<PrimType> T = this->classify(VD->getType())) {
- const Expr *Init = VD->getInit();
-
- unsigned Offset =
- this->allocateLocalPrimitive(VD, *T, VD->getType().isConstQualified());
- // Compile the initializer in its own scope.
- if (Init) {
- ExprScope<Emitter> Scope(this);
- if (!this->visit(Init))
- return false;
-
- return this->emitSetLocal(*T, Offset, VD);
- }
- return true;
- }
-
- // Composite types - allocate storage and initialize it.
- if (std::optional<unsigned> Offset = this->allocateLocal(VD)) {
- if (!VD->getInit())
- return true;
-
- return this->visitLocalInitializer(VD->getInit(), *Offset);
- }
-
- return this->bail(VD);
-}
-
namespace clang {
namespace interp {