xref: /llvm-project/clang/lib/AST/ByteCode/Descriptor.h (revision 23fbaff9a3fd2b26418e0c2f10b701049399251f)
1a07aba5dSTimm Baeder //===--- Descriptor.h - Types for the constexpr VM --------------*- C++ -*-===//
2a07aba5dSTimm Baeder //
3a07aba5dSTimm Baeder // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4a07aba5dSTimm Baeder // See https://llvm.org/LICENSE.txt for license information.
5a07aba5dSTimm Baeder // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6a07aba5dSTimm Baeder //
7a07aba5dSTimm Baeder //===----------------------------------------------------------------------===//
8a07aba5dSTimm Baeder //
9a07aba5dSTimm Baeder // Defines descriptors which characterise allocations.
10a07aba5dSTimm Baeder //
11a07aba5dSTimm Baeder //===----------------------------------------------------------------------===//
12a07aba5dSTimm Baeder 
13a07aba5dSTimm Baeder #ifndef LLVM_CLANG_AST_INTERP_DESCRIPTOR_H
14a07aba5dSTimm Baeder #define LLVM_CLANG_AST_INTERP_DESCRIPTOR_H
15a07aba5dSTimm Baeder 
16a07aba5dSTimm Baeder #include "PrimType.h"
17a07aba5dSTimm Baeder #include "clang/AST/Decl.h"
18a07aba5dSTimm Baeder #include "clang/AST/Expr.h"
19a07aba5dSTimm Baeder 
20a07aba5dSTimm Baeder namespace clang {
21a07aba5dSTimm Baeder namespace interp {
22a07aba5dSTimm Baeder class Block;
23a07aba5dSTimm Baeder class Record;
243ea55d3cSTimm Baeder class SourceInfo;
25a07aba5dSTimm Baeder struct InitMap;
26a07aba5dSTimm Baeder struct Descriptor;
27a07aba5dSTimm Baeder enum PrimType : unsigned;
28a07aba5dSTimm Baeder 
29a07aba5dSTimm Baeder using DeclTy = llvm::PointerUnion<const Decl *, const Expr *>;
30a07aba5dSTimm Baeder using InitMapPtr = std::optional<std::pair<bool, std::shared_ptr<InitMap>>>;
31a07aba5dSTimm Baeder 
32a07aba5dSTimm Baeder /// Invoked whenever a block is created. The constructor method fills in the
33a07aba5dSTimm Baeder /// inline descriptors of all fields and array elements. It also initializes
34a07aba5dSTimm Baeder /// all the fields which contain non-trivial types.
35a07aba5dSTimm Baeder using BlockCtorFn = void (*)(Block *Storage, std::byte *FieldPtr, bool IsConst,
36a07aba5dSTimm Baeder                              bool IsMutable, bool IsActive, bool InUnion,
37a07aba5dSTimm Baeder                              const Descriptor *FieldDesc);
38a07aba5dSTimm Baeder 
39a07aba5dSTimm Baeder /// Invoked when a block is destroyed. Invokes the destructors of all
40a07aba5dSTimm Baeder /// non-trivial nested fields of arrays and records.
41a07aba5dSTimm Baeder using BlockDtorFn = void (*)(Block *Storage, std::byte *FieldPtr,
42a07aba5dSTimm Baeder                              const Descriptor *FieldDesc);
43a07aba5dSTimm Baeder 
44a07aba5dSTimm Baeder /// Invoked when a block with pointers referencing it goes out of scope. Such
45a07aba5dSTimm Baeder /// blocks are persisted: the move function copies all inline descriptors and
46a07aba5dSTimm Baeder /// non-trivial fields, as existing pointers might need to reference those
47a07aba5dSTimm Baeder /// descriptors. Data is not copied since it cannot be legally read.
48a69ba0a5STimm Baeder using BlockMoveFn = void (*)(Block *Storage, std::byte *SrcFieldPtr,
49a07aba5dSTimm Baeder                              std::byte *DstFieldPtr,
50a07aba5dSTimm Baeder                              const Descriptor *FieldDesc);
51a07aba5dSTimm Baeder 
52a07aba5dSTimm Baeder enum class GlobalInitState {
53a07aba5dSTimm Baeder   Initialized,
54a07aba5dSTimm Baeder   NoInitializer,
55a07aba5dSTimm Baeder   InitializerFailed,
56a07aba5dSTimm Baeder };
57a07aba5dSTimm Baeder 
58a07aba5dSTimm Baeder /// Descriptor used for global variables.
59a07aba5dSTimm Baeder struct alignas(void *) GlobalInlineDescriptor {
60a07aba5dSTimm Baeder   GlobalInitState InitState = GlobalInitState::InitializerFailed;
61a07aba5dSTimm Baeder };
62a07aba5dSTimm Baeder static_assert(sizeof(GlobalInlineDescriptor) == sizeof(void *), "");
63a07aba5dSTimm Baeder 
64a07aba5dSTimm Baeder /// Inline descriptor embedded in structures and arrays.
65a07aba5dSTimm Baeder ///
66a07aba5dSTimm Baeder /// Such descriptors precede all composite array elements and structure fields.
67a07aba5dSTimm Baeder /// If the base of a pointer is not zero, the base points to the end of this
68a07aba5dSTimm Baeder /// structure. The offset field is used to traverse the pointer chain up
69a07aba5dSTimm Baeder /// to the root structure which allocated the object.
70a07aba5dSTimm Baeder struct InlineDescriptor {
71a07aba5dSTimm Baeder   /// Offset inside the structure/array.
72a07aba5dSTimm Baeder   unsigned Offset;
73a07aba5dSTimm Baeder 
74a07aba5dSTimm Baeder   /// Flag indicating if the storage is constant or not.
75a07aba5dSTimm Baeder   /// Relevant for primitive fields.
76a07aba5dSTimm Baeder   LLVM_PREFERRED_TYPE(bool)
77a07aba5dSTimm Baeder   unsigned IsConst : 1;
78a07aba5dSTimm Baeder   /// For primitive fields, it indicates if the field was initialized.
79a07aba5dSTimm Baeder   /// Primitive fields in static storage are always initialized.
80a07aba5dSTimm Baeder   /// Arrays are always initialized, even though their elements might not be.
81a07aba5dSTimm Baeder   /// Base classes are initialized after the constructor is invoked.
82a07aba5dSTimm Baeder   LLVM_PREFERRED_TYPE(bool)
83a07aba5dSTimm Baeder   unsigned IsInitialized : 1;
84a07aba5dSTimm Baeder   /// Flag indicating if the field is an embedded base class.
85a07aba5dSTimm Baeder   LLVM_PREFERRED_TYPE(bool)
86a07aba5dSTimm Baeder   unsigned IsBase : 1;
87a07aba5dSTimm Baeder   /// Flag inidcating if the field is a virtual base class.
88a07aba5dSTimm Baeder   LLVM_PREFERRED_TYPE(bool)
89a07aba5dSTimm Baeder   unsigned IsVirtualBase : 1;
90a07aba5dSTimm Baeder   /// Flag indicating if the field is the active member of a union.
91a07aba5dSTimm Baeder   LLVM_PREFERRED_TYPE(bool)
92a07aba5dSTimm Baeder   unsigned IsActive : 1;
93a07aba5dSTimm Baeder   /// Flat indicating if this field is in a union (even if nested).
94a07aba5dSTimm Baeder   unsigned InUnion : 1;
95a07aba5dSTimm Baeder   LLVM_PREFERRED_TYPE(bool)
96a07aba5dSTimm Baeder   /// Flag indicating if the field is mutable (if in a record).
97a07aba5dSTimm Baeder   LLVM_PREFERRED_TYPE(bool)
98a07aba5dSTimm Baeder   unsigned IsFieldMutable : 1;
99800b0739STimm Baeder   /// Flag indicating if the field is an element of a composite array.
100800b0739STimm Baeder   LLVM_PREFERRED_TYPE(bool)
101800b0739STimm Baeder   unsigned IsArrayElement : 1;
102a07aba5dSTimm Baeder 
103a07aba5dSTimm Baeder   const Descriptor *Desc;
104a07aba5dSTimm Baeder 
105a07aba5dSTimm Baeder   InlineDescriptor(const Descriptor *D)
106a07aba5dSTimm Baeder       : Offset(sizeof(InlineDescriptor)), IsConst(false), IsInitialized(false),
107800b0739STimm Baeder         IsBase(false), IsActive(false), IsFieldMutable(false),
108800b0739STimm Baeder         IsArrayElement(false), Desc(D) {}
109a07aba5dSTimm Baeder 
110a07aba5dSTimm Baeder   void dump() const { dump(llvm::errs()); }
111a07aba5dSTimm Baeder   void dump(llvm::raw_ostream &OS) const;
112a07aba5dSTimm Baeder };
113a07aba5dSTimm Baeder static_assert(sizeof(GlobalInlineDescriptor) != sizeof(InlineDescriptor), "");
114a07aba5dSTimm Baeder 
115a07aba5dSTimm Baeder /// Describes a memory block created by an allocation site.
116a07aba5dSTimm Baeder struct Descriptor final {
117a07aba5dSTimm Baeder private:
118a07aba5dSTimm Baeder   /// Original declaration, used to emit the error message.
119a07aba5dSTimm Baeder   const DeclTy Source;
120a07aba5dSTimm Baeder   /// Size of an element, in host bytes.
121a07aba5dSTimm Baeder   const unsigned ElemSize;
122a07aba5dSTimm Baeder   /// Size of the storage, in host bytes.
123a07aba5dSTimm Baeder   const unsigned Size;
124a07aba5dSTimm Baeder   /// Size of the metadata.
125a07aba5dSTimm Baeder   const unsigned MDSize;
126a07aba5dSTimm Baeder   /// Size of the allocation (storage + metadata), in host bytes.
127a07aba5dSTimm Baeder   const unsigned AllocSize;
128a07aba5dSTimm Baeder 
129a07aba5dSTimm Baeder   /// Value to denote arrays of unknown size.
130a07aba5dSTimm Baeder   static constexpr unsigned UnknownSizeMark = (unsigned)-1;
131a07aba5dSTimm Baeder 
132a07aba5dSTimm Baeder public:
133a07aba5dSTimm Baeder   /// Token to denote structures of unknown size.
134a07aba5dSTimm Baeder   struct UnknownSize {};
135a07aba5dSTimm Baeder 
136a07aba5dSTimm Baeder   using MetadataSize = std::optional<unsigned>;
137a07aba5dSTimm Baeder   static constexpr MetadataSize InlineDescMD = sizeof(InlineDescriptor);
138a07aba5dSTimm Baeder   static constexpr MetadataSize GlobalMD = sizeof(GlobalInlineDescriptor);
139a07aba5dSTimm Baeder 
140a07aba5dSTimm Baeder   /// Maximum number of bytes to be used for array elements.
141a07aba5dSTimm Baeder   static constexpr unsigned MaxArrayElemBytes =
142a07aba5dSTimm Baeder       std::numeric_limits<decltype(AllocSize)>::max() - sizeof(InitMapPtr) -
143a07aba5dSTimm Baeder       align(std::max(*InlineDescMD, *GlobalMD));
144a07aba5dSTimm Baeder 
145a07aba5dSTimm Baeder   /// Pointer to the record, if block contains records.
146a07aba5dSTimm Baeder   const Record *const ElemRecord = nullptr;
147a07aba5dSTimm Baeder   /// Descriptor of the array element.
148a07aba5dSTimm Baeder   const Descriptor *const ElemDesc = nullptr;
149a07aba5dSTimm Baeder   /// The primitive type this descriptor was created for,
150a07aba5dSTimm Baeder   /// or the primitive element type in case this is
151a07aba5dSTimm Baeder   /// a primitive array.
152a07aba5dSTimm Baeder   const std::optional<PrimType> PrimT = std::nullopt;
153a07aba5dSTimm Baeder   /// Flag indicating if the block is mutable.
154a07aba5dSTimm Baeder   const bool IsConst = false;
155a07aba5dSTimm Baeder   /// Flag indicating if a field is mutable.
156a07aba5dSTimm Baeder   const bool IsMutable = false;
157a07aba5dSTimm Baeder   /// Flag indicating if the block is a temporary.
158a07aba5dSTimm Baeder   const bool IsTemporary = false;
159a07aba5dSTimm Baeder   /// Flag indicating if the block is an array.
160a07aba5dSTimm Baeder   const bool IsArray = false;
161a07aba5dSTimm Baeder   /// Flag indicating if this is a dummy descriptor.
162a07aba5dSTimm Baeder   bool IsDummy = false;
163a07aba5dSTimm Baeder 
164a07aba5dSTimm Baeder   /// Storage management methods.
165a07aba5dSTimm Baeder   const BlockCtorFn CtorFn = nullptr;
166a07aba5dSTimm Baeder   const BlockDtorFn DtorFn = nullptr;
167a07aba5dSTimm Baeder   const BlockMoveFn MoveFn = nullptr;
168a07aba5dSTimm Baeder 
169a07aba5dSTimm Baeder   /// Allocates a descriptor for a primitive.
170a07aba5dSTimm Baeder   Descriptor(const DeclTy &D, PrimType Type, MetadataSize MD, bool IsConst,
171a07aba5dSTimm Baeder              bool IsTemporary, bool IsMutable);
172a07aba5dSTimm Baeder 
173a07aba5dSTimm Baeder   /// Allocates a descriptor for an array of primitives.
174a07aba5dSTimm Baeder   Descriptor(const DeclTy &D, PrimType Type, MetadataSize MD, size_t NumElems,
175a07aba5dSTimm Baeder              bool IsConst, bool IsTemporary, bool IsMutable);
176a07aba5dSTimm Baeder 
177a07aba5dSTimm Baeder   /// Allocates a descriptor for an array of primitives of unknown size.
178a07aba5dSTimm Baeder   Descriptor(const DeclTy &D, PrimType Type, MetadataSize MDSize,
179a07aba5dSTimm Baeder              bool IsTemporary, UnknownSize);
180a07aba5dSTimm Baeder 
181a07aba5dSTimm Baeder   /// Allocates a descriptor for an array of composites.
182a07aba5dSTimm Baeder   Descriptor(const DeclTy &D, const Descriptor *Elem, MetadataSize MD,
183a07aba5dSTimm Baeder              unsigned NumElems, bool IsConst, bool IsTemporary, bool IsMutable);
184a07aba5dSTimm Baeder 
185a07aba5dSTimm Baeder   /// Allocates a descriptor for an array of composites of unknown size.
186a07aba5dSTimm Baeder   Descriptor(const DeclTy &D, const Descriptor *Elem, MetadataSize MD,
187a07aba5dSTimm Baeder              bool IsTemporary, UnknownSize);
188a07aba5dSTimm Baeder 
189a07aba5dSTimm Baeder   /// Allocates a descriptor for a record.
190a07aba5dSTimm Baeder   Descriptor(const DeclTy &D, const Record *R, MetadataSize MD, bool IsConst,
191a07aba5dSTimm Baeder              bool IsTemporary, bool IsMutable);
192a07aba5dSTimm Baeder 
193a07aba5dSTimm Baeder   /// Allocates a dummy descriptor.
194a07aba5dSTimm Baeder   Descriptor(const DeclTy &D);
195a07aba5dSTimm Baeder 
196a07aba5dSTimm Baeder   /// Make this descriptor a dummy descriptor.
197a07aba5dSTimm Baeder   void makeDummy() { IsDummy = true; }
198a07aba5dSTimm Baeder 
199a07aba5dSTimm Baeder   QualType getType() const;
200a07aba5dSTimm Baeder   QualType getElemQualType() const;
201a07aba5dSTimm Baeder   SourceLocation getLocation() const;
2023ea55d3cSTimm Baeder   SourceInfo getLoc() const;
203a07aba5dSTimm Baeder 
204*23fbaff9SKazu Hirata   const Decl *asDecl() const { return dyn_cast<const Decl *>(Source); }
205*23fbaff9SKazu Hirata   const Expr *asExpr() const { return dyn_cast<const Expr *>(Source); }
206a07aba5dSTimm Baeder   const DeclTy &getSource() const { return Source; }
207a07aba5dSTimm Baeder 
208a07aba5dSTimm Baeder   const ValueDecl *asValueDecl() const {
209a07aba5dSTimm Baeder     return dyn_cast_if_present<ValueDecl>(asDecl());
210a07aba5dSTimm Baeder   }
211a07aba5dSTimm Baeder 
212a07aba5dSTimm Baeder   const VarDecl *asVarDecl() const {
213a07aba5dSTimm Baeder     return dyn_cast_if_present<VarDecl>(asDecl());
214a07aba5dSTimm Baeder   }
215a07aba5dSTimm Baeder 
216a07aba5dSTimm Baeder   const FieldDecl *asFieldDecl() const {
217a07aba5dSTimm Baeder     return dyn_cast_if_present<FieldDecl>(asDecl());
218a07aba5dSTimm Baeder   }
219a07aba5dSTimm Baeder 
220a07aba5dSTimm Baeder   const RecordDecl *asRecordDecl() const {
221a07aba5dSTimm Baeder     return dyn_cast_if_present<RecordDecl>(asDecl());
222a07aba5dSTimm Baeder   }
223a07aba5dSTimm Baeder 
224a07aba5dSTimm Baeder   /// Returns the size of the object without metadata.
225a07aba5dSTimm Baeder   unsigned getSize() const {
226a07aba5dSTimm Baeder     assert(!isUnknownSizeArray() && "Array of unknown size");
227a07aba5dSTimm Baeder     return Size;
228a07aba5dSTimm Baeder   }
229a07aba5dSTimm Baeder 
230a07aba5dSTimm Baeder   PrimType getPrimType() const {
231a07aba5dSTimm Baeder     assert(isPrimitiveArray() || isPrimitive());
232a07aba5dSTimm Baeder     return *PrimT;
233a07aba5dSTimm Baeder   }
234a07aba5dSTimm Baeder 
235a07aba5dSTimm Baeder   /// Returns the allocated size, including metadata.
236a07aba5dSTimm Baeder   unsigned getAllocSize() const { return AllocSize; }
237a07aba5dSTimm Baeder   /// returns the size of an element when the structure is viewed as an array.
238a07aba5dSTimm Baeder   unsigned getElemSize() const { return ElemSize; }
239a07aba5dSTimm Baeder   /// Returns the size of the metadata.
240a07aba5dSTimm Baeder   unsigned getMetadataSize() const { return MDSize; }
241a07aba5dSTimm Baeder 
242a07aba5dSTimm Baeder   /// Returns the number of elements stored in the block.
243a07aba5dSTimm Baeder   unsigned getNumElems() const {
244a07aba5dSTimm Baeder     return Size == UnknownSizeMark ? 0 : (getSize() / getElemSize());
245a07aba5dSTimm Baeder   }
246a07aba5dSTimm Baeder 
247a07aba5dSTimm Baeder   /// Checks if the descriptor is of an array of primitives.
248a07aba5dSTimm Baeder   bool isPrimitiveArray() const { return IsArray && !ElemDesc; }
249a07aba5dSTimm Baeder   /// Checks if the descriptor is of an array of composites.
250a07aba5dSTimm Baeder   bool isCompositeArray() const { return IsArray && ElemDesc; }
251a07aba5dSTimm Baeder   /// Checks if the descriptor is of an array of zero size.
252a07aba5dSTimm Baeder   bool isZeroSizeArray() const { return Size == 0; }
253a07aba5dSTimm Baeder   /// Checks if the descriptor is of an array of unknown size.
254a07aba5dSTimm Baeder   bool isUnknownSizeArray() const { return Size == UnknownSizeMark; }
255a07aba5dSTimm Baeder 
256a07aba5dSTimm Baeder   /// Checks if the descriptor is of a primitive.
257a07aba5dSTimm Baeder   bool isPrimitive() const { return !IsArray && !ElemRecord; }
258a07aba5dSTimm Baeder 
259a07aba5dSTimm Baeder   /// Checks if the descriptor is of an array.
260a07aba5dSTimm Baeder   bool isArray() const { return IsArray; }
261a07aba5dSTimm Baeder   /// Checks if the descriptor is of a record.
262a07aba5dSTimm Baeder   bool isRecord() const { return !IsArray && ElemRecord; }
263a07aba5dSTimm Baeder   /// Checks if the descriptor is of a union.
264a07aba5dSTimm Baeder   bool isUnion() const;
265a07aba5dSTimm Baeder   /// Checks if this is a dummy descriptor.
266a07aba5dSTimm Baeder   bool isDummy() const { return IsDummy; }
267a07aba5dSTimm Baeder 
268a07aba5dSTimm Baeder   void dump() const;
269a07aba5dSTimm Baeder   void dump(llvm::raw_ostream &OS) const;
270a07aba5dSTimm Baeder };
271a07aba5dSTimm Baeder 
272a07aba5dSTimm Baeder /// Bitfield tracking the initialisation status of elements of primitive arrays.
273a07aba5dSTimm Baeder struct InitMap final {
274a07aba5dSTimm Baeder private:
275a07aba5dSTimm Baeder   /// Type packing bits.
276a07aba5dSTimm Baeder   using T = uint64_t;
277a07aba5dSTimm Baeder   /// Bits stored in a single field.
278a07aba5dSTimm Baeder   static constexpr uint64_t PER_FIELD = sizeof(T) * CHAR_BIT;
279a07aba5dSTimm Baeder 
280a07aba5dSTimm Baeder public:
281a07aba5dSTimm Baeder   /// Initializes the map with no fields set.
282a07aba5dSTimm Baeder   explicit InitMap(unsigned N);
283a07aba5dSTimm Baeder 
284a07aba5dSTimm Baeder private:
285a07aba5dSTimm Baeder   friend class Pointer;
286a07aba5dSTimm Baeder 
287a07aba5dSTimm Baeder   /// Returns a pointer to storage.
288a07aba5dSTimm Baeder   T *data() { return Data.get(); }
289a07aba5dSTimm Baeder   const T *data() const { return Data.get(); }
290a07aba5dSTimm Baeder 
291a07aba5dSTimm Baeder   /// Initializes an element. Returns true when object if fully initialized.
292a07aba5dSTimm Baeder   bool initializeElement(unsigned I);
293a07aba5dSTimm Baeder 
294a07aba5dSTimm Baeder   /// Checks if an element was initialized.
295a07aba5dSTimm Baeder   bool isElementInitialized(unsigned I) const;
296a07aba5dSTimm Baeder 
297a07aba5dSTimm Baeder   static constexpr size_t numFields(unsigned N) {
298a07aba5dSTimm Baeder     return (N + PER_FIELD - 1) / PER_FIELD;
299a07aba5dSTimm Baeder   }
300a07aba5dSTimm Baeder   /// Number of fields not initialized.
301a07aba5dSTimm Baeder   unsigned UninitFields;
302a07aba5dSTimm Baeder   std::unique_ptr<T[]> Data;
303a07aba5dSTimm Baeder };
304a07aba5dSTimm Baeder 
305a07aba5dSTimm Baeder } // namespace interp
306a07aba5dSTimm Baeder } // namespace clang
307a07aba5dSTimm Baeder 
308a07aba5dSTimm Baeder #endif
309