[clang] 32c0048 - [clang][Interp] Handle casts between complex types (#79269)
via cfe-commits
cfe-commits at lists.llvm.org
Wed Jan 31 07:53:37 PST 2024
Author: Timm Baeder
Date: 2024-01-31T16:53:33+01:00
New Revision: 32c00485f1e896d472549324218878ba6444f4f6
URL: https://github.com/llvm/llvm-project/commit/32c00485f1e896d472549324218878ba6444f4f6
DIFF: https://github.com/llvm/llvm-project/commit/32c00485f1e896d472549324218878ba6444f4f6.diff
LOG: [clang][Interp] Handle casts between complex types (#79269)
Just handle this like two primtive casts.
Added:
Modified:
clang/lib/AST/Interp/ByteCodeExprGen.cpp
clang/lib/AST/Interp/Pointer.h
clang/test/AST/Interp/complex.cpp
Removed:
################################################################################
diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
index 386abef598594..c4598151f95d6 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -311,6 +311,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 7ae4617f28137..53b89c51b5a81 100644
--- a/clang/lib/AST/Interp/Pointer.h
+++ b/clang/lib/AST/Interp/Pointer.h
@@ -238,8 +238,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()->getAs<ComplexType>())
+ return CT->getElementType();
+ }
return getFieldDesc()->getType();
}
diff --git a/clang/test/AST/Interp/complex.cpp b/clang/test/AST/Interp/complex.cpp
index 836ea552adac8..8c57df7d9a3ed 100644
--- a/clang/test/AST/Interp/complex.cpp
+++ b/clang/test/AST/Interp/complex.cpp
@@ -47,16 +47,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, "");
More information about the cfe-commits
mailing list