[clang] [clang][Interp] Handle casts between complex types (PR #79269)

Timm Baeder via cfe-commits cfe-commits at lists.llvm.org
Wed Jan 24 01:08:48 PST 2024


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?= <tbaeder at 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, "");
 



More information about the cfe-commits mailing list