clang 24.0.0git
Program.cpp
Go to the documentation of this file.
1//===--- Program.cpp - Bytecode for the constexpr VM ------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "Program.h"
10#include "Context.h"
11#include "Function.h"
12#include "PrimType.h"
13#include "clang/AST/Decl.h"
14#include "clang/AST/DeclCXX.h"
16
17using namespace clang;
18using namespace clang::interp;
19
20Pointer Program::getPtrGlobal(unsigned Idx) const {
21 assert(Idx < Globals.size());
22
23 Block *B = Globals[Idx];
24
25 // Force de-serialization of a redeclaration that might initialize this
26 // global.
29 if (const VarDecl *VD = B->getDescriptor()->asVarDecl()) {
30 const VarDecl *MD = VD->getMostRecentDecl();
31 if (MD != VD && MD->hasInit() && !MD->getInit()->isValueDependent()) {
32 MD->evaluateValue();
33 // Note that we need to get Globals[Idx] here again since the code block
34 // above might've actually changed what global Idx points to.
35 return Pointer(Globals[Idx]);
36 }
37 }
38 }
39
40 return Pointer(B);
41}
42
44 if (auto It = GlobalIndices.find(VD); It != GlobalIndices.end())
45 return It->second;
46
47 // Find any previous declarations which were already evaluated.
48 std::optional<unsigned> Index;
49 for (const Decl *P = VD->getPreviousDecl(); P; P = P->getPreviousDecl()) {
50 if (auto It = GlobalIndices.find(P); It != GlobalIndices.end()) {
51 Index = It->second;
52 break;
53 }
54 }
55
56 // Map the decl to the existing index.
57 if (Index)
58 GlobalIndices[VD] = *Index;
59
60 return std::nullopt;
61}
62
64 if (auto It = GlobalIndices.find(E); It != GlobalIndices.end())
65 return It->second;
66 return std::nullopt;
67}
68
70 const Expr *Init) {
71 if (auto Idx = getGlobal(VD))
72 return Idx;
73
74 if (auto Idx = createGlobal(VD, Init)) {
75 GlobalIndices[VD] = *Idx;
76 return Idx;
77 }
78 return std::nullopt;
79}
80
82 bool IsConstexprUnknown,
83 bool CanBeExtern) {
84 bool IsExtern;
85 bool IsWeak = VD->isWeak();
86 if (const auto *Var = dyn_cast<VarDecl>(VD)) {
87 IsExtern = CanBeExtern && !Init && Var->hasExternalStorage();
88 } else {
90 VD)));
91 IsExtern = false;
92 }
93
94 // Register all previous declarations as well. For extern blocks, just replace
95 // the index with the new variable.
96 UnsignedOrNone Idx = createGlobal(VD, VD->getType(), IsExtern, IsWeak,
97 IsConstexprUnknown, Init);
98 if (!Idx)
99 return std::nullopt;
100
101 Block *NewGlobal = Globals[*Idx];
102 GlobalIndices[VD] = *Idx;
103
104 for (const Decl *Redecl = VD->getPreviousDecl(); Redecl;
105 Redecl = Redecl->getPreviousDecl()) {
106 // If the redeclaration hasn't been registered yet at all, we just set its
107 // global index to Idx. If it has been registered yet, it might have
108 // pointers pointing to it and we need to transfer those pointers to the new
109 // block.
110 auto [Iter, Inserted] = GlobalIndices.try_emplace(Redecl);
111 if (Inserted) {
112 Iter->second = *Idx;
113 continue;
114 }
115
116 Block *RedeclBlock = Globals[Iter->second];
117 // All pointers pointing to the previous extern decl now point to the
118 // new decl.
119 // A previous iteration might've already fixed up the pointers for this
120 // global.
121 if (RedeclBlock != NewGlobal) {
122 RedeclBlock->movePointersTo(NewGlobal);
123 RedeclBlock->invokeDtor();
124 }
125
126 Globals[Iter->second] = NewGlobal;
127 Iter->second = *Idx;
128 }
129
130 return *Idx;
131}
132
134 if (auto Idx = getGlobal(E))
135 return Idx;
136 if (auto Idx = createGlobal(E, ExprType,
137 /*IsExtern=*/false, /*IsWeak=*/false,
138 /*IsConstexprUnknown=*/false)) {
139 GlobalIndices[E] = *Idx;
140 return *Idx;
141 }
142 return std::nullopt;
143}
144
146 bool IsWeak, bool IsConstexprUnknown,
147 const Expr *Init) {
148 // Since this global variable is constexpr-unknown and a reference, register
149 // the pointee type instead. When referencing the variable, the pointer will
150 // then be of the pointee type instead of just PT_Ptr.
151 if (Ty->isReferenceType() && IsConstexprUnknown)
152 Ty = Ty->getPointeeType();
153
154 // Create a descriptor for the global.
155 Descriptor *Desc;
156 const bool IsConst = Ty.isConstQualified();
157 const bool IsTemporary = D.isExpr();
158 const bool IsVolatile = Ty.isVolatileQualified();
159 if (OptPrimType T = Ctx.classify(Ty))
160 Desc = createDescriptor(D, *T, nullptr, IsConst, IsTemporary,
161 /*IsMutable=*/false, IsVolatile);
162 else
163 Desc = createDescriptor(D, Ty.getTypePtr(), IsConst, IsTemporary,
164 /*IsMutable=*/false, IsVolatile);
165
166 if (!Desc)
167 return std::nullopt;
168
169 // Allocate a block for storage.
170 unsigned I = Globals.size();
171
172 BlockFlags Flags =
174 IsConstexprUnknown);
175 auto *G =
176 new (Allocate(Block::allocSize(Desc, Block::Global), alignof(Block)))
177 Block(Ctx.getEvalID(), getCurrentDecl(), Desc, Block::Global, Flags);
178 G->invokeCtor();
179
180 // Initialize GlobalInlineDescriptor fields.
181 auto *GD =
182 new (&G->getBlockDesc<GlobalInlineDescriptor>()) GlobalInlineDescriptor();
183 if (!Init)
185 Globals.push_back(G);
186
187 return I;
188}
189
191 F = F->getFirstDecl();
192 assert(F);
193 auto It = Funcs.find(F);
194 return It == Funcs.end() ? nullptr : It->second;
195}
196
198 // Use the actual definition as a key.
199 RD = RD->getDefinition();
200 if (!RD)
201 return nullptr;
202
203 if (!RD->isCompleteDefinition())
204 return nullptr;
205
206 // Return an existing record if available. Otherwise, we insert nullptr now
207 // and replace that later, so recursive calls to this function with the same
208 // RecordDecl don't run into infinite recursion.
209 auto [It, Inserted] = Records.try_emplace(RD);
210 if (!Inserted)
211 return It->second;
212
213 // Number of bytes required by fields and base classes.
214 unsigned BaseSize = 0;
215 // Number of bytes required by virtual base.
216 unsigned VirtSize = 0;
217
218 // Helper to get a base descriptor.
219 auto GetBaseDesc = [this](const RecordDecl *BD,
220 const Record *BR) -> const Descriptor * {
221 if (!BR)
222 return nullptr;
223 return allocateDescriptor(BD, BR, /*IsConst=*/false, /*IsTemporary=*/false,
224 /*IsMutable=*/false, /*IsVolatile=*/false);
225 };
226
227 bool HasPtrField = false;
228 // Reserve space for base classes.
229 unsigned NumBases = 0;
230 Record::Base *Bases = nullptr;
231 unsigned NumVBases = 0;
232 Record::Base *VBases = nullptr;
233 if (const auto *CD = dyn_cast<CXXRecordDecl>(RD)) {
234 NumBases = CD->getNumBases();
235 // NB: This overallocates by all explicitly specified virtual bases.
236 if (NumBases != 0)
237 Bases = Allocate<Record::Base>(NumBases);
238
239 unsigned I = 0;
240 for (const CXXBaseSpecifier &Spec : CD->bases()) {
241 assert(I <= NumBases);
242 if (Spec.isVirtual())
243 continue;
244
245 // In error cases, the base might not be a RecordType.
246 const auto *BD = Spec.getType()->getAsCXXRecordDecl();
247 if (!BD)
248 return nullptr;
249 const Record *BR = getOrCreateRecord(BD);
250
251 const Descriptor *Desc = GetBaseDesc(BD, BR);
252 if (!Desc)
253 return nullptr;
254
255 BaseSize += align(sizeof(InlineDescriptor));
256 new (&Bases[I]) Record::Base(BD, Desc, BR, BaseSize);
257 BaseSize += align(BR->getSize());
258 HasPtrField |= BR->hasPtrField();
259 ++I;
260 }
261 // Make sure we don't include the virtual base specifiers we skipped above.
262 NumBases = I;
263
264 I = 0;
265 NumVBases = CD->getNumVBases();
266 if (NumVBases != 0)
267 VBases = Allocate<Record::Base>(NumVBases);
268 for (const CXXBaseSpecifier &Spec : CD->vbases()) {
269 assert(I <= NumVBases);
270 const auto *BD = Spec.getType()->castAsCXXRecordDecl();
271 const Record *BR = getOrCreateRecord(BD);
272
273 const Descriptor *Desc = GetBaseDesc(BD, BR);
274 if (!Desc)
275 return nullptr;
276
277 VirtSize += align(sizeof(InlineDescriptor));
278 new (&VBases[I]) Record::Base(BD, Desc, BR, VirtSize);
279 VirtSize += align(BR->getSize());
280 HasPtrField |= BR->hasPtrField();
281 ++I;
282 }
283 assert(I == NumVBases);
284 }
285
286 // Reserve space for fields.
287 unsigned NumFields = RD->getNumFields();
288 Record::Field *Fields = nullptr;
289 if (NumFields != 0)
290 Fields = Allocate<Record::Field>(NumFields);
291 unsigned I = 0;
292 for (const FieldDecl *FD : RD->fields()) {
293 FD = FD->getFirstDecl();
294 // Note that we DO create fields and descriptors
295 // for unnamed bitfields here, even though we later ignore
296 // them everywhere. That's so the FieldDecl's getFieldIndex() matches.
297
298 // Reserve space for the field's descriptor and the offset.
299 BaseSize += align(sizeof(InlineDescriptor));
300
301 // Classify the field and add its metadata.
302 QualType FT = FD->getType();
303 const bool IsConst = FT.isConstQualified();
304 const bool IsMutable = FD->isMutable();
305 const bool IsVolatile = FT.isVolatileQualified();
306 const Descriptor *Desc;
307 OptPrimType T = Ctx.classify(FT);
308 if (T) {
309 Desc = createDescriptor(FD, *T, nullptr, IsConst,
310 /*IsTemporary=*/false, IsMutable, IsVolatile);
311 HasPtrField = HasPtrField || (T == PT_Ptr);
312 } else if ((Desc = createDescriptor(FD, FT.getTypePtr(), IsConst,
313 /*IsTemporary=*/false, IsMutable,
314 IsVolatile))) {
315 HasPtrField =
316 HasPtrField ||
317 (Desc->isPrimitiveArray() && Desc->getPrimType() == PT_Ptr) ||
318 (Desc->ElemRecord && Desc->ElemRecord->hasPtrField());
319 } else {
320 Desc = allocateDescriptor(FD);
321 }
322 assert(Desc);
323 new (&Fields[I]) Record::Field(FD, Desc, BaseSize, T);
324 BaseSize += align(Desc->getAllocSize());
325 ++I;
326 }
327
328 // Adjust virtual base offsets to account for base size.
329 for (unsigned I = 0; I != NumVBases; ++I)
330 VBases[I].Offset += BaseSize;
331
332 Record *R = new (Allocator)
333 Record(RD, {Bases, NumBases}, {Fields, NumFields}, {VBases, NumVBases},
334 VirtSize, BaseSize, HasPtrField);
335 Records[RD] = R;
336 return R;
337}
338
340 bool IsConst, bool IsTemporary,
341 bool IsMutable, bool IsVolatile,
342 const Expr *Init) {
343 // Classes and structures.
344 if (const auto *RD = Ty->getAsRecordDecl()) {
345 if (const auto *Record = getOrCreateRecord(RD))
346 return allocateDescriptor(D, Record, IsConst, IsTemporary, IsMutable,
347 IsVolatile);
348 return allocateDescriptor(D);
349 }
350
351 // Arrays.
352 if (const auto *ArrayType = Ty->getAsArrayTypeUnsafe()) {
354 // Array of well-known bounds.
355 if (const auto *CAT = dyn_cast<ConstantArrayType>(ArrayType)) {
356 size_t NumElems = CAT->getZExtSize();
357 if (OptPrimType T = Ctx.classify(ElemTy)) {
358 // Arrays of primitives.
359 unsigned ElemSize = primSize(*T);
360 if ((Descriptor::MaxArrayElemBytes / ElemSize) < NumElems) {
361 return nullptr;
362 }
363 return allocateDescriptor(D, CAT, *T, NumElems, IsConst, IsTemporary,
364 IsMutable, IsVolatile);
365 }
366 // Arrays of composites. In this case, the array is a list of pointers,
367 // followed by the actual elements.
368 const Descriptor *ElemDesc =
369 createDescriptor(D, ElemTy.getTypePtr(), IsConst, IsTemporary);
370 if (!ElemDesc)
371 return nullptr;
372 unsigned ElemSize = ElemDesc->getAllocSize() + sizeof(InlineDescriptor);
373 if (std::numeric_limits<unsigned>::max() / ElemSize <= NumElems)
374 return nullptr;
375 return allocateDescriptor(D, Ty, ElemDesc, NumElems, IsConst, IsTemporary,
376 IsMutable);
377 }
378
379 // Array of unknown bounds - cannot be accessed and pointer arithmetic
380 // is forbidden on pointers to such objects.
383 if (OptPrimType T = Ctx.classify(ElemTy)) {
384 return allocateDescriptor(D, *T, IsConst, IsTemporary,
386 }
387 const Descriptor *Desc =
388 createDescriptor(D, ElemTy.getTypePtr(), IsConst, IsTemporary);
389 if (!Desc)
390 return nullptr;
391 return allocateDescriptor(D, Desc, IsTemporary,
393 }
394 }
395
396 // Atomic types.
397 if (const auto *AT = Ty->getAs<AtomicType>()) {
398 const Type *InnerTy = AT->getValueType().getTypePtr();
399 return createDescriptor(D, InnerTy, IsConst, IsTemporary, IsMutable);
400 }
401
402 // Complex types - represented as arrays of elements.
403 if (const auto *CT = Ty->getAs<ComplexType>()) {
404 OptPrimType ElemTy = Ctx.classify(CT->getElementType());
405 if (!ElemTy)
406 return nullptr;
407
408 return allocateDescriptor(D, CT, *ElemTy, 2, IsConst, IsTemporary,
409 IsMutable, IsVolatile);
410 }
411
412 // Same with vector types.
413 if (const auto *VT = Ty->getAs<VectorType>()) {
414 OptPrimType ElemTy = Ctx.classify(VT->getElementType());
415 if (!ElemTy)
416 return nullptr;
417
418 return allocateDescriptor(D, VT, *ElemTy, VT->getNumElements(), IsConst,
419 IsTemporary, IsMutable, IsVolatile);
420 }
421
422 // Same with constant matrix types.
423 if (const auto *MT = Ty->getAs<ConstantMatrixType>()) {
424 OptPrimType ElemTy = Ctx.classify(MT->getElementType());
425 if (!ElemTy)
426 return nullptr;
427
428 return allocateDescriptor(D, MT, *ElemTy, MT->getNumElementsFlattened(),
429 IsConst, IsTemporary, IsMutable, IsVolatile);
430 }
431
432 return nullptr;
433}
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
Defines the C++ template declaration subclasses.
llvm::MachO::Record Record
Definition MachO.h:31
Represents an array type, per C99 6.7.5.2 - Array Declarators.
Definition TypeBase.h:3820
QualType getElementType() const
Definition TypeBase.h:3832
Represents a base class of a C++ class.
Definition DeclCXX.h:146
Complex values, per C99 6.2.5p11.
Definition TypeBase.h:3362
Represents a concrete matrix type with constant number of rows and columns.
Definition TypeBase.h:4622
Decl - This represents one declaration (or definition), e.g.
Definition DeclBase.h:86
Decl * getPreviousDecl()
Retrieve the previous declaration that declares the same entity as this declaration,...
Definition DeclBase.h:1079
This represents one expression.
Definition Expr.h:114
bool isValueDependent() const
Determines whether the value of this expression depends on.
Definition Expr.h:179
Represents a member of a struct/union/class.
Definition Decl.h:3341
Represents a function declaration or definition.
Definition Decl.h:2082
A (possibly-)qualified type.
Definition TypeBase.h:938
bool isVolatileQualified() const
Determine whether this type is volatile-qualified.
Definition TypeBase.h:8753
const Type * getTypePtr() const
Retrieves a pointer to the underlying (unqualified) type.
Definition TypeBase.h:8669
bool isConstQualified() const
Determine whether this type is const-qualified.
Definition TypeBase.h:8742
Represents a struct/union/class.
Definition Decl.h:4506
unsigned getNumFields() const
Returns the number of fields (non-static data members) in this record.
Definition Decl.h:4722
field_range fields() const
Definition Decl.h:4709
RecordDecl * getDefinition() const
Returns the RecordDecl that actually defines this struct/union/class.
Definition Decl.h:4690
decl_type * getFirstDecl()
Return the first declaration of this declaration or itself if this is the only declaration.
bool isCompleteDefinition() const
Return true if this decl has its body fully specified.
Definition Decl.h:3999
The base class of the type hierarchy.
Definition TypeBase.h:1879
RecordDecl * getAsRecordDecl() const
Retrieves the RecordDecl this type refers to.
Definition Type.h:41
bool isReferenceType() const
Definition TypeBase.h:8930
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
Definition Type.cpp:885
const ArrayType * getAsArrayTypeUnsafe() const
A variant of getAs<> for array types which silently discards qualifiers from the outermost type.
Definition TypeBase.h:9575
const T * getAs() const
Member-template getAs<specific type>'.
Definition TypeBase.h:9522
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
Definition Decl.h:714
QualType getType() const
Definition Decl.h:725
bool isWeak() const
Determine whether this symbol is weakly-imported, or declared with the weak or weak-ref attr.
Definition Decl.cpp:5689
Represents a variable declaration or definition.
Definition Decl.h:934
bool hasInit() const
Definition Decl.cpp:2400
VarDecl * getMostRecentDecl()
Returns the most recent (re)declaration of this declaration.
const Expr * getInit() const
Definition Decl.h:1393
const APValue * evaluateValue() const
Attempt to evaluate the value of the initializer attached to this declaration, and produce notes expl...
Definition Decl.cpp:2568
Represents a GCC generic vector type.
Definition TypeBase.h:4398
A memory block, either on the stack or in the heap.
Definition Block.h:68
static unsigned allocSize(const Descriptor *D, BlockKind K)
Number of bytes needed to allocate the block.
Definition Block.h:83
void invokeDtor()
Invokes the Destructor.
Definition Block.h:181
bool isGlobal() const
Definition Block.h:99
const Descriptor * getDescriptor() const
Returns the block's descriptor.
Definition Block.h:103
void movePointersTo(Block *B)
Move all pointers from this block to.
Definition Block.cpp:103
OptPrimType classify(QualType T) const
Classifies a type.
Definition Context.cpp:524
unsigned getEvalID() const
Definition Context.h:190
Bytecode function.
Definition Function.h:98
A pointer to a memory block, live or dead.
Definition Pointer.h:547
Function * getFunction(const FunctionDecl *F)
Returns a function.
Definition Program.cpp:190
Block * getGlobal(unsigned Idx)
Returns the value of a global.
Definition Program.h:68
Descriptor * createDescriptor(DeclOrExpr D, PrimType T, const Type *SourceTy=nullptr, bool IsConst=false, bool IsTemporary=false, bool IsMutable=false, bool IsVolatile=false)
Creates a descriptor for a primitive type.
Definition Program.h:116
UnsignedOrNone getOrCreateGlobal(const ValueDecl *VD, const Expr *Init=nullptr)
Returns or creates a global an creates an index to it.
Definition Program.cpp:69
UnsignedOrNone createGlobal(const ValueDecl *VD, const Expr *Init, bool IsConstexprUnknown=false, bool CanBeExtern=true)
Creates a global and returns its index.
Definition Program.cpp:81
Pointer getPtrGlobal(unsigned Idx) const
Returns a pointer to a global.
Definition Program.cpp:20
UnsignedOrNone getCurrentDecl() const
Returns the current declaration ID.
Definition Program.h:154
Record * getOrCreateRecord(const RecordDecl *RD)
Returns a record or creates one if it does not exist.
Definition Program.cpp:197
void * Allocate(size_t Size, unsigned Align=8)
Definition Program.h:131
Structure/Class descriptor.
Definition Record.h:27
bool hasPtrField() const
If this record (or any of its bases) contains a field of type PT_Ptr.
Definition Record.h:85
unsigned getSize() const
Returns the size of the record.
Definition Record.h:75
constexpr size_t align(size_t Size)
Aligns a size to the pointer alignment.
Definition PrimType.h:218
bool Init(InterpState &S, CodePtr OpPC)
Definition Interp.h:2381
size_t primSize(PrimType Type)
Returns the size of a primitive type in bytes.
Definition PrimType.cpp:25
Top level wrappers for InstallAPI frontend operations.
bool isa(CodeGen::Address addr)
Definition Address.h:330
nullptr
This class represents a compute construct, representing a 'Kind' of ‘parallel’, 'serial',...
OptionalUnsigned< unsigned > UnsignedOrNone
const FunctionProtoType * T
constexpr BlockFlags withExtern(bool B=true) const
Definition Block.h:37
constexpr BlockFlags withWeak(bool B=true) const
Definition Block.h:43
constexpr BlockFlags withConstexprUnknown(bool B=true) const
Definition Block.h:46
Token to denote structures of unknown size.
Definition Descriptor.h:143
Describes a memory block created by an allocation site.
Definition Descriptor.h:126
unsigned getAllocSize() const
Returns the allocated size, including metadata.
Definition Descriptor.h:240
static constexpr unsigned MaxArrayElemBytes
Maximum number of bytes to be used for array elements.
Definition Descriptor.h:146
bool isPrimitiveArray() const
Checks if the descriptor is of an array of primitives.
Definition Descriptor.h:254
const VarDecl * asVarDecl() const
Definition Descriptor.h:212
PrimType getPrimType() const
Definition Descriptor.h:234
const Record *const ElemRecord
Pointer to the record, if block contains records.
Definition Descriptor.h:150
Descriptor used for global variables.
Definition Descriptor.h:48
Inline descriptor embedded in structures and arrays.
Definition Descriptor.h:78