Author: Timm Bäder Date: 2024-03-07T17:04:05+01:00 New Revision: 8aed911fe91bb6cbfb95789683dadf3e77ea713a
URL: https://github.com/llvm/llvm-project/commit/8aed911fe91bb6cbfb95789683dadf3e77ea713a DIFF: https://github.com/llvm/llvm-project/commit/8aed911fe91bb6cbfb95789683dadf3e77ea713a.diff LOG: [clang][Interp] Implement complex comparisons Added: Modified: clang/lib/AST/Interp/ByteCodeExprGen.cpp clang/lib/AST/Interp/ByteCodeExprGen.h clang/test/AST/Interp/complex.c clang/test/AST/Interp/complex.cpp Removed: ################################################################################ diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp index d887170cbc5d2d..8872579e12dc82 100644 --- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -393,12 +393,16 @@ bool ByteCodeExprGen<Emitter>::VisitBinaryOperator(const BinaryOperator *BO) { if (BO->isLogicalOp()) return this->VisitLogicalBinOp(BO); - if (BO->getType()->isAnyComplexType()) - return this->VisitComplexBinOp(BO); - const Expr *LHS = BO->getLHS(); const Expr *RHS = BO->getRHS(); + if (BO->getType()->isAnyComplexType()) + return this->VisitComplexBinOp(BO); + if ((LHS->getType()->isAnyComplexType() || + RHS->getType()->isAnyComplexType()) && + BO->isComparisonOp()) + return this->emitComplexComparison(LHS, RHS, BO); + if (BO->isPtrMemOp()) return this->visit(RHS); @@ -3410,6 +3414,102 @@ bool ByteCodeExprGen<Emitter>::emitComplexBoolCast(const Expr *E) { return true; } +template <class Emitter> +bool ByteCodeExprGen<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/ByteCodeExprGen.h b/clang/lib/AST/Interp/ByteCodeExprGen.h index acbbcc3dc9619a..5977bb5e6ff25d 100644 --- a/clang/lib/AST/Interp/ByteCodeExprGen.h +++ b/clang/lib/AST/Interp/ByteCodeExprGen.h @@ -268,6 +268,8 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>, bool emitComplexReal(const Expr *SubExpr); bool emitComplexBoolCast(const Expr *E); + bool emitComplexComparison(const Expr *LHS, const Expr *RHS, + const BinaryOperator *E); bool emitRecordDestruction(const Record *R); bool emitDestruction(const Descriptor *Desc); diff --git a/clang/test/AST/Interp/complex.c b/clang/test/AST/Interp/complex.c index b07d0241da12d6..c9c2efb5974531 100644 --- a/clang/test/AST/Interp/complex.c +++ b/clang/test/AST/Interp/complex.c @@ -1,9 +1,6 @@ // RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify=expected,both -Wno-unused-value %s // RUN: %clang_cc1 -verify=ref,both -Wno-unused-value %s -// expected-no-diagnostics -// ref-no-diagnostics - void blah() { __complex__ unsigned xx; __complex__ signed yy; @@ -12,3 +9,8 @@ void blah() { /// The following line calls into the constant interpreter. result = xx * yy; } + + +_Static_assert((0.0 + 0.0j) == (0.0 + 0.0j), ""); +_Static_assert((0.0 + 0.0j) != (0.0 + 0.0j), ""); // both-error {{static assertion}} \ + // both-note {{evaluates to}} diff --git a/clang/test/AST/Interp/complex.cpp b/clang/test/AST/Interp/complex.cpp index 8acce7b734d85a..6a42afc68d26c7 100644 --- a/clang/test/AST/Interp/complex.cpp +++ b/clang/test/AST/Interp/complex.cpp @@ -266,3 +266,50 @@ namespace Builtin { constexpr _Complex float C = __builtin_complex(10.0f, 20.0); // both-error {{arguments are of diff erent types}} } + +namespace Cmp { + static_assert((0.0 + 0.0j) == (0.0 + 0.0j)); + static_assert((0.0 + 0.0j) != (0.0 + 0.0j)); // both-error {{static assertion}} \ + // both-note {{evaluates to}} + + static_assert((0.0 + 0.0j) == 0.0); + static_assert(0.0 == (0.0 + 0.0j)); + static_assert(0.0 == 0.0j); + static_assert((0.0 + 1.0j) != 0.0); + static_assert(1.0 != (0.0 + 0.0j)); + static_assert(0.0 != 1.0j); + + // Walk around the complex plane stepping between angular diff erences and + // equality. + static_assert((1.0 + 0.0j) == (0.0 + 0.0j)); // both-error {{static assertion}} \ + // both-note {{evaluates to}} + static_assert((1.0 + 0.0j) == (1.0 + 0.0j)); + static_assert((1.0 + 1.0j) == (1.0 + 0.0j)); // both-error {{static assertion}} \ + // both-note {{evaluates to}} + static_assert((1.0 + 1.0j) == (1.0 + 1.0j)); + static_assert((0.0 + 1.0j) == (1.0 + 1.0j)); // both-error {{static assertion}} \ + // both-note {{evaluates to}} + static_assert((0.0 + 1.0j) == (0.0 + 1.0j)); + static_assert((-1.0 + 1.0j) == (0.0 + 1.0j)); // both-error {{static assertion}} \ + // both-note {{evaluates to}} + static_assert((-1.0 + 1.0j) == (-1.0 + 1.0j)); + static_assert((-1.0 + 0.0j) == (-1.0 + 1.0j)); // both-error {{static assertion}} \ + // both-note {{evaluates to}} + static_assert((-1.0 + 0.0j) == (-1.0 + 0.0j)); + static_assert((-1.0 - 1.0j) == (-1.0 + 0.0j)); // both-error {{static assertion}} \ + // both-note {{evaluates to}} + static_assert((-1.0 - 1.0j) == (-1.0 - 1.0j)); + static_assert((0.0 - 1.0j) == (-1.0 - 1.0j)); // both-error {{static assertion}} \ + // both-note {{evaluates to}} + static_assert((0.0 - 1.0j) == (0.0 - 1.0j)); + static_assert((1.0 - 1.0j) == (0.0 - 1.0j)); // both-error {{static assertion}} \ + // both-note {{evaluates to}} + static_assert((1.0 - 1.0j) == (1.0 - 1.0j)); + + /// Make sure these are rejected before reaching the constexpr interpreter. + static_assert((0.0 + 0.0j) & (0.0 + 0.0j)); // both-error {{invalid operands to binary expression}} + static_assert((0.0 + 0.0j) | (0.0 + 0.0j)); // both-error {{invalid operands to binary expression}} + static_assert((0.0 + 0.0j) < (0.0 + 0.0j)); // both-error {{invalid operands to binary expression}} + static_assert((0.0 + 0.0j) > (0.0 + 0.0j)); // both-error {{invalid operands to binary expression}} + static_assert((0.0 + 0.0j) ^ (0.0 + 0.0j)); // both-error {{invalid operands to binary expression}} +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits