Skip to content

Commit 8aed911

Browse files
committed
[clang][Interp] Implement complex comparisons
1 parent d6b3be3 commit 8aed911

File tree

4 files changed

+157
-6
lines changed

4 files changed

+157
-6
lines changed

clang/lib/AST/Interp/ByteCodeExprGen.cpp

Lines changed: 103 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -393,12 +393,16 @@ bool ByteCodeExprGen<Emitter>::VisitBinaryOperator(const BinaryOperator *BO) {
393393
if (BO->isLogicalOp())
394394
return this->VisitLogicalBinOp(BO);
395395

396-
if (BO->getType()->isAnyComplexType())
397-
return this->VisitComplexBinOp(BO);
398-
399396
const Expr *LHS = BO->getLHS();
400397
const Expr *RHS = BO->getRHS();
401398

399+
if (BO->getType()->isAnyComplexType())
400+
return this->VisitComplexBinOp(BO);
401+
if ((LHS->getType()->isAnyComplexType() ||
402+
RHS->getType()->isAnyComplexType()) &&
403+
BO->isComparisonOp())
404+
return this->emitComplexComparison(LHS, RHS, BO);
405+
402406
if (BO->isPtrMemOp())
403407
return this->visit(RHS);
404408

@@ -3410,6 +3414,102 @@ bool ByteCodeExprGen<Emitter>::emitComplexBoolCast(const Expr *E) {
34103414
return true;
34113415
}
34123416

3417+
template <class Emitter>
3418+
bool ByteCodeExprGen<Emitter>::emitComplexComparison(const Expr *LHS,
3419+
const Expr *RHS,
3420+
const BinaryOperator *E) {
3421+
assert(E->isComparisonOp());
3422+
assert(!Initializing);
3423+
assert(!DiscardResult);
3424+
3425+
PrimType ElemT;
3426+
bool LHSIsComplex;
3427+
unsigned LHSOffset;
3428+
if (LHS->getType()->isAnyComplexType()) {
3429+
LHSIsComplex = true;
3430+
ElemT = classifyComplexElementType(LHS->getType());
3431+
LHSOffset = allocateLocalPrimitive(LHS, PT_Ptr, /*IsConst=*/true,
3432+
/*IsExtended=*/false);
3433+
if (!this->visit(LHS))
3434+
return false;
3435+
if (!this->emitSetLocal(PT_Ptr, LHSOffset, E))
3436+
return false;
3437+
} else {
3438+
LHSIsComplex = false;
3439+
PrimType LHST = classifyPrim(LHS->getType());
3440+
LHSOffset = this->allocateLocalPrimitive(LHS, LHST, true, false);
3441+
if (!this->visit(LHS))
3442+
return false;
3443+
if (!this->emitSetLocal(LHST, LHSOffset, E))
3444+
return false;
3445+
}
3446+
3447+
bool RHSIsComplex;
3448+
unsigned RHSOffset;
3449+
if (RHS->getType()->isAnyComplexType()) {
3450+
RHSIsComplex = true;
3451+
ElemT = classifyComplexElementType(RHS->getType());
3452+
RHSOffset = allocateLocalPrimitive(RHS, PT_Ptr, /*IsConst=*/true,
3453+
/*IsExtended=*/false);
3454+
if (!this->visit(RHS))
3455+
return false;
3456+
if (!this->emitSetLocal(PT_Ptr, RHSOffset, E))
3457+
return false;
3458+
} else {
3459+
RHSIsComplex = false;
3460+
PrimType RHST = classifyPrim(RHS->getType());
3461+
RHSOffset = this->allocateLocalPrimitive(RHS, RHST, true, false);
3462+
if (!this->visit(RHS))
3463+
return false;
3464+
if (!this->emitSetLocal(RHST, RHSOffset, E))
3465+
return false;
3466+
}
3467+
3468+
auto getElem = [&](unsigned LocalOffset, unsigned Index,
3469+
bool IsComplex) -> bool {
3470+
if (IsComplex) {
3471+
if (!this->emitGetLocal(PT_Ptr, LocalOffset, E))
3472+
return false;
3473+
return this->emitArrayElemPop(ElemT, Index, E);
3474+
}
3475+
return this->emitGetLocal(ElemT, LocalOffset, E);
3476+
};
3477+
3478+
for (unsigned I = 0; I != 2; ++I) {
3479+
// Get both values.
3480+
if (!getElem(LHSOffset, I, LHSIsComplex))
3481+
return false;
3482+
if (!getElem(RHSOffset, I, RHSIsComplex))
3483+
return false;
3484+
// And compare them.
3485+
if (!this->emitEQ(ElemT, E))
3486+
return false;
3487+
3488+
if (!this->emitCastBoolUint8(E))
3489+
return false;
3490+
}
3491+
3492+
// We now have two bool values on the stack. Compare those.
3493+
if (!this->emitAddUint8(E))
3494+
return false;
3495+
if (!this->emitConstUint8(2, E))
3496+
return false;
3497+
3498+
if (E->getOpcode() == BO_EQ) {
3499+
if (!this->emitEQUint8(E))
3500+
return false;
3501+
} else if (E->getOpcode() == BO_NE) {
3502+
if (!this->emitNEUint8(E))
3503+
return false;
3504+
} else
3505+
return false;
3506+
3507+
// In C, this returns an int.
3508+
if (PrimType ResT = classifyPrim(E->getType()); ResT != PT_Bool)
3509+
return this->emitCast(PT_Bool, ResT, E);
3510+
return true;
3511+
}
3512+
34133513
/// When calling this, we have a pointer of the local-to-destroy
34143514
/// on the stack.
34153515
/// Emit destruction of record types (or arrays of record types).

clang/lib/AST/Interp/ByteCodeExprGen.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,8 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
268268

269269
bool emitComplexReal(const Expr *SubExpr);
270270
bool emitComplexBoolCast(const Expr *E);
271+
bool emitComplexComparison(const Expr *LHS, const Expr *RHS,
272+
const BinaryOperator *E);
271273

272274
bool emitRecordDestruction(const Record *R);
273275
bool emitDestruction(const Descriptor *Desc);

clang/test/AST/Interp/complex.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify=expected,both -Wno-unused-value %s
22
// RUN: %clang_cc1 -verify=ref,both -Wno-unused-value %s
33

4-
// expected-no-diagnostics
5-
// ref-no-diagnostics
6-
74
void blah() {
85
__complex__ unsigned xx;
96
__complex__ signed yy;
@@ -12,3 +9,8 @@ void blah() {
129
/// The following line calls into the constant interpreter.
1310
result = xx * yy;
1411
}
12+
13+
14+
_Static_assert((0.0 + 0.0j) == (0.0 + 0.0j), "");
15+
_Static_assert((0.0 + 0.0j) != (0.0 + 0.0j), ""); // both-error {{static assertion}} \
16+
// both-note {{evaluates to}}

clang/test/AST/Interp/complex.cpp

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,3 +266,50 @@ namespace Builtin {
266266

267267
constexpr _Complex float C = __builtin_complex(10.0f, 20.0); // both-error {{arguments are of different types}}
268268
}
269+
270+
namespace Cmp {
271+
static_assert((0.0 + 0.0j) == (0.0 + 0.0j));
272+
static_assert((0.0 + 0.0j) != (0.0 + 0.0j)); // both-error {{static assertion}} \
273+
// both-note {{evaluates to}}
274+
275+
static_assert((0.0 + 0.0j) == 0.0);
276+
static_assert(0.0 == (0.0 + 0.0j));
277+
static_assert(0.0 == 0.0j);
278+
static_assert((0.0 + 1.0j) != 0.0);
279+
static_assert(1.0 != (0.0 + 0.0j));
280+
static_assert(0.0 != 1.0j);
281+
282+
// Walk around the complex plane stepping between angular differences and
283+
// equality.
284+
static_assert((1.0 + 0.0j) == (0.0 + 0.0j)); // both-error {{static assertion}} \
285+
// both-note {{evaluates to}}
286+
static_assert((1.0 + 0.0j) == (1.0 + 0.0j));
287+
static_assert((1.0 + 1.0j) == (1.0 + 0.0j)); // both-error {{static assertion}} \
288+
// both-note {{evaluates to}}
289+
static_assert((1.0 + 1.0j) == (1.0 + 1.0j));
290+
static_assert((0.0 + 1.0j) == (1.0 + 1.0j)); // both-error {{static assertion}} \
291+
// both-note {{evaluates to}}
292+
static_assert((0.0 + 1.0j) == (0.0 + 1.0j));
293+
static_assert((-1.0 + 1.0j) == (0.0 + 1.0j)); // both-error {{static assertion}} \
294+
// both-note {{evaluates to}}
295+
static_assert((-1.0 + 1.0j) == (-1.0 + 1.0j));
296+
static_assert((-1.0 + 0.0j) == (-1.0 + 1.0j)); // both-error {{static assertion}} \
297+
// both-note {{evaluates to}}
298+
static_assert((-1.0 + 0.0j) == (-1.0 + 0.0j));
299+
static_assert((-1.0 - 1.0j) == (-1.0 + 0.0j)); // both-error {{static assertion}} \
300+
// both-note {{evaluates to}}
301+
static_assert((-1.0 - 1.0j) == (-1.0 - 1.0j));
302+
static_assert((0.0 - 1.0j) == (-1.0 - 1.0j)); // both-error {{static assertion}} \
303+
// both-note {{evaluates to}}
304+
static_assert((0.0 - 1.0j) == (0.0 - 1.0j));
305+
static_assert((1.0 - 1.0j) == (0.0 - 1.0j)); // both-error {{static assertion}} \
306+
// both-note {{evaluates to}}
307+
static_assert((1.0 - 1.0j) == (1.0 - 1.0j));
308+
309+
/// Make sure these are rejected before reaching the constexpr interpreter.
310+
static_assert((0.0 + 0.0j) & (0.0 + 0.0j)); // both-error {{invalid operands to binary expression}}
311+
static_assert((0.0 + 0.0j) | (0.0 + 0.0j)); // both-error {{invalid operands to binary expression}}
312+
static_assert((0.0 + 0.0j) < (0.0 + 0.0j)); // both-error {{invalid operands to binary expression}}
313+
static_assert((0.0 + 0.0j) > (0.0 + 0.0j)); // both-error {{invalid operands to binary expression}}
314+
static_assert((0.0 + 0.0j) ^ (0.0 + 0.0j)); // both-error {{invalid operands to binary expression}}
315+
}

0 commit comments

Comments
 (0)