[clang] 8c84096 - [clang][Interp] Fix initializing _Complex values from DeclRefExpr
Timm Bäder via cfe-commits
cfe-commits at lists.llvm.org
Tue Feb 6 23:07:17 PST 2024
Author: Timm Bäder
Date: 2024-02-07T08:07:05+01:00
New Revision: 8c84096da195ae38336ba9aa700dc35e567157ba
URL: https://github.com/llvm/llvm-project/commit/8c84096da195ae38336ba9aa700dc35e567157ba
DIFF: https://github.com/llvm/llvm-project/commit/8c84096da195ae38336ba9aa700dc35e567157ba.diff
LOG: [clang][Interp] Fix initializing _Complex values from DeclRefExpr
See the comment I added. When initializing a complex value from a
DeclRefExpr, we need to manually copy both array elements.
This adds some unfortunate code duplication that I'm still pondering
on how to get rid of best.
Added:
Modified:
clang/lib/AST/Interp/ByteCodeExprGen.cpp
clang/lib/AST/Interp/Interp.h
clang/lib/AST/Interp/Opcodes.td
clang/test/AST/Interp/complex.cpp
Removed:
################################################################################
diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
index 79d44842d83195..49f9878d42480f 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -3009,21 +3009,53 @@ bool ByteCodeExprGen<Emitter>::VisitDeclRefExpr(const DeclRefExpr *E) {
// pointer to the actual value) instead of a pointer to the pointer to the
// value.
bool IsReference = D->getType()->isReferenceType();
+ // Complex values are copied in the AST via a simply assignment or
+ // ltor cast. But we represent them as two-element arrays, which means
+ // we pass them around as pointers. So, to assignm from them, we will
+ // have to copy both (primitive) elements instead.
+ bool IsComplex = D->getType()->isAnyComplexType();
// Check for local/global variables and parameters.
if (auto It = Locals.find(D); It != Locals.end()) {
const unsigned Offset = It->second.Offset;
+ // FIXME: Fix the code duplication here with the code in the global case.
+ if (Initializing && IsComplex) {
+ PrimType ElemT = classifyComplexElementType(D->getType());
+ for (unsigned I = 0; I != 2; ++I) {
+ if (!this->emitGetPtrLocal(Offset, E))
+ return false;
+ if (!this->emitArrayElemPop(ElemT, I, E))
+ return false;
+ if (!this->emitInitElem(ElemT, I, E))
+ return false;
+ }
+ return true;
+ }
if (IsReference)
return this->emitGetLocal(PT_Ptr, Offset, E);
return this->emitGetPtrLocal(Offset, E);
} else if (auto GlobalIndex = P.getGlobal(D)) {
+ if (Initializing && IsComplex) {
+ PrimType ElemT = classifyComplexElementType(D->getType());
+ for (unsigned I = 0; I != 2; ++I) {
+ if (!this->emitGetPtrGlobal(*GlobalIndex, E))
+ return false;
+ if (!this->emitArrayElemPop(ElemT, I, E))
+ return false;
+ if (!this->emitInitElem(ElemT, I, E))
+ return false;
+ }
+ return true;
+ }
+
if (IsReference)
return this->emitGetGlobalPtr(*GlobalIndex, E);
return this->emitGetPtrGlobal(*GlobalIndex, E);
} else if (const auto *PVD = dyn_cast<ParmVarDecl>(D)) {
if (auto It = this->Params.find(PVD); It != this->Params.end()) {
+ // FIXME: _Complex initializing case?
if (IsReference || !It->second.IsPtr)
return this->emitGetParamPtr(It->second.Offset, E);
diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h
index b33cf55c61f036..a76e63395157f7 100644
--- a/clang/lib/AST/Interp/Interp.h
+++ b/clang/lib/AST/Interp/Interp.h
@@ -1878,6 +1878,14 @@ inline bool ArrayElemPtrPop(InterpState &S, CodePtr OpPC) {
return NarrowPtr(S, OpPC);
}
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+inline bool ArrayElemPop(InterpState &S, CodePtr OpPC, uint32_t Index) {
+ const Pointer &Ptr = S.Stk.pop<Pointer>();
+
+ S.Stk.push<T>(Ptr.atIndex(Index).deref<T>());
+ return true;
+}
+
/// Just takes a pointer and checks if it's an incomplete
/// array type.
inline bool ArrayDecay(InterpState &S, CodePtr OpPC) {
diff --git a/clang/lib/AST/Interp/Opcodes.td b/clang/lib/AST/Interp/Opcodes.td
index e720b95498f17f..7f5bd7e5b44bca 100644
--- a/clang/lib/AST/Interp/Opcodes.td
+++ b/clang/lib/AST/Interp/Opcodes.td
@@ -357,6 +357,12 @@ def ExpandPtr : Opcode;
def ArrayElemPtr : AluOpcode;
def ArrayElemPtrPop : AluOpcode;
+def ArrayElemPop : Opcode {
+ let Args = [ArgUint32];
+ let Types = [AllTypeClass];
+ let HasGroup = 1;
+}
+
//===----------------------------------------------------------------------===//
// Direct field accessors
//===----------------------------------------------------------------------===//
diff --git a/clang/test/AST/Interp/complex.cpp b/clang/test/AST/Interp/complex.cpp
index 7f02bfa18bbdb0..20c00b8e1ba3fe 100644
--- a/clang/test/AST/Interp/complex.cpp
+++ b/clang/test/AST/Interp/complex.cpp
@@ -194,3 +194,21 @@ namespace ZeroInit {
constexpr int ignored = (fcomplex(), 0);
}
+
+namespace DeclRefCopy {
+ constexpr _Complex int ComplexInt = 42 + 24i;
+
+ constexpr _Complex int B = ComplexInt;
+ constexpr _Complex int ArrayOfComplexInt[4] = {ComplexInt, ComplexInt, ComplexInt, ComplexInt};
+ static_assert(__real(ArrayOfComplexInt[0]) == 42, "");
+ static_assert(__imag(ArrayOfComplexInt[0]) == 24, "");
+ static_assert(__real(ArrayOfComplexInt[3]) == 42, "");
+ static_assert(__imag(ArrayOfComplexInt[3]) == 24, "");
+
+ constexpr int localComplexArray() {
+ _Complex int A = 42 + 24i;
+ _Complex int ArrayOfComplexInt[4] = {A, A, A, A};
+ return __real(ArrayOfComplexInt[0]) + __imag(ArrayOfComplexInt[3]);
+ }
+ static_assert(localComplexArray() == (24 + 42), "");
+}
More information about the cfe-commits
mailing list