clang  14.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 "ByteCodeStmtGen.h"
11 #include "Context.h"
12 #include "Function.h"
13 #include "Opcode.h"
14 #include "PrimType.h"
15 #include "clang/AST/Decl.h"
16 #include "clang/AST/DeclCXX.h"
17 
18 using namespace clang;
19 using namespace clang::interp;
20 
21 unsigned Program::getOrCreateNativePointer(const void *Ptr) {
22  auto It = NativePointerIndices.find(Ptr);
23  if (It != NativePointerIndices.end())
24  return It->second;
25 
26  unsigned Idx = NativePointers.size();
27  NativePointers.push_back(Ptr);
28  NativePointerIndices[Ptr] = Idx;
29  return Idx;
30 }
31 
32 const void *Program::getNativePointer(unsigned Idx) {
33  return NativePointers[Idx];
34 }
35 
37  const size_t CharWidth = S->getCharByteWidth();
38  const size_t BitWidth = CharWidth * Ctx.getCharBit();
39 
40  PrimType CharType;
41  switch (CharWidth) {
42  case 1:
43  CharType = PT_Sint8;
44  break;
45  case 2:
46  CharType = PT_Uint16;
47  break;
48  case 4:
49  CharType = PT_Uint32;
50  break;
51  default:
52  llvm_unreachable("unsupported character width");
53  }
54 
55  // Create a descriptor for the string.
56  Descriptor *Desc = allocateDescriptor(S, CharType, S->getLength() + 1,
57  /*isConst=*/true,
58  /*isTemporary=*/false,
59  /*isMutable=*/false);
60 
61  // Allocate storage for the string.
62  // The byte length does not include the null terminator.
63  unsigned I = Globals.size();
64  unsigned Sz = Desc->getAllocSize();
65  auto *G = new (Allocator, Sz) Global(Desc, /*isStatic=*/true,
66  /*isExtern=*/false);
67  Globals.push_back(G);
68 
69  // Construct the string in storage.
70  const Pointer Ptr(G->block());
71  for (unsigned I = 0, N = S->getLength(); I <= N; ++I) {
72  Pointer Field = Ptr.atIndex(I).narrow();
73  const uint32_t CodePoint = I == N ? 0 : S->getCodeUnit(I);
74  switch (CharType) {
75  case PT_Sint8: {
76  using T = PrimConv<PT_Sint8>::T;
77  Field.deref<T>() = T::from(CodePoint, BitWidth);
78  break;
79  }
80  case PT_Uint16: {
81  using T = PrimConv<PT_Uint16>::T;
82  Field.deref<T>() = T::from(CodePoint, BitWidth);
83  break;
84  }
85  case PT_Uint32: {
86  using T = PrimConv<PT_Uint32>::T;
87  Field.deref<T>() = T::from(CodePoint, BitWidth);
88  break;
89  }
90  default:
91  llvm_unreachable("unsupported character type");
92  }
93  }
94  return I;
95 }
96 
98  assert(Idx < Globals.size());
99  return Pointer(Globals[Idx]->block());
100 }
101 
103  auto It = GlobalIndices.find(VD);
104  if (It != GlobalIndices.end())
105  return It->second;
106 
107  // Find any previous declarations which were already evaluated.
109  for (const Decl *P = VD; P; P = P->getPreviousDecl()) {
110  auto It = GlobalIndices.find(P);
111  if (It != GlobalIndices.end()) {
112  Index = It->second;
113  break;
114  }
115  }
116 
117  // Map the decl to the existing index.
118  if (Index) {
119  GlobalIndices[VD] = *Index;
120  return {};
121  }
122 
123  return Index;
124 }
125 
127  if (auto Idx = getGlobal(VD))
128  return Idx;
129 
130  if (auto Idx = createGlobal(VD)) {
131  GlobalIndices[VD] = *Idx;
132  return Idx;
133  }
134  return {};
135 }
136 
138  auto &ASTCtx = Ctx.getASTContext();
139 
140  // Create a pointer to an incomplete array of the specified elements.
141  QualType ElemTy = PD->getType()->castAs<PointerType>()->getPointeeType();
142  QualType Ty = ASTCtx.getIncompleteArrayType(ElemTy, ArrayType::Normal, 0);
143 
144  // Dedup blocks since they are immutable and pointers cannot be compared.
145  auto It = DummyParams.find(PD);
146  if (It != DummyParams.end())
147  return It->second;
148 
149  if (auto Idx = createGlobal(PD, Ty, /*isStatic=*/true, /*isExtern=*/true)) {
150  DummyParams[PD] = *Idx;
151  return Idx;
152  }
153  return {};
154 }
155 
157  bool IsStatic, IsExtern;
158  if (auto *Var = dyn_cast<VarDecl>(VD)) {
159  IsStatic = !Var->hasLocalStorage();
160  IsExtern = !Var->getAnyInitializer();
161  } else {
162  IsStatic = false;
163  IsExtern = true;
164  }
165  if (auto Idx = createGlobal(VD, VD->getType(), IsStatic, IsExtern)) {
166  for (const Decl *P = VD; P; P = P->getPreviousDecl())
167  GlobalIndices[P] = *Idx;
168  return *Idx;
169  }
170  return {};
171 }
172 
174  return createGlobal(E, E->getType(), /*isStatic=*/true, /*isExtern=*/false);
175 }
176 
178  bool IsStatic, bool IsExtern) {
179  // Create a descriptor for the global.
180  Descriptor *Desc;
181  const bool IsConst = Ty.isConstQualified();
182  const bool IsTemporary = D.dyn_cast<const Expr *>();
183  if (auto T = Ctx.classify(Ty)) {
184  Desc = createDescriptor(D, *T, IsConst, IsTemporary);
185  } else {
186  Desc = createDescriptor(D, Ty.getTypePtr(), IsConst, IsTemporary);
187  }
188  if (!Desc)
189  return {};
190 
191  // Allocate a block for storage.
192  unsigned I = Globals.size();
193 
194  auto *G = new (Allocator, Desc->getAllocSize())
195  Global(getCurrentDecl(), Desc, IsStatic, IsExtern);
196  G->block()->invokeCtor();
197 
198  Globals.push_back(G);
199 
200  return I;
201 }
202 
204  F = F->getDefinition();
205  auto It = Funcs.find(F);
206  return It == Funcs.end() ? nullptr : It->second.get();
207 }
208 
210  if (Function *Func = getFunction(F)) {
211  return Func;
212  }
213 
214  // Try to compile the function if it wasn't compiled yet.
215  if (const FunctionDecl *FD = F->getDefinition())
216  return ByteCodeStmtGen<ByteCodeEmitter>(Ctx, *this).compileFunc(FD);
217 
218  // A relocation which traps if not resolved.
219  return nullptr;
220 }
221 
223  // Use the actual definition as a key.
224  RD = RD->getDefinition();
225  if (!RD)
226  return nullptr;
227 
228  // Deduplicate records.
229  auto It = Records.find(RD);
230  if (It != Records.end()) {
231  return It->second;
232  }
233 
234  // Number of bytes required by fields and base classes.
235  unsigned Size = 0;
236  // Number of bytes required by virtual base.
237  unsigned VirtSize = 0;
238 
239  // Helper to get a base descriptor.
240  auto GetBaseDesc = [this](const RecordDecl *BD, Record *BR) -> Descriptor * {
241  if (!BR)
242  return nullptr;
243  return allocateDescriptor(BD, BR, /*isConst=*/false,
244  /*isTemporary=*/false,
245  /*isMutable=*/false);
246  };
247 
248  // Reserve space for base classes.
249  Record::BaseList Bases;
250  Record::VirtualBaseList VirtBases;
251  if (auto *CD = dyn_cast<CXXRecordDecl>(RD)) {
252  for (const CXXBaseSpecifier &Spec : CD->bases()) {
253  if (Spec.isVirtual())
254  continue;
255 
256  const RecordDecl *BD = Spec.getType()->castAs<RecordType>()->getDecl();
257  Record *BR = getOrCreateRecord(BD);
258  if (Descriptor *Desc = GetBaseDesc(BD, BR)) {
259  Size += align(sizeof(InlineDescriptor));
260  Bases.push_back({BD, Size, Desc, BR});
261  Size += align(BR->getSize());
262  continue;
263  }
264  return nullptr;
265  }
266 
267  for (const CXXBaseSpecifier &Spec : CD->vbases()) {
268  const RecordDecl *BD = Spec.getType()->castAs<RecordType>()->getDecl();
269  Record *BR = getOrCreateRecord(BD);
270 
271  if (Descriptor *Desc = GetBaseDesc(BD, BR)) {
272  VirtSize += align(sizeof(InlineDescriptor));
273  VirtBases.push_back({BD, VirtSize, Desc, BR});
274  VirtSize += align(BR->getSize());
275  continue;
276  }
277  return nullptr;
278  }
279  }
280 
281  // Reserve space for fields.
282  Record::FieldList Fields;
283  for (const FieldDecl *FD : RD->fields()) {
284  // Reserve space for the field's descriptor and the offset.
285  Size += align(sizeof(InlineDescriptor));
286 
287  // Classify the field and add its metadata.
288  QualType FT = FD->getType();
289  const bool IsConst = FT.isConstQualified();
290  const bool IsMutable = FD->isMutable();
291  Descriptor *Desc;
292  if (llvm::Optional<PrimType> T = Ctx.classify(FT)) {
293  Desc = createDescriptor(FD, *T, IsConst, /*isTemporary=*/false,
294  IsMutable);
295  } else {
296  Desc = createDescriptor(FD, FT.getTypePtr(), IsConst,
297  /*isTemporary=*/false, IsMutable);
298  }
299  if (!Desc)
300  return nullptr;
301  Fields.push_back({FD, Size, Desc});
302  Size += align(Desc->getAllocSize());
303  }
304 
305  Record *R = new (Allocator) Record(RD, std::move(Bases), std::move(Fields),
306  std::move(VirtBases), VirtSize, Size);
307  Records.insert({RD, R});
308  return R;
309 }
310 
312  bool IsConst, bool IsTemporary,
313  bool IsMutable) {
314  // Classes and structures.
315  if (auto *RT = Ty->getAs<RecordType>()) {
316  if (auto *Record = getOrCreateRecord(RT->getDecl()))
317  return allocateDescriptor(D, Record, IsConst, IsTemporary, IsMutable);
318  }
319 
320  // Arrays.
321  if (auto ArrayType = Ty->getAsArrayTypeUnsafe()) {
322  QualType ElemTy = ArrayType->getElementType();
323  // Array of well-known bounds.
324  if (auto CAT = dyn_cast<ConstantArrayType>(ArrayType)) {
325  size_t NumElems = CAT->getSize().getZExtValue();
326  if (llvm::Optional<PrimType> T = Ctx.classify(ElemTy)) {
327  // Arrays of primitives.
328  unsigned ElemSize = primSize(*T);
329  if (std::numeric_limits<unsigned>::max() / ElemSize <= NumElems) {
330  return {};
331  }
332  return allocateDescriptor(D, *T, NumElems, IsConst, IsTemporary,
333  IsMutable);
334  } else {
335  // Arrays of composites. In this case, the array is a list of pointers,
336  // followed by the actual elements.
337  Descriptor *Desc =
338  createDescriptor(D, ElemTy.getTypePtr(), IsConst, IsTemporary);
339  if (!Desc)
340  return nullptr;
341  InterpSize ElemSize = Desc->getAllocSize() + sizeof(InlineDescriptor);
342  if (std::numeric_limits<unsigned>::max() / ElemSize <= NumElems)
343  return {};
344  return allocateDescriptor(D, Desc, NumElems, IsConst, IsTemporary,
345  IsMutable);
346  }
347  }
348 
349  // Array of unknown bounds - cannot be accessed and pointer arithmetic
350  // is forbidden on pointers to such objects.
351  if (isa<IncompleteArrayType>(ArrayType)) {
352  if (llvm::Optional<PrimType> T = Ctx.classify(ElemTy)) {
353  return allocateDescriptor(D, *T, IsTemporary,
355  } else {
356  Descriptor *Desc =
357  createDescriptor(D, ElemTy.getTypePtr(), IsConst, IsTemporary);
358  if (!Desc)
359  return nullptr;
360  return allocateDescriptor(D, Desc, IsTemporary,
362  }
363  }
364  }
365 
366  // Atomic types.
367  if (auto *AT = Ty->getAs<AtomicType>()) {
368  const Type *InnerTy = AT->getValueType().getTypePtr();
369  return createDescriptor(D, InnerTy, IsConst, IsTemporary, IsMutable);
370  }
371 
372  // Complex types - represented as arrays of elements.
373  if (auto *CT = Ty->getAs<ComplexType>()) {
374  PrimType ElemTy = *Ctx.classify(CT->getElementType());
375  return allocateDescriptor(D, ElemTy, 2, IsConst, IsTemporary, IsMutable);
376  }
377 
378  return nullptr;
379 }
max
__DEVICE__ int max(int __a, int __b)
Definition: __clang_cuda_math.h:196
clang::Type::getAsArrayTypeUnsafe
const ArrayType * getAsArrayTypeUnsafe() const
A variant of getAs<> for array types which silently discards qualifiers from the outermost type.
Definition: Type.h:7213
clang::interp::align
constexpr size_t align(size_t Size)
Aligns a size to the pointer alignment.
Definition: PrimType.h:57
clang::QualType::isConstQualified
bool isConstQualified() const
Determine whether this type is const-qualified.
Definition: Type.h:6484
Opcode.h
llvm::SmallVector< Base, 8 >
clang::interp::Context::getCharBit
unsigned getCharBit() const
Returns CHAR_BIT.
Definition: Context.cpp:109
clang::QualType
A (possibly-)qualified type.
Definition: Type.h:673
clang::interp::ByteCodeStmtGen
Compilation context for statements.
Definition: ByteCodeStmtGen.h:40
clang::FieldDecl
Represents a member of a struct/union/class.
Definition: Decl.h:2835
clang::ParmVarDecl
Represents a parameter to a function.
Definition: Decl.h:1665
DeclCXX.h
clang::interp::PT_Uint16
@ PT_Uint16
Definition: PrimType.h:31
llvm::Optional< unsigned >
clang::RecordDecl::getDefinition
RecordDecl * getDefinition() const
Returns the RecordDecl that actually defines this struct/union/class.
Definition: Decl.h:4064
clang::interp::Program::getCurrentDecl
llvm::Optional< unsigned > getCurrentDecl() const
Returns the current declaration ID.
Definition: Program.h:130
llvm::Expected
Definition: LLVM.h:41
clang::interp::Descriptor::getAllocSize
unsigned getAllocSize() const
Returns the allocated size, including metadata.
Definition: Descriptor.h:134
clang::interp::Program::getFunction
Function * getFunction(const FunctionDecl *F)
Returns a function.
Definition: Program.cpp:203
clang::interp::Pointer
A pointer to a memory block, live or dead.
Definition: Pointer.h:39
clang::ArrayType::Normal
@ Normal
Definition: Type.h:2890
clang::Type
The base class of the type hierarchy.
Definition: Type.h:1490
Decl.h
ByteCodeStmtGen.h
clang::FunctionDecl::getDefinition
FunctionDecl * getDefinition()
Get the definition for this declaration.
Definition: Decl.h:2119
clang::interp::Program::getGlobal
Block * getGlobal(unsigned Idx)
Returns the value of a global.
Definition: Program.h:60
clang::interp::Descriptor::UnknownSize
Token to denote structures of unknown size.
Definition: Descriptor.h:67
clang::interp
Definition: ASTContext.h:158
clang::RecordType
A helper class that allows the use of isa/cast/dyncast to detect TagType objects of structs/unions/cl...
Definition: Type.h:4613
clang::interp::Program::createDescriptor
Descriptor * createDescriptor(const DeclTy &D, PrimType Type, bool IsConst=false, bool IsTemporary=false, bool IsMutable=false)
Creates a descriptor for a primitive type.
Definition: Program.h:107
clang::ArrayType
Represents an array type, per C99 6.7.5.2 - Array Declarators.
Definition: Type.h:2883
clang::Type::getAs
const T * getAs() const
Member-template getAs<specific type>'.
Definition: Type.h:7162
clang::interp::PT_Uint32
@ PT_Uint32
Definition: PrimType.h:33
clang::interp::PrimType
PrimType
Enumeration of the primitive types of the VM.
Definition: PrimType.h:27
clang::interp::Pointer::atIndex
Pointer atIndex(unsigned Idx) const
Offsets a pointer inside an array.
Definition: Pointer.h:58
clang::StringLiteral
StringLiteral - This represents a string literal expression, e.g.
Definition: Expr.h:1761
PrimType.h
clang::interp::Program::getOrCreateNativePointer
unsigned getOrCreateNativePointer(const void *Ptr)
Marshals a native pointer to an ID for embedding in bytecode.
Definition: Program.cpp:21
clang::interp::Program::getOrCreateFunction
llvm::Expected< Function * > getOrCreateFunction(const FunctionDecl *F)
Returns a pointer to a function if it exists and can be compiled.
Definition: Program.cpp:209
clang::interp::Program::getOrCreateGlobal
llvm::Optional< unsigned > getOrCreateGlobal(const ValueDecl *VD)
Returns or creates a global an creates an index to it.
Definition: Program.cpp:126
clang::interp::Program::getOrCreateRecord
Record * getOrCreateRecord(const RecordDecl *RD)
Returns a record or creates one if it does not exist.
Definition: Program.cpp:222
clang::Type::castAs
const T * castAs() const
Member-template castAs<specific type>.
Definition: Type.h:7227
clang::interp::Program::getPtrGlobal
Pointer getPtrGlobal(unsigned Idx)
Returns a pointer to a global.
Definition: Program.cpp:97
P
StringRef P
Definition: ASTMatchersInternal.cpp:563
clang::interp::primSize
size_t primSize(PrimType Type)
Returns the size of a primitive type in bytes.
Definition: PrimType.cpp:17
clang::ValueDecl
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
Definition: Decl.h:676
clang::ComplexType
Complex values, per C99 6.2.5p11.
Definition: Type.h:2587
clang::RecordDecl::fields
field_range fields() const
Definition: Decl.h:4079
clang::interp::InlineDescriptor
Inline descriptor embedded in structures and arrays.
Definition: Descriptor.h:163
clang::Decl
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:89
clang::interp::Program::getOrCreateDummy
llvm::Optional< unsigned > getOrCreateDummy(const ParmVarDecl *PD)
Returns or creates a dummy value for parameters.
Definition: Program.cpp:137
IsStatic
bool IsStatic
Definition: Format.cpp:2345
clang::interp::PT_Sint8
@ PT_Sint8
Definition: PrimType.h:28
clang::interp::Descriptor
Describes a memory block created by an allocation site.
Definition: Descriptor.h:51
clang::PointerType
PointerType - C99 6.7.5.1 - Pointer Declarators.
Definition: Type.h:2640
clang
Definition: CalledOnceCheck.h:17
Function.h
clang::interp::Function
Bytecode function.
Definition: Function.h:59
clang::Expr::getType
QualType getType() const
Definition: Expr.h:141
clang::CXXBaseSpecifier
Represents a base class of a C++ class.
Definition: DeclCXX.h:147
unsigned
clang::interp::Context::getASTContext
ASTContext & getASTContext() const
Returns the AST context.
Definition: Context.h:55
clang::QualType::getTypePtr
const Type * getTypePtr() const
Retrieves a pointer to the underlying (unqualified) type.
Definition: Type.h:6425
Program.h
clang::interp::DeclTy
unsigned llvm::PointerUnion< const Decl *, const Expr * > DeclTy
Definition: Descriptor.h:26
clang::interp::Program::createGlobalString
unsigned createGlobalString(const StringLiteral *S)
Emits a string literal among global data.
Definition: Program.cpp:36
clang::AtomicType
Definition: Type.h:6243
clang::ValueDecl::getType
QualType getType() const
Definition: Decl.h:687
clang::ArrayType::getElementType
QualType getElementType() const
Definition: Type.h:2904
clang::Expr
This represents one expression.
Definition: Expr.h:109
clang::interp::Program::createGlobal
llvm::Optional< unsigned > createGlobal(const ValueDecl *VD)
Creates a global and returns its index.
Definition: Program.cpp:156
clang::interp::Record
Structure/Class descriptor.
Definition: Record.h:23
clang::FunctionDecl
Represents a function declaration or definition.
Definition: Decl.h:1856
clang::interp::PrimConv
Mapping from primitive types to their representation.
Definition: PrimType.h:41
clang::RecordDecl
Represents a struct/union/class.
Definition: Decl.h:3859
clang::interp::Program::getNativePointer
const void * getNativePointer(unsigned Idx)
Returns the value of a marshalled native pointer.
Definition: Program.cpp:32
clang::interp::Context::classify
llvm::Optional< PrimType > classify(QualType T)
Classifies an expression.
Definition: Context.cpp:62
Context.h
clang::interp::Pointer::narrow
Pointer narrow() const
Restricts the scope of an array element pointer.
Definition: Pointer.h:76
clang::interp::Record::getSize
unsigned getSize() const
Returns the size of the record.
Definition: Record.h:53