https://github.com/philnik777 updated https://github.com/llvm/llvm-project/pull/224903
>From 005721818ed263907b15b874efd7c23935b19640 Mon Sep 17 00:00:00 2001 From: Nikolas Klauser <[email protected]> Date: Sun, 20 Sep 2026 11:58:05 +0200 Subject: [PATCH 1/2] [Clang][ByteCode] Store type information inside the custom stack --- clang/lib/AST/ByteCode/FixedPoint.h | 2 +- clang/lib/AST/ByteCode/Integral.h | 2 +- clang/lib/AST/ByteCode/InterpStack.cpp | 32 ++++++------ clang/lib/AST/ByteCode/InterpStack.h | 71 +++++++++++++++++--------- clang/lib/AST/ByteCode/Pointer.h | 2 +- 5 files changed, 66 insertions(+), 43 deletions(-) diff --git a/clang/lib/AST/ByteCode/FixedPoint.h b/clang/lib/AST/ByteCode/FixedPoint.h index fcb3c79cc1097..7aab21a77c8f9 100644 --- a/clang/lib/AST/ByteCode/FixedPoint.h +++ b/clang/lib/AST/ByteCode/FixedPoint.h @@ -22,7 +22,7 @@ using APSInt = llvm::APSInt; /// Wrapper around fixed point types. class FixedPoint final { private: - llvm::APFixedPoint V; + LLVM_NO_UNIQUE_ADDRESS llvm::APFixedPoint V; public: FixedPoint(llvm::APFixedPoint &&V) : V(std::move(V)) {} diff --git a/clang/lib/AST/ByteCode/Integral.h b/clang/lib/AST/ByteCode/Integral.h index 543d7f7fd43a9..e2bde2a0c82f7 100644 --- a/clang/lib/AST/ByteCode/Integral.h +++ b/clang/lib/AST/ByteCode/Integral.h @@ -78,7 +78,6 @@ template <unsigned Bits, bool Signed> class Integral final { static_assert(std::is_trivially_copyable_v<ReprT>); template <unsigned OtherBits, bool OtherSigned> friend class Integral; - IntegralKind Kind = IntegralKind::Number; union { ReprT V; struct { @@ -90,6 +89,7 @@ template <unsigned Bits, bool Signed> class Integral final { const AddrLabelExpr *L2; } AddrLabelDiff; }; + IntegralKind Kind = IntegralKind::Number; /// Primitive representing limits. static const auto Min = std::numeric_limits<ReprT>::min(); diff --git a/clang/lib/AST/ByteCode/InterpStack.cpp b/clang/lib/AST/ByteCode/InterpStack.cpp index 839540a7912f8..b85c271931052 100644 --- a/clang/lib/AST/ByteCode/InterpStack.cpp +++ b/clang/lib/AST/ByteCode/InterpStack.cpp @@ -25,15 +25,22 @@ InterpStack::~InterpStack() { std::free(Chunk->Next); if (Chunk) std::free(Chunk); + +#if __has_cpp_attribute(no_unique_address) + TYPE_SWITCH(PrimType(), { + using Frame = StackFrame<T>; + static_assert(offsetof(Frame, type) == sizeof(Frame) - 1); + static_assert(sizeof(void *) != 8 || sizeof(Frame) == sizeof(T) || + sizeof(T) < sizeof(void *)); + }); +#endif } // We keep the last chunk around to reuse. void InterpStack::clear() { - for (PrimType Item : llvm::reverse(ItemTypes)) { - TYPE_SWITCH(Item, { this->discard<T>(); }); + while (!empty()) { + TYPE_SWITCH(getNextObjectType(), { this->discard<T>(); }); } - assert(ItemTypes.empty()); - assert(empty()); } void InterpStack::clearTo(size_t NewSize) { @@ -43,12 +50,8 @@ void InterpStack::clearTo(size_t NewSize) { return; assert(NewSize <= size()); - for (PrimType Item : llvm::reverse(ItemTypes)) { - TYPE_SWITCH(Item, { this->discard<T>(); }); - - if (size() == NewSize) - break; - } + while (size() != NewSize) + TYPE_SWITCH(getNextObjectType(), { this->discard<T>(); }); // Note: discard() above already removed the types from ItemTypes. assert(size() == NewSize); @@ -96,16 +99,13 @@ void InterpStack::shrink(size_t Size) { } void InterpStack::dump() const { - llvm::errs() << "Items: " << ItemTypes.size() << ". Size: " << size() << '\n'; - if (ItemTypes.empty()) - return; - size_t Index = 0; size_t Offset = 0; // The type of the item on the top of the stack is inserted to the back // of the vector, so the iteration has to happen backwards. - for (PrimType Item : llvm::reverse(ItemTypes)) { + while (Offset != size()) { + PrimType Item = *static_cast<PrimType *>(peekData(Offset + 1)); Offset += align(primSize(Item)); llvm::errs() << Index << '/' << Offset << ": "; @@ -122,5 +122,5 @@ void InterpStack::dump() const { void InterpStack::discardSlow() { assert(!empty()); - TYPE_SWITCH(ItemTypes.back(), { discard<T>(); }); + TYPE_SWITCH(getNextObjectType(), { discard<T>(); }); } diff --git a/clang/lib/AST/ByteCode/InterpStack.h b/clang/lib/AST/ByteCode/InterpStack.h index 2c02979ee6eec..faaab371fbf59 100644 --- a/clang/lib/AST/ByteCode/InterpStack.h +++ b/clang/lib/AST/ByteCode/InterpStack.h @@ -21,6 +21,15 @@ namespace clang { namespace interp { +template <class T> +struct datasizeof_impl { + LLVM_NO_UNIQUE_ADDRESS T v; + char first_padding_byte; +}; + +template <class T> +constexpr size_t datasizeof_v = offsetof(datasizeof_impl<T>, first_padding_byte); + /// Stack frame storing temporaries and parameters. class InterpStack final { public: @@ -29,40 +38,63 @@ class InterpStack final { /// Destroys the stack, freeing up storage. ~InterpStack(); + template <size_t N> struct Padding { + char padding[N]; + }; + + template <> struct Padding<0> {}; + + template <class T> struct alignas(void *) StackFrame { + static_assert(alignof(T) <= alignof(void *), + "Unexpected overaligned object"); + + template <class... Args> + StackFrame(Args &&...args) + : v(std::forward<Args>(args)...), type(toPrimType<T>()) {} + + static constexpr size_t getPaddingSize() { + if constexpr (sizeof(T) < sizeof(void*)) + return sizeof(void*) - datasizeof_v<T> - 1; + else if constexpr (sizeof(T) == datasizeof_v<T>) + return sizeof(void*) - 1; + else + return sizeof(T) - datasizeof_v<T> - 1; + } + + LLVM_NO_UNIQUE_ADDRESS T v; + LLVM_NO_UNIQUE_ADDRESS Padding<getPaddingSize()> padding; + PrimType type; + }; + /// Constructs a value in place on the top of the stack. template <typename T, typename... Tys> void push(Tys &&...Args) { - new (grow<aligned_size<T>()>()) T(std::forward<Tys>(Args)...); - ItemTypes.push_back(toPrimType<T>()); + using Frame = StackFrame<T>; + new (grow<sizeof(Frame)>()) Frame(std::forward<Tys>(Args)...); } /// Returns the value from the top of the stack and removes it. template <typename T> T pop() { - assert(!ItemTypes.empty()); - assert(ItemTypes.back() == toPrimType<T>()); - ItemTypes.pop_back(); + assert(getNextObjectType() == toPrimType<T>()); T *Ptr = &peekInternal<T>(); T Value = std::move(*Ptr); - shrink(aligned_size<T>()); + shrink(sizeof(StackFrame<T>)); return Value; } /// Discards the top value from the stack. template <typename T> void discard() { - assert(!ItemTypes.empty()); - assert(ItemTypes.back() == toPrimType<T>()); - ItemTypes.pop_back(); + assert(getNextObjectType() == toPrimType<T>()); T *Ptr = &peekInternal<T>(); if constexpr (!std::is_trivially_destructible_v<T>) { Ptr->~T(); } - shrink(aligned_size<T>()); + shrink(sizeof(StackFrame<T>)); } void discardSlow(); /// Returns a reference to the value on the top of the stack. template <typename T> T &peek() const { - assert(!ItemTypes.empty()); - assert(ItemTypes.back() == toPrimType<T>()); + assert(getNextObjectType() == toPrimType<T>()); return peekInternal<T>(); } @@ -88,16 +120,13 @@ class InterpStack final { void dump() const; private: - /// All stack slots are aligned to the native pointer alignment for storage. - /// The size of an object is rounded up to a pointer alignment multiple. - template <typename T> static constexpr size_t aligned_size() { - constexpr size_t PtrAlign = alignof(void *); - return ((sizeof(T) + PtrAlign - 1) / PtrAlign) * PtrAlign; + PrimType getNextObjectType() const { + return *static_cast<PrimType *>(peekData(1)); } /// Like the public peek(), but without the debug type checks. template <typename T> T &peekInternal() const { - return *reinterpret_cast<T *>(peekData(aligned_size<T>())); + return static_cast<StackFrame<T> *>(peekData(sizeof(StackFrame<T>)))->v; } /// Grows the stack to accommodate a value and returns a pointer to it. @@ -163,12 +192,6 @@ class InterpStack final { /// Total size of the stack. size_t StackSize = 0; - /// SmallVector recording the type of data we pushed into the stack. - /// We don't usually need this during normal code interpretation but - /// when aborting, we need type information to call the destructors - /// for what's left on the stack. - llvm::SmallVector<PrimType> ItemTypes; - template <typename T> static constexpr PrimType toPrimType() { if constexpr (std::is_same_v<T, Pointer>) return PT_Ptr; diff --git a/clang/lib/AST/ByteCode/Pointer.h b/clang/lib/AST/ByteCode/Pointer.h index 54e0f858b4fa0..975f1cc15aa58 100644 --- a/clang/lib/AST/ByteCode/Pointer.h +++ b/clang/lib/AST/ByteCode/Pointer.h @@ -1334,7 +1334,6 @@ class Pointer { /// Offset into the storage. uint64_t Offset = 0; - Storage StorageKind = Storage::Int; union { IntPointer Int; BlockPointer BS; @@ -1343,6 +1342,7 @@ class Pointer { StringPointer Str; OpaquePointer Opaque; }; + Storage StorageKind = Storage::Int; }; inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Pointer &P) { >From 354b68fa8a5b726fdcaf9a418397ec9c1e57b509 Mon Sep 17 00:00:00 2001 From: Nikolas Klauser <[email protected]> Date: Sun, 20 Sep 2026 12:39:47 +0200 Subject: [PATCH 2/2] Move Padding outside InterpStack --- clang/lib/AST/ByteCode/InterpStack.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/clang/lib/AST/ByteCode/InterpStack.h b/clang/lib/AST/ByteCode/InterpStack.h index faaab371fbf59..9ad1c5712d86e 100644 --- a/clang/lib/AST/ByteCode/InterpStack.h +++ b/clang/lib/AST/ByteCode/InterpStack.h @@ -30,6 +30,12 @@ struct datasizeof_impl { template <class T> constexpr size_t datasizeof_v = offsetof(datasizeof_impl<T>, first_padding_byte); +template <size_t N> struct Padding { + char padding[N]; +}; + +template <> struct Padding<0> {}; + /// Stack frame storing temporaries and parameters. class InterpStack final { public: @@ -38,12 +44,6 @@ class InterpStack final { /// Destroys the stack, freeing up storage. ~InterpStack(); - template <size_t N> struct Padding { - char padding[N]; - }; - - template <> struct Padding<0> {}; - template <class T> struct alignas(void *) StackFrame { static_assert(alignof(T) <= alignof(void *), "Unexpected overaligned object"); _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
