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 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits