[clang] d16cf47 - [clang][Interp] Start implementing binary operators for complex types

Timm Bäder via cfe-commits cfe-commits at lists.llvm.org
Thu Dec 14 06:41:52 PST 2023


Author: Timm Bäder
Date: 2023-12-14T15:33:52+01:00
New Revision: d16cf470ac4600bb1a6b462ed843078ad65a3d93

URL: https://github.com/llvm/llvm-project/commit/d16cf470ac4600bb1a6b462ed843078ad65a3d93
DIFF: https://github.com/llvm/llvm-project/commit/d16cf470ac4600bb1a6b462ed843078ad65a3d93.diff

LOG: [clang][Interp] Start implementing binary operators for complex types

Differential Revision: https://reviews.llvm.org/D155572

Added: 
    

Modified: 
    clang/lib/AST/Interp/ByteCodeExprGen.cpp
    clang/lib/AST/Interp/ByteCodeExprGen.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 080b7e896a8201..d0980882f402b9 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -316,6 +316,9 @@ bool ByteCodeExprGen<Emitter>::VisitBinaryOperator(const BinaryOperator *BO) {
   if (BO->isLogicalOp())
     return this->VisitLogicalBinOp(BO);
 
+  if (BO->getType()->isAnyComplexType())
+    return this->VisitComplexBinOp(BO);
+
   const Expr *LHS = BO->getLHS();
   const Expr *RHS = BO->getRHS();
 
@@ -558,6 +561,107 @@ bool ByteCodeExprGen<Emitter>::VisitLogicalBinOp(const BinaryOperator *E) {
   return true;
 }
 
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitComplexBinOp(const BinaryOperator *E) {
+  // FIXME: We expect a pointer on the stack here.
+  //   we should not do that, but that's part of a bigger rework.
+  const Expr *LHS = E->getLHS();
+  const Expr *RHS = E->getRHS();
+  PrimType LHSElemT = *this->classifyComplexElementType(LHS->getType());
+  PrimType RHSElemT = *this->classifyComplexElementType(RHS->getType());
+
+  unsigned LHSOffset = this->allocateLocalPrimitive(LHS, PT_Ptr, true, false);
+  unsigned RHSOffset = this->allocateLocalPrimitive(RHS, PT_Ptr, true, false);
+  unsigned ResultOffset = ~0u;
+  if (!this->DiscardResult)
+    ResultOffset = this->allocateLocalPrimitive(E, PT_Ptr, true, false);
+
+  assert(LHSElemT == RHSElemT);
+
+  // Save result pointer in ResultOffset
+  if (!this->DiscardResult) {
+    if (!this->emitDupPtr(E))
+      return false;
+    if (!this->emitSetLocal(PT_Ptr, ResultOffset, E))
+      return false;
+  }
+
+  // Evaluate LHS and save value to LHSOffset.
+  if (!this->visit(LHS))
+    return false;
+  if (!this->emitSetLocal(PT_Ptr, LHSOffset, E))
+    return false;
+
+  // Same with RHS.
+  if (!this->visit(RHS))
+    return false;
+  if (!this->emitSetLocal(PT_Ptr, RHSOffset, E))
+    return false;
+
+  // Now we can get pointers to the LHS and RHS from the offsets above.
+  BinaryOperatorKind Op = E->getOpcode();
+  for (unsigned ElemIndex = 0; ElemIndex != 2; ++ElemIndex) {
+    // Result pointer for the store later.
+    if (!this->DiscardResult) {
+      if (!this->emitGetLocal(PT_Ptr, ResultOffset, E))
+        return false;
+    }
+
+    if (!this->emitGetLocal(PT_Ptr, LHSOffset, E))
+      return false;
+    if (!this->emitConstUint8(ElemIndex, E))
+      return false;
+    if (!this->emitArrayElemPtrPopUint8(E))
+      return false;
+    if (!this->emitLoadPop(LHSElemT, E))
+      return false;
+
+    if (!this->emitGetLocal(PT_Ptr, RHSOffset, E))
+      return false;
+    if (!this->emitConstUint8(ElemIndex, E))
+      return false;
+    if (!this->emitArrayElemPtrPopUint8(E))
+      return false;
+    if (!this->emitLoadPop(RHSElemT, E))
+      return false;
+
+    // The actual operation.
+    switch (Op) {
+    case BO_Add:
+      if (LHSElemT == PT_Float) {
+        if (!this->emitAddf(getRoundingMode(E), E))
+          return false;
+      } else {
+        if (!this->emitAdd(LHSElemT, E))
+          return false;
+      }
+      break;
+    case BO_Sub:
+      if (LHSElemT == PT_Float) {
+        if (!this->emitSubf(getRoundingMode(E), E))
+          return false;
+      } else {
+        if (!this->emitSub(LHSElemT, E))
+          return false;
+      }
+      break;
+
+    default:
+      return false;
+    }
+
+    if (!this->DiscardResult) {
+      // Initialize array element with the value we just computed.
+      if (!this->emitInitElemPop(LHSElemT, ElemIndex, E))
+        return false;
+    } else {
+      if (!this->emitPop(LHSElemT, E))
+        return false;
+    }
+  }
+  return true;
+}
+
 template <class Emitter>
 bool ByteCodeExprGen<Emitter>::VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E) {
   QualType QT = E->getType();

diff  --git a/clang/lib/AST/Interp/ByteCodeExprGen.h b/clang/lib/AST/Interp/ByteCodeExprGen.h
index 1c4739544454af..bbb13e97e72569 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.h
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.h
@@ -65,6 +65,7 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
   bool VisitBinaryOperator(const BinaryOperator *E);
   bool VisitLogicalBinOp(const BinaryOperator *E);
   bool VisitPointerArithBinOp(const BinaryOperator *E);
+  bool VisitComplexBinOp(const BinaryOperator *E);
   bool VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E);
   bool VisitCallExpr(const CallExpr *E);
   bool VisitBuiltinCallExpr(const CallExpr *E);

