Skip to content

[clang][Interp] Cleaning up FIXMEs added during ArrayInitLoopExpr implementation. #70053

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jan 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 8 additions & 12 deletions clang/lib/AST/Interp/ByteCodeExprGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -816,22 +816,18 @@ bool ByteCodeExprGen<Emitter>::VisitArrayInitLoopExpr(
const ArrayInitLoopExpr *E) {
assert(Initializing);
assert(!DiscardResult);

// We visit the common opaque expression here once so we have its value
// cached.
if (!this->discard(E->getCommonExpr()))
return false;

// TODO: This compiles to quite a lot of bytecode if the array is larger.
// Investigate compiling this to a loop.

const Expr *SubExpr = E->getSubExpr();
const Expr *CommonExpr = E->getCommonExpr();
size_t Size = E->getArraySize().getZExtValue();
std::optional<PrimType> ElemT = classify(SubExpr->getType());

// If the common expression is an opaque expression, we visit it
// here once so we have its value cached.
// FIXME: This might be necessary (or useful) for all expressions.
if (isa<OpaqueValueExpr>(CommonExpr)) {
if (!this->discard(CommonExpr))
return false;
}

// So, every iteration, we execute an assignment here
// where the LHS is on the stack (the target array)
// and the RHS is our SubExpr.
Expand Down Expand Up @@ -882,13 +878,13 @@ bool ByteCodeExprGen<Emitter>::VisitOpaqueValueExpr(const OpaqueValueExpr *E) {
return false;

// Here the local variable is created but the value is removed from the stack,
// so we put it back, because the caller might need it.
// so we put it back if the caller needs it.
if (!DiscardResult) {
if (!this->emitGetLocal(SubExprT, *LocalIndex, E))
return false;
}

// FIXME: Ideally the cached value should be cleaned up later.
// This is cleaned up when the local variable is destroyed.
OpaqueExprs.insert({E, *LocalIndex});

return true;
Expand Down
21 changes: 21 additions & 0 deletions clang/lib/AST/Interp/ByteCodeExprGen.h
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,7 @@ template <class Emitter> class LocalScope : public VariableScope<Emitter> {
if (!Idx)
return;
this->Ctx->emitDestroy(*Idx, SourceInfo{});
removeStoredOpaqueValues();
}

/// Overriden to support explicit destruction.
Expand All @@ -368,6 +369,7 @@ template <class Emitter> class LocalScope : public VariableScope<Emitter> {
return;
this->emitDestructors();
this->Ctx->emitDestroy(*Idx, SourceInfo{});
removeStoredOpaqueValues();
this->Idx = std::nullopt;
}

Expand All @@ -389,10 +391,29 @@ template <class Emitter> class LocalScope : public VariableScope<Emitter> {
if (!Local.Desc->isPrimitive() && !Local.Desc->isPrimitiveArray()) {
this->Ctx->emitGetPtrLocal(Local.Offset, SourceInfo{});
this->Ctx->emitRecordDestruction(Local.Desc);
removeIfStoredOpaqueValue(Local);
}
}
}

void removeStoredOpaqueValues() {
if (!Idx)
return;

for (const Scope::Local &Local : this->Ctx->Descriptors[*Idx]) {
removeIfStoredOpaqueValue(Local);
}
}

void removeIfStoredOpaqueValue(const Scope::Local &Local) {
if (const auto *OVE =
llvm::dyn_cast_if_present<OpaqueValueExpr>(Local.Desc->asExpr())) {
if (auto It = this->Ctx->OpaqueExprs.find(OVE);
It != this->Ctx->OpaqueExprs.end())
this->Ctx->OpaqueExprs.erase(It);
};
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is just leaving them in the map such a big deal?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There might be cases like loops or recursive functions, where we might want to evaluate the same OpaqueValueExpr multiple times, but we will fail if it is left in the map. I'm just trying to be careful here.

/// Index of the scope in the chain.
std::optional<unsigned> Idx;
};
Expand Down