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 return Pointer(Globals[Idx]->block());
23}
24
26 if (auto It = GlobalIndices.find(VD); It != GlobalIndices.end())
27 return It->second;
28
29 // Find any previous declarations which were already evaluated.
30 std::optional<unsigned> Index;
31 for (const Decl *P = VD->getPreviousDecl(); P; P = P->getPreviousDecl()) {
32 if (auto It = GlobalIndices.find(P); It != GlobalIndices.end()) {
33 Index = It->second;
34 break;
35 }
36 }
37
38 // Map the decl to the existing index.
39 if (Index)
40 GlobalIndices[VD] = *Index;
41
42 return std::nullopt;
43}
44
46 if (auto It = GlobalIndices.find(E); It != GlobalIndices.end())
47 return It->second;
48 return std::nullopt;
49}
50
52 const Expr *Init) {
53 if (auto Idx = getGlobal(VD))
54 return Idx;
55
56 if (auto Idx = createGlobal(VD, Init)) {
57 GlobalIndices[VD] = *Idx;
58 return Idx;
59 }
60 return std::nullopt;
61}
62
64 bool IsConstexprUnknown) {
65 bool IsStatic, IsExtern;
66 bool IsWeak = VD->isWeak();
67 if (const auto *Var = dyn_cast<VarDecl>(VD)) {
69 IsExtern = Var->hasExternalStorage();
72 IsStatic = true;
73 IsExtern = false;
74 } else {
75 IsStatic = false;
76 IsExtern = true;
77 }
78
79 // Register all previous declarations as well. For extern blocks, just replace
80 // the index with the new variable.
81 UnsignedOrNone Idx = createGlobal(VD, VD->getType(), IsStatic, IsExtern,
82 IsWeak, IsConstexprUnknown, Init);
83 if (!Idx)
84 return std::nullopt;
85
86 Global *NewGlobal = Globals[*Idx];
87 GlobalIndices[VD] = *Idx;
88
89 for (const Decl *Redecl = VD->getPreviousDecl(); Redecl;
90 Redecl = Redecl->getPreviousDecl()) {
91 // If the redeclaration hasn't been registered yet at all, we just set its
92 // global index to Idx. If it has been registered yet, it might have
93 // pointers pointing to it and we need to transfer those pointers to the new
94 // block.
95 auto [Iter, Inserted] = GlobalIndices.try_emplace(Redecl);
96 if (Inserted) {
97 Iter->second = *Idx;
98 continue;
99 }
100
101 Block *RedeclBlock = Globals[Iter->second]->block();
102 // All pointers pointing to the previous extern decl now point to the
103 // new decl.
104 // A previous iteration might've already fixed up the pointers for this
105 // global.
106 if (RedeclBlock != NewGlobal->block())
107 RedeclBlock->movePointersTo(NewGlobal->block());
108
109 Globals[Iter->second] = NewGlobal;
110 Iter->second = *Idx;
111 }
112
113 return *Idx;
114}
115
117 if (auto Idx = getGlobal(E))
118 return Idx;
119 if (auto Idx = createGlobal(E, ExprType, /*IsStatic=*/true,
120 /*IsExtern=*/false, /*IsWeak=*/false,
121 /*IsConstexprUnknown=*/false)) {
122 GlobalIndices[E] = *Idx;
123 return *Idx;
124 }
125 return std::nullopt;
126}
127
129 bool IsExtern, bool IsWeak,
130 bool IsConstexprUnknown,
131 const Expr *Init) {
132 // Since this global variable is constexpr-unknown and a reference, register
133 // the pointee type instead. When referencing the variable, the pointer will
134 // then be of the pointee type instead of just PT_Ptr.
135 if (Ty->isReferenceType() && IsConstexprUnknown)
136 Ty = Ty->getPointeeType();
137
138 // Create a descriptor for the global.
139 Descriptor *Desc;
140 const bool IsConst = Ty.isConstQualified();
141 const bool IsTemporary = D.isExpr();
142 const bool IsVolatile = Ty.isVolatileQualified();
143 if (OptPrimType T = Ctx.classify(Ty))
144 Desc = createDescriptor(D, *T, nullptr, IsConst, IsTemporary,
145 /*IsMutable=*/false, IsVolatile);
146 else
147 Desc = createDescriptor(D, Ty.getTypePtr(), IsConst, IsTemporary,
148 /*IsMutable=*/false, IsVolatile);
149
150 if (!Desc)
151 return std::nullopt;
152 Desc->IsConstexprUnknown = IsConstexprUnknown;
153
154 // Allocate a block for storage.
155 unsigned I = Globals.size();
156
157 auto *G = new (Allocator, Desc->getAllocSize() + Block::GlobalMD)
158 Global(Ctx.getEvalID(), getCurrentDecl(), Desc, Block::GlobalMD, IsStatic,
159 IsExtern, IsWeak);
160 G->block()->invokeCtor();
161
162 // Initialize GlobalInlineDescriptor fields.
163 auto *GD = new (G->block()->rawData()) GlobalInlineDescriptor();
164 if (!Init)
165 GD->InitState = GlobalInitState::NoInitializer;
166 Globals.push_back(G);
167
168 return I;
169}
170
172 F = F->getFirstDecl();
173 assert(F);
174 auto It = Funcs.find(F);
175 return It == Funcs.end() ? nullptr : It->second;
176}
177
179 // Use the actual definition as a key.
180 RD = RD->getDefinition();
181 if (!RD)
182 return nullptr;
183
184 if (!RD->isCompleteDefinition())
185 return nullptr;
186
187 // Return an existing record if available. Otherwise, we insert nullptr now
188 // and replace that later, so recursive calls to this function with the same
189 // RecordDecl don't run into infinite recursion.
190 auto [It, Inserted] = Records.try_emplace(RD);
191 if (!Inserted)
192 return It->second;
193
194 // Number of bytes required by fields and base classes.
195 unsigned BaseSize = 0;
196 // Number of bytes required by virtual base.
197 unsigned VirtSize = 0;
198
199 // Helper to get a base descriptor.
200 auto GetBaseDesc = [this](const RecordDecl *BD,
201 const Record *BR) -> const Descriptor * {
202 if (!BR)
203 return nullptr;
204 return allocateDescriptor(BD, BR, /*IsConst=*/false, /*IsTemporary=*/false,
205 /*IsMutable=*/false, /*IsVolatile=*/false);
206 };
207
208 bool HasPtrField = false;
209 // Reserve space for base classes.
210 unsigned NumBases = 0;
211 Record::Base *Bases = nullptr;
212 unsigned NumVBases = 0;
213 Record::Base *VBases = nullptr;
214 if (const auto *CD = dyn_cast<CXXRecordDecl>(RD)) {
215 NumBases = CD->getNumBases();
216 // NB: This overallocates by all explicitly specified virtual bases.
217 if (NumBases != 0)
218 Bases = Allocate<Record::Base>(NumBases);
219
220 unsigned I = 0;
221 for (const CXXBaseSpecifier &Spec : CD->bases()) {
222 assert(I <= NumBases);
223 if (Spec.isVirtual())
224 continue;
225
226 // In error cases, the base might not be a RecordType.
227 const auto *BD = Spec.getType()->getAsCXXRecordDecl();
228 if (!BD)
229 return nullptr;
230 const Record *BR = getOrCreateRecord(BD);
231
232 const Descriptor *Desc = GetBaseDesc(BD, BR);
233 if (!Desc)
234 return nullptr;
235
236 BaseSize += align(sizeof(InlineDescriptor));
237 new (&Bases[I]) Record::Base(BD, Desc, BR, BaseSize);
238 BaseSize += align(BR->getSize());
239 HasPtrField |= BR->hasPtrField();
240 ++I;
241 }
242 // Make sure we don't include the virtual base specifiers we skipped above.
243 NumBases = I;
244
245 I = 0;
246 NumVBases = CD->getNumVBases();
247 if (NumVBases != 0)
248 VBases = Allocate<Record::Base>(NumVBases);
249 for (const CXXBaseSpecifier &Spec : CD->vbases()) {
250 assert(I <= NumVBases);
251 const auto *BD = Spec.getType()->castAsCXXRecordDecl();
252 const Record *BR = getOrCreateRecord(BD);
253
254 const Descriptor *Desc = GetBaseDesc(BD, BR);
255 if (!Desc)
256 return nullptr;
257
258 VirtSize += align(sizeof(InlineDescriptor));
259 new (&VBases[I]) Record::Base(BD, Desc, BR, VirtSize);
260 VirtSize += align(BR->getSize());
261 HasPtrField |= BR->hasPtrField();
262 ++I;
263 }
264 assert(I == NumVBases);
265 }
266
267 // Reserve space for fields.
268 unsigned NumFields = RD->getNumFields();
269 Record::Field *Fields = nullptr;
270 if (NumFields != 0)
271 Fields = Allocate<Record::Field>(NumFields);
272 unsigned I = 0;
273 for (const FieldDecl *FD : RD->fields()) {
274 FD = FD->getFirstDecl();
275 // Note that we DO create fields and descriptors
276 // for unnamed bitfields here, even though we later ignore
277 // them everywhere. That's so the FieldDecl's getFieldIndex() matches.
278
279 // Reserve space for the field's descriptor and the offset.
280 BaseSize += align(sizeof(InlineDescriptor));
281
282 // Classify the field and add its metadata.
283 QualType FT = FD->getType();
284 const bool IsConst = FT.isConstQualified();
285 const bool IsMutable = FD->isMutable();
286 const bool IsVolatile = FT.isVolatileQualified();
287 const Descriptor *Desc;
288 OptPrimType T = Ctx.classify(FT);
289 if (T) {
290 Desc = createDescriptor(FD, *T, nullptr, IsConst,
291 /*IsTemporary=*/false, IsMutable, IsVolatile);
292 HasPtrField = HasPtrField || (T == PT_Ptr);
293 } else if ((Desc = createDescriptor(FD, FT.getTypePtr(), IsConst,
294 /*IsTemporary=*/false, IsMutable,
295 IsVolatile))) {
296 HasPtrField =
297 HasPtrField ||
298 (Desc->isPrimitiveArray() && Desc->getPrimType() == PT_Ptr) ||
299 (Desc->ElemRecord && Desc->ElemRecord->hasPtrField());
300 } else {
301 Desc = allocateDescriptor(FD);
302 }
303 assert(Desc);
304 new (&Fields[I]) Record::Field(FD, Desc, BaseSize, T);
305 BaseSize += align(Desc->getAllocSize());
306 ++I;
307 }
308
309 // Adjust virtual base offsets to account for base size.
310 for (unsigned I = 0; I != NumVBases; ++I)
311 VBases[I].Offset += BaseSize;
312
313 Record *R = new (Allocator)
314 Record(RD, {Bases, NumBases}, {Fields, NumFields}, {VBases, NumVBases},
315 VirtSize, BaseSize, HasPtrField);
316 Records[RD] = R;
317 return R;
318}
319
321 bool IsConst, bool IsTemporary,
322 bool IsMutable, bool IsVolatile,
323 const Expr *Init) {
324 // Classes and structures.
325 if (const auto *RD = Ty->getAsRecordDecl()) {
326 if (const auto *Record = getOrCreateRecord(RD))
327 return allocateDescriptor(D, Record, IsConst, IsTemporary, IsMutable,
328 IsVolatile);
329 return allocateDescriptor(D);
330 }
331
332 // Arrays.
333 if (const auto *ArrayType = Ty->getAsArrayTypeUnsafe()) {
335 // Array of well-known bounds.
336 if (const auto *CAT = dyn_cast<ConstantArrayType>(ArrayType)) {
337 size_t NumElems = CAT->getZExtSize();
338 if (OptPrimType T = Ctx.classify(ElemTy)) {
339 // Arrays of primitives.
340 unsigned ElemSize = primSize(*T);
341 if ((Descriptor::MaxArrayElemBytes / ElemSize) < NumElems) {
342 return nullptr;
343 }
344 return allocateDescriptor(D, CAT, *T, NumElems, IsConst, IsTemporary,
345 IsMutable, IsVolatile);
346 }
347 // Arrays of composites. In this case, the array is a list of pointers,
348 // followed by the actual elements.
349 const Descriptor *ElemDesc =
350 createDescriptor(D, ElemTy.getTypePtr(), IsConst, IsTemporary);
351 if (!ElemDesc)
352 return nullptr;
353 unsigned ElemSize = ElemDesc->getAllocSize() + sizeof(InlineDescriptor);
354 if (std::numeric_limits<unsigned>::max() / ElemSize <= NumElems)
355 return nullptr;
356 return allocateDescriptor(D, Ty, ElemDesc, NumElems, IsConst, IsTemporary,
357 IsMutable);
358 }
359
360 // Array of unknown bounds - cannot be accessed and pointer arithmetic
361 // is forbidden on pointers to such objects.
364 if (OptPrimType T = Ctx.classify(ElemTy)) {
365 return allocateDescriptor(D, *T, IsConst, IsTemporary,
367 }
368 const Descriptor *Desc =
369 createDescriptor(D, ElemTy.getTypePtr(), IsConst, IsTemporary);
370 if (!Desc)
371 return nullptr;
372 return allocateDescriptor(D, Desc, IsTemporary,
374 }
375 }
376
377 // Atomic types.
378 if (const auto *AT = Ty->getAs<AtomicType>()) {
379 const Type *InnerTy = AT->getValueType().getTypePtr();
380 return createDescriptor(D, InnerTy, IsConst, IsTemporary, IsMutable);
381 }
382
383 // Complex types - represented as arrays of elements.
384 if (const auto *CT = Ty->getAs<ComplexType>()) {
385 OptPrimType ElemTy = Ctx.classify(CT->getElementType());
386 if (!ElemTy)
387 return nullptr;
388
389 return allocateDescriptor(D, CT, *ElemTy, 2, IsConst, IsTemporary,
390 IsMutable, IsVolatile);
391 }
392
393 // Same with vector types.
394 if (const auto *VT = Ty->getAs<VectorType>()) {
395 OptPrimType ElemTy = Ctx.classify(VT->getElementType());
396 if (!ElemTy)
397 return nullptr;
398
399 return allocateDescriptor(D, VT, *ElemTy, VT->getNumElements(), IsConst,
400 IsTemporary, IsMutable, IsVolatile);
401 }
402
403 // Same with constant matrix types.
404 if (const auto *MT = Ty->getAs<ConstantMatrixType>()) {
405 OptPrimType ElemTy = Ctx.classify(MT->getElementType());
406 if (!ElemTy)
407 return nullptr;
408
409 return allocateDescriptor(D, MT, *ElemTy, MT->getNumElementsFlattened(),
410 IsConst, IsTemporary, IsMutable, IsVolatile);
411 }
412
413 return nullptr;
414}
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:3800
QualType getElementType() const
Definition TypeBase.h:3812
Represents a base class of a C++ class.
Definition DeclCXX.h:146
Complex values, per C99 6.2.5p11.
Definition TypeBase.h:3355
Represents a concrete matrix type with constant number of rows and columns.
Definition TypeBase.h:4465
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:1078
This represents one expression.
Definition Expr.h:113
Represents a member of a struct/union/class.
Definition Decl.h:3295
Represents a function declaration or definition.
Definition Decl.h:2059
A global _GUID constant.
Definition DeclCXX.h:4432
A (possibly-)qualified type.
Definition TypeBase.h:938
bool isVolatileQualified() const
Determine whether this type is volatile-qualified.
Definition TypeBase.h:8505
const Type * getTypePtr() const
Retrieves a pointer to the underlying (unqualified) type.
Definition TypeBase.h:8421
bool isConstQualified() const
Determine whether this type is const-qualified.
Definition TypeBase.h:8494
Represents a struct/union/class.
Definition Decl.h:4460
unsigned getNumFields() const
Returns the number of fields (non-static data members) in this record.
Definition Decl.h:4676
field_range fields() const
Definition Decl.h:4663
RecordDecl * getDefinition() const
Returns the RecordDecl that actually defines this struct/union/class.
Definition Decl.h:4644
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:3953
A template parameter object.
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:8682
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
Definition Type.cpp:798
const ArrayType * getAsArrayTypeUnsafe() const
A variant of getAs<> for array types which silently discards qualifiers from the outermost type.
Definition TypeBase.h:9310
const T * getAs() const
Member-template getAs<specific type>'.
Definition TypeBase.h:9257
An artificial decl, representing a global anonymous constant value which is uniquified by value withi...
Definition DeclCXX.h:4489
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
Definition Decl.h:713
QualType getType() const
Definition Decl.h:724
bool isWeak() const
Determine whether this symbol is weakly-imported, or declared with the weak or weak-ref attr.
Definition Decl.cpp:5648
Represents a GCC generic vector type.
Definition TypeBase.h:4253
A memory block, either on the stack or in the heap.
Definition InterpBlock.h:43
static constexpr uint8_t GlobalMD
Definition InterpBlock.h:51
void movePointersTo(Block *B)
Move all pointers from this block to.
static bool shouldBeGloballyIndexed(const ValueDecl *VD)
Returns whether we should create a global variable for the given ValueDecl.
Definition Context.h:166
OptPrimType classify(QualType T) const
Classifies a type.
Definition Context.cpp:506
unsigned getEvalID() const
Definition Context.h:181
Bytecode function.
Definition Function.h:98
A pointer to a memory block, live or dead.
Definition Pointer.h:532
UnsignedOrNone createGlobal(const ValueDecl *VD, const Expr *Init, bool IsConstexprUnknown=false)
Creates a global and returns its index.
Definition Program.cpp:63
void * Allocate(size_t Size, unsigned Align=8) const
Definition Program.h:129
Function * getFunction(const FunctionDecl *F)
Returns a function.
Definition Program.cpp:171
Block * getGlobal(unsigned Idx)
Returns the value of a global.
Definition Program.h:67
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:114
UnsignedOrNone getOrCreateGlobal(const ValueDecl *VD, const Expr *Init=nullptr)
Returns or creates a global an creates an index to it.
Definition Program.cpp:51
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:152
Record * getOrCreateRecord(const RecordDecl *RD)
Returns a record or creates one if it does not exist.
Definition Program.cpp:178
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:213
bool Init(InterpState &S, CodePtr OpPC)
Definition Interp.h:2440
size_t primSize(PrimType Type)
Returns the size of a primitive type in bytes.
Definition PrimType.cpp:24
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
Token to denote structures of unknown size.
Definition Descriptor.h:139
Describes a memory block created by an allocation site.
Definition Descriptor.h:122
unsigned getAllocSize() const
Returns the allocated size, including metadata.
Definition Descriptor.h:237
static constexpr unsigned MaxArrayElemBytes
Maximum number of bytes to be used for array elements.
Definition Descriptor.h:142
bool isPrimitiveArray() const
Checks if the descriptor is of an array of primitives.
Definition Descriptor.h:251
PrimType getPrimType() const
Definition Descriptor.h:231
const Record *const ElemRecord
Pointer to the record, if block contains records.
Definition Descriptor.h:146
Descriptor used for global variables.
Definition Descriptor.h:49
Inline descriptor embedded in structures and arrays.
Definition Descriptor.h:67