Skip to content

Commit 8c84096

Browse files
committed
[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.
1 parent c5e5661 commit 8c84096

File tree

4 files changed

+64
-0
lines changed

4 files changed

+64
-0
lines changed

clang/lib/AST/Interp/ByteCodeExprGen.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3009,21 +3009,53 @@ bool ByteCodeExprGen<Emitter>::VisitDeclRefExpr(const DeclRefExpr *E) {
30093009
// pointer to the actual value) instead of a pointer to the pointer to the
30103010
// value.
30113011
bool IsReference = D->getType()->isReferenceType();
3012+
// Complex values are copied in the AST via a simply assignment or
3013+
// ltor cast. But we represent them as two-element arrays, which means
3014+
// we pass them around as pointers. So, to assignm from them, we will
3015+
// have to copy both (primitive) elements instead.
3016+
bool IsComplex = D->getType()->isAnyComplexType();
30123017

30133018
// Check for local/global variables and parameters.
30143019
if (auto It = Locals.find(D); It != Locals.end()) {
30153020
const unsigned Offset = It->second.Offset;
3021+
// FIXME: Fix the code duplication here with the code in the global case.
3022+
if (Initializing && IsComplex) {
3023+
PrimType ElemT = classifyComplexElementType(D->getType());
3024+
for (unsigned I = 0; I != 2; ++I) {
3025+
if (!this->emitGetPtrLocal(Offset, E))
3026+
return false;
3027+
if (!this->emitArrayElemPop(ElemT, I, E))
3028+
return false;
3029+
if (!this->emitInitElem(ElemT, I, E))
3030+
return false;
3031+
}
3032+
return true;
3033+
}
30163034

30173035
if (IsReference)
30183036
return this->emitGetLocal(PT_Ptr, Offset, E);
30193037
return this->emitGetPtrLocal(Offset, E);
30203038
} else if (auto GlobalIndex = P.getGlobal(D)) {
3039+
if (Initializing && IsComplex) {
3040+
PrimType ElemT = classifyComplexElementType(D->getType());
3041+
for (unsigned I = 0; I != 2; ++I) {
3042+
if (!this->emitGetPtrGlobal(*GlobalIndex, E))
3043+
return false;
3044+
if (!this->emitArrayElemPop(ElemT, I, E))
3045+
return false;
3046+
if (!this->emitInitElem(ElemT, I, E))
3047+
return false;
3048+
}
3049+
return true;
3050+
}
3051+
30213052
if (IsReference)
30223053
return this->emitGetGlobalPtr(*GlobalIndex, E);
30233054

30243055
return this->emitGetPtrGlobal(*GlobalIndex, E);
30253056
} else if (const auto *PVD = dyn_cast<ParmVarDecl>(D)) {
30263057
if (auto It = this->Params.find(PVD); It != this->Params.end()) {
3058+
// FIXME: _Complex initializing case?
30273059
if (IsReference || !It->second.IsPtr)
30283060
return this->emitGetParamPtr(It->second.Offset, E);
30293061

clang/lib/AST/Interp/Interp.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1878,6 +1878,14 @@ inline bool ArrayElemPtrPop(InterpState &S, CodePtr OpPC) {
18781878
return NarrowPtr(S, OpPC);
18791879
}
18801880

1881+
template <PrimType Name, class T = typename PrimConv<Name>::T>
1882+
inline bool ArrayElemPop(InterpState &S, CodePtr OpPC, uint32_t Index) {
1883+
const Pointer &Ptr = S.Stk.pop<Pointer>();
1884+
1885+
S.Stk.push<T>(Ptr.atIndex(Index).deref<T>());
1886+
return true;
1887+
}
1888+
18811889
/// Just takes a pointer and checks if it's an incomplete
18821890
/// array type.
18831891
inline bool ArrayDecay(InterpState &S, CodePtr OpPC) {

clang/lib/AST/Interp/Opcodes.td

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,12 @@ def ExpandPtr : Opcode;
357357
def ArrayElemPtr : AluOpcode;
358358
def ArrayElemPtrPop : AluOpcode;
359359

360+
def ArrayElemPop : Opcode {
361+
let Args = [ArgUint32];
362+
let Types = [AllTypeClass];
363+
let HasGroup = 1;
364+
}
365+
360366
//===----------------------------------------------------------------------===//
361367
// Direct field accessors
362368
//===----------------------------------------------------------------------===//

clang/test/AST/Interp/complex.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,3 +194,21 @@ namespace ZeroInit {
194194

195195
constexpr int ignored = (fcomplex(), 0);
196196
}
197+
198+
namespace DeclRefCopy {
199+
constexpr _Complex int ComplexInt = 42 + 24i;
200+
201+
constexpr _Complex int B = ComplexInt;
202+
constexpr _Complex int ArrayOfComplexInt[4] = {ComplexInt, ComplexInt, ComplexInt, ComplexInt};
203+
static_assert(__real(ArrayOfComplexInt[0]) == 42, "");
204+
static_assert(__imag(ArrayOfComplexInt[0]) == 24, "");
205+
static_assert(__real(ArrayOfComplexInt[3]) == 42, "");
206+
static_assert(__imag(ArrayOfComplexInt[3]) == 24, "");
207+
208+
constexpr int localComplexArray() {
209+
_Complex int A = 42 + 24i;
210+
_Complex int ArrayOfComplexInt[4] = {A, A, A, A};
211+
return __real(ArrayOfComplexInt[0]) + __imag(ArrayOfComplexInt[3]);
212+
}
213+
static_assert(localComplexArray() == (24 + 42), "");
214+
}

0 commit comments

Comments
 (0)