Skip to content

[clang][Interp] Implement ComplexToReal casts #77294

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jan 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 30 additions & 15 deletions clang/lib/AST/Interp/ByteCodeExprGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,10 @@ bool ByteCodeExprGen<Emitter>::VisitCastExpr(const CastExpr *CE) {
return true;
}

case CK_IntegralComplexToReal:
case CK_FloatingComplexToReal:
return this->emitComplexReal(SubExpr);

case CK_ToVoid:
return discard(SubExpr);

Expand Down Expand Up @@ -2030,7 +2034,7 @@ bool ByteCodeExprGen<Emitter>::dereference(
}

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

return false;
}
Expand Down Expand Up @@ -2767,22 +2771,10 @@ bool ByteCodeExprGen<Emitter>::VisitUnaryOperator(const UnaryOperator *E) {
if (!this->visit(SubExpr))
return false;
return DiscardResult ? this->emitPop(*T, E) : this->emitComp(*T, E);
case UO_Real: { // __real x
case UO_Real: // __real x
if (T)
return this->delegate(SubExpr);
if (!this->visit(SubExpr))
return false;
if (!this->emitConstUint8(0, E))
return false;
if (!this->emitArrayElemPtrPopUint8(E))
return false;

// Since our _Complex implementation does not map to a primitive type,
// we sometimes have to do the lvalue-to-rvalue conversion here manually.
if (!SubExpr->isLValue())
return this->emitLoadPop(classifyPrim(E->getType()), E);
return true;
}
return this->emitComplexReal(SubExpr);
case UO_Imag: { // __imag x
if (T) {
if (!this->discard(SubExpr))
Expand Down Expand Up @@ -2953,6 +2945,29 @@ bool ByteCodeExprGen<Emitter>::emitPrimCast(PrimType FromT, PrimType ToT,
return false;
}

/// Emits __real(SubExpr)
template <class Emitter>
bool ByteCodeExprGen<Emitter>::emitComplexReal(const Expr *SubExpr) {
assert(SubExpr->getType()->isAnyComplexType());

if (DiscardResult)
return this->discard(SubExpr);

if (!this->visit(SubExpr))
return false;
if (!this->emitConstUint8(0, SubExpr))
return false;
if (!this->emitArrayElemPtrPopUint8(SubExpr))
return false;

// Since our _Complex implementation does not map to a primitive type,
// we sometimes have to do the lvalue-to-rvalue conversion here manually.
if (!SubExpr->isLValue())
return this->emitLoadPop(*classifyComplexElementType(SubExpr->getType()),
SubExpr);
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).
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/AST/Interp/ByteCodeExprGen.h
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,8 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
return this->classify(ElemType);
}

bool emitComplexReal(const Expr *SubExpr);

bool emitRecordDestruction(const Descriptor *Desc);
unsigned collectBaseOffset(const RecordType *BaseType,
const RecordType *DerivedType);
Expand Down
16 changes: 14 additions & 2 deletions clang/test/AST/Interp/complex.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify %s
// RUN: %clang_cc1 -verify=ref %s
// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify -Wno-unused-value %s
// RUN: %clang_cc1 -verify=ref -Wno-unused-value %s

// expected-no-diagnostics
// ref-no-diagnostics
Expand Down Expand Up @@ -42,6 +42,18 @@ static_assert(__real(12u) == 12u, "");
static_assert(__imag(4.0) == 0.0, "");
static_assert(__imag(13) == 0, "");

constexpr int ignoredCast() {
I2;
(int)I2;
(float)I2;
D1;
(int)D1;
(double)D1;
return 0;
}
static_assert(ignoredCast() == 0, "");
static_assert((int)I1 == 1, "");
static_assert((float)D == 1.0f, "");


/// Standalone complex expressions.
Expand Down