https://github.com/tbaederr created https://github.com/llvm/llvm-project/pull/79269
Just handle this like two primtive casts. >From ecc963e4fbcfe1cd1c1f40c642c1c0fbf916a8c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbae...@redhat.com> Date: Wed, 24 Jan 2024 10:04:50 +0100 Subject: [PATCH] [clang][Interp] Handle casts between complex types Just handle this like two primtive casts. --- clang/lib/AST/Interp/ByteCodeExprGen.cpp | 57 ++++++++++++++++++++++++ clang/lib/AST/Interp/Pointer.h | 10 ++++- clang/test/AST/Interp/complex.cpp | 19 +++++++- 3 files changed, 82 insertions(+), 4 deletions(-) diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp index cfcef067b92bdc..fd9e6ee47614bc 100644 --- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -314,6 +314,63 @@ bool ByteCodeExprGen<Emitter>::VisitCastExpr(const CastExpr *CE) { return this->emitInitElem(T, 1, SubExpr); } + case CK_IntegralComplexCast: + case CK_FloatingComplexCast: + case CK_IntegralComplexToFloatingComplex: + case CK_FloatingComplexToIntegralComplex: { + assert(CE->getType()->isAnyComplexType()); + assert(SubExpr->getType()->isAnyComplexType()); + if (DiscardResult) + return this->discard(SubExpr); + + if (!Initializing) { + std::optional<unsigned> LocalIndex = + allocateLocal(CE, /*IsExtended=*/true); + if (!LocalIndex) + return false; + if (!this->emitGetPtrLocal(*LocalIndex, CE)) + return false; + } + + // Location for the SubExpr. + // Since SubExpr is of complex type, visiting it results in a pointer + // anyway, so we just create a temporary pointer variable. + std::optional<unsigned> SubExprOffset = allocateLocalPrimitive( + SubExpr, PT_Ptr, /*IsConst=*/true, /*IsExtended=*/false); + if (!SubExprOffset) + return false; + + if (!this->visit(SubExpr)) + return false; + if (!this->emitSetLocal(PT_Ptr, *SubExprOffset, CE)) + return false; + + PrimType SourceElemT = *classifyComplexElementType(SubExpr->getType()); + QualType DestElemType = + CE->getType()->getAs<ComplexType>()->getElementType(); + PrimType DestElemT = classifyPrim(DestElemType); + // Cast both elements individually. + for (unsigned I = 0; I != 2; ++I) { + if (!this->emitGetLocal(PT_Ptr, *SubExprOffset, CE)) + return false; + if (!this->emitConstUint8(I, CE)) + return false; + if (!this->emitArrayElemPtrPopUint8(CE)) + return false; + if (!this->emitLoadPop(SourceElemT, CE)) + return false; + + // Do the cast. + if (!this->emitPrimCast(SourceElemT, DestElemT, DestElemType, CE)) + return false; + + // Save the value. + if (!this->emitInitElem(DestElemT, I, CE)) + return false; + } + return true; + } + case CK_ToVoid: return discard(SubExpr); diff --git a/clang/lib/AST/Interp/Pointer.h b/clang/lib/AST/Interp/Pointer.h index 8ccaff41ded8da..15be54d4110b71 100644 --- a/clang/lib/AST/Interp/Pointer.h +++ b/clang/lib/AST/Interp/Pointer.h @@ -234,8 +234,14 @@ class Pointer { /// Returns the type of the innermost field. QualType getType() const { - if (inPrimitiveArray() && Offset != Base) - return getFieldDesc()->getType()->getAsArrayTypeUnsafe()->getElementType(); + if (inPrimitiveArray() && Offset != Base) { + // Unfortunately, complex types are not array types in clang, but they are + // for us. + if (const auto *AT = getFieldDesc()->getType()->getAsArrayTypeUnsafe()) + return AT->getElementType(); + if (const auto *CT = getFieldDesc()->getType()->castAs<ComplexType>()) + return CT->getElementType(); + } return getFieldDesc()->getType(); } diff --git a/clang/test/AST/Interp/complex.cpp b/clang/test/AST/Interp/complex.cpp index 99c0dd141d0b77..e9c0ffa5f4a56a 100644 --- a/clang/test/AST/Interp/complex.cpp +++ b/clang/test/AST/Interp/complex.cpp @@ -42,16 +42,31 @@ static_assert(__real(12u) == 12u, ""); static_assert(__imag(4.0) == 0.0, ""); static_assert(__imag(13) == 0, ""); -constexpr int ignoredCast() { + +constexpr _Complex long L1 = D; +static_assert(__real(L1) == 1.0, ""); +static_assert(__imag(L1) == 3.0, ""); + +constexpr _Complex short I4 = L1; +static_assert(__real(I4) == 1, ""); +static_assert(__imag(I4) == 3, ""); + +constexpr _Complex float D3 = D; +static_assert(__real(D3) == 1.0, ""); +static_assert(__imag(D3) == 3.0, ""); + + +constexpr int ignored() { I2; (int)I2; (float)I2; D1; (int)D1; (double)D1; + (_Complex float)I2; return 0; } -static_assert(ignoredCast() == 0, ""); +static_assert(ignored() == 0, ""); static_assert((int)I1 == 1, ""); static_assert((float)D == 1.0f, ""); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits