From 5f6a91cd7f709a3c94c65dc4ea41b5967b9fe343 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timm=20B=C3=A4der?= Date: Mon, 8 Jan 2024 11:14:41 +0100 Subject: [PATCH 1/3] [clang][Interp] Implement ComplexToReal casts Add a new emitComplexReal() helper function and use that for the new casts as well as the old __real implementation. --- clang/lib/AST/Interp/ByteCodeExprGen.cpp | 45 ++++++++++++++++-------- clang/lib/AST/Interp/ByteCodeExprGen.h | 2 ++ clang/test/AST/Interp/complex.cpp | 15 ++++++-- 3 files changed, 45 insertions(+), 17 deletions(-) diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp index 5839123a5b95f..138ffed392fca 100644 --- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -287,6 +287,10 @@ bool ByteCodeExprGen::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::dereference( } if (LV->getType()->isAnyComplexType()) - return visit(LV); + return this->delegate(LV); return false; } @@ -2767,22 +2771,10 @@ bool ByteCodeExprGen::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::emitPrimCast(PrimType FromT, PrimType ToT, return false; } +/// Emits __real(SubExpr) +template +bool ByteCodeExprGen::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). diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.h b/clang/lib/AST/Interp/ByteCodeExprGen.h index bbb13e97e7256..48005ce05724b 100644 --- a/clang/lib/AST/Interp/ByteCodeExprGen.h +++ b/clang/lib/AST/Interp/ByteCodeExprGen.h @@ -294,6 +294,8 @@ class ByteCodeExprGen : public ConstStmtVisitor, bool>, return this->classify(ElemType); } + bool emitComplexReal(const Expr *SubExpr); + bool emitRecordDestruction(const Descriptor *Desc); unsigned collectBaseOffset(const RecordType *BaseType, const RecordType *DerivedType); diff --git a/clang/test/AST/Interp/complex.cpp b/clang/test/AST/Interp/complex.cpp index 1e97cc6184952..a5bc204366399 100644 --- a/clang/test/AST/Interp/complex.cpp +++ b/clang/test/AST/Interp/complex.cpp @@ -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,17 @@ 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; FIXME*/ + D1; + /* (int)D1; FIXME*/ + (double)D1; + return 0; +} +static_assert(ignoredCast() == 0, ""); +static_assert((int)I1 == 1, ""); /// Standalone complex expressions. From 85d4ffb15f466b8b2aa5d3e522ce4e449de662ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timm=20B=C3=A4der?= Date: Mon, 15 Jan 2024 09:52:26 +0100 Subject: [PATCH 2/3] Enable commented-out tests --- clang/test/AST/Interp/complex.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/test/AST/Interp/complex.cpp b/clang/test/AST/Interp/complex.cpp index a5bc204366399..7870a2a1eb5e6 100644 --- a/clang/test/AST/Interp/complex.cpp +++ b/clang/test/AST/Interp/complex.cpp @@ -45,9 +45,9 @@ static_assert(__imag(13) == 0, ""); constexpr int ignoredCast() { I2; (int)I2; - /* (float)I2; FIXME*/ + (float)I2; D1; - /* (int)D1; FIXME*/ + (int)D1; (double)D1; return 0; } From 7d84c479869259ad47953ffe58f3ab7d6178addc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timm=20B=C3=A4der?= Date: Mon, 15 Jan 2024 16:34:31 +0100 Subject: [PATCH 3/3] Add another test --- clang/test/AST/Interp/complex.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/clang/test/AST/Interp/complex.cpp b/clang/test/AST/Interp/complex.cpp index 7870a2a1eb5e6..e63693a0cfaa1 100644 --- a/clang/test/AST/Interp/complex.cpp +++ b/clang/test/AST/Interp/complex.cpp @@ -53,6 +53,7 @@ constexpr int ignoredCast() { } static_assert(ignoredCast() == 0, ""); static_assert((int)I1 == 1, ""); +static_assert((float)D == 1.0f, ""); /// Standalone complex expressions.