[clang] 8aed911 - [clang][Interp] Implement complex comparisons
Timm Bäder via cfe-commits
cfe-commits at lists.llvm.org
Thu Mar 7 08:04:19 PST 2024
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}}
+}
More information about the cfe-commits
mailing list