Skip to content

Commit

Permalink
[clang][Interp] IntegralComplexToBoolean casts
Browse files Browse the repository at this point in the history
Differential Revision: https://reviews.llvm.org/D148426
  • Loading branch information
tbaederr committed Dec 14, 2023
1 parent 2141a51 commit 497480b
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 4 deletions.
52 changes: 51 additions & 1 deletion clang/lib/AST/Interp/ByteCodeExprGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,52 @@ bool ByteCodeExprGen<Emitter>::VisitCastExpr(const CastExpr *CE) {
return this->emitNE(PtrT, CE);
}

case CK_IntegralComplexToBoolean: {
std::optional<PrimType> ElemT =
classifyComplexElementType(SubExpr->getType());
if (!ElemT)
return false;
// We emit the expression (__real(E) != 0 || __imag(E) != 0)
// for us, that means (bool)E[0] || (bool)E[1]
if (!this->visit(SubExpr))
return false;
if (!this->emitConstUint8(0, CE))
return false;
if (!this->emitArrayElemPtrUint8(CE))
return false;
if (!this->emitLoadPop(*ElemT, CE))
return false;
if (!this->emitCast(*ElemT, PT_Bool, CE))
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->emitConstUint8(1, CE))
return false;
if (!this->emitArrayElemPtrPopUint8(CE))
return false;
if (!this->emitLoadPop(*ElemT, CE))
return false;
if (!this->emitCast(*ElemT, PT_Bool, CE))
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(CE))
return false;
if (!this->emitConstBool(true, CE))
return false;

this->fallthrough(EndLabel);
this->emitLabel(EndLabel);

return true;
}

case CK_ToVoid:
return discard(SubExpr);

Expand Down Expand Up @@ -1673,7 +1719,8 @@ template <class Emitter> bool ByteCodeExprGen<Emitter>::visit(const Expr *E) {
return this->discard(E);

// Create local variable to hold the return value.
if (!E->isGLValue() && !classify(E->getType())) {
if (!E->isGLValue() && !E->getType()->isAnyComplexType() &&
!classify(E->getType())) {
std::optional<unsigned> LocalIndex = allocateLocal(E, /*IsExtended=*/true);
if (!LocalIndex)
return false;
Expand Down Expand Up @@ -1859,6 +1906,9 @@ bool ByteCodeExprGen<Emitter>::dereference(
return Indirect(*T);
}

if (LV->getType()->isAnyComplexType())
return visit(LV);

return false;
}

Expand Down
8 changes: 8 additions & 0 deletions clang/lib/AST/Interp/ByteCodeExprGen.h
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,14 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
}

bool emitPrimCast(PrimType FromT, PrimType ToT, QualType ToQT, const Expr *E);
std::optional<PrimType> classifyComplexElementType(QualType T) const {
assert(T->isAnyComplexType());

QualType ElemType = T->getAs<ComplexType>()->getElementType();

return this->classify(ElemType);
}

bool emitRecordDestruction(const Descriptor *Desc);
unsigned collectBaseOffset(const RecordType *BaseType,
const RecordType *DerivedType);
Expand Down
19 changes: 16 additions & 3 deletions clang/test/AST/Interp/complex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,21 @@ static_assert(__real(I3) == 15, "");
static_assert(__imag(I3) == 15, "");
#endif




/// FIXME: This should work in the new interpreter as well.
// constexpr _Complex _BitInt(8) A = 0;// = {4};

namespace CastToBool {
constexpr _Complex int F = {0, 1};
static_assert(F, "");
constexpr _Complex int F2 = {1, 0};
static_assert(F2, "");
constexpr _Complex int F3 = {0, 0};
static_assert(!F3, "");

constexpr _Complex unsigned char F4 = {0, 1};
static_assert(F4, "");
constexpr _Complex unsigned char F5 = {1, 0};
static_assert(F5, "");
constexpr _Complex unsigned char F6 = {0, 0};
static_assert(!F6, "");
}

0 comments on commit 497480b

Please sign in to comment.