tbaeder updated this revision to Diff 509021.
tbaeder set the repository for this revision to rG LLVM Github Monorepo.
tbaeder added a comment.

Add support for integer complex types as well.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D146408/new/

https://reviews.llvm.org/D146408

Files:
  clang/lib/AST/Interp/ByteCodeExprGen.cpp
  clang/lib/AST/Interp/ByteCodeExprGen.h
  clang/lib/AST/Interp/Context.cpp
  clang/lib/AST/Interp/EvalEmitter.cpp
  clang/lib/AST/Interp/PrimType.h
  clang/test/AST/Interp/complex.cpp

Index: clang/test/AST/Interp/complex.cpp
===================================================================
--- /dev/null
+++ clang/test/AST/Interp/complex.cpp
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify %s
+// RUN: %clang_cc1 -verify=ref %s
+
+// expected-no-diagnostics
+// ref-no-diagnostics
+
+constexpr _Complex double z1 = {1.0, 2.0};
+static_assert(__real(z1) == 1.0, "");
+static_assert(__imag(z1) == 2.0, "");
+
+constexpr double setter() {
+  _Complex float d = {1.0, 2.0};
+
+  __imag(d) = 4.0;
+  return __imag(d);
+}
+static_assert(setter() == 4, "");
+
+constexpr _Complex double getter() {
+  return {1.0, 3.0};
+}
+constexpr _Complex double D = getter();
+static_assert(__real(D) == 1.0, "");
+static_assert(__imag(D) == 3.0, "");
+
+
+constexpr _Complex int I1 = {1, 2};
+static_assert(__real(I1) == 1, "");
+static_assert(__imag(I1) == 2, "");
Index: clang/lib/AST/Interp/PrimType.h
===================================================================
--- clang/lib/AST/Interp/PrimType.h
+++ clang/lib/AST/Interp/PrimType.h
@@ -102,6 +102,22 @@
     }                                                                          \
   } while (0)
 
+#define INT_TYPE_SWITCH(Expr, B)                                               \
+  do {                                                                         \
+    switch (Expr) {                                                            \
+      TYPE_SWITCH_CASE(PT_Sint8, B)                                            \
+      TYPE_SWITCH_CASE(PT_Uint8, B)                                            \
+      TYPE_SWITCH_CASE(PT_Sint16, B)                                           \
+      TYPE_SWITCH_CASE(PT_Uint16, B)                                           \
+      TYPE_SWITCH_CASE(PT_Sint32, B)                                           \
+      TYPE_SWITCH_CASE(PT_Uint32, B)                                           \
+      TYPE_SWITCH_CASE(PT_Sint64, B)                                           \
+      TYPE_SWITCH_CASE(PT_Uint64, B)                                           \
+    default:                                                                   \
+      llvm_unreachable("Unhandled integer type");                              \
+    }                                                                          \
+  } while (0)
+
 #define BITCAST_TYPE_SWITCH(Expr, B)                                           \
   do {                                                                         \
     switch (Expr) {                                                            \
Index: clang/lib/AST/Interp/EvalEmitter.cpp
===================================================================
--- clang/lib/AST/Interp/EvalEmitter.cpp
+++ clang/lib/AST/Interp/EvalEmitter.cpp
@@ -196,6 +196,28 @@
       }
       return Ok;
     }
+
+    // Complex types.
+    if (const auto *CT = Ty->getAs<ComplexType>()) {
+      QualType ElemTy = CT->getElementType();
+      std::optional<PrimType> ElemT = Ctx.classify(ElemTy);
+      assert(ElemT);
+
+      if (ElemTy->isIntegerType()) {
+        INT_TYPE_SWITCH(*ElemT, {
+          auto V1 = Ptr.atIndex(0).deref<T>();
+          auto V2 = Ptr.atIndex(1).deref<T>();
+          Result = APValue(V1.toAPSInt(), V2.toAPSInt());
+          return true;
+        });
+        return false;
+      } else if (ElemTy->isFloatingType()) {
+        Result = APValue(Ptr.atIndex(0).deref<Floating>().getAPFloat(),
+                         Ptr.atIndex(1).deref<Floating>().getAPFloat());
+        return true;
+      }
+      return false;
+    }
     llvm_unreachable("invalid value to return");
   };
 
Index: clang/lib/AST/Interp/Context.cpp
===================================================================
--- clang/lib/AST/Interp/Context.cpp
+++ clang/lib/AST/Interp/Context.cpp
@@ -81,6 +81,9 @@
   if (T->isBooleanType())
     return PT_Bool;
 
+  if (T->isAnyComplexType())
+    return std::nullopt;
+
   if (T->isSignedIntegerOrEnumerationType()) {
     switch (Ctx.getIntWidth(T)) {
     case 64:
Index: clang/lib/AST/Interp/ByteCodeExprGen.h
===================================================================
--- clang/lib/AST/Interp/ByteCodeExprGen.h
+++ clang/lib/AST/Interp/ByteCodeExprGen.h
@@ -139,6 +139,7 @@
   bool visitArrayInitializer(const Expr *Initializer);
   /// Compiles a record initializer.
   bool visitRecordInitializer(const Expr *Initializer);
+  bool visitComplexInitializer(const Expr *Initializer);
   /// Creates and initializes a variable from the given decl.
   bool visitVarDecl(const VarDecl *VD);
 
Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp
===================================================================
--- clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -1573,6 +1573,33 @@
   return false;
 }
 
+/// Visit an initializer for a _Complex type.
+/// They are represented as two-element arrays.
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::visitComplexInitializer(
+    const Expr *Initializer) {
+  if (const auto *InitList = dyn_cast<InitListExpr>(Initializer)) {
+    unsigned InitIndex = 0;
+    for (const Expr *Init : InitList->inits()) {
+      PrimType InitT = classifyPrim(Init->getType());
+
+      if (!this->visit(Init))
+        return false;
+
+      if (!this->emitInitElem(InitT, InitIndex, InitList))
+        return false;
+      ++InitIndex;
+    }
+    assert(InitIndex == 2);
+    return true;
+  } else if (const auto *CE = dyn_cast<CallExpr>(Initializer)) {
+    if (!this->emitDupPtr(Initializer))
+      return false;
+    return this->visit(CE);
+  }
+  return false;
+}
+
 template <class Emitter>
 bool ByteCodeExprGen<Emitter>::visitInitializer(const Expr *Initializer) {
   QualType InitializerType = Initializer->getType();
@@ -1583,6 +1610,9 @@
   if (InitializerType->isRecordType())
     return visitRecordInitializer(Initializer);
 
+  if (InitializerType->isAnyComplexType())
+    return visitComplexInitializer(Initializer);
+
   // Otherwise, visit the expression like normal.
   return this->visit(Initializer);
 }
@@ -1983,8 +2013,22 @@
     if (!this->visit(SubExpr))
       return false;
     return DiscardResult ? this->emitPop(*T, E) : this->emitComp(*T, E);
-  case UO_Real:   // __real x
-  case UO_Imag:   // __imag x
+  case UO_Real: { // __real x
+    assert(!T);
+    if (!this->visit(SubExpr))
+      return false;
+    if (!this->emitConstUint8(0, E))
+      return false;
+    return this->emitArrayElemPtrPopUint8(E);
+  }
+  case UO_Imag: { // __imag x
+    assert(!T);
+    if (!this->visit(SubExpr))
+      return false;
+    if (!this->emitConstUint8(1, E))
+      return false;
+    return this->emitArrayElemPtrPopUint8(E);
+  }
   case UO_Extension:
   case UO_Coawait:
     assert(false && "Unhandled opcode");
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to