[clang][Interp] Implement ComplexToReal casts (#77294)

Add a new emitComplexReal() helper function and use that for the new
casts as well as the old __real implementation.
This commit is contained in:
Timm Baeder 2024-01-18 13:55:04 +01:00 committed by GitHub
parent 11ec512f44
commit 18d0a7e4c0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 46 additions and 17 deletions

View File

@ -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);
@ -2030,7 +2034,7 @@ bool ByteCodeExprGen<Emitter>::dereference(
}
if (LV->getType()->isAnyComplexType())
return visit(LV);
return this->delegate(LV);
return false;
}
@ -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))
@ -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).

View File

@ -294,6 +294,8 @@ private:
return this->classify(ElemType);
}
bool emitComplexReal(const Expr *SubExpr);
bool emitRecordDestruction(const Descriptor *Desc);
unsigned collectBaseOffset(const RecordType *BaseType,
const RecordType *DerivedType);

View File

@ -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
@ -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.