[clang] 9022f40 - [clang][Interp] Only evaluate the source array initialization of an `ArrayInitLoopExpr` once (#68039)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Oct 23 08:52:31 PDT 2023
Author: isuckatcs
Date: 2023-10-23T17:52:27+02:00
New Revision: 9022f402120b4e55ec1201c16f8f6d2388498e1d
URL: https://github.com/llvm/llvm-project/commit/9022f402120b4e55ec1201c16f8f6d2388498e1d
DIFF: https://github.com/llvm/llvm-project/commit/9022f402120b4e55ec1201c16f8f6d2388498e1d.diff
LOG: [clang][Interp] Only evaluate the source array initialization of an `ArrayInitLoopExpr` once (#68039)
This patch implements an `OpaqueValueExpr` caching functionality in `Interp`
by storing the result of the expression in a local variable.
Added:
Modified:
clang/lib/AST/Interp/ByteCodeExprGen.cpp
clang/test/AST/Interp/arrays.cpp
clang/test/AST/Interp/cxx20.cpp
Removed:
################################################################################
diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
index ed971fe0f650f22..d3e0d1112935a98 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -817,8 +817,8 @@ bool ByteCodeExprGen<Emitter>::VisitArrayInitLoopExpr(
assert(Initializing);
assert(!DiscardResult);
// 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.
+ // Investigate compiling this to a loop.
+
const Expr *SubExpr = E->getSubExpr();
size_t Size = E->getArraySize().getZExtValue();
std::optional<PrimType> ElemT = classify(SubExpr->getType());
@@ -853,7 +853,33 @@ template <class Emitter>
bool ByteCodeExprGen<Emitter>::VisitOpaqueValueExpr(const OpaqueValueExpr *E) {
if (Initializing)
return this->visitInitializer(E->getSourceExpr());
- return this->visit(E->getSourceExpr());
+
+ PrimType SubExprT = classify(E->getSourceExpr()).value_or(PT_Ptr);
+ if (auto It = OpaqueExprs.find(E); It != OpaqueExprs.end())
+ return this->emitGetLocal(SubExprT, It->getSecond(), E);
+
+ if (!this->visit(E->getSourceExpr()))
+ return false;
+
+ // At this point we either have the evaluated source expression or a pointer
+ // to an object on the stack. We want to create a local variable that stores
+ // this value.
+ std::optional<unsigned> LocalIndex =
+ allocateLocalPrimitive(E, SubExprT, /*IsConst=*/true);
+ if (!LocalIndex)
+ return false;
+ if (!this->emitSetLocal(SubExprT, *LocalIndex, 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.
+ if (!this->emitGetLocal(SubExprT, *LocalIndex, E))
+ return false;
+
+ // FIXME: Ideally the cached value should be cleaned up later.
+ OpaqueExprs.insert({E, *LocalIndex});
+
+ return true;
}
template <class Emitter>
diff --git a/clang/test/AST/Interp/arrays.cpp b/clang/test/AST/Interp/arrays.cpp
index 18c4ae4354f54a0..ba29632e97c30a6 100644
--- a/clang/test/AST/Interp/arrays.cpp
+++ b/clang/test/AST/Interp/arrays.cpp
@@ -372,9 +372,6 @@ namespace ZeroInit {
}
namespace ArrayInitLoop {
- /// FIXME: The ArrayInitLoop for the decomposition initializer in g() has
- /// f(n) as its CommonExpr. We need to evaluate that exactly once and not
- /// N times as we do right now.
struct X {
int arr[3];
};
@@ -386,8 +383,7 @@ namespace ArrayInitLoop {
auto [a, b, c] = f(n).arr;
return a + b + c;
}
- static_assert(g() == 6); // expected-error {{failed}} \
- // expected-note {{15 == 6}}
+ static_assert(g() == 6, "");
}
namespace StringZeroFill {
diff --git a/clang/test/AST/Interp/cxx20.cpp b/clang/test/AST/Interp/cxx20.cpp
index 197090b0a37d9df..553bc6eb4d5244f 100644
--- a/clang/test/AST/Interp/cxx20.cpp
+++ b/clang/test/AST/Interp/cxx20.cpp
@@ -733,3 +733,15 @@ namespace ConstexprArrayInitLoopExprDestructors
return f();
}
}
+
+namespace NonPrimitiveOpaqueValue
+{
+ struct X {
+ int x;
+ constexpr operator bool() const { return x != 0; }
+ };
+
+ constexpr int ternary() { return X(0) ?: X(0); }
+
+ static_assert(!ternary(), "");
+}
More information about the cfe-commits
mailing list