[clang] [clang][Interp] Integral pointers (PR #84159)
@@ -22,7 +22,11 @@ class FunctionPointer final { const Function *Func; public: - FunctionPointer() : Func(nullptr) {} + // FIXME: We might want to track the fact that the Function pointer + // has been created from an integer and is most likely garbage anyway. + FunctionPointer(int IntVal = 0, const Descriptor *Desc = nullptr) RKSimon wrote: For reference @AaronBallman fixed this in 4d80dff819d1164775d0d55fc68bffedb90ba53c https://github.com/llvm/llvm-project/pull/84159 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][Interp] Integral pointers (PR #84159)
@@ -22,7 +22,11 @@ class FunctionPointer final { const Function *Func; public: - FunctionPointer() : Func(nullptr) {} + // FIXME: We might want to track the fact that the Function pointer + // has been created from an integer and is most likely garbage anyway. + FunctionPointer(int IntVal = 0, const Descriptor *Desc = nullptr) tbaederr wrote: Ah sorry, looks like I'm too slow :upside_down_face: https://github.com/llvm/llvm-project/pull/84159 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][Interp] Integral pointers (PR #84159)
@@ -22,7 +22,11 @@ class FunctionPointer final { const Function *Func; public: - FunctionPointer() : Func(nullptr) {} + // FIXME: We might want to track the fact that the Function pointer + // has been created from an integer and is most likely garbage anyway. + FunctionPointer(int IntVal = 0, const Descriptor *Desc = nullptr) tbaederr wrote: Sorry, will fix that. https://github.com/llvm/llvm-project/pull/84159 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][Interp] Integral pointers (PR #84159)
@@ -22,7 +22,11 @@ class FunctionPointer final { const Function *Func; public: - FunctionPointer() : Func(nullptr) {} + // FIXME: We might want to track the fact that the Function pointer + // has been created from an integer and is most likely garbage anyway. + FunctionPointer(int IntVal = 0, const Descriptor *Desc = nullptr) RKSimon wrote: @tbaederr This is causing a lot of MSVC warnings - `int IntVal` -> `intptr_t IntVal`? `warning C4312: 'reinterpret_cast': conversion from 'int' to 'const clang::interp::Function *' of greater size` https://github.com/llvm/llvm-project/pull/84159 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][Interp] Integral pointers (PR #84159)
https://github.com/tbaederr closed https://github.com/llvm/llvm-project/pull/84159 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][Interp] Integral pointers (PR #84159)
https://github.com/tbaederr updated https://github.com/llvm/llvm-project/pull/84159 >From 3d6a09d1324dbd354668b0341644fb70fe09a47c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timm=20B=C3=A4der?= Date: Wed, 6 Mar 2024 08:36:52 +0100 Subject: [PATCH] [clang][Interp] Integral pointers --- clang/lib/AST/Interp/ByteCodeExprGen.cpp | 81 - clang/lib/AST/Interp/ByteCodeStmtGen.cpp | 2 +- clang/lib/AST/Interp/Descriptor.h| 1 + clang/lib/AST/Interp/FunctionPointer.h | 10 +- clang/lib/AST/Interp/Interp.cpp | 5 + clang/lib/AST/Interp/Interp.h| 85 +++-- clang/lib/AST/Interp/InterpBlock.cpp | 4 +- clang/lib/AST/Interp/Opcodes.td | 12 + clang/lib/AST/Interp/Pointer.cpp | 168 +++--- clang/lib/AST/Interp/Pointer.h | 383 +-- clang/lib/AST/Interp/PrimType.h | 4 + clang/test/AST/Interp/c.c| 18 ++ clang/test/AST/Interp/const-eval.c | 192 clang/test/AST/Interp/functions.cpp | 15 + 14 files changed, 798 insertions(+), 182 deletions(-) create mode 100644 clang/test/AST/Interp/const-eval.c diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp index a1ce6575148325..4e650d49d180bb 100644 --- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -173,10 +173,18 @@ bool ByteCodeExprGen::VisitCastExpr(const CastExpr *CE) { return this->emitCastFloatingIntegral(*ToT, CE); } - case CK_NullToPointer: + case CK_NullToPointer: { if (DiscardResult) return true; -return this->emitNull(classifyPrim(CE->getType()), CE); + +const Descriptor *Desc = nullptr; +const QualType PointeeType = CE->getType()->getPointeeType(); +if (!PointeeType.isNull()) { + if (std::optional T = classify(PointeeType)) +Desc = P.createDescriptor(SubExpr, *T); +} +return this->emitNull(classifyPrim(CE->getType()), Desc, CE); + } case CK_PointerToIntegral: { if (DiscardResult) @@ -199,6 +207,41 @@ bool ByteCodeExprGen::VisitCastExpr(const CastExpr *CE) { return true; } + case CK_IntegralToPointer: { +QualType IntType = SubExpr->getType(); +assert(IntType->isIntegralOrEnumerationType()); +if (!this->visit(SubExpr)) + return false; +// FIXME: I think the discard is wrong since the int->ptr cast might cause a +// diagnostic. +PrimType T = classifyPrim(IntType); +if (DiscardResult) + return this->emitPop(T, CE); + +QualType PtrType = CE->getType(); +assert(PtrType->isPointerType()); + +const Descriptor *Desc; +if (std::optional T = classify(PtrType->getPointeeType())) + Desc = P.createDescriptor(SubExpr, *T); +else if (PtrType->getPointeeType()->isVoidType()) + Desc = nullptr; +else + Desc = P.createDescriptor(CE, PtrType->getPointeeType().getTypePtr(), +Descriptor::InlineDescMD, true, false, +/*IsMutable=*/false, nullptr); + +if (!this->emitGetIntPtr(T, Desc, CE)) + return false; + +PrimType DestPtrT = classifyPrim(PtrType); +if (DestPtrT == PT_Ptr) + return true; + +// In case we're converting the integer to a non-Pointer. +return this->emitDecayPtr(PT_Ptr, DestPtrT, CE); + } + case CK_AtomicToNonAtomic: case CK_ConstructorConversion: case CK_FunctionToPointerDecay: @@ -207,13 +250,31 @@ bool ByteCodeExprGen::VisitCastExpr(const CastExpr *CE) { case CK_UserDefinedConversion: return this->delegate(SubExpr); - case CK_BitCast: + case CK_BitCast: { +// Reject bitcasts to atomic types. if (CE->getType()->isAtomicType()) { if (!this->discard(SubExpr)) return false; return this->emitInvalidCast(CastKind::Reinterpret, CE); } -return this->delegate(SubExpr); + +if (DiscardResult) + return this->discard(SubExpr); + +std::optional FromT = classify(SubExpr->getType()); +std::optional ToT = classifyPrim(CE->getType()); +if (!FromT || !ToT) + return false; + +assert(isPtrType(*FromT)); +assert(isPtrType(*ToT)); +if (FromT == ToT) + return this->delegate(SubExpr); + +if (!this->visit(SubExpr)) + return false; +return this->emitDecayPtr(*FromT, *ToT, CE); + } case CK_IntegralToBoolean: case CK_IntegralCast: { @@ -245,7 +306,7 @@ bool ByteCodeExprGen::VisitCastExpr(const CastExpr *CE) { if (!this->visit(SubExpr)) return false; -if (!this->emitNull(PtrT, CE)) +if (!this->emitNull(PtrT, nullptr, CE)) return false; return this->emitNE(PtrT, CE); @@ -455,7 +516,7 @@ bool ByteCodeExprGen::VisitBinaryOperator(const BinaryOperator *BO) { // Pointer arithmetic special case. if (BO->getOpcode() == BO_Add || BO->getOpcode() == BO_Sub) { -if (T == PT_Ptr || (LT == PT_Ptr && RT == PT_Ptr)) +if (isPtrType(*T) ||
[clang] [clang][Interp] Integral pointers (PR #84159)
Timm =?utf-8?q?B=C3=A4der?= , Timm =?utf-8?q?B=C3=A4der?= , Timm =?utf-8?q?B=C3=A4der?= , Timm =?utf-8?q?B=C3=A4der?= , Timm =?utf-8?q?B=C3=A4der?= Message-ID: In-Reply-To: @@ -1912,6 +1929,10 @@ inline bool NoRet(InterpState , CodePtr OpPC) { inline bool NarrowPtr(InterpState , CodePtr OpPC) { const Pointer = S.Stk.pop(); + if (!S.getLangOpts().CPlusPlus) { +S.Stk.push(Ptr); tbaederr wrote: Don't remember why I added that but it's not necessary. https://github.com/llvm/llvm-project/pull/84159 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][Interp] Integral pointers (PR #84159)
Timm =?utf-8?q?Bäder?= , Timm =?utf-8?q?Bäder?= , Timm =?utf-8?q?Bäder?= , Timm =?utf-8?q?Bäder?= , Timm =?utf-8?q?Bäder?= Message-ID: In-Reply-To: @@ -2218,6 +2238,14 @@ inline bool GetFnPtr(InterpState , CodePtr OpPC, const Function *Func) { return true; } +template ::T> +inline bool GetIntPtr(InterpState , CodePtr OpPC, const Descriptor *Desc) { + const T = S.Stk.pop(); + + S.Stk.push(static_cast(IntVal), Desc); AaronBallman wrote: `uint64_t`? https://github.com/llvm/llvm-project/pull/84159 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][Interp] Integral pointers (PR #84159)
Timm =?utf-8?q?Bäder?= , Timm =?utf-8?q?Bäder?= , Timm =?utf-8?q?Bäder?= , Timm =?utf-8?q?Bäder?= , Timm =?utf-8?q?Bäder?= Message-ID: In-Reply-To: @@ -199,6 +207,41 @@ bool ByteCodeExprGen::VisitCastExpr(const CastExpr *CE) { return true; } + case CK_IntegralToPointer: { +QualType IntType = SubExpr->getType(); +assert(IntType->isIntegralOrEnumerationType()); +if (!this->visit(SubExpr)) + return false; +// FIXME: I think the discard is wrong since the int->ptr cast might cause a +// diagnostic. +PrimType T = classifyPrim(IntType); +if (DiscardResult) + return this->emitPop(T, CE); + +QualType PtrType = CE->getType(); +assert(PtrType->isPointerType()); + +const Descriptor *Desc; +if (std::optional T = classify(PtrType->getPointeeType())) + Desc = P.createDescriptor(SubExpr, *T); +else if (PtrType->getPointeeType()->isVoidType()) + Desc = nullptr; +else + Desc = P.createDescriptor(CE, PtrType->getPointeeType().getTypePtr(), +Descriptor::InlineDescMD, true, false, +/*IsMutable=*/false, nullptr); + +if (!this->emitGetIntPtr(T, Desc, CE)) + return false; + +PrimType DestPtrT = classifyPrim(PtrType); +if (DestPtrT == PT_Ptr) + return true; + +// // In case we're converting the integer to a non-Pointer. AaronBallman wrote: ```suggestion // In case we're converting the integer to a non-Pointer. ``` https://github.com/llvm/llvm-project/pull/84159 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][Interp] Integral pointers (PR #84159)
Timm =?utf-8?q?B=C3=A4der?= , Timm =?utf-8?q?B=C3=A4der?= , Timm =?utf-8?q?B=C3=A4der?= , Timm =?utf-8?q?B=C3=A4der?= , Timm =?utf-8?q?B=C3=A4der?= Message-ID: In-Reply-To: @@ -1912,6 +1929,10 @@ inline bool NoRet(InterpState , CodePtr OpPC) { inline bool NarrowPtr(InterpState , CodePtr OpPC) { const Pointer = S.Stk.pop(); + if (!S.getLangOpts().CPlusPlus) { +S.Stk.push(Ptr); AaronBallman wrote: Still think a comment here would be helpful https://github.com/llvm/llvm-project/pull/84159 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][Interp] Integral pointers (PR #84159)
Timm =?utf-8?q?B=C3=A4der?= , Timm =?utf-8?q?B=C3=A4der?= , Timm =?utf-8?q?B=C3=A4der?= , Timm =?utf-8?q?B=C3=A4der?= , Timm =?utf-8?q?B=C3=A4der?= Message-ID: In-Reply-To: https://github.com/AaronBallman approved this pull request. Basically LGTM, just a few minor things. https://github.com/llvm/llvm-project/pull/84159 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][Interp] Integral pointers (PR #84159)
Timm =?utf-8?q?Bäder?= , Timm =?utf-8?q?Bäder?= , Timm =?utf-8?q?Bäder?= , Timm =?utf-8?q?Bäder?= , Timm =?utf-8?q?Bäder?= Message-ID: In-Reply-To: https://github.com/AaronBallman edited https://github.com/llvm/llvm-project/pull/84159 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][Interp] Integral pointers (PR #84159)
Timm =?utf-8?q?B=C3=A4der?= , Timm =?utf-8?q?B=C3=A4der?= , Timm =?utf-8?q?B=C3=A4der?= , Timm =?utf-8?q?B=C3=A4der?= , Timm =?utf-8?q?B=C3=A4der?= Message-ID: In-Reply-To: tbaederr wrote: Ping https://github.com/llvm/llvm-project/pull/84159 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][Interp] Integral pointers (PR #84159)
Timm =?utf-8?q?Bäder?= , Timm =?utf-8?q?Bäder?= , Timm =?utf-8?q?Bäder?= , Timm =?utf-8?q?Bäder?= , Timm =?utf-8?q?Bäder?= Message-ID: In-Reply-To: https://github.com/tbaederr updated https://github.com/llvm/llvm-project/pull/84159 >From 1c06781e92b8fec78ae82b0d6a85965524d223d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timm=20B=C3=A4der?= Date: Mon, 18 Mar 2024 12:21:16 +0100 Subject: [PATCH 1/6] [clang][Interp] Handle CXXDefaultInitExpr of composite type --- clang/lib/AST/Interp/ByteCodeExprGen.cpp | 6 +- clang/test/AST/Interp/records.cpp| 21 + 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp index 6cee3c1af9f66a..d943dcbe06507b 100644 --- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -2916,11 +2916,7 @@ template bool ByteCodeExprGen::VisitCXXDefaultInitExpr( const CXXDefaultInitExpr *E) { SourceLocScope SLS(this, E); - if (Initializing) -return this->visitInitializer(E->getExpr()); - - assert(classify(E->getType())); - return this->visit(E->getExpr()); + return this->delegate(E->getExpr()); } template diff --git a/clang/test/AST/Interp/records.cpp b/clang/test/AST/Interp/records.cpp index d37d4410c763fb..0f76e0cfe99277 100644 --- a/clang/test/AST/Interp/records.cpp +++ b/clang/test/AST/Interp/records.cpp @@ -1264,3 +1264,24 @@ namespace { static_assert(true_type::value, ""); static_assert(true_type::value, ""); } + +#if __cplusplus >= 202002L +namespace { + /// Used to crash because the CXXDefaultInitExpr is of compound type. + struct A { +int +constexpr ~A() { --x; } + }; + struct B { +int +const A = A{x}; + }; + constexpr int a() { +int x = 1; +int f = B{x}.x; +B{x}; // both-warning {{expression result unused}} + +return 1; + } +} +#endif >From 3f47e6fde4b0b05ac243d1afa69eb9adde650614 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timm=20B=C3=A4der?= Date: Wed, 6 Mar 2024 08:36:52 +0100 Subject: [PATCH 2/6] Integral pointers --- clang/lib/AST/Interp/ByteCodeExprGen.cpp | 74 - clang/lib/AST/Interp/ByteCodeStmtGen.cpp | 2 +- clang/lib/AST/Interp/Descriptor.h| 1 + clang/lib/AST/Interp/FunctionPointer.h | 10 +- clang/lib/AST/Interp/Interp.cpp | 5 + clang/lib/AST/Interp/Interp.h| 89 -- clang/lib/AST/Interp/InterpBlock.cpp | 4 +- clang/lib/AST/Interp/Opcodes.td | 12 + clang/lib/AST/Interp/Pointer.cpp | 176 --- clang/lib/AST/Interp/Pointer.h | 369 --- clang/lib/AST/Interp/PrimType.h | 4 + clang/test/AST/Interp/c.c| 18 ++ clang/test/AST/Interp/const-eval.c | 194 13 files changed, 777 insertions(+), 181 deletions(-) create mode 100644 clang/test/AST/Interp/const-eval.c diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp index d943dcbe06507b..464e598cdd77e8 100644 --- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -173,10 +173,18 @@ bool ByteCodeExprGen::VisitCastExpr(const CastExpr *CE) { return this->emitCastFloatingIntegral(*ToT, CE); } - case CK_NullToPointer: + case CK_NullToPointer: { if (DiscardResult) return true; -return this->emitNull(classifyPrim(CE->getType()), CE); + +const Descriptor *Desc = nullptr; +const QualType PointeeType = CE->getType()->getPointeeType(); +if (!PointeeType.isNull()) { + if (std::optional T = classify(PointeeType)) +Desc = P.createDescriptor(SubExpr, *T); +} +return this->emitNull(classifyPrim(CE->getType()), Desc, CE); + } case CK_PointerToIntegral: { if (DiscardResult) @@ -199,6 +207,34 @@ bool ByteCodeExprGen::VisitCastExpr(const CastExpr *CE) { return true; } + case CK_IntegralToPointer: { +QualType IntType = SubExpr->getType(); +assert(IntType->isIntegralOrEnumerationType()); +if (!this->visit(SubExpr)) + return false; +// FIXME: I think the discard is wrong since the int->ptr cast might cause a +// diagnostic. +PrimType T = classifyPrim(IntType); +if (DiscardResult) + return this->emitPop(T, CE); + +QualType PtrType = CE->getType(); +assert(PtrType->isPointerType()); + +const Descriptor *Desc; +if (std::optional T = classify(PtrType->getPointeeType())) { + Desc = P.createDescriptor(SubExpr, *T); +} else if (PtrType->getPointeeType()->isVoidType()) + Desc = nullptr; +else { + Desc = P.createDescriptor(CE, PtrType->getPointeeType().getTypePtr(), +Descriptor::InlineDescMD, true, false, +/*IsMutable=*/false, nullptr); +} + +return this->emitGetIntPtr(T, Desc, CE); + } + case CK_AtomicToNonAtomic: case
[clang] [clang][Interp] Integral pointers (PR #84159)
Timm =?utf-8?q?Bäder?= , Timm =?utf-8?q?Bäder?= , Timm =?utf-8?q?Bäder?= , Timm =?utf-8?q?Bäder?= Message-ID: In-Reply-To: github-actions[bot] wrote: :warning: C/C++ code formatter, clang-format found issues in your code. :warning: You can test this locally with the following command: ``bash git-clang-format --diff 5143a1241362616840af826d18c067025dae 6b7b99579fb50c338617af58d3e82ec099430f35 -- clang/test/AST/Interp/const-eval.c clang/lib/AST/Interp/ByteCodeExprGen.cpp clang/lib/AST/Interp/ByteCodeStmtGen.cpp clang/lib/AST/Interp/Descriptor.h clang/lib/AST/Interp/FunctionPointer.h clang/lib/AST/Interp/Interp.cpp clang/lib/AST/Interp/Interp.h clang/lib/AST/Interp/InterpBlock.cpp clang/lib/AST/Interp/Pointer.cpp clang/lib/AST/Interp/Pointer.h clang/lib/AST/Interp/PrimType.h clang/test/AST/Interp/c.c clang/test/AST/Interp/functions.cpp `` View the diff from clang-format here. ``diff diff --git a/clang/lib/AST/Interp/Pointer.h b/clang/lib/AST/Interp/Pointer.h index 7521d44e3a..387a3e9fd2 100644 --- a/clang/lib/AST/Interp/Pointer.h +++ b/clang/lib/AST/Interp/Pointer.h @@ -390,7 +390,8 @@ public: // If this points inside a dummy block, return true. // FIXME: This might change in the future. If it does, we need // to set the proper Ctor/Dtor functions for dummy Descriptors. -if (asBlockPointer().Base != 0 && asBlockPointer().Base != sizeof(InlineDescriptor) && isDummy()) +if (asBlockPointer().Base != 0 && +asBlockPointer().Base != sizeof(InlineDescriptor) && isDummy()) return true; return getFieldDesc()->isUnknownSizeArray(); } `` https://github.com/llvm/llvm-project/pull/84159 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][Interp] Integral pointers (PR #84159)
Timm =?utf-8?q?Bäder?= , Timm =?utf-8?q?Bäder?= , Timm =?utf-8?q?Bäder?= , Timm =?utf-8?q?Bäder?= Message-ID: In-Reply-To: https://github.com/tbaederr updated https://github.com/llvm/llvm-project/pull/84159 >From 7d49f0f7310c86fae986f0b84bfbf2bb6e79a745 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timm=20B=C3=A4der?= Date: Wed, 6 Mar 2024 08:36:52 +0100 Subject: [PATCH 1/5] Integral pointers --- clang/lib/AST/Interp/ByteCodeExprGen.cpp | 74 - clang/lib/AST/Interp/ByteCodeStmtGen.cpp | 2 +- clang/lib/AST/Interp/Descriptor.h| 1 + clang/lib/AST/Interp/FunctionPointer.h | 10 +- clang/lib/AST/Interp/Interp.cpp | 5 + clang/lib/AST/Interp/Interp.h| 89 -- clang/lib/AST/Interp/InterpBlock.cpp | 4 +- clang/lib/AST/Interp/Opcodes.td | 12 + clang/lib/AST/Interp/Pointer.cpp | 176 --- clang/lib/AST/Interp/Pointer.h | 368 --- clang/lib/AST/Interp/PrimType.h | 4 + clang/test/AST/Interp/c.c| 18 ++ clang/test/AST/Interp/const-eval.c | 194 13 files changed, 776 insertions(+), 181 deletions(-) create mode 100644 clang/test/AST/Interp/const-eval.c diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp index 6cee3c1af9f66a..65b68f70b890e4 100644 --- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -173,10 +173,18 @@ bool ByteCodeExprGen::VisitCastExpr(const CastExpr *CE) { return this->emitCastFloatingIntegral(*ToT, CE); } - case CK_NullToPointer: + case CK_NullToPointer: { if (DiscardResult) return true; -return this->emitNull(classifyPrim(CE->getType()), CE); + +const Descriptor *Desc = nullptr; +const QualType PointeeType = CE->getType()->getPointeeType(); +if (!PointeeType.isNull()) { + if (std::optional T = classify(PointeeType)) +Desc = P.createDescriptor(SubExpr, *T); +} +return this->emitNull(classifyPrim(CE->getType()), Desc, CE); + } case CK_PointerToIntegral: { if (DiscardResult) @@ -199,6 +207,34 @@ bool ByteCodeExprGen::VisitCastExpr(const CastExpr *CE) { return true; } + case CK_IntegralToPointer: { +QualType IntType = SubExpr->getType(); +assert(IntType->isIntegralOrEnumerationType()); +if (!this->visit(SubExpr)) + return false; +// FIXME: I think the discard is wrong since the int->ptr cast might cause a +// diagnostic. +PrimType T = classifyPrim(IntType); +if (DiscardResult) + return this->emitPop(T, CE); + +QualType PtrType = CE->getType(); +assert(PtrType->isPointerType()); + +const Descriptor *Desc; +if (std::optional T = classify(PtrType->getPointeeType())) { + Desc = P.createDescriptor(SubExpr, *T); +} else if (PtrType->getPointeeType()->isVoidType()) + Desc = nullptr; +else { + Desc = P.createDescriptor(CE, PtrType->getPointeeType().getTypePtr(), +Descriptor::InlineDescMD, true, false, +/*IsMutable=*/false, nullptr); +} + +return this->emitGetIntPtr(T, Desc, CE); + } + case CK_AtomicToNonAtomic: case CK_ConstructorConversion: case CK_FunctionToPointerDecay: @@ -207,13 +243,31 @@ bool ByteCodeExprGen::VisitCastExpr(const CastExpr *CE) { case CK_UserDefinedConversion: return this->delegate(SubExpr); - case CK_BitCast: + case CK_BitCast: { +// Reject bitcasts to atomic types. if (CE->getType()->isAtomicType()) { if (!this->discard(SubExpr)) return false; return this->emitInvalidCast(CastKind::Reinterpret, CE); } -return this->delegate(SubExpr); + +if (DiscardResult) + return this->discard(SubExpr); + +std::optional FromT = classify(SubExpr->getType()); +std::optional ToT = classifyPrim(CE->getType()); +if (!FromT || !ToT) + return false; + +assert(isPtrType(*FromT)); +assert(isPtrType(*ToT)); +if (FromT == ToT) + return this->delegate(SubExpr); + +if (!this->visit(SubExpr)) + return false; +return this->emitDecayPtr(*FromT, *ToT, CE); + } case CK_IntegralToBoolean: case CK_IntegralCast: { @@ -245,7 +299,7 @@ bool ByteCodeExprGen::VisitCastExpr(const CastExpr *CE) { if (!this->visit(SubExpr)) return false; -if (!this->emitNull(PtrT, CE)) +if (!this->emitNull(PtrT, nullptr, CE)) return false; return this->emitNE(PtrT, CE); @@ -454,7 +508,7 @@ bool ByteCodeExprGen::VisitBinaryOperator(const BinaryOperator *BO) { // Pointer arithmetic special case. if (BO->getOpcode() == BO_Add || BO->getOpcode() == BO_Sub) { -if (T == PT_Ptr || (LT == PT_Ptr && RT == PT_Ptr)) +if (isPtrType(*T) || (isPtrType(*LT) && isPtrType(*RT))) return this->VisitPointerArithBinOp(BO); } @@ -2322,7 +2376,7 @@ bool ByteCodeExprGen::visitBool(const Expr *E) {
[clang] [clang][Interp] Integral pointers (PR #84159)
Timm =?utf-8?q?B=C3=A4der?= , Timm =?utf-8?q?B=C3=A4der?= Message-ID: In-Reply-To: @@ -53,6 +57,10 @@ class FunctionPointer final { return toAPValue().getAsString(Ctx, Func->getDecl()->getType()); } + uint32_t getIntegerRepresentation() const { +return static_cast(reinterpret_cast(Func)); + } AaronBallman wrote: Yeah, same here as below. https://github.com/llvm/llvm-project/pull/84159 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][Interp] Integral pointers (PR #84159)
Timm =?utf-8?q?Bäder?= , Timm =?utf-8?q?Bäder?= Message-ID: In-Reply-To: @@ -28,11 +28,26 @@ class Block; class DeadBlock; class Pointer; class Context; +template class Integral; enum PrimType : unsigned; class Pointer; inline llvm::raw_ostream <<(llvm::raw_ostream , const Pointer ); +struct BlockPointer { + /// The block the pointer is pointing to. + Block *Pointee; + /// Start of the current subfield. + unsigned Base; +}; + +struct IntPointer { + const Descriptor *Desc; + int Value; AaronBallman wrote: ah that's a good point, it probably should be uint64_t consistently. https://github.com/llvm/llvm-project/pull/84159 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][Interp] Integral pointers (PR #84159)
Timm =?utf-8?q?Bäder?= , Timm =?utf-8?q?Bäder?= Message-ID: In-Reply-To: @@ -28,11 +28,26 @@ class Block; class DeadBlock; class Pointer; class Context; +template class Integral; enum PrimType : unsigned; class Pointer; inline llvm::raw_ostream <<(llvm::raw_ostream , const Pointer ); +struct BlockPointer { AaronBallman wrote: Let's leave it alone for now. https://github.com/llvm/llvm-project/pull/84159 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][Interp] Integral pointers (PR #84159)
Timm =?utf-8?q?Bäder?= , Timm =?utf-8?q?Bäder?= Message-ID: In-Reply-To: @@ -28,11 +28,26 @@ class Block; class DeadBlock; class Pointer; class Context; +template class Integral; enum PrimType : unsigned; class Pointer; inline llvm::raw_ostream <<(llvm::raw_ostream , const Pointer ); +struct BlockPointer { tbaederr wrote: I don't have that problem but I could imaging renaming to `MemoryPointer` or something similar - we do have a `interp::Block` class though, so the name `BlockPointer` makes sense in the context. Not sure what I would rename `Block` to. https://github.com/llvm/llvm-project/pull/84159 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][Interp] Integral pointers (PR #84159)
Timm =?utf-8?q?B=C3=A4der?= , Timm =?utf-8?q?B=C3=A4der?= Message-ID: In-Reply-To: @@ -53,6 +57,10 @@ class FunctionPointer final { return toAPValue().getAsString(Ctx, Func->getDecl()->getType()); } + uint32_t getIntegerRepresentation() const { +return static_cast(reinterpret_cast(Func)); + } tbaederr wrote: Same comment as below - it should probably be a 64bit int? https://github.com/llvm/llvm-project/pull/84159 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][Interp] Integral pointers (PR #84159)
Timm =?utf-8?q?Bäder?= , Timm =?utf-8?q?Bäder?= Message-ID: In-Reply-To: https://github.com/tbaederr updated https://github.com/llvm/llvm-project/pull/84159 >From 5eacd7478d3db7472d5ab983468a441b1f61ad7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timm=20B=C3=A4der?= Date: Wed, 6 Mar 2024 08:36:52 +0100 Subject: [PATCH 1/3] Integral pointers --- clang/lib/AST/Interp/ByteCodeExprGen.cpp | 74 - clang/lib/AST/Interp/ByteCodeStmtGen.cpp | 2 +- clang/lib/AST/Interp/Descriptor.h| 1 + clang/lib/AST/Interp/FunctionPointer.h | 10 +- clang/lib/AST/Interp/Interp.cpp | 5 + clang/lib/AST/Interp/Interp.h| 89 -- clang/lib/AST/Interp/InterpBlock.cpp | 4 +- clang/lib/AST/Interp/Opcodes.td | 12 + clang/lib/AST/Interp/Pointer.cpp | 176 --- clang/lib/AST/Interp/Pointer.h | 366 --- clang/lib/AST/Interp/PrimType.h | 4 + clang/test/AST/Interp/c.c| 18 ++ clang/test/AST/Interp/const-eval.c | 194 13 files changed, 775 insertions(+), 180 deletions(-) create mode 100644 clang/test/AST/Interp/const-eval.c diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp index d887170cbc5d2d..67e7d89c033d63 100644 --- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -161,10 +161,18 @@ bool ByteCodeExprGen::VisitCastExpr(const CastExpr *CE) { return this->emitCastFloatingIntegral(*ToT, CE); } - case CK_NullToPointer: + case CK_NullToPointer: { if (DiscardResult) return true; -return this->emitNull(classifyPrim(CE->getType()), CE); + +const Descriptor *Desc = nullptr; +const QualType PointeeType = CE->getType()->getPointeeType(); +if (!PointeeType.isNull()) { + if (std::optional T = classify(PointeeType)) +Desc = P.createDescriptor(SubExpr, *T); +} +return this->emitNull(classifyPrim(CE->getType()), Desc, CE); + } case CK_PointerToIntegral: { if (DiscardResult) @@ -187,6 +195,34 @@ bool ByteCodeExprGen::VisitCastExpr(const CastExpr *CE) { return true; } + case CK_IntegralToPointer: { +QualType IntType = SubExpr->getType(); +assert(IntType->isIntegralOrEnumerationType()); +if (!this->visit(SubExpr)) + return false; +// FIXME: I think the discard is wrong since the int->ptr cast might cause a +// diagnostic. +PrimType T = classifyPrim(IntType); +if (DiscardResult) + return this->emitPop(T, CE); + +QualType PtrType = CE->getType(); +assert(PtrType->isPointerType()); + +const Descriptor *Desc; +if (std::optional T = classify(PtrType->getPointeeType())) { + Desc = P.createDescriptor(SubExpr, *T); +} else if (PtrType->getPointeeType()->isVoidType()) + Desc = nullptr; +else { + Desc = P.createDescriptor(CE, PtrType->getPointeeType().getTypePtr(), +Descriptor::InlineDescMD, true, false, +/*IsMutable=*/false, nullptr); +} + +return this->emitGetIntPtr(T, Desc, CE); + } + case CK_AtomicToNonAtomic: case CK_ConstructorConversion: case CK_FunctionToPointerDecay: @@ -195,13 +231,31 @@ bool ByteCodeExprGen::VisitCastExpr(const CastExpr *CE) { case CK_UserDefinedConversion: return this->delegate(SubExpr); - case CK_BitCast: + case CK_BitCast: { +// Reject bitcasts to atomic types. if (CE->getType()->isAtomicType()) { if (!this->discard(SubExpr)) return false; return this->emitInvalidCast(CastKind::Reinterpret, CE); } -return this->delegate(SubExpr); + +if (DiscardResult) + return this->discard(SubExpr); + +std::optional FromT = classify(SubExpr->getType()); +std::optional ToT = classifyPrim(CE->getType()); +if (!FromT || !ToT) + return false; + +assert(isPtrType(*FromT)); +assert(isPtrType(*ToT)); +if (FromT == ToT) + return this->delegate(SubExpr); + +if (!this->visit(SubExpr)) + return false; +return this->emitDecayPtr(*FromT, *ToT, CE); + } case CK_IntegralToBoolean: case CK_IntegralCast: { @@ -233,7 +287,7 @@ bool ByteCodeExprGen::VisitCastExpr(const CastExpr *CE) { if (!this->visit(SubExpr)) return false; -if (!this->emitNull(PtrT, CE)) +if (!this->emitNull(PtrT, nullptr, CE)) return false; return this->emitNE(PtrT, CE); @@ -445,7 +499,7 @@ bool ByteCodeExprGen::VisitBinaryOperator(const BinaryOperator *BO) { // Pointer arithmetic special case. if (BO->getOpcode() == BO_Add || BO->getOpcode() == BO_Sub) { -if (T == PT_Ptr || (LT == PT_Ptr && RT == PT_Ptr)) +if (isPtrType(*T) || (isPtrType(*LT) && isPtrType(*RT))) return this->VisitPointerArithBinOp(BO); } @@ -2296,7 +2350,7 @@ bool ByteCodeExprGen::visitBool(const Expr *E) { // Convert pointers to bool. if (T ==
[clang] [clang][Interp] Integral pointers (PR #84159)
Timm =?utf-8?q?Bäder?= Message-ID: In-Reply-To: @@ -28,11 +28,26 @@ class Block; class DeadBlock; class Pointer; class Context; +template class Integral; enum PrimType : unsigned; class Pointer; inline llvm::raw_ostream <<(llvm::raw_ostream , const Pointer ); +struct BlockPointer { + /// The block the pointer is pointing to. + Block *Pointee; + /// Start of the current subfield. + unsigned Base; +}; + +struct IntPointer { + const Descriptor *Desc; + int Value; tbaederr wrote: I was wondering about that... shouldn't it be a `uint64_t`? For the case where we're on a 32 bit host and compile for a 64 bit target? https://github.com/llvm/llvm-project/pull/84159 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][Interp] Integral pointers (PR #84159)
Timm =?utf-8?q?B=C3=A4der?= Message-ID: In-Reply-To: @@ -123,8 +167,9 @@ APValue Pointer::toAPValue() const { Path.push_back(APValue::LValuePathEntry({BaseOrMember, IsVirtual})); Ptr = Ptr.getBase(); continue; + +llvm_unreachable("Invalid field type"); tbaederr wrote: It does have _some_ use in its old place. https://github.com/llvm/llvm-project/pull/84159 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][Interp] Integral pointers (PR #84159)
Timm =?utf-8?q?Bäder?= Message-ID: In-Reply-To: https://github.com/tbaederr updated https://github.com/llvm/llvm-project/pull/84159 >From 5eacd7478d3db7472d5ab983468a441b1f61ad7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timm=20B=C3=A4der?= Date: Wed, 6 Mar 2024 08:36:52 +0100 Subject: [PATCH 1/2] Integral pointers --- clang/lib/AST/Interp/ByteCodeExprGen.cpp | 74 - clang/lib/AST/Interp/ByteCodeStmtGen.cpp | 2 +- clang/lib/AST/Interp/Descriptor.h| 1 + clang/lib/AST/Interp/FunctionPointer.h | 10 +- clang/lib/AST/Interp/Interp.cpp | 5 + clang/lib/AST/Interp/Interp.h| 89 -- clang/lib/AST/Interp/InterpBlock.cpp | 4 +- clang/lib/AST/Interp/Opcodes.td | 12 + clang/lib/AST/Interp/Pointer.cpp | 176 --- clang/lib/AST/Interp/Pointer.h | 366 --- clang/lib/AST/Interp/PrimType.h | 4 + clang/test/AST/Interp/c.c| 18 ++ clang/test/AST/Interp/const-eval.c | 194 13 files changed, 775 insertions(+), 180 deletions(-) create mode 100644 clang/test/AST/Interp/const-eval.c diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp index d887170cbc5d2d..67e7d89c033d63 100644 --- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -161,10 +161,18 @@ bool ByteCodeExprGen::VisitCastExpr(const CastExpr *CE) { return this->emitCastFloatingIntegral(*ToT, CE); } - case CK_NullToPointer: + case CK_NullToPointer: { if (DiscardResult) return true; -return this->emitNull(classifyPrim(CE->getType()), CE); + +const Descriptor *Desc = nullptr; +const QualType PointeeType = CE->getType()->getPointeeType(); +if (!PointeeType.isNull()) { + if (std::optional T = classify(PointeeType)) +Desc = P.createDescriptor(SubExpr, *T); +} +return this->emitNull(classifyPrim(CE->getType()), Desc, CE); + } case CK_PointerToIntegral: { if (DiscardResult) @@ -187,6 +195,34 @@ bool ByteCodeExprGen::VisitCastExpr(const CastExpr *CE) { return true; } + case CK_IntegralToPointer: { +QualType IntType = SubExpr->getType(); +assert(IntType->isIntegralOrEnumerationType()); +if (!this->visit(SubExpr)) + return false; +// FIXME: I think the discard is wrong since the int->ptr cast might cause a +// diagnostic. +PrimType T = classifyPrim(IntType); +if (DiscardResult) + return this->emitPop(T, CE); + +QualType PtrType = CE->getType(); +assert(PtrType->isPointerType()); + +const Descriptor *Desc; +if (std::optional T = classify(PtrType->getPointeeType())) { + Desc = P.createDescriptor(SubExpr, *T); +} else if (PtrType->getPointeeType()->isVoidType()) + Desc = nullptr; +else { + Desc = P.createDescriptor(CE, PtrType->getPointeeType().getTypePtr(), +Descriptor::InlineDescMD, true, false, +/*IsMutable=*/false, nullptr); +} + +return this->emitGetIntPtr(T, Desc, CE); + } + case CK_AtomicToNonAtomic: case CK_ConstructorConversion: case CK_FunctionToPointerDecay: @@ -195,13 +231,31 @@ bool ByteCodeExprGen::VisitCastExpr(const CastExpr *CE) { case CK_UserDefinedConversion: return this->delegate(SubExpr); - case CK_BitCast: + case CK_BitCast: { +// Reject bitcasts to atomic types. if (CE->getType()->isAtomicType()) { if (!this->discard(SubExpr)) return false; return this->emitInvalidCast(CastKind::Reinterpret, CE); } -return this->delegate(SubExpr); + +if (DiscardResult) + return this->discard(SubExpr); + +std::optional FromT = classify(SubExpr->getType()); +std::optional ToT = classifyPrim(CE->getType()); +if (!FromT || !ToT) + return false; + +assert(isPtrType(*FromT)); +assert(isPtrType(*ToT)); +if (FromT == ToT) + return this->delegate(SubExpr); + +if (!this->visit(SubExpr)) + return false; +return this->emitDecayPtr(*FromT, *ToT, CE); + } case CK_IntegralToBoolean: case CK_IntegralCast: { @@ -233,7 +287,7 @@ bool ByteCodeExprGen::VisitCastExpr(const CastExpr *CE) { if (!this->visit(SubExpr)) return false; -if (!this->emitNull(PtrT, CE)) +if (!this->emitNull(PtrT, nullptr, CE)) return false; return this->emitNE(PtrT, CE); @@ -445,7 +499,7 @@ bool ByteCodeExprGen::VisitBinaryOperator(const BinaryOperator *BO) { // Pointer arithmetic special case. if (BO->getOpcode() == BO_Add || BO->getOpcode() == BO_Sub) { -if (T == PT_Ptr || (LT == PT_Ptr && RT == PT_Ptr)) +if (isPtrType(*T) || (isPtrType(*LT) && isPtrType(*RT))) return this->VisitPointerArithBinOp(BO); } @@ -2296,7 +2350,7 @@ bool ByteCodeExprGen::visitBool(const Expr *E) { // Convert pointers to bool. if (T == PT_Ptr || T == PT_FnPtr) { -
[clang] [clang][Interp] Integral pointers (PR #84159)
tbaederr wrote: FWIW I've been tracking test failures by enabling the new interpreter by default and running `ninja check-clang-{ast,sema,semacxx,codegen}` at https://tbaederr.github.io/stats/. With this patch, we're down from 281 to 262 (with only one new failure, `Sema/callingconv-cast.c`). https://github.com/llvm/llvm-project/pull/84159 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][Interp] Integral pointers (PR #84159)
@@ -26,60 +26,98 @@ Pointer::Pointer(Block *Pointee) Pointer::Pointer(Block *Pointee, unsigned BaseAndOffset) : Pointer(Pointee, BaseAndOffset, BaseAndOffset) {} -Pointer::Pointer(const Pointer ) : Pointer(P.Pointee, P.Base, P.Offset) {} +Pointer::Pointer(const Pointer ) +: Offset(P.Offset), PointeeStorage(P.PointeeStorage), + StorageKind(P.StorageKind) { -Pointer::Pointer(Pointer &) -: Pointee(P.Pointee), Base(P.Base), Offset(P.Offset) { - if (Pointee) -Pointee->replacePointer(, this); + if (isBlockPointer() && PointeeStorage.BS.Pointee) +PointeeStorage.BS.Pointee->addPointer(this); } Pointer::Pointer(Block *Pointee, unsigned Base, unsigned Offset) -: Pointee(Pointee), Base(Base), Offset(Offset) { +: Offset(Offset), StorageKind(Storage::Block) { assert((Base == RootPtrMark || Base % alignof(void *) == 0) && "wrong base"); + + PointeeStorage.BS = {Pointee, Base}; + if (Pointee) Pointee->addPointer(this); } +Pointer::Pointer(Pointer &) +: Offset(P.Offset), PointeeStorage(P.PointeeStorage), + StorageKind(P.StorageKind) { + + if (StorageKind == Storage::Block && PointeeStorage.BS.Pointee) { +PointeeStorage.BS.Pointee->replacePointer(, this); + } +} + Pointer::~Pointer() { - if (Pointee) { -Pointee->removePointer(this); -Pointee->cleanup(); + if (isIntegralPointer()) +return; + + if (PointeeStorage.BS.Pointee) { +PointeeStorage.BS.Pointee->removePointer(this); +PointeeStorage.BS.Pointee->cleanup(); } } void Pointer::operator=(const Pointer ) { - Block *Old = Pointee; - if (Pointee) -Pointee->removePointer(this); + if (this->isIntegralPointer() && P.isBlockPointer()) { + } else { +assert(P.StorageKind == StorageKind); + } AaronBallman wrote: ```suggestion if (!this->isIntegralPointer() || !P.isBlockPointer()) assert(P.StorageKind == StorageKind); ``` https://github.com/llvm/llvm-project/pull/84159 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][Interp] Integral pointers (PR #84159)
@@ -28,11 +28,26 @@ class Block; class DeadBlock; class Pointer; class Context; +template class Integral; enum PrimType : unsigned; class Pointer; inline llvm::raw_ostream <<(llvm::raw_ostream , const Pointer ); +struct BlockPointer { AaronBallman wrote: This is not the first time I've hit this cognitive issue, but `Block` is an existing term of art in the compiler and means something totally different from how we use it in the interpreter. My very first thought was that this was a significant amount of work just to support Objective-C block pointers, why aren't we doing the same thing for member pointers, etc. It took me a while to realize you mean a descriptor for a chunk of memory. I don't know if others reviewing the interpreter have hit similar issues with "block" or not, so I'm not recommending any changes. But it is something to keep in mind when naming stuff. https://github.com/llvm/llvm-project/pull/84159 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][Interp] Integral pointers (PR #84159)
@@ -172,72 +217,107 @@ class Pointer { Adjust = sizeof(InitMapPtr); else Adjust = sizeof(InlineDescriptor); - return Pointer(Pointee, Base, Base + getSize() + Adjust); + return Pointer(asBlockPointer().Pointee, asBlockPointer().Base, + asBlockPointer().Base + getSize() + Adjust); } // Do not step out of array elements. -if (Base != Offset) +if (asBlockPointer().Base != Offset) return *this; // If at base, point to an array of base types. -if (Base == 0 || Base == sizeof(InlineDescriptor)) - return Pointer(Pointee, RootPtrMark, 0); +if (asBlockPointer().Base == 0 || +asBlockPointer().Base == sizeof(InlineDescriptor)) + return Pointer(asBlockPointer().Pointee, RootPtrMark, 0); // Step into the containing array, if inside one. -unsigned Next = Base - getInlineDesc()->Offset; +unsigned Next = asBlockPointer().Base - getInlineDesc()->Offset; const Descriptor *Desc = Next == 0 ? getDeclDesc() : getDescriptor(Next)->Desc; if (!Desc->IsArray) return *this; -return Pointer(Pointee, Next, Offset); +return Pointer(asBlockPointer().Pointee, Next, Offset); } /// Checks if the pointer is null. - bool isZero() const { return Pointee == nullptr; } + bool isZero() const { +if (Offset != 0) + return false; + +if (isBlockPointer()) + return asBlockPointer().Pointee == nullptr; +else if (isIntegralPointer()) + return asIntPointer().Value == 0; +llvm_unreachable("zomg"); AaronBallman wrote: ```suggestion assert(isIntegralPointer() && "expected an integral pointer"); return asIntPointer().Value == 0; ``` https://github.com/llvm/llvm-project/pull/84159 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][Interp] Integral pointers (PR #84159)
@@ -26,60 +26,98 @@ Pointer::Pointer(Block *Pointee) Pointer::Pointer(Block *Pointee, unsigned BaseAndOffset) : Pointer(Pointee, BaseAndOffset, BaseAndOffset) {} -Pointer::Pointer(const Pointer ) : Pointer(P.Pointee, P.Base, P.Offset) {} +Pointer::Pointer(const Pointer ) +: Offset(P.Offset), PointeeStorage(P.PointeeStorage), + StorageKind(P.StorageKind) { -Pointer::Pointer(Pointer &) -: Pointee(P.Pointee), Base(P.Base), Offset(P.Offset) { - if (Pointee) -Pointee->replacePointer(, this); + if (isBlockPointer() && PointeeStorage.BS.Pointee) +PointeeStorage.BS.Pointee->addPointer(this); } Pointer::Pointer(Block *Pointee, unsigned Base, unsigned Offset) -: Pointee(Pointee), Base(Base), Offset(Offset) { +: Offset(Offset), StorageKind(Storage::Block) { assert((Base == RootPtrMark || Base % alignof(void *) == 0) && "wrong base"); + + PointeeStorage.BS = {Pointee, Base}; + if (Pointee) Pointee->addPointer(this); } +Pointer::Pointer(Pointer &) +: Offset(P.Offset), PointeeStorage(P.PointeeStorage), + StorageKind(P.StorageKind) { + + if (StorageKind == Storage::Block && PointeeStorage.BS.Pointee) { +PointeeStorage.BS.Pointee->replacePointer(, this); + } AaronBallman wrote: ```suggestion if (StorageKind == Storage::Block && PointeeStorage.BS.Pointee) PointeeStorage.BS.Pointee->replacePointer(, this); ``` https://github.com/llvm/llvm-project/pull/84159 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][Interp] Integral pointers (PR #84159)
@@ -123,8 +167,9 @@ APValue Pointer::toAPValue() const { Path.push_back(APValue::LValuePathEntry({BaseOrMember, IsVirtual})); Ptr = Ptr.getBase(); continue; + +llvm_unreachable("Invalid field type"); AaronBallman wrote: Errr... given the unconditional `continue` on the line above, I agree this is unreachable... but does this actually help anything? https://github.com/llvm/llvm-project/pull/84159 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][Interp] Integral pointers (PR #84159)
@@ -88,6 +126,12 @@ APValue Pointer::toAPValue() const { if (isZero()) return APValue(static_cast(nullptr), CharUnits::Zero(), Path, /*IsOnePastEnd=*/false, /*IsNullPtr=*/true); + if (isIntegralPointer()) { +return APValue(static_cast(nullptr), + CharUnits::fromQuantity(asIntPointer().Value + this->Offset), + Path, + /*IsOnePastEnd=*/false, /*IsNullPtr=*/false); + } AaronBallman wrote: ```suggestion if (isIntegralPointer()) return APValue(static_cast(nullptr), CharUnits::fromQuantity(asIntPointer().Value + this->Offset), Path, /*IsOnePastEnd=*/false, /*IsNullPtr=*/false); ``` https://github.com/llvm/llvm-project/pull/84159 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][Interp] Integral pointers (PR #84159)
@@ -809,9 +809,9 @@ inline bool CmpHelperEQ(InterpState , CodePtr OpPC, CompareFn Fn) { // element in the same array are NOT equal. They have the same Base value, // but a different Offset. This is a pretty rare case, so we fix this here // by comparing pointers to the first elements. -if (!LHS.isDummy() && LHS.isArrayRoot()) +if (!LHS.isZero() && !LHS.isDummy() && LHS.isArrayRoot()) VL = LHS.atIndex(0).getByteOffset(); -if (!RHS.isDummy() && RHS.isArrayRoot()) +if (!RHS.isDummy() && !RHS.isDummy() && RHS.isArrayRoot()) AaronBallman wrote: ```suggestion if (!RHS.isZero() && !RHS.isDummy() && RHS.isArrayRoot()) ``` Right? (Might be missing test coverage.) https://github.com/llvm/llvm-project/pull/84159 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][Interp] Integral pointers (PR #84159)
@@ -2180,6 +2201,14 @@ inline bool GetFnPtr(InterpState , CodePtr OpPC, const Function *Func) { return true; } +template ::T> +inline bool GetIntPtr(InterpState , CodePtr OpPC, const Descriptor *Desc) { + const T = S.Stk.pop(); + + S.Stk.push(static_cast(IntVal), Desc); AaronBallman wrote: `uintptr_t` instead? https://github.com/llvm/llvm-project/pull/84159 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][Interp] Integral pointers (PR #84159)
@@ -187,6 +195,34 @@ bool ByteCodeExprGen::VisitCastExpr(const CastExpr *CE) { return true; } + case CK_IntegralToPointer: { +QualType IntType = SubExpr->getType(); +assert(IntType->isIntegralOrEnumerationType()); +if (!this->visit(SubExpr)) + return false; +// FIXME: I think the discard is wrong since the int->ptr cast might cause a +// diagnostic. +PrimType T = classifyPrim(IntType); +if (DiscardResult) + return this->emitPop(T, CE); + +QualType PtrType = CE->getType(); +assert(PtrType->isPointerType()); + +const Descriptor *Desc; +if (std::optional T = classify(PtrType->getPointeeType())) { + Desc = P.createDescriptor(SubExpr, *T); +} else if (PtrType->getPointeeType()->isVoidType()) + Desc = nullptr; +else { + Desc = P.createDescriptor(CE, PtrType->getPointeeType().getTypePtr(), +Descriptor::InlineDescMD, true, false, +/*IsMutable=*/false, nullptr); +} AaronBallman wrote: ```suggestion if (std::optional T = classify(PtrType->getPointeeType())) Desc = P.createDescriptor(SubExpr, *T); else if (PtrType->getPointeeType()->isVoidType()) Desc = nullptr; else Desc = P.createDescriptor(CE, PtrType->getPointeeType().getTypePtr(), Descriptor::InlineDescMD, true, false, /*IsMutable=*/false, nullptr); ``` https://github.com/llvm/llvm-project/pull/84159 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][Interp] Integral pointers (PR #84159)
@@ -26,60 +26,98 @@ Pointer::Pointer(Block *Pointee) Pointer::Pointer(Block *Pointee, unsigned BaseAndOffset) : Pointer(Pointee, BaseAndOffset, BaseAndOffset) {} -Pointer::Pointer(const Pointer ) : Pointer(P.Pointee, P.Base, P.Offset) {} +Pointer::Pointer(const Pointer ) +: Offset(P.Offset), PointeeStorage(P.PointeeStorage), + StorageKind(P.StorageKind) { -Pointer::Pointer(Pointer &) -: Pointee(P.Pointee), Base(P.Base), Offset(P.Offset) { - if (Pointee) -Pointee->replacePointer(, this); + if (isBlockPointer() && PointeeStorage.BS.Pointee) +PointeeStorage.BS.Pointee->addPointer(this); } Pointer::Pointer(Block *Pointee, unsigned Base, unsigned Offset) -: Pointee(Pointee), Base(Base), Offset(Offset) { +: Offset(Offset), StorageKind(Storage::Block) { assert((Base == RootPtrMark || Base % alignof(void *) == 0) && "wrong base"); + + PointeeStorage.BS = {Pointee, Base}; + if (Pointee) Pointee->addPointer(this); } +Pointer::Pointer(Pointer &) +: Offset(P.Offset), PointeeStorage(P.PointeeStorage), + StorageKind(P.StorageKind) { + + if (StorageKind == Storage::Block && PointeeStorage.BS.Pointee) { +PointeeStorage.BS.Pointee->replacePointer(, this); + } +} + Pointer::~Pointer() { - if (Pointee) { -Pointee->removePointer(this); -Pointee->cleanup(); + if (isIntegralPointer()) +return; + + if (PointeeStorage.BS.Pointee) { +PointeeStorage.BS.Pointee->removePointer(this); +PointeeStorage.BS.Pointee->cleanup(); } } void Pointer::operator=(const Pointer ) { - Block *Old = Pointee; - if (Pointee) -Pointee->removePointer(this); + if (this->isIntegralPointer() && P.isBlockPointer()) { + } else { +assert(P.StorageKind == StorageKind); + } - Offset = P.Offset; - Base = P.Base; + bool WasBlockPointer = isBlockPointer(); + StorageKind = P.StorageKind; + if (StorageKind == Storage::Block) { +Block *Old = PointeeStorage.BS.Pointee; +if (WasBlockPointer && PointeeStorage.BS.Pointee) + PointeeStorage.BS.Pointee->removePointer(this); - Pointee = P.Pointee; - if (Pointee) -Pointee->addPointer(this); +Offset = P.Offset; +PointeeStorage.BS = P.PointeeStorage.BS; + +if (PointeeStorage.BS.Pointee) + PointeeStorage.BS.Pointee->addPointer(this); - if (Old) -Old->cleanup(); +if (WasBlockPointer && Old) + Old->cleanup(); + + } else if (StorageKind == Storage::Int) { +PointeeStorage.Int = P.PointeeStorage.Int; + } else +assert(false); } void Pointer::operator=(Pointer &) { - Block *Old = Pointee; + if (this->isIntegralPointer() && P.isBlockPointer()) { + } else { +assert(P.StorageKind == StorageKind); + } - if (Pointee) -Pointee->removePointer(this); + bool WasBlockPointer = isBlockPointer(); + StorageKind = P.StorageKind; + if (StorageKind == Storage::Block) { +Block *Old = PointeeStorage.BS.Pointee; +if (WasBlockPointer && PointeeStorage.BS.Pointee) + PointeeStorage.BS.Pointee->removePointer(this); - Offset = P.Offset; - Base = P.Base; +Offset = P.Offset; +PointeeStorage.BS = P.PointeeStorage.BS; - Pointee = P.Pointee; - if (Pointee) -Pointee->replacePointer(, this); +if (PointeeStorage.BS.Pointee) + PointeeStorage.BS.Pointee->addPointer(this); + +if (WasBlockPointer && Old) + Old->cleanup(); - if (Old) -Old->cleanup(); + } else if (StorageKind == Storage::Int) { +PointeeStorage.Int = P.PointeeStorage.Int; + } else +assert(false); AaronBallman wrote: ```suggestion } else { assert(false); } ``` Same suggestion here as above. https://github.com/llvm/llvm-project/pull/84159 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][Interp] Integral pointers (PR #84159)
@@ -1912,6 +1929,10 @@ inline bool NoRet(InterpState , CodePtr OpPC) { inline bool NarrowPtr(InterpState , CodePtr OpPC) { const Pointer = S.Stk.pop(); + if (!S.getLangOpts().CPlusPlus) { +S.Stk.push(Ptr); AaronBallman wrote: Might be a good idea to comment why the C logic is different from the C++ logic. https://github.com/llvm/llvm-project/pull/84159 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][Interp] Integral pointers (PR #84159)
@@ -1505,12 +1509,17 @@ bool OffsetHelper(InterpState , CodePtr OpPC, const T , return true; } - if (!CheckNull(S, OpPC, Ptr, CSK_ArrayIndex)) -return false; + if (!CheckNull(S, OpPC, Ptr, CSK_ArrayIndex)) { +// The CheckNul will have emitted a note already, but we only +// abort in C++, since this is fine in C. +if (S.getLangOpts().CPlusPlus) + return false; + } // Arrays of unknown bounds cannot have pointers into them. - if (!CheckArray(S, OpPC, Ptr)) + if (!CheckArray(S, OpPC, Ptr)) { return false; + } AaronBallman wrote: ```suggestion if (!CheckArray(S, OpPC, Ptr)) return false; ``` https://github.com/llvm/llvm-project/pull/84159 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][Interp] Integral pointers (PR #84159)
https://github.com/AaronBallman commented: I think the general direction is pretty reasonable. https://github.com/llvm/llvm-project/pull/84159 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][Interp] Integral pointers (PR #84159)
https://github.com/AaronBallman edited https://github.com/llvm/llvm-project/pull/84159 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][Interp] Integral pointers (PR #84159)
@@ -53,6 +57,10 @@ class FunctionPointer final { return toAPValue().getAsString(Ctx, Func->getDecl()->getType()); } + uint32_t getIntegerRepresentation() const { +return static_cast(reinterpret_cast(Func)); + } AaronBallman wrote: This seems dangerous to me. `Func` is a pointer, so casting to `uintptr_t` makes sense, but then casting to a 32-bit value seems likely to cause problems due to truncation. Any reason why this shouldn't return a `uintptr_t`? https://github.com/llvm/llvm-project/pull/84159 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][Interp] Integral pointers (PR #84159)
@@ -26,60 +26,98 @@ Pointer::Pointer(Block *Pointee) Pointer::Pointer(Block *Pointee, unsigned BaseAndOffset) : Pointer(Pointee, BaseAndOffset, BaseAndOffset) {} -Pointer::Pointer(const Pointer ) : Pointer(P.Pointee, P.Base, P.Offset) {} +Pointer::Pointer(const Pointer ) +: Offset(P.Offset), PointeeStorage(P.PointeeStorage), + StorageKind(P.StorageKind) { -Pointer::Pointer(Pointer &) -: Pointee(P.Pointee), Base(P.Base), Offset(P.Offset) { - if (Pointee) -Pointee->replacePointer(, this); + if (isBlockPointer() && PointeeStorage.BS.Pointee) +PointeeStorage.BS.Pointee->addPointer(this); } Pointer::Pointer(Block *Pointee, unsigned Base, unsigned Offset) -: Pointee(Pointee), Base(Base), Offset(Offset) { +: Offset(Offset), StorageKind(Storage::Block) { assert((Base == RootPtrMark || Base % alignof(void *) == 0) && "wrong base"); + + PointeeStorage.BS = {Pointee, Base}; + if (Pointee) Pointee->addPointer(this); } +Pointer::Pointer(Pointer &) +: Offset(P.Offset), PointeeStorage(P.PointeeStorage), + StorageKind(P.StorageKind) { + + if (StorageKind == Storage::Block && PointeeStorage.BS.Pointee) { +PointeeStorage.BS.Pointee->replacePointer(, this); + } +} + Pointer::~Pointer() { - if (Pointee) { -Pointee->removePointer(this); -Pointee->cleanup(); + if (isIntegralPointer()) +return; + + if (PointeeStorage.BS.Pointee) { +PointeeStorage.BS.Pointee->removePointer(this); +PointeeStorage.BS.Pointee->cleanup(); } } void Pointer::operator=(const Pointer ) { - Block *Old = Pointee; - if (Pointee) -Pointee->removePointer(this); + if (this->isIntegralPointer() && P.isBlockPointer()) { + } else { +assert(P.StorageKind == StorageKind); + } - Offset = P.Offset; - Base = P.Base; + bool WasBlockPointer = isBlockPointer(); + StorageKind = P.StorageKind; + if (StorageKind == Storage::Block) { +Block *Old = PointeeStorage.BS.Pointee; +if (WasBlockPointer && PointeeStorage.BS.Pointee) + PointeeStorage.BS.Pointee->removePointer(this); - Pointee = P.Pointee; - if (Pointee) -Pointee->addPointer(this); +Offset = P.Offset; +PointeeStorage.BS = P.PointeeStorage.BS; + +if (PointeeStorage.BS.Pointee) + PointeeStorage.BS.Pointee->addPointer(this); + +if (WasBlockPointer && Old) + Old->cleanup(); - if (Old) -Old->cleanup(); + } else if (StorageKind == Storage::Int) { +PointeeStorage.Int = P.PointeeStorage.Int; + } else +assert(false); AaronBallman wrote: ```suggestion } else { assert(false); } ``` It would be good to add `&& "some useful message"` to this assertion. https://github.com/llvm/llvm-project/pull/84159 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][Interp] Integral pointers (PR #84159)
llvmbot wrote: @llvm/pr-subscribers-clang Author: Timm Baeder (tbaederr) Changes This turns the current `Pointer` class into a discriminated union of `BlockPointer` and `IntPointer`. The former is what `Pointer` currently is while the latter is just an integer value and an optional `Descriptor*`. The `Pointer` then has type check functions like `isBlockPointer()`/`isIntegralPointer()`/`asBlockPointer()`/`asIntPointer()`, which can be used to access its data. Right now, the `IntPointer` and `BlockPointer` structs do not have any methods of their own and everything is instead implemented in Pointer (like it was before) and the functions now just either assert for the right type or decide what to do based on it. This also implements bitcasts by decaying the pointer to an integral pointer. `test/AST/Interp/const-eval.c` is a new test testing all kinds of stuff related to this. It still has a few tests `#ifdef`-ed out but that mostly depends on other unimplemented things like `__builtin_constant_p`. --- Patch is 56.29 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/84159.diff 13 Files Affected: - (modified) clang/lib/AST/Interp/ByteCodeExprGen.cpp (+61-10) - (modified) clang/lib/AST/Interp/ByteCodeStmtGen.cpp (+1-1) - (modified) clang/lib/AST/Interp/Descriptor.h (+1) - (modified) clang/lib/AST/Interp/FunctionPointer.h (+9-1) - (modified) clang/lib/AST/Interp/Interp.cpp (+5) - (modified) clang/lib/AST/Interp/Interp.h (+65-24) - (modified) clang/lib/AST/Interp/InterpBlock.cpp (+2-2) - (modified) clang/lib/AST/Interp/Opcodes.td (+12) - (modified) clang/lib/AST/Interp/Pointer.cpp (+133-40) - (modified) clang/lib/AST/Interp/Pointer.h (+264-102) - (modified) clang/lib/AST/Interp/PrimType.h (+4) - (modified) clang/test/AST/Interp/c.c (+18) - (added) clang/test/AST/Interp/const-eval.c (+194) ``diff diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp index d887170cbc5d2d..ace571dd6bd821 100644 --- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -161,10 +161,18 @@ bool ByteCodeExprGen::VisitCastExpr(const CastExpr *CE) { return this->emitCastFloatingIntegral(*ToT, CE); } - case CK_NullToPointer: + case CK_NullToPointer: { if (DiscardResult) return true; -return this->emitNull(classifyPrim(CE->getType()), CE); + +const Descriptor *Desc = nullptr; +const QualType PointeeType = CE->getType()->getPointeeType(); +if (!PointeeType.isNull()) { + if (std::optional T = classify(PointeeType)) +Desc = P.createDescriptor(SubExpr, *T); +} +return this->emitNull(classifyPrim(CE->getType()), Desc, CE); + } case CK_PointerToIntegral: { if (DiscardResult) @@ -187,6 +195,34 @@ bool ByteCodeExprGen::VisitCastExpr(const CastExpr *CE) { return true; } + case CK_IntegralToPointer: { +QualType IntType = SubExpr->getType(); +assert(IntType->isIntegralOrEnumerationType()); +if (!this->visit(SubExpr)) + return false; +// FIXME: I think the discard is wrong since the int->ptr cast might cause a +// diagnostic. +PrimType T = classifyPrim(IntType); +if (DiscardResult) + return this->emitPop(T, CE); + +QualType PtrType = CE->getType(); +assert(PtrType->isPointerType()); + +const Descriptor *Desc; +if (std::optional T = classify(PtrType->getPointeeType())) { + Desc = P.createDescriptor(SubExpr, *T); +} else if (PtrType->getPointeeType()->isVoidType()) + Desc = nullptr; +else { + Desc = P.createDescriptor(CE, PtrType->getPointeeType().getTypePtr(), +Descriptor::InlineDescMD, true, false, +/*IsMutable=*/false, nullptr); +} + +return this->emitGetIntPtr(T, Desc, CE); + } + case CK_AtomicToNonAtomic: case CK_ConstructorConversion: case CK_FunctionToPointerDecay: @@ -195,13 +231,28 @@ bool ByteCodeExprGen::VisitCastExpr(const CastExpr *CE) { case CK_UserDefinedConversion: return this->delegate(SubExpr); - case CK_BitCast: + case CK_BitCast: { +// Reject bitcasts to atomic types. if (CE->getType()->isAtomicType()) { if (!this->discard(SubExpr)) return false; return this->emitInvalidCast(CastKind::Reinterpret, CE); } -return this->delegate(SubExpr); + +if (DiscardResult) + return this->discard(SubExpr); + +PrimType FromT = classifyPrim(SubExpr->getType()); +PrimType ToT = classifyPrim(CE->getType()); +assert(isPtrType(FromT)); +assert(isPtrType(ToT)); +if (FromT == ToT) + return this->delegate(SubExpr); + +if (!this->visit(SubExpr)) + return false; +return this->emitDecayPtr(FromT, ToT, CE); + } case CK_IntegralToBoolean: case CK_IntegralCast: { @@ -233,7 +284,7 @@ bool ByteCodeExprGen::VisitCastExpr(const CastExpr *CE) {
[clang] [clang][Interp] Integral pointers (PR #84159)
https://github.com/tbaederr created https://github.com/llvm/llvm-project/pull/84159 This turns the current `Pointer` class into a discriminated union of `BlockPointer` and `IntPointer`. The former is what `Pointer` currently is while the latter is just an integer value and an optional `Descriptor*`. The `Pointer` then has type check functions like `isBlockPointer()`/`isIntegralPointer()`/`asBlockPointer()`/`asIntPointer()`, which can be used to access its data. Right now, the `IntPointer` and `BlockPointer` structs do not have any methods of their own and everything is instead implemented in Pointer (like it was before) and the functions now just either assert for the right type or decide what to do based on it. This also implements bitcasts by decaying the pointer to an integral pointer. `test/AST/Interp/const-eval.c` is a new test testing all kinds of stuff related to this. It still has a few tests `#ifdef`-ed out but that mostly depends on other unimplemented things like `__builtin_constant_p`. >From 0ffa1ff8e909d4fa7a324b3623348fac9969572f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timm=20B=C3=A4der?= Date: Wed, 6 Mar 2024 08:36:52 +0100 Subject: [PATCH] Integral pointers --- clang/lib/AST/Interp/ByteCodeExprGen.cpp | 71 - clang/lib/AST/Interp/ByteCodeStmtGen.cpp | 2 +- clang/lib/AST/Interp/Descriptor.h| 1 + clang/lib/AST/Interp/FunctionPointer.h | 10 +- clang/lib/AST/Interp/Interp.cpp | 5 + clang/lib/AST/Interp/Interp.h| 89 -- clang/lib/AST/Interp/InterpBlock.cpp | 4 +- clang/lib/AST/Interp/Opcodes.td | 12 + clang/lib/AST/Interp/Pointer.cpp | 173 --- clang/lib/AST/Interp/Pointer.h | 366 --- clang/lib/AST/Interp/PrimType.h | 4 + clang/test/AST/Interp/c.c| 18 ++ clang/test/AST/Interp/const-eval.c | 194 13 files changed, 769 insertions(+), 180 deletions(-) create mode 100644 clang/test/AST/Interp/const-eval.c diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp index d887170cbc5d2d..ace571dd6bd821 100644 --- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -161,10 +161,18 @@ bool ByteCodeExprGen::VisitCastExpr(const CastExpr *CE) { return this->emitCastFloatingIntegral(*ToT, CE); } - case CK_NullToPointer: + case CK_NullToPointer: { if (DiscardResult) return true; -return this->emitNull(classifyPrim(CE->getType()), CE); + +const Descriptor *Desc = nullptr; +const QualType PointeeType = CE->getType()->getPointeeType(); +if (!PointeeType.isNull()) { + if (std::optional T = classify(PointeeType)) +Desc = P.createDescriptor(SubExpr, *T); +} +return this->emitNull(classifyPrim(CE->getType()), Desc, CE); + } case CK_PointerToIntegral: { if (DiscardResult) @@ -187,6 +195,34 @@ bool ByteCodeExprGen::VisitCastExpr(const CastExpr *CE) { return true; } + case CK_IntegralToPointer: { +QualType IntType = SubExpr->getType(); +assert(IntType->isIntegralOrEnumerationType()); +if (!this->visit(SubExpr)) + return false; +// FIXME: I think the discard is wrong since the int->ptr cast might cause a +// diagnostic. +PrimType T = classifyPrim(IntType); +if (DiscardResult) + return this->emitPop(T, CE); + +QualType PtrType = CE->getType(); +assert(PtrType->isPointerType()); + +const Descriptor *Desc; +if (std::optional T = classify(PtrType->getPointeeType())) { + Desc = P.createDescriptor(SubExpr, *T); +} else if (PtrType->getPointeeType()->isVoidType()) + Desc = nullptr; +else { + Desc = P.createDescriptor(CE, PtrType->getPointeeType().getTypePtr(), +Descriptor::InlineDescMD, true, false, +/*IsMutable=*/false, nullptr); +} + +return this->emitGetIntPtr(T, Desc, CE); + } + case CK_AtomicToNonAtomic: case CK_ConstructorConversion: case CK_FunctionToPointerDecay: @@ -195,13 +231,28 @@ bool ByteCodeExprGen::VisitCastExpr(const CastExpr *CE) { case CK_UserDefinedConversion: return this->delegate(SubExpr); - case CK_BitCast: + case CK_BitCast: { +// Reject bitcasts to atomic types. if (CE->getType()->isAtomicType()) { if (!this->discard(SubExpr)) return false; return this->emitInvalidCast(CastKind::Reinterpret, CE); } -return this->delegate(SubExpr); + +if (DiscardResult) + return this->discard(SubExpr); + +PrimType FromT = classifyPrim(SubExpr->getType()); +PrimType ToT = classifyPrim(CE->getType()); +assert(isPtrType(FromT)); +assert(isPtrType(ToT)); +if (FromT == ToT) + return this->delegate(SubExpr); + +if (!this->visit(SubExpr)) + return false; +return this->emitDecayPtr(FromT, ToT, CE); + } case