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
63unsigned Program::getOrCreateDummy(DeclOrExpr D, bool IsConstexprUnknown) {
64 assert(D);
65
66 if (const auto *VD = D.asVarDecl())
67 D = VD->getFirstDecl();
68
69 // Dedup blocks since they are immutable and pointers cannot be compared.
70 if (auto It = DummyVariables.find(D.getOpaqueValue());
71 It != DummyVariables.end())
72 return It->second;
73
74 QualType QT;
75 bool IsWeak = false;
76 if (const auto *E = D.asExpr()) {
77 QT = E->getType();
78 } else {
79 const auto *VD = D.asValueDecl();
80 IsWeak = VD->isWeak();
81 QT = VD->getType();
82
83 if (QT->isReferenceType())
84 QT = QT->getPointeeType();
85 }
86
87 assert(!QT.isNull());
88
89 Descriptor *Desc;
90 if (OptPrimType T = Ctx.classify(QT))
91 Desc = createDescriptor(D, *T, /*SourceTy=*/nullptr,
92 /*IsConst=*/QT.isConstQualified());
93 else
94 Desc = createDescriptor(D, QT.getTypePtr(),
95 /*IsConst=*/QT.isConstQualified());
96 if (!Desc)
97 Desc = allocateDescriptor(D);
98
99 Desc->IsConstexprUnknown = IsConstexprUnknown;
100
101 assert(Desc);
102
103 // Allocate a block for storage.
104 unsigned I = Globals.size();
105
106 auto *G = new (Allocator, Desc->getAllocSize())
107 Global(Ctx.getEvalID(), getCurrentDecl(), Desc, /*MDSize=*/0u,
108 /*IsStatic=*/true, /*IsExtern=*/false, IsWeak, /*IsDummy=*/true);
109 G->block()->invokeCtor();
110 assert(G->block()->isDummy());
111
112 Globals.push_back(G);
113 DummyVariables[D.getOpaqueValue()] = I;
114 return I;
115}
116
118 bool IsConstexprUnknown) {
119 bool IsStatic, IsExtern;
120 bool IsWeak = VD->isWeak();
121 if (const auto *Var = dyn_cast<VarDecl>(VD)) {
123 IsExtern = Var->hasExternalStorage();
126 IsStatic = true;
127 IsExtern = false;
128 } else {
129 IsStatic = false;
130 IsExtern = true;
131 }
132
133 // Register all previous declarations as well. For extern blocks, just replace
134 // the index with the new variable.
135 UnsignedOrNone Idx = createGlobal(VD, VD->getType(), IsStatic, IsExtern,
136 IsWeak, IsConstexprUnknown, Init);
137 if (!Idx)
138 return std::nullopt;
139
140 Global *NewGlobal = Globals[*Idx];
141 GlobalIndices[VD] = *Idx;
142
143 for (const Decl *Redecl = VD->getPreviousDecl(); Redecl;
144 Redecl = Redecl->getPreviousDecl()) {
145 // If this redecl was registered as a dummy variable, it is now a proper
146 // global variable and points to the block we just created.
147 if (auto DummyIt = DummyVariables.find(Redecl);
148 DummyIt != DummyVariables.end()) {
149 Global *Dummy = Globals[DummyIt->second];
150 Dummy->block()->movePointersTo(NewGlobal->block());
151 Globals[DummyIt->second] = NewGlobal;
152 DummyVariables.erase(DummyIt);
153 }
154 // If the redeclaration hasn't been registered yet at all, we just set its
155 // global index to Idx. If it has been registered yet, it might have
156 // pointers pointing to it and we need to transfer those pointers to the new
157 // block.
158 auto [Iter, Inserted] = GlobalIndices.try_emplace(Redecl);
159 if (Inserted) {
160 Iter->second = *Idx;
161 continue;
162 }
163
164 Block *RedeclBlock = Globals[Iter->second]->block();
165 // All pointers pointing to the previous extern decl now point to the
166 // new decl.
167 // A previous iteration might've already fixed up the pointers for this
168 // global.
169 if (RedeclBlock != NewGlobal->block())
170 RedeclBlock->movePointersTo(NewGlobal->block());
171
172 Globals[Iter->second] = NewGlobal;
173 Iter->second = *Idx;
174 }
175
176 return *Idx;
177}
178
180 if (auto Idx = getGlobal(E))
181 return Idx;
182 if (auto Idx = createGlobal(E, ExprType, /*IsStatic=*/true,
183 /*IsExtern=*/false, /*IsWeak=*/false,
184 /*IsConstexprUnknown=*/false)) {
185 GlobalIndices[E] = *Idx;
186 return *Idx;
187 }
188 return std::nullopt;
189}
190
192 bool IsExtern, bool IsWeak,
193 bool IsConstexprUnknown,
194 const Expr *Init) {
195 // Since this global variable is constexpr-unknown and a reference, register
196 // the pointee type instead. When referencing the variable, the pointer will
197 // then be of the pointee type instead of just PT_Ptr.
198 if (Ty->isReferenceType() && IsConstexprUnknown)
199 Ty = Ty->getPointeeType();
200
201 // Create a descriptor for the global.
202 Descriptor *Desc;
203 const bool IsConst = Ty.isConstQualified();
204 const bool IsTemporary = D.isExpr();
205 const bool IsVolatile = Ty.isVolatileQualified();
206 if (OptPrimType T = Ctx.classify(Ty))
207 Desc = createDescriptor(D, *T, nullptr, IsConst, IsTemporary,
208 /*IsMutable=*/false, IsVolatile);
209 else
210 Desc = createDescriptor(D, Ty.getTypePtr(), IsConst, IsTemporary,
211 /*IsMutable=*/false, IsVolatile);
212
213 if (!Desc)
214 return std::nullopt;
215 Desc->IsConstexprUnknown = IsConstexprUnknown;
216
217 // Allocate a block for storage.
218 unsigned I = Globals.size();
219
220 auto *G = new (Allocator, Desc->getAllocSize() + Block::GlobalMD)
221 Global(Ctx.getEvalID(), getCurrentDecl(), Desc, Block::GlobalMD, IsStatic,
222 IsExtern, IsWeak);
223 G->block()->invokeCtor();
224
225 // Initialize GlobalInlineDescriptor fields.
226 auto *GD = new (G->block()->rawData()) GlobalInlineDescriptor();
227 if (!Init)
228 GD->InitState = GlobalInitState::NoInitializer;
229 Globals.push_back(G);
230
231 return I;
232}
233
235 F = F->getFirstDecl();
236 assert(F);
237 auto It = Funcs.find(F);
238 return It == Funcs.end() ? nullptr : It->second;
239}
240
242 // Use the actual definition as a key.
243 RD = RD->getDefinition();
244 if (!RD)
245 return nullptr;
246
247 if (!RD->isCompleteDefinition())
248 return nullptr;
249
250 // Return an existing record if available. Otherwise, we insert nullptr now
251 // and replace that later, so recursive calls to this function with the same
252 // RecordDecl don't run into infinite recursion.
253 auto [It, Inserted] = Records.try_emplace(RD);
254 if (!Inserted)
255 return It->second;
256
257 // Number of bytes required by fields and base classes.
258 unsigned BaseSize = 0;
259 // Number of bytes required by virtual base.
260 unsigned VirtSize = 0;
261
262 // Helper to get a base descriptor.
263 auto GetBaseDesc = [this](const RecordDecl *BD,
264 const Record *BR) -> const Descriptor * {
265 if (!BR)
266 return nullptr;
267 return allocateDescriptor(BD, BR, /*IsConst=*/false, /*IsTemporary=*/false,
268 /*IsMutable=*/false, /*IsVolatile=*/false);
269 };
270
271 // Reserve space for base classes.
272 Record::BaseList Bases;
273 Record::VirtualBaseList VirtBases;
274 if (const auto *CD = dyn_cast<CXXRecordDecl>(RD)) {
275 Bases.reserve(CD->getNumBases());
276 for (const CXXBaseSpecifier &Spec : CD->bases()) {
277 if (Spec.isVirtual())
278 continue;
279
280 // In error cases, the base might not be a RecordType.
281 const auto *BD = Spec.getType()->getAsCXXRecordDecl();
282 if (!BD)
283 return nullptr;
284 const Record *BR = getOrCreateRecord(BD);
285
286 const Descriptor *Desc = GetBaseDesc(BD, BR);
287 if (!Desc)
288 return nullptr;
289
290 BaseSize += align(sizeof(InlineDescriptor));
291 Bases.emplace_back(BD, Desc, BR, BaseSize);
292 BaseSize += align(BR->getSize());
293 }
294
295 for (const CXXBaseSpecifier &Spec : CD->vbases()) {
296 const auto *BD = Spec.getType()->castAsCXXRecordDecl();
297 const Record *BR = getOrCreateRecord(BD);
298
299 const Descriptor *Desc = GetBaseDesc(BD, BR);
300 if (!Desc)
301 return nullptr;
302
303 VirtSize += align(sizeof(InlineDescriptor));
304 VirtBases.emplace_back(BD, Desc, BR, VirtSize);
305 VirtSize += align(BR->getSize());
306 }
307 }
308
309 // Reserve space for fields.
310 Record::FieldList Fields;
311 Fields.reserve(RD->getNumFields());
312 bool HasPtrField = false;
313 for (const FieldDecl *FD : RD->fields()) {
314 FD = FD->getFirstDecl();
315 // Note that we DO create fields and descriptors
316 // for unnamed bitfields here, even though we later ignore
317 // them everywhere. That's so the FieldDecl's getFieldIndex() matches.
318
319 // Reserve space for the field's descriptor and the offset.
320 BaseSize += align(sizeof(InlineDescriptor));
321
322 // Classify the field and add its metadata.
323 QualType FT = FD->getType();
324 const bool IsConst = FT.isConstQualified();
325 const bool IsMutable = FD->isMutable();
326 const bool IsVolatile = FT.isVolatileQualified();
327 const Descriptor *Desc;
328 OptPrimType T = Ctx.classify(FT);
329 if (T) {
330 Desc = createDescriptor(FD, *T, nullptr, IsConst,
331 /*IsTemporary=*/false, IsMutable, IsVolatile);
332 HasPtrField = HasPtrField || (T == PT_Ptr);
333 } else if ((Desc = createDescriptor(FD, FT.getTypePtr(), IsConst,
334 /*IsTemporary=*/false, IsMutable,
335 IsVolatile))) {
336 HasPtrField =
337 HasPtrField ||
338 (Desc->isPrimitiveArray() && Desc->getPrimType() == PT_Ptr) ||
339 (Desc->ElemRecord && Desc->ElemRecord->hasPtrField());
340 } else {
341 Desc = allocateDescriptor(FD);
342 }
343 Fields.emplace_back(FD, Desc, BaseSize, T);
344 BaseSize += align(Desc->getAllocSize());
345 }
346
347 Record *R = new (Allocator)
348 Record(RD, std::move(Bases), std::move(Fields), std::move(VirtBases),
349 VirtSize, BaseSize, HasPtrField);
350 Records[RD] = R;
351 return R;
352}
353
355 bool IsConst, bool IsTemporary,
356 bool IsMutable, bool IsVolatile,
357 const Expr *Init) {
358 // Classes and structures.
359 if (const auto *RD = Ty->getAsRecordDecl()) {
360 if (const auto *Record = getOrCreateRecord(RD))
361 return allocateDescriptor(D, Record, IsConst, IsTemporary, IsMutable,
362 IsVolatile);
363 return allocateDescriptor(D);
364 }
365
366 // Arrays.
367 if (const auto *ArrayType = Ty->getAsArrayTypeUnsafe()) {
369 // Array of well-known bounds.
370 if (const auto *CAT = dyn_cast<ConstantArrayType>(ArrayType)) {
371 size_t NumElems = CAT->getZExtSize();
372 if (OptPrimType T = Ctx.classify(ElemTy)) {
373 // Arrays of primitives.
374 unsigned ElemSize = primSize(*T);
375 if ((Descriptor::MaxArrayElemBytes / ElemSize) < NumElems) {
376 return nullptr;
377 }
378 return allocateDescriptor(D, CAT, *T, NumElems, IsConst, IsTemporary,
379 IsMutable, IsVolatile);
380 }
381 // Arrays of composites. In this case, the array is a list of pointers,
382 // followed by the actual elements.
383 const Descriptor *ElemDesc =
384 createDescriptor(D, ElemTy.getTypePtr(), IsConst, IsTemporary);
385 if (!ElemDesc)
386 return nullptr;
387 unsigned ElemSize = ElemDesc->getAllocSize() + sizeof(InlineDescriptor);
388 if (std::numeric_limits<unsigned>::max() / ElemSize <= NumElems)
389 return nullptr;
390 return allocateDescriptor(D, Ty, ElemDesc, NumElems, IsConst, IsTemporary,
391 IsMutable);
392 }
393
394 // Array of unknown bounds - cannot be accessed and pointer arithmetic
395 // is forbidden on pointers to such objects.
398 if (OptPrimType T = Ctx.classify(ElemTy)) {
399 return allocateDescriptor(D, *T, IsConst, IsTemporary,
401 }
402 const Descriptor *Desc =
403 createDescriptor(D, ElemTy.getTypePtr(), IsConst, IsTemporary);
404 if (!Desc)
405 return nullptr;
406 return allocateDescriptor(D, Desc, IsTemporary,
408 }
409 }
410
411 // Atomic types.
412 if (const auto *AT = Ty->getAs<AtomicType>()) {
413 const Type *InnerTy = AT->getValueType().getTypePtr();
414 return createDescriptor(D, InnerTy, IsConst, IsTemporary, IsMutable);
415 }
416
417 // Complex types - represented as arrays of elements.
418 if (const auto *CT = Ty->getAs<ComplexType>()) {
419 OptPrimType ElemTy = Ctx.classify(CT->getElementType());
420 if (!ElemTy)
421 return nullptr;
422
423 return allocateDescriptor(D, CT, *ElemTy, 2, IsConst, IsTemporary,
424 IsMutable, IsVolatile);
425 }
426
427 // Same with vector types.
428 if (const auto *VT = Ty->getAs<VectorType>()) {
429 OptPrimType ElemTy = Ctx.classify(VT->getElementType());
430 if (!ElemTy)
431 return nullptr;
432
433 return allocateDescriptor(D, VT, *ElemTy, VT->getNumElements(), IsConst,
434 IsTemporary, IsMutable, IsVolatile);
435 }
436
437 // Same with constant matrix types.
438 if (const auto *MT = Ty->getAs<ConstantMatrixType>()) {
439 OptPrimType ElemTy = Ctx.classify(MT->getElementType());
440 if (!ElemTy)
441 return nullptr;
442
443 return allocateDescriptor(D, MT, *ElemTy, MT->getNumElementsFlattened(),
444 IsConst, IsTemporary, IsMutable, IsVolatile);
445 }
446
447 return nullptr;
448}
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:8502
bool isNull() const
Return true if this QualType doesn't point to a type yet.
Definition TypeBase.h:1005
const Type * getTypePtr() const
Retrieves a pointer to the underlying (unqualified) type.
Definition TypeBase.h:8418
bool isConstQualified() const
Determine whether this type is const-qualified.
Definition TypeBase.h:8491
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:8679
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
Definition Type.cpp:789
const ArrayType * getAsArrayTypeUnsafe() const
A variant of getAs<> for array types which silently discards qualifiers from the outermost type.
Definition TypeBase.h:9307
const T * getAs() const
Member-template getAs<specific type>'.
Definition TypeBase.h:9254
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:52
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:530
UnsignedOrNone createGlobal(const ValueDecl *VD, const Expr *Init, bool IsConstexprUnknown=false)
Creates a global and returns its index.
Definition Program.cpp:117
Function * getFunction(const FunctionDecl *F)
Returns a function.
Definition Program.cpp:234
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:117
UnsignedOrNone getOrCreateGlobal(const ValueDecl *VD, const Expr *Init=nullptr)
Returns or creates a global an creates an index to it.
Definition Program.cpp:51
unsigned getOrCreateDummy(DeclOrExpr D, bool IsConstexprUnknown=false)
Returns or creates a dummy value for unknown declarations.
Definition Program.cpp:63
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:155
Record * getOrCreateRecord(const RecordDecl *RD)
Returns a record or creates one if it does not exist.
Definition Program.cpp:241
Structure/Class descriptor.
Definition Record.h:26
bool hasPtrField() const
If this record (or any of its bases) contains a field of type PT_Ptr.
Definition Record.h:91
unsigned getSize() const
Returns the size of the record.
Definition Record.h:81
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:2443
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
const ValueDecl * asValueDecl() const
Definition DeclOrExpr.h:34
const VarDecl * asVarDecl() const
Definition DeclOrExpr.h:37
const Expr * asExpr() const
Definition DeclOrExpr.h:32
const void * getOpaqueValue() const
Definition DeclOrExpr.h:41
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