[clang] 486adc5 - Revert "[clang][Interp][NFC] Move _Complex compiler code to separate file (#103004)"

Timm Bäder via cfe-commits cfe-commits at lists.llvm.org
Wed Aug 14 06:33:25 PDT 2024


Author: Timm Bäder
Date: 2024-08-14T15:32:56+02:00
New Revision: 486adc500c8ecb855936830e380ea2d3c3bfb137

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

LOG: Revert "[clang][Interp][NFC] Move _Complex compiler code to separate file (#103004)"

This reverts commit 2d53f0aab7851b09e8773eb1ca8bd1aa85d20d4b.

This causes warnings when building with MSVC.

Added: 
    

Modified: 
    clang/lib/AST/CMakeLists.txt
    clang/lib/AST/Interp/Compiler.cpp

Removed: 
    clang/lib/AST/Interp/CompilerComplex.cpp


################################################################################
diff  --git a/clang/lib/AST/CMakeLists.txt b/clang/lib/AST/CMakeLists.txt
index 44d944d4e948cb..70aecb781c2ff2 100644
--- a/clang/lib/AST/CMakeLists.txt
+++ b/clang/lib/AST/CMakeLists.txt
@@ -66,7 +66,6 @@ add_clang_library(clangAST
   InheritViz.cpp
   Interp/ByteCodeEmitter.cpp
   Interp/Compiler.cpp
-  Interp/CompilerComplex.cpp
   Interp/Context.cpp
   Interp/Descriptor.cpp
   Interp/Disasm.cpp

diff  --git a/clang/lib/AST/Interp/Compiler.cpp b/clang/lib/AST/Interp/Compiler.cpp
index 3b42590a61eb50..d32b595f9f0724 100644
--- a/clang/lib/AST/Interp/Compiler.cpp
+++ b/clang/lib/AST/Interp/Compiler.cpp
@@ -982,6 +982,234 @@ bool Compiler<Emitter>::VisitLogicalBinOp(const BinaryOperator *E) {
   return true;
 }
 
+template <class Emitter>
+bool Compiler<Emitter>::VisitComplexBinOp(const BinaryOperator *E) {
+  // Prepare storage for result.
+  if (!Initializing) {
+    std::optional<unsigned> LocalIndex = allocateLocal(E);
+    if (!LocalIndex)
+      return false;
+    if (!this->emitGetPtrLocal(*LocalIndex, E))
+      return false;
+  }
+
+  // Both LHS and RHS might _not_ be of complex type, but one of them
+  // needs to be.
+  const Expr *LHS = E->getLHS();
+  const Expr *RHS = E->getRHS();
+
+  PrimType ResultElemT = this->classifyComplexElementType(E->getType());
+  unsigned ResultOffset = ~0u;
+  if (!DiscardResult)
+    ResultOffset = this->allocateLocalPrimitive(E, PT_Ptr, true, false);
+
+  // Save result pointer in ResultOffset
+  if (!this->DiscardResult) {
+    if (!this->emitDupPtr(E))
+      return false;
+    if (!this->emitSetLocal(PT_Ptr, ResultOffset, E))
+      return false;
+  }
+  QualType LHSType = LHS->getType();
+  if (const auto *AT = LHSType->getAs<AtomicType>())
+    LHSType = AT->getValueType();
+  QualType RHSType = RHS->getType();
+  if (const auto *AT = RHSType->getAs<AtomicType>())
+    RHSType = AT->getValueType();
+
+  bool LHSIsComplex = LHSType->isAnyComplexType();
+  unsigned LHSOffset;
+  bool RHSIsComplex = RHSType->isAnyComplexType();
+
+  // For ComplexComplex Mul, we have special ops to make their implementation
+  // easier.
+  BinaryOperatorKind Op = E->getOpcode();
+  if (Op == BO_Mul && LHSIsComplex && RHSIsComplex) {
+    assert(classifyPrim(LHSType->getAs<ComplexType>()->getElementType()) ==
+           classifyPrim(RHSType->getAs<ComplexType>()->getElementType()));
+    PrimType ElemT =
+        classifyPrim(LHSType->getAs<ComplexType>()->getElementType());
+    if (!this->visit(LHS))
+      return false;
+    if (!this->visit(RHS))
+      return false;
+    return this->emitMulc(ElemT, E);
+  }
+
+  if (Op == BO_Div && RHSIsComplex) {
+    QualType ElemQT = RHSType->getAs<ComplexType>()->getElementType();
+    PrimType ElemT = classifyPrim(ElemQT);
+    // If the LHS is not complex, we still need to do the full complex
+    // division, so just stub create a complex value and stub it out with
+    // the LHS and a zero.
+
+    if (!LHSIsComplex) {
+      // This is using the RHS type for the fake-complex LHS.
+      if (auto LHSO = allocateLocal(RHS))
+        LHSOffset = *LHSO;
+      else
+        return false;
+
+      if (!this->emitGetPtrLocal(LHSOffset, E))
+        return false;
+
+      if (!this->visit(LHS))
+        return false;
+      // real is LHS
+      if (!this->emitInitElem(ElemT, 0, E))
+        return false;
+      // imag is zero
+      if (!this->visitZeroInitializer(ElemT, ElemQT, E))
+        return false;
+      if (!this->emitInitElem(ElemT, 1, E))
+        return false;
+    } else {
+      if (!this->visit(LHS))
+        return false;
+    }
+
+    if (!this->visit(RHS))
+      return false;
+    return this->emitDivc(ElemT, E);
+  }
+
+  // Evaluate LHS and save value to LHSOffset.
+  if (LHSType->isAnyComplexType()) {
+    LHSOffset = this->allocateLocalPrimitive(LHS, PT_Ptr, true, false);
+    if (!this->visit(LHS))
+      return false;
+    if (!this->emitSetLocal(PT_Ptr, LHSOffset, E))
+      return false;
+  } else {
+    PrimType LHST = classifyPrim(LHSType);
+    LHSOffset = this->allocateLocalPrimitive(LHS, LHST, true, false);
+    if (!this->visit(LHS))
+      return false;
+    if (!this->emitSetLocal(LHST, LHSOffset, E))
+      return false;
+  }
+
+  // Same with RHS.
+  unsigned RHSOffset;
+  if (RHSType->isAnyComplexType()) {
+    RHSOffset = this->allocateLocalPrimitive(RHS, PT_Ptr, true, false);
+    if (!this->visit(RHS))
+      return false;
+    if (!this->emitSetLocal(PT_Ptr, RHSOffset, E))
+      return false;
+  } else {
+    PrimType RHST = classifyPrim(RHSType);
+    RHSOffset = this->allocateLocalPrimitive(RHS, RHST, true, false);
+    if (!this->visit(RHS))
+      return false;
+    if (!this->emitSetLocal(RHST, RHSOffset, E))
+      return false;
+  }
+
+  // For both LHS and RHS, either load the value from the complex pointer, or
+  // directly from the local variable. For index 1 (i.e. the imaginary part),
+  // just load 0 and do the operation anyway.
+  auto loadComplexValue = [this](bool IsComplex, bool LoadZero,
+                                 unsigned ElemIndex, unsigned Offset,
+                                 const Expr *E) -> bool {
+    if (IsComplex) {
+      if (!this->emitGetLocal(PT_Ptr, Offset, E))
+        return false;
+      return this->emitArrayElemPop(classifyComplexElementType(E->getType()),
+                                    ElemIndex, E);
+    }
+    if (ElemIndex == 0 || !LoadZero)
+      return this->emitGetLocal(classifyPrim(E->getType()), Offset, E);
+    return this->visitZeroInitializer(classifyPrim(E->getType()), E->getType(),
+                                      E);
+  };
+
+  // Now we can get pointers to the LHS and RHS from the offsets above.
+  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;
+    }
+
+    // The actual operation.
+    switch (Op) {
+    case BO_Add:
+      if (!loadComplexValue(LHSIsComplex, true, ElemIndex, LHSOffset, LHS))
+        return false;
+
+      if (!loadComplexValue(RHSIsComplex, true, ElemIndex, RHSOffset, RHS))
+        return false;
+      if (ResultElemT == PT_Float) {
+        if (!this->emitAddf(getRoundingMode(E), E))
+          return false;
+      } else {
+        if (!this->emitAdd(ResultElemT, E))
+          return false;
+      }
+      break;
+    case BO_Sub:
+      if (!loadComplexValue(LHSIsComplex, true, ElemIndex, LHSOffset, LHS))
+        return false;
+
+      if (!loadComplexValue(RHSIsComplex, true, ElemIndex, RHSOffset, RHS))
+        return false;
+      if (ResultElemT == PT_Float) {
+        if (!this->emitSubf(getRoundingMode(E), E))
+          return false;
+      } else {
+        if (!this->emitSub(ResultElemT, E))
+          return false;
+      }
+      break;
+    case BO_Mul:
+      if (!loadComplexValue(LHSIsComplex, false, ElemIndex, LHSOffset, LHS))
+        return false;
+
+      if (!loadComplexValue(RHSIsComplex, false, ElemIndex, RHSOffset, RHS))
+        return false;
+
+      if (ResultElemT == PT_Float) {
+        if (!this->emitMulf(getRoundingMode(E), E))
+          return false;
+      } else {
+        if (!this->emitMul(ResultElemT, E))
+          return false;
+      }
+      break;
+    case BO_Div:
+      assert(!RHSIsComplex);
+      if (!loadComplexValue(LHSIsComplex, false, ElemIndex, LHSOffset, LHS))
+        return false;
+
+      if (!loadComplexValue(RHSIsComplex, false, ElemIndex, RHSOffset, RHS))
+        return false;
+
+      if (ResultElemT == PT_Float) {
+        if (!this->emitDivf(getRoundingMode(E), E))
+          return false;
+      } else {
+        if (!this->emitDiv(ResultElemT, E))
+          return false;
+      }
+      break;
+
+    default:
+      return false;
+    }
+
+    if (!this->DiscardResult) {
+      // Initialize array element with the value we just computed.
+      if (!this->emitInitElemPop(ResultElemT, ElemIndex, E))
+        return false;
+    } else {
+      if (!this->emitPop(ResultElemT, E))
+        return false;
+    }
+  }
+  return true;
+}
+
 template <class Emitter>
 bool Compiler<Emitter>::VisitImplicitValueInitExpr(
     const ImplicitValueInitExpr *E) {
@@ -4917,6 +5145,113 @@ bool Compiler<Emitter>::VisitUnaryOperator(const UnaryOperator *E) {
   return false;
 }
 
+template <class Emitter>
+bool Compiler<Emitter>::VisitComplexUnaryOperator(const UnaryOperator *E) {
+  const Expr *SubExpr = E->getSubExpr();
+  assert(SubExpr->getType()->isAnyComplexType());
+
+  if (DiscardResult)
+    return this->discard(SubExpr);
+
+  std::optional<PrimType> ResT = classify(E);
+  auto prepareResult = [=]() -> bool {
+    if (!ResT && !Initializing) {
+      std::optional<unsigned> LocalIndex = allocateLocal(SubExpr);
+      if (!LocalIndex)
+        return false;
+      return this->emitGetPtrLocal(*LocalIndex, E);
+    }
+
+    return true;
+  };
+
+  // The offset of the temporary, if we created one.
+  unsigned SubExprOffset = ~0u;
+  auto createTemp = [=, &SubExprOffset]() -> bool {
+    SubExprOffset = this->allocateLocalPrimitive(SubExpr, PT_Ptr, true, false);
+    if (!this->visit(SubExpr))
+      return false;
+    return this->emitSetLocal(PT_Ptr, SubExprOffset, E);
+  };
+
+  PrimType ElemT = classifyComplexElementType(SubExpr->getType());
+  auto getElem = [=](unsigned Offset, unsigned Index) -> bool {
+    if (!this->emitGetLocal(PT_Ptr, Offset, E))
+      return false;
+    return this->emitArrayElemPop(ElemT, Index, E);
+  };
+
+  switch (E->getOpcode()) {
+  case UO_Minus:
+    if (!prepareResult())
+      return false;
+    if (!createTemp())
+      return false;
+    for (unsigned I = 0; I != 2; ++I) {
+      if (!getElem(SubExprOffset, I))
+        return false;
+      if (!this->emitNeg(ElemT, E))
+        return false;
+      if (!this->emitInitElem(ElemT, I, E))
+        return false;
+    }
+    break;
+
+  case UO_Plus:   // +x
+  case UO_AddrOf: // &x
+  case UO_Deref:  // *x
+    return this->delegate(SubExpr);
+
+  case UO_LNot:
+    if (!this->visit(SubExpr))
+      return false;
+    if (!this->emitComplexBoolCast(SubExpr))
+      return false;
+    if (!this->emitInvBool(E))
+      return false;
+    if (PrimType ET = classifyPrim(E->getType()); ET != PT_Bool)
+      return this->emitCast(PT_Bool, ET, E);
+    return true;
+
+  case UO_Real:
+    return this->emitComplexReal(SubExpr);
+
+  case UO_Imag:
+    if (!this->visit(SubExpr))
+      return false;
+
+    if (SubExpr->isLValue()) {
+      if (!this->emitConstUint8(1, E))
+        return false;
+      return this->emitArrayElemPtrPopUint8(E);
+    }
+
+    // Since our _Complex implementation does not map to a primitive type,
+    // we sometimes have to do the lvalue-to-rvalue conversion here manually.
+    return this->emitArrayElemPop(classifyPrim(E->getType()), 1, E);
+
+  case UO_Not: // ~x
+    if (!this->visit(SubExpr))
+      return false;
+    // Negate the imaginary component.
+    if (!this->emitArrayElem(ElemT, 1, E))
+      return false;
+    if (!this->emitNeg(ElemT, E))
+      return false;
+    if (!this->emitInitElem(ElemT, 1, E))
+      return false;
+    return DiscardResult ? this->emitPopPtr(E) : true;
+
+  case UO_Extension:
+    return this->delegate(SubExpr);
+
+  default:
+    return this->emitInvalid(E);
+  }
+
+  return true;
+}
+
 template <class Emitter>
 bool Compiler<Emitter>::visitDeclRef(const ValueDecl *D, const Expr *E) {
   if (DiscardResult)
@@ -5116,6 +5451,168 @@ bool Compiler<Emitter>::emitPrimCast(PrimType FromT, PrimType ToT,
   return false;
 }
 
+/// Emits __real(SubExpr)
+template <class Emitter>
+bool Compiler<Emitter>::emitComplexReal(const Expr *SubExpr) {
+  assert(SubExpr->getType()->isAnyComplexType());
+
+  if (DiscardResult)
+    return this->discard(SubExpr);
+
+  if (!this->visit(SubExpr))
+    return false;
+  if (SubExpr->isLValue()) {
+    if (!this->emitConstUint8(0, SubExpr))
+      return false;
+    return this->emitArrayElemPtrPopUint8(SubExpr);
+  }
+
+  // Rvalue, load the actual element.
+  return this->emitArrayElemPop(classifyComplexElementType(SubExpr->getType()),
+                                0, SubExpr);
+}
+
+template <class Emitter>
+bool Compiler<Emitter>::emitComplexBoolCast(const Expr *E) {
+  assert(!DiscardResult);
+  PrimType ElemT = classifyComplexElementType(E->getType());
+  // We emit the expression (__real(E) != 0 || __imag(E) != 0)
+  // for us, that means (bool)E[0] || (bool)E[1]
+  if (!this->emitArrayElem(ElemT, 0, E))
+    return false;
+  if (ElemT == PT_Float) {
+    if (!this->emitCastFloatingIntegral(PT_Bool, E))
+      return false;
+  } else {
+    if (!this->emitCast(ElemT, PT_Bool, E))
+      return false;
+  }
+
+  // We now have the bool value of E[0] on the stack.
+  LabelTy LabelTrue = this->getLabel();
+  if (!this->jumpTrue(LabelTrue))
+    return false;
+
+  if (!this->emitArrayElemPop(ElemT, 1, E))
+    return false;
+  if (ElemT == PT_Float) {
+    if (!this->emitCastFloatingIntegral(PT_Bool, E))
+      return false;
+  } else {
+    if (!this->emitCast(ElemT, PT_Bool, E))
+      return false;
+  }
+  // Leave the boolean value of E[1] on the stack.
+  LabelTy EndLabel = this->getLabel();
+  this->jump(EndLabel);
+
+  this->emitLabel(LabelTrue);
+  if (!this->emitPopPtr(E))
+    return false;
+  if (!this->emitConstBool(true, E))
+    return false;
+
+  this->fallthrough(EndLabel);
+  this->emitLabel(EndLabel);
+
+  return true;
+}
+
+template <class Emitter>
+bool Compiler<Emitter>::emitComplexComparison(const Expr *LHS, const Expr *RHS,
+                                              const BinaryOperator *E) {
+  assert(E->isComparisonOp());
+  assert(!Initializing);
+  assert(!DiscardResult);
+
+  PrimType ElemT;
+  bool LHSIsComplex;
+  unsigned LHSOffset;
+  if (LHS->getType()->isAnyComplexType()) {
+    LHSIsComplex = true;
+    ElemT = classifyComplexElementType(LHS->getType());
+    LHSOffset = allocateLocalPrimitive(LHS, PT_Ptr, /*IsConst=*/true,
+                                       /*IsExtended=*/false);
+    if (!this->visit(LHS))
+      return false;
+    if (!this->emitSetLocal(PT_Ptr, LHSOffset, E))
+      return false;
+  } else {
+    LHSIsComplex = false;
+    PrimType LHST = classifyPrim(LHS->getType());
+    LHSOffset = this->allocateLocalPrimitive(LHS, LHST, true, false);
+    if (!this->visit(LHS))
+      return false;
+    if (!this->emitSetLocal(LHST, LHSOffset, E))
+      return false;
+  }
+
+  bool RHSIsComplex;
+  unsigned RHSOffset;
+  if (RHS->getType()->isAnyComplexType()) {
+    RHSIsComplex = true;
+    ElemT = classifyComplexElementType(RHS->getType());
+    RHSOffset = allocateLocalPrimitive(RHS, PT_Ptr, /*IsConst=*/true,
+                                       /*IsExtended=*/false);
+    if (!this->visit(RHS))
+      return false;
+    if (!this->emitSetLocal(PT_Ptr, RHSOffset, E))
+      return false;
+  } else {
+    RHSIsComplex = false;
+    PrimType RHST = classifyPrim(RHS->getType());
+    RHSOffset = this->allocateLocalPrimitive(RHS, RHST, true, false);
+    if (!this->visit(RHS))
+      return false;
+    if (!this->emitSetLocal(RHST, RHSOffset, E))
+      return false;
+  }
+
+  auto getElem = [&](unsigned LocalOffset, unsigned Index,
+                     bool IsComplex) -> bool {
+    if (IsComplex) {
+      if (!this->emitGetLocal(PT_Ptr, LocalOffset, E))
+        return false;
+      return this->emitArrayElemPop(ElemT, Index, E);
+    }
+    return this->emitGetLocal(ElemT, LocalOffset, E);
+  };
+
+  for (unsigned I = 0; I != 2; ++I) {
+    // Get both values.
+    if (!getElem(LHSOffset, I, LHSIsComplex))
+      return false;
+    if (!getElem(RHSOffset, I, RHSIsComplex))
+      return false;
+    // And compare them.
+    if (!this->emitEQ(ElemT, E))
+      return false;
+
+    if (!this->emitCastBoolUint8(E))
+      return false;
+  }
+
+  // We now have two bool values on the stack. Compare those.
+  if (!this->emitAddUint8(E))
+    return false;
+  if (!this->emitConstUint8(2, E))
+    return false;
+
+  if (E->getOpcode() == BO_EQ) {
+    if (!this->emitEQUint8(E))
+      return false;
+  } else if (E->getOpcode() == BO_NE) {
+    if (!this->emitNEUint8(E))
+      return false;
+  } else
+    return false;
+
+  // In C, this returns an int.
+  if (PrimType ResT = classifyPrim(E->getType()); ResT != PT_Bool)
+    return this->emitCast(PT_Bool, ResT, E);
+  return true;
+}
+
 /// When calling this, we have a pointer of the local-to-destroy
 /// on the stack.
 /// Emit destruction of record types (or arrays of record types).

diff  --git a/clang/lib/AST/Interp/CompilerComplex.cpp b/clang/lib/AST/Interp/CompilerComplex.cpp
deleted file mode 100644
index e22c72785373d1..00000000000000
--- a/clang/lib/AST/Interp/CompilerComplex.cpp
+++ /dev/null
@@ -1,526 +0,0 @@
-//===--- CompilerComplex.cpp.cpp --------------------------------*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#include "ByteCodeEmitter.h"
-#include "Compiler.h"
-#include "Context.h"
-#include "Floating.h"
-#include "Function.h"
-#include "InterpShared.h"
-#include "PrimType.h"
-#include "Program.h"
-#include "clang/AST/Attr.h"
-
-using namespace clang;
-using namespace clang::interp;
-
-template <class Emitter>
-bool Compiler<Emitter>::VisitComplexBinOp(const BinaryOperator *E) {
-  // Prepare storage for result.
-  if (!Initializing) {
-    std::optional<unsigned> LocalIndex = allocateLocal(E);
-    if (!LocalIndex)
-      return false;
-    if (!this->emitGetPtrLocal(*LocalIndex, E))
-      return false;
-  }
-
-  // Both LHS and RHS might _not_ be of complex type, but one of them
-  // needs to be.
-  const Expr *LHS = E->getLHS();
-  const Expr *RHS = E->getRHS();
-
-  PrimType ResultElemT = this->classifyComplexElementType(E->getType());
-  unsigned ResultOffset = ~0u;
-  if (!DiscardResult)
-    ResultOffset = this->allocateLocalPrimitive(E, PT_Ptr, true, false);
-
-  // Save result pointer in ResultOffset
-  if (!this->DiscardResult) {
-    if (!this->emitDupPtr(E))
-      return false;
-    if (!this->emitSetLocal(PT_Ptr, ResultOffset, E))
-      return false;
-  }
-  QualType LHSType = LHS->getType();
-  if (const auto *AT = LHSType->getAs<AtomicType>())
-    LHSType = AT->getValueType();
-  QualType RHSType = RHS->getType();
-  if (const auto *AT = RHSType->getAs<AtomicType>())
-    RHSType = AT->getValueType();
-
-  bool LHSIsComplex = LHSType->isAnyComplexType();
-  unsigned LHSOffset;
-  bool RHSIsComplex = RHSType->isAnyComplexType();
-
-  // For ComplexComplex Mul, we have special ops to make their implementation
-  // easier.
-  BinaryOperatorKind Op = E->getOpcode();
-  if (Op == BO_Mul && LHSIsComplex && RHSIsComplex) {
-    assert(classifyPrim(LHSType->getAs<ComplexType>()->getElementType()) ==
-           classifyPrim(RHSType->getAs<ComplexType>()->getElementType()));
-    PrimType ElemT =
-        classifyPrim(LHSType->getAs<ComplexType>()->getElementType());
-    if (!this->visit(LHS))
-      return false;
-    if (!this->visit(RHS))
-      return false;
-    return this->emitMulc(ElemT, E);
-  }
-
-  if (Op == BO_Div && RHSIsComplex) {
-    QualType ElemQT = RHSType->getAs<ComplexType>()->getElementType();
-    PrimType ElemT = classifyPrim(ElemQT);
-    // If the LHS is not complex, we still need to do the full complex
-    // division, so just stub create a complex value and stub it out with
-    // the LHS and a zero.
-
-    if (!LHSIsComplex) {
-      // This is using the RHS type for the fake-complex LHS.
-      if (auto LHSO = allocateLocal(RHS))
-        LHSOffset = *LHSO;
-      else
-        return false;
-
-      if (!this->emitGetPtrLocal(LHSOffset, E))
-        return false;
-
-      if (!this->visit(LHS))
-        return false;
-      // real is LHS
-      if (!this->emitInitElem(ElemT, 0, E))
-        return false;
-      // imag is zero
-      if (!this->visitZeroInitializer(ElemT, ElemQT, E))
-        return false;
-      if (!this->emitInitElem(ElemT, 1, E))
-        return false;
-    } else {
-      if (!this->visit(LHS))
-        return false;
-    }
-
-    if (!this->visit(RHS))
-      return false;
-    return this->emitDivc(ElemT, E);
-  }
-
-  // Evaluate LHS and save value to LHSOffset.
-  if (LHSType->isAnyComplexType()) {
-    LHSOffset = this->allocateLocalPrimitive(LHS, PT_Ptr, true, false);
-    if (!this->visit(LHS))
-      return false;
-    if (!this->emitSetLocal(PT_Ptr, LHSOffset, E))
-      return false;
-  } else {
-    PrimType LHST = classifyPrim(LHSType);
-    LHSOffset = this->allocateLocalPrimitive(LHS, LHST, true, false);
-    if (!this->visit(LHS))
-      return false;
-    if (!this->emitSetLocal(LHST, LHSOffset, E))
-      return false;
-  }
-
-  // Same with RHS.
-  unsigned RHSOffset;
-  if (RHSType->isAnyComplexType()) {
-    RHSOffset = this->allocateLocalPrimitive(RHS, PT_Ptr, true, false);
-    if (!this->visit(RHS))
-      return false;
-    if (!this->emitSetLocal(PT_Ptr, RHSOffset, E))
-      return false;
-  } else {
-    PrimType RHST = classifyPrim(RHSType);
-    RHSOffset = this->allocateLocalPrimitive(RHS, RHST, true, false);
-    if (!this->visit(RHS))
-      return false;
-    if (!this->emitSetLocal(RHST, RHSOffset, E))
-      return false;
-  }
-
-  // For both LHS and RHS, either load the value from the complex pointer, or
-  // directly from the local variable. For index 1 (i.e. the imaginary part),
-  // just load 0 and do the operation anyway.
-  auto loadComplexValue = [this](bool IsComplex, bool LoadZero,
-                                 unsigned ElemIndex, unsigned Offset,
-                                 const Expr *E) -> bool {
-    if (IsComplex) {
-      if (!this->emitGetLocal(PT_Ptr, Offset, E))
-        return false;
-      return this->emitArrayElemPop(classifyComplexElementType(E->getType()),
-                                    ElemIndex, E);
-    }
-    if (ElemIndex == 0 || !LoadZero)
-      return this->emitGetLocal(classifyPrim(E->getType()), Offset, E);
-    return this->visitZeroInitializer(classifyPrim(E->getType()), E->getType(),
-                                      E);
-  };
-
-  // Now we can get pointers to the LHS and RHS from the offsets above.
-  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;
-    }
-
-    // The actual operation.
-    switch (Op) {
-    case BO_Add:
-      if (!loadComplexValue(LHSIsComplex, true, ElemIndex, LHSOffset, LHS))
-        return false;
-
-      if (!loadComplexValue(RHSIsComplex, true, ElemIndex, RHSOffset, RHS))
-        return false;
-      if (ResultElemT == PT_Float) {
-        if (!this->emitAddf(getRoundingMode(E), E))
-          return false;
-      } else {
-        if (!this->emitAdd(ResultElemT, E))
-          return false;
-      }
-      break;
-    case BO_Sub:
-      if (!loadComplexValue(LHSIsComplex, true, ElemIndex, LHSOffset, LHS))
-        return false;
-
-      if (!loadComplexValue(RHSIsComplex, true, ElemIndex, RHSOffset, RHS))
-        return false;
-      if (ResultElemT == PT_Float) {
-        if (!this->emitSubf(getRoundingMode(E), E))
-          return false;
-      } else {
-        if (!this->emitSub(ResultElemT, E))
-          return false;
-      }
-      break;
-    case BO_Mul:
-      if (!loadComplexValue(LHSIsComplex, false, ElemIndex, LHSOffset, LHS))
-        return false;
-
-      if (!loadComplexValue(RHSIsComplex, false, ElemIndex, RHSOffset, RHS))
-        return false;
-
-      if (ResultElemT == PT_Float) {
-        if (!this->emitMulf(getRoundingMode(E), E))
-          return false;
-      } else {
-        if (!this->emitMul(ResultElemT, E))
-          return false;
-      }
-      break;
-    case BO_Div:
-      assert(!RHSIsComplex);
-      if (!loadComplexValue(LHSIsComplex, false, ElemIndex, LHSOffset, LHS))
-        return false;
-
-      if (!loadComplexValue(RHSIsComplex, false, ElemIndex, RHSOffset, RHS))
-        return false;
-
-      if (ResultElemT == PT_Float) {
-        if (!this->emitDivf(getRoundingMode(E), E))
-          return false;
-      } else {
-        if (!this->emitDiv(ResultElemT, E))
-          return false;
-      }
-      break;
-
-    default:
-      return false;
-    }
-
-    if (!this->DiscardResult) {
-      // Initialize array element with the value we just computed.
-      if (!this->emitInitElemPop(ResultElemT, ElemIndex, E))
-        return false;
-    } else {
-      if (!this->emitPop(ResultElemT, E))
-        return false;
-    }
-  }
-  return true;
-}
-
-template <class Emitter>
-bool Compiler<Emitter>::emitComplexComparison(const Expr *LHS, const Expr *RHS,
-                                              const BinaryOperator *E) {
-  assert(E->isComparisonOp());
-  assert(!Initializing);
-  assert(!DiscardResult);
-
-  PrimType ElemT;
-  bool LHSIsComplex;
-  unsigned LHSOffset;
-  if (LHS->getType()->isAnyComplexType()) {
-    LHSIsComplex = true;
-    ElemT = classifyComplexElementType(LHS->getType());
-    LHSOffset = allocateLocalPrimitive(LHS, PT_Ptr, /*IsConst=*/true,
-                                       /*IsExtended=*/false);
-    if (!this->visit(LHS))
-      return false;
-    if (!this->emitSetLocal(PT_Ptr, LHSOffset, E))
-      return false;
-  } else {
-    LHSIsComplex = false;
-    PrimType LHST = classifyPrim(LHS->getType());
-    LHSOffset = this->allocateLocalPrimitive(LHS, LHST, true, false);
-    if (!this->visit(LHS))
-      return false;
-    if (!this->emitSetLocal(LHST, LHSOffset, E))
-      return false;
-  }
-
-  bool RHSIsComplex;
-  unsigned RHSOffset;
-  if (RHS->getType()->isAnyComplexType()) {
-    RHSIsComplex = true;
-    ElemT = classifyComplexElementType(RHS->getType());
-    RHSOffset = allocateLocalPrimitive(RHS, PT_Ptr, /*IsConst=*/true,
-                                       /*IsExtended=*/false);
-    if (!this->visit(RHS))
-      return false;
-    if (!this->emitSetLocal(PT_Ptr, RHSOffset, E))
-      return false;
-  } else {
-    RHSIsComplex = false;
-    PrimType RHST = classifyPrim(RHS->getType());
-    RHSOffset = this->allocateLocalPrimitive(RHS, RHST, true, false);
-    if (!this->visit(RHS))
-      return false;
-    if (!this->emitSetLocal(RHST, RHSOffset, E))
-      return false;
-  }
-
-  auto getElem = [&](unsigned LocalOffset, unsigned Index,
-                     bool IsComplex) -> bool {
-    if (IsComplex) {
-      if (!this->emitGetLocal(PT_Ptr, LocalOffset, E))
-        return false;
-      return this->emitArrayElemPop(ElemT, Index, E);
-    }
-    return this->emitGetLocal(ElemT, LocalOffset, E);
-  };
-
-  for (unsigned I = 0; I != 2; ++I) {
-    // Get both values.
-    if (!getElem(LHSOffset, I, LHSIsComplex))
-      return false;
-    if (!getElem(RHSOffset, I, RHSIsComplex))
-      return false;
-    // And compare them.
-    if (!this->emitEQ(ElemT, E))
-      return false;
-
-    if (!this->emitCastBoolUint8(E))
-      return false;
-  }
-
-  // We now have two bool values on the stack. Compare those.
-  if (!this->emitAddUint8(E))
-    return false;
-  if (!this->emitConstUint8(2, E))
-    return false;
-
-  if (E->getOpcode() == BO_EQ) {
-    if (!this->emitEQUint8(E))
-      return false;
-  } else if (E->getOpcode() == BO_NE) {
-    if (!this->emitNEUint8(E))
-      return false;
-  } else
-    return false;
-
-  // In C, this returns an int.
-  if (PrimType ResT = classifyPrim(E->getType()); ResT != PT_Bool)
-    return this->emitCast(PT_Bool, ResT, E);
-  return true;
-}
-
-/// Emits __real(SubExpr)
-template <class Emitter>
-bool Compiler<Emitter>::emitComplexReal(const Expr *SubExpr) {
-  assert(SubExpr->getType()->isAnyComplexType());
-
-  if (DiscardResult)
-    return this->discard(SubExpr);
-
-  if (!this->visit(SubExpr))
-    return false;
-  if (SubExpr->isLValue()) {
-    if (!this->emitConstUint8(0, SubExpr))
-      return false;
-    return this->emitArrayElemPtrPopUint8(SubExpr);
-  }
-
-  // Rvalue, load the actual element.
-  return this->emitArrayElemPop(classifyComplexElementType(SubExpr->getType()),
-                                0, SubExpr);
-}
-
-template <class Emitter>
-bool Compiler<Emitter>::emitComplexBoolCast(const Expr *E) {
-  assert(!DiscardResult);
-  PrimType ElemT = classifyComplexElementType(E->getType());
-  // We emit the expression (__real(E) != 0 || __imag(E) != 0)
-  // for us, that means (bool)E[0] || (bool)E[1]
-  if (!this->emitArrayElem(ElemT, 0, E))
-    return false;
-  if (ElemT == PT_Float) {
-    if (!this->emitCastFloatingIntegral(PT_Bool, E))
-      return false;
-  } else {
-    if (!this->emitCast(ElemT, PT_Bool, E))
-      return false;
-  }
-
-  // We now have the bool value of E[0] on the stack.
-  LabelTy LabelTrue = this->getLabel();
-  if (!this->jumpTrue(LabelTrue))
-    return false;
-
-  if (!this->emitArrayElemPop(ElemT, 1, E))
-    return false;
-  if (ElemT == PT_Float) {
-    if (!this->emitCastFloatingIntegral(PT_Bool, E))
-      return false;
-  } else {
-    if (!this->emitCast(ElemT, PT_Bool, E))
-      return false;
-  }
-  // Leave the boolean value of E[1] on the stack.
-  LabelTy EndLabel = this->getLabel();
-  this->jump(EndLabel);
-
-  this->emitLabel(LabelTrue);
-  if (!this->emitPopPtr(E))
-    return false;
-  if (!this->emitConstBool(true, E))
-    return false;
-
-  this->fallthrough(EndLabel);
-  this->emitLabel(EndLabel);
-
-  return true;
-}
-
-template <class Emitter>
-bool Compiler<Emitter>::VisitComplexUnaryOperator(const UnaryOperator *E) {
-  const Expr *SubExpr = E->getSubExpr();
-  assert(SubExpr->getType()->isAnyComplexType());
-
-  if (DiscardResult)
-    return this->discard(SubExpr);
-
-  std::optional<PrimType> ResT = classify(E);
-  auto prepareResult = [=]() -> bool {
-    if (!ResT && !Initializing) {
-      std::optional<unsigned> LocalIndex = allocateLocal(SubExpr);
-      if (!LocalIndex)
-        return false;
-      return this->emitGetPtrLocal(*LocalIndex, E);
-    }
-
-    return true;
-  };
-
-  // The offset of the temporary, if we created one.
-  unsigned SubExprOffset = ~0u;
-  auto createTemp = [=, &SubExprOffset]() -> bool {
-    SubExprOffset = this->allocateLocalPrimitive(SubExpr, PT_Ptr, true, false);
-    if (!this->visit(SubExpr))
-      return false;
-    return this->emitSetLocal(PT_Ptr, SubExprOffset, E);
-  };
-
-  PrimType ElemT = classifyComplexElementType(SubExpr->getType());
-  auto getElem = [=](unsigned Offset, unsigned Index) -> bool {
-    if (!this->emitGetLocal(PT_Ptr, Offset, E))
-      return false;
-    return this->emitArrayElemPop(ElemT, Index, E);
-  };
-
-  switch (E->getOpcode()) {
-  case UO_Minus:
-    if (!prepareResult())
-      return false;
-    if (!createTemp())
-      return false;
-    for (unsigned I = 0; I != 2; ++I) {
-      if (!getElem(SubExprOffset, I))
-        return false;
-      if (!this->emitNeg(ElemT, E))
-        return false;
-      if (!this->emitInitElem(ElemT, I, E))
-        return false;
-    }
-    break;
-
-  case UO_Plus:   // +x
-  case UO_AddrOf: // &x
-  case UO_Deref:  // *x
-    return this->delegate(SubExpr);
-
-  case UO_LNot:
-    if (!this->visit(SubExpr))
-      return false;
-    if (!this->emitComplexBoolCast(SubExpr))
-      return false;
-    if (!this->emitInvBool(E))
-      return false;
-    if (PrimType ET = classifyPrim(E->getType()); ET != PT_Bool)
-      return this->emitCast(PT_Bool, ET, E);
-    return true;
-
-  case UO_Real:
-    return this->emitComplexReal(SubExpr);
-
-  case UO_Imag:
-    if (!this->visit(SubExpr))
-      return false;
-
-    if (SubExpr->isLValue()) {
-      if (!this->emitConstUint8(1, E))
-        return false;
-      return this->emitArrayElemPtrPopUint8(E);
-    }
-
-    // Since our _Complex implementation does not map to a primitive type,
-    // we sometimes have to do the lvalue-to-rvalue conversion here manually.
-    return this->emitArrayElemPop(classifyPrim(E->getType()), 1, E);
-
-  case UO_Not: // ~x
-    if (!this->visit(SubExpr))
-      return false;
-    // Negate the imaginary component.
-    if (!this->emitArrayElem(ElemT, 1, E))
-      return false;
-    if (!this->emitNeg(ElemT, E))
-      return false;
-    if (!this->emitInitElem(ElemT, 1, E))
-      return false;
-    return DiscardResult ? this->emitPopPtr(E) : true;
-
-  case UO_Extension:
-    return this->delegate(SubExpr);
-
-  default:
-    return this->emitInvalid(E);
-  }
-
-  return true;
-}
-
-namespace clang {
-namespace interp {
-
-template class Compiler<ByteCodeEmitter>;
-template class Compiler<EvalEmitter>;
-
-} // namespace interp
-} // namespace clang


        


More information about the cfe-commits mailing list