diff  --git a/clang/test/AST/Interp/complex.cpp b/clang/test/AST/Interp/complex.cpp
index 1eb70a1b9ce3b4..66490e973988bb 100644
--- a/clang/test/AST/Interp/complex.cpp
+++ b/clang/test/AST/Interp/complex.cpp
@@ -78,3 +78,49 @@ namespace CastToBool {
   constexpr _Complex double F9 = {0, 0};
   static_assert(!F9, "");
 }
+
+namespace BinOps {
+namespace Add {
+  constexpr _Complex float A = { 13.0, 2.0 };
+  constexpr _Complex float B = { 2.0, 1.0  };
+  constexpr _Complex float C = A + B;
+  static_assert(__real(C) == 15.0, "");
+  static_assert(__imag(C) == 3.0, "");
+
+  constexpr _Complex float D = B + A;
+  static_assert(__real(D) == 15.0, "");
+  static_assert(__imag(D) == 3.0, "");
+
+  constexpr _Complex unsigned int I1 = { 5,  10 };
+  constexpr _Complex unsigned int I2 = { 40, 2  };
+  constexpr _Complex unsigned int I3 = I1 + I2;
+  static_assert(__real(I3) == 45, "");
+  static_assert(__imag(I3) == 12, "");
+}
+
+namespace Sub {
+  constexpr _Complex float A = { 13.0, 2.0 };
+  constexpr _Complex float B = { 2.0, 1.0  };
+  constexpr _Complex float C = A - B;
+  static_assert(__real(C) == 11.0, "");
+  static_assert(__imag(C) == 1.0, "");
+
+  constexpr _Complex float D = B - A;
+  static_assert(__real(D) == -11.0, "");
+  static_assert(__imag(D) == -1.0, "");
+
+  constexpr _Complex unsigned int I1 = { 5,  10 };
+  constexpr _Complex unsigned int I2 = { 40, 2  };
+  constexpr _Complex unsigned int I3 = I1 - I2;
+  static_assert(__real(I3) == -35, "");
+  static_assert(__imag(I3) == 8, "");
+
+  using Bobble = _Complex float;
+  constexpr _Complex float A_ = { 13.0, 2.0 };
+  constexpr Bobble B_ = { 2.0, 1.0  };
+  constexpr _Complex float D_ = A_ - B_;
+  static_assert(__real(D_) == 11.0, "");
+  static_assert(__imag(D_) == 1.0, "");
+}
+
+}


        


More information about the cfe-commits mailing list