[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