Skip to content

Commit 1542601

Browse files
committed
[clang][Interp] Handle non-complex operands in complex bin ops
Either LHS or RHS might be non-complex, but not both.
1 parent 892b4be commit 1542601

File tree

2 files changed

+93
-35
lines changed

2 files changed

+93
-35
lines changed

clang/lib/AST/Interp/ByteCodeExprGen.cpp

Lines changed: 68 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -660,19 +660,16 @@ bool ByteCodeExprGen<Emitter>::VisitComplexBinOp(const BinaryOperator *E) {
660660
return false;
661661
}
662662

663+
// Both LHS and RHS might _not_ be of complex type, but one of them
664+
// needs to be.
663665
const Expr *LHS = E->getLHS();
664666
const Expr *RHS = E->getRHS();
665-
PrimType LHSElemT = this->classifyComplexElementType(LHS->getType());
666-
PrimType RHSElemT = this->classifyComplexElementType(RHS->getType());
667667

668-
unsigned LHSOffset = this->allocateLocalPrimitive(LHS, PT_Ptr, true, false);
669-
unsigned RHSOffset = this->allocateLocalPrimitive(RHS, PT_Ptr, true, false);
668+
PrimType ResultElemT = this->classifyComplexElementType(E->getType());
670669
unsigned ResultOffset = ~0u;
671-
if (!this->DiscardResult)
670+
if (!DiscardResult)
672671
ResultOffset = this->allocateLocalPrimitive(E, PT_Ptr, true, false);
673672

674-
assert(LHSElemT == RHSElemT);
675-
676673
// Save result pointer in ResultOffset
677674
if (!this->DiscardResult) {
678675
if (!this->emitDupPtr(E))
@@ -682,16 +679,64 @@ bool ByteCodeExprGen<Emitter>::VisitComplexBinOp(const BinaryOperator *E) {
682679
}
683680

684681
// Evaluate LHS and save value to LHSOffset.
685-
if (!this->visit(LHS))
686-
return false;
687-
if (!this->emitSetLocal(PT_Ptr, LHSOffset, E))
688-
return false;
682+
bool LHSIsComplex;
683+
unsigned LHSOffset;
684+
if (LHS->getType()->isAnyComplexType()) {
685+
LHSIsComplex = true;
686+
LHSOffset = this->allocateLocalPrimitive(LHS, PT_Ptr, true, false);
687+
if (!this->visit(LHS))
688+
return false;
689+
if (!this->emitSetLocal(PT_Ptr, LHSOffset, E))
690+
return false;
691+
} else {
692+
LHSIsComplex = false;
693+
PrimType LHST = classifyPrim(LHS->getType());
694+
LHSOffset = this->allocateLocalPrimitive(LHS, LHST, true, false);
695+
if (!this->visit(LHS))
696+
return false;
697+
if (!this->emitSetLocal(LHST, LHSOffset, E))
698+
return false;
699+
}
689700

690701
// Same with RHS.
691-
if (!this->visit(RHS))
692-
return false;
693-
if (!this->emitSetLocal(PT_Ptr, RHSOffset, E))
694-
return false;
702+
bool RHSIsComplex;
703+
unsigned RHSOffset;
704+
if (RHS->getType()->isAnyComplexType()) {
705+
RHSIsComplex = true;
706+
RHSOffset = this->allocateLocalPrimitive(RHS, PT_Ptr, true, false);
707+
if (!this->visit(RHS))
708+
return false;
709+
if (!this->emitSetLocal(PT_Ptr, RHSOffset, E))
710+
return false;
711+
} else {
712+
RHSIsComplex = false;
713+
PrimType RHST = classifyPrim(RHS->getType());
714+
RHSOffset = this->allocateLocalPrimitive(RHS, RHST, true, false);
715+
if (!this->visit(RHS))
716+
return false;
717+
if (!this->emitSetLocal(RHST, RHSOffset, E))
718+
return false;
719+
}
720+
721+
// For both LHS and RHS, either load the value from the complex pointer, or
722+
// directly from the local variable. For index 1 (i.e. the imaginary part),
723+
// just load 0 and do the operation anyway.
724+
auto loadComplexValue = [this](bool IsComplex, unsigned ElemIndex,
725+
unsigned Offset, const Expr *E) -> bool {
726+
if (IsComplex) {
727+
if (!this->emitGetLocal(PT_Ptr, Offset, E))
728+
return false;
729+
if (!this->emitConstUint8(ElemIndex, E))
730+
return false;
731+
if (!this->emitArrayElemPtrPopUint8(E))
732+
return false;
733+
return this->emitLoadPop(classifyComplexElementType(E->getType()), E);
734+
}
735+
if (ElemIndex == 0)
736+
return this->emitGetLocal(classifyPrim(E->getType()), Offset, E);
737+
return this->visitZeroInitializer(classifyPrim(E->getType()), E->getType(),
738+
E);
739+
};
695740

696741
// Now we can get pointers to the LHS and RHS from the offsets above.
697742
BinaryOperatorKind Op = E->getOpcode();
@@ -702,41 +747,29 @@ bool ByteCodeExprGen<Emitter>::VisitComplexBinOp(const BinaryOperator *E) {
702747
return false;
703748
}
704749

705-
if (!this->emitGetLocal(PT_Ptr, LHSOffset, E))
706-
return false;
707-
if (!this->emitConstUint8(ElemIndex, E))
708-
return false;
709-
if (!this->emitArrayElemPtrPopUint8(E))
710-
return false;
711-
if (!this->emitLoadPop(LHSElemT, E))
750+
if (!loadComplexValue(LHSIsComplex, ElemIndex, LHSOffset, LHS))
712751
return false;
713752

714-
if (!this->emitGetLocal(PT_Ptr, RHSOffset, E))
715-
return false;
716-
if (!this->emitConstUint8(ElemIndex, E))
717-
return false;
718-
if (!this->emitArrayElemPtrPopUint8(E))
719-
return false;
720-
if (!this->emitLoadPop(RHSElemT, E))
753+
if (!loadComplexValue(RHSIsComplex, ElemIndex, RHSOffset, RHS))
721754
return false;
722755

723756
// The actual operation.
724757
switch (Op) {
725758
case BO_Add:
726-
if (LHSElemT == PT_Float) {
759+
if (ResultElemT == PT_Float) {
727760
if (!this->emitAddf(getRoundingMode(E), E))
728761
return false;
729762
} else {
730-
if (!this->emitAdd(LHSElemT, E))
763+
if (!this->emitAdd(ResultElemT, E))
731764
return false;
732765
}
733766
break;
734767
case BO_Sub:
735-
if (LHSElemT == PT_Float) {
768+
if (ResultElemT == PT_Float) {
736769
if (!this->emitSubf(getRoundingMode(E), E))
737770
return false;
738771
} else {
739-
if (!this->emitSub(LHSElemT, E))
772+
if (!this->emitSub(ResultElemT, E))
740773
return false;
741774
}
742775
break;
@@ -747,10 +780,10 @@ bool ByteCodeExprGen<Emitter>::VisitComplexBinOp(const BinaryOperator *E) {
747780

748781
if (!this->DiscardResult) {
749782
// Initialize array element with the value we just computed.
750-
if (!this->emitInitElemPop(LHSElemT, ElemIndex, E))
783+
if (!this->emitInitElemPop(ResultElemT, ElemIndex, E))
751784
return false;
752785
} else {
753-
if (!this->emitPop(LHSElemT, E))
786+
if (!this->emitPop(ResultElemT, E))
754787
return false;
755788
}
756789
}

clang/test/AST/Interp/complex.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,20 @@ namespace Add {
164164
constexpr _Complex unsigned int I3 = I1 + I2;
165165
static_assert(__real(I3) == 45, "");
166166
static_assert(__imag(I3) == 12, "");
167+
168+
static_assert(__real(A + 2.0) == 15, "");
169+
static_assert(__imag(A + 2.0) == 2, "");
170+
static_assert(__real(2.0 + A) == 15, "");
171+
static_assert(__imag(2.0 + A) == 2, "");
172+
173+
static_assert(__real(D + 1) == 16, "");
174+
static_assert(__real(D + 1.0) == 16, "");
175+
constexpr _Complex double D2 = D + 3.0;
176+
static_assert(__real(D2) == 18.0, "");
177+
static_assert(__imag(D2) == 3.0, "");
178+
constexpr _Complex double D3 = 3.0 + D;
179+
static_assert(__real(D3) == 18.0, "");
180+
static_assert(__imag(D3) == 3.0, "");
167181
}
168182

169183
namespace Sub {
@@ -172,6 +186,8 @@ namespace Sub {
172186
constexpr _Complex float C = A - B;
173187
static_assert(__real(C) == 11.0, "");
174188
static_assert(__imag(C) == 1.0, "");
189+
static_assert(__real(A - 2.0) == 11, "");
190+
static_assert(__real(2.0 - A) == -11, "");
175191

176192
constexpr _Complex float D = B - A;
177193
static_assert(__real(D) == -11.0, "");
@@ -189,6 +205,15 @@ namespace Sub {
189205
constexpr _Complex float D_ = A_ - B_;
190206
static_assert(__real(D_) == 11.0, "");
191207
static_assert(__imag(D_) == 1.0, "");
208+
209+
static_assert(__real(D - 1) == -12, "");
210+
static_assert(__real(D - 1.0) == -12, "");
211+
constexpr _Complex double D2 = D - 3.0;
212+
static_assert(__real(D2) == -14.0, "");
213+
static_assert(__imag(D2) == -1.0, "");
214+
constexpr _Complex double D3 = 3.0 - D;
215+
static_assert(__real(D3) == 14.0, "");
216+
static_assert(__imag(D3) == 1.0, "");
192217
}
193218

194219
}

0 commit comments

Comments
 (0)