Skip to content

Commit

Permalink
[clang][Interp] Fix initializing _Complex values from DeclRefExpr
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
tbaederr committed Feb 7, 2024
1 parent c5e5661 commit 8c84096
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 0 deletions.
32 changes: 32 additions & 0 deletions clang/lib/AST/Interp/ByteCodeExprGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
8 changes: 8 additions & 0 deletions clang/lib/AST/Interp/Interp.h
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/AST/Interp/Opcodes.td
Original file line number Diff line number Diff line change
Expand Up @@ -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
//===----------------------------------------------------------------------===//
Expand Down
18 changes: 18 additions & 0 deletions clang/test/AST/Interp/complex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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), "");
}

0 comments on commit 8c84096

Please sign in to comment.