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