Coverage Report

Created: 2024-01-17 10:31

/src/llvm-project/clang/lib/AST/Interp/Program.cpp
Line
Count
Source (jump to first uncovered line)
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 "Integral.h"
14
#include "Opcode.h"
15
#include "PrimType.h"
16
#include "clang/AST/Decl.h"
17
#include "clang/AST/DeclCXX.h"
18
19
using namespace clang;
20
using namespace clang::interp;
21
22
0
unsigned Program::getOrCreateNativePointer(const void *Ptr) {
23
0
  auto It = NativePointerIndices.find(Ptr);
24
0
  if (It != NativePointerIndices.end())
25
0
    return It->second;
26
27
0
  unsigned Idx = NativePointers.size();
28
0
  NativePointers.push_back(Ptr);
29
0
  NativePointerIndices[Ptr] = Idx;
30
0
  return Idx;
31
0
}
32
33
0
const void *Program::getNativePointer(unsigned Idx) {
34
0
  return NativePointers[Idx];
35
0
}
36
37
0
unsigned Program::createGlobalString(const StringLiteral *S) {
38
0
  const size_t CharWidth = S->getCharByteWidth();
39
0
  const size_t BitWidth = CharWidth * Ctx.getCharBit();
40
41
0
  PrimType CharType;
42
0
  switch (CharWidth) {
43
0
  case 1:
44
0
    CharType = PT_Sint8;
45
0
    break;
46
0
  case 2:
47
0
    CharType = PT_Uint16;
48
0
    break;
49
0
  case 4:
50
0
    CharType = PT_Uint32;
51
0
    break;
52
0
  default:
53
0
    llvm_unreachable("unsupported character width");
54
0
  }
55
56
  // Create a descriptor for the string.
57
0
  Descriptor *Desc =
58
0
      allocateDescriptor(S, CharType, std::nullopt, S->getLength() + 1,
59
0
                         /*isConst=*/true,
60
0
                         /*isTemporary=*/false,
61
0
                         /*isMutable=*/false);
62
63
  // Allocate storage for the string.
64
  // The byte length does not include the null terminator.
65
0
  unsigned I = Globals.size();
66
0
  unsigned Sz = Desc->getAllocSize();
67
0
  auto *G = new (Allocator, Sz) Global(Desc, /*isStatic=*/true,
68
0
                                       /*isExtern=*/false);
69
0
  G->block()->invokeCtor();
70
0
  Globals.push_back(G);
71
72
  // Construct the string in storage.
73
0
  const Pointer Ptr(G->block());
74
0
  for (unsigned I = 0, N = S->getLength(); I <= N; ++I) {
75
0
    Pointer Field = Ptr.atIndex(I).narrow();
76
0
    const uint32_t CodePoint = I == N ? 0 : S->getCodeUnit(I);
77
0
    switch (CharType) {
78
0
      case PT_Sint8: {
79
0
        using T = PrimConv<PT_Sint8>::T;
80
0
        Field.deref<T>() = T::from(CodePoint, BitWidth);
81
0
        break;
82
0
      }
83
0
      case PT_Uint16: {
84
0
        using T = PrimConv<PT_Uint16>::T;
85
0
        Field.deref<T>() = T::from(CodePoint, BitWidth);
86
0
        break;
87
0
      }
88
0
      case PT_Uint32: {
89
0
        using T = PrimConv<PT_Uint32>::T;
90
0
        Field.deref<T>() = T::from(CodePoint, BitWidth);
91
0
        break;
92
0
      }
93
0
      default:
94
0
        llvm_unreachable("unsupported character type");
95
0
    }
96
0
  }
97
0
  return I;
98
0
}
99
100
0
Pointer Program::getPtrGlobal(unsigned Idx) {
101
0
  assert(Idx < Globals.size());
102
0
  return Pointer(Globals[Idx]->block());
103
0
}
104
105
0
std::optional<unsigned> Program::getGlobal(const ValueDecl *VD) {
106
0
  auto It = GlobalIndices.find(VD);
107
0
  if (It != GlobalIndices.end())
108
0
    return It->second;
109
110
  // Find any previous declarations which were already evaluated.
111
0
  std::optional<unsigned> Index;
112
0
  for (const Decl *P = VD; P; P = P->getPreviousDecl()) {
113
0
    auto It = GlobalIndices.find(P);
114
0
    if (It != GlobalIndices.end()) {
115
0
      Index = It->second;
116
0
      break;
117
0
    }
118
0
  }
119
120
  // Map the decl to the existing index.
121
0
  if (Index) {
122
0
    GlobalIndices[VD] = *Index;
123
0
    return std::nullopt;
124
0
  }
125
126
0
  return Index;
127
0
}
128
129
std::optional<unsigned> Program::getOrCreateGlobal(const ValueDecl *VD,
130
0
                                                   const Expr *Init) {
131
0
  if (auto Idx = getGlobal(VD))
132
0
    return Idx;
133
134
0
  if (auto Idx = createGlobal(VD, Init)) {
135
0
    GlobalIndices[VD] = *Idx;
136
0
    return Idx;
137
0
  }
138
0
  return std::nullopt;
139
0
}
140
141
0
std::optional<unsigned> Program::getOrCreateDummy(const ValueDecl *VD) {
142
  // Dedup blocks since they are immutable and pointers cannot be compared.
143
0
  if (auto It = DummyParams.find(VD); It != DummyParams.end())
144
0
    return It->second;
145
146
  // Create dummy descriptor.
147
0
  Descriptor *Desc = allocateDescriptor(VD, std::nullopt);
148
  // Allocate a block for storage.
149
0
  unsigned I = Globals.size();
150
151
0
  auto *G = new (Allocator, Desc->getAllocSize())
152
0
      Global(getCurrentDecl(), Desc, /*IsStatic=*/true, /*IsExtern=*/false);
153
0
  G->block()->invokeCtor();
154
155
0
  Globals.push_back(G);
156
0
  DummyParams[VD] = I;
157
0
  return I;
158
0
}
159
160
std::optional<unsigned> Program::createGlobal(const ValueDecl *VD,
161
0
                                              const Expr *Init) {
162
0
  assert(!getGlobal(VD));
163
0
  bool IsStatic, IsExtern;
164
0
  if (const auto *Var = dyn_cast<VarDecl>(VD)) {
165
0
    IsStatic = Context::shouldBeGloballyIndexed(VD);
166
0
    IsExtern = !Var->getAnyInitializer();
167
0
  } else if (isa<UnnamedGlobalConstantDecl>(VD)) {
168
0
    IsStatic = true;
169
0
    IsExtern = false;
170
0
  } else {
171
0
    IsStatic = false;
172
0
    IsExtern = true;
173
0
  }
174
0
  if (auto Idx = createGlobal(VD, VD->getType(), IsStatic, IsExtern, Init)) {
175
0
    for (const Decl *P = VD; P; P = P->getPreviousDecl())
176
0
      GlobalIndices[P] = *Idx;
177
0
    return *Idx;
178
0
  }
179
0
  return std::nullopt;
180
0
}
181
182
0
std::optional<unsigned> Program::createGlobal(const Expr *E) {
183
0
  return createGlobal(E, E->getType(), /*isStatic=*/true, /*isExtern=*/false);
184
0
}
185
186
std::optional<unsigned> Program::createGlobal(const DeclTy &D, QualType Ty,
187
                                              bool IsStatic, bool IsExtern,
188
0
                                              const Expr *Init) {
189
  // Create a descriptor for the global.
190
0
  Descriptor *Desc;
191
0
  const bool IsConst = Ty.isConstQualified();
192
0
  const bool IsTemporary = D.dyn_cast<const Expr *>();
193
0
  if (auto T = Ctx.classify(Ty)) {
194
0
    Desc = createDescriptor(D, *T, std::nullopt, IsConst, IsTemporary);
195
0
  } else {
196
0
    Desc = createDescriptor(D, Ty.getTypePtr(), std::nullopt, IsConst,
197
0
                            IsTemporary);
198
0
  }
199
0
  if (!Desc)
200
0
    return std::nullopt;
201
202
  // Allocate a block for storage.
203
0
  unsigned I = Globals.size();
204
205
0
  auto *G = new (Allocator, Desc->getAllocSize())
206
0
      Global(getCurrentDecl(), Desc, IsStatic, IsExtern);
207
0
  G->block()->invokeCtor();
208
209
0
  Globals.push_back(G);
210
211
0
  return I;
212
0
}
213
214
0
Function *Program::getFunction(const FunctionDecl *F) {
215
0
  F = F->getCanonicalDecl();
216
0
  assert(F);
217
0
  auto It = Funcs.find(F);
218
0
  return It == Funcs.end() ? nullptr : It->second.get();
219
0
}
220
221
0
Record *Program::getOrCreateRecord(const RecordDecl *RD) {
222
  // Use the actual definition as a key.
223
0
  RD = RD->getDefinition();
224
0
  if (!RD)
225
0
    return nullptr;
226
227
  // Deduplicate records.
228
0
  if (auto It = Records.find(RD); It != Records.end())
229
0
    return It->second;
230
231
  // We insert nullptr now and replace that later, so recursive calls
232
  // to this function with the same RecordDecl don't run into
233
  // infinite recursion.
234
0
  Records.insert({RD, nullptr});
235
236
  // Number of bytes required by fields and base classes.
237
0
  unsigned BaseSize = 0;
238
  // Number of bytes required by virtual base.
239
0
  unsigned VirtSize = 0;
240
241
  // Helper to get a base descriptor.
242
0
  auto GetBaseDesc = [this](const RecordDecl *BD, Record *BR) -> Descriptor * {
243
0
    if (!BR)
244
0
      return nullptr;
245
0
    return allocateDescriptor(BD, BR, std::nullopt, /*isConst=*/false,
246
0
                              /*isTemporary=*/false,
247
0
                              /*isMutable=*/false);
248
0
  };
249
250
  // Reserve space for base classes.
251
0
  Record::BaseList Bases;
252
0
  Record::VirtualBaseList VirtBases;
253
0
  if (auto *CD = dyn_cast<CXXRecordDecl>(RD)) {
254
0
    for (const CXXBaseSpecifier &Spec : CD->bases()) {
255
0
      if (Spec.isVirtual())
256
0
        continue;
257
258
0
      const RecordDecl *BD = Spec.getType()->castAs<RecordType>()->getDecl();
259
0
      Record *BR = getOrCreateRecord(BD);
260
0
      if (Descriptor *Desc = GetBaseDesc(BD, BR)) {
261
0
        BaseSize += align(sizeof(InlineDescriptor));
262
0
        Bases.push_back({BD, BaseSize, Desc, BR});
263
0
        BaseSize += align(BR->getSize());
264
0
        continue;
265
0
      }
266
0
      return nullptr;
267
0
    }
268
269
0
    for (const CXXBaseSpecifier &Spec : CD->vbases()) {
270
0
      const RecordDecl *BD = Spec.getType()->castAs<RecordType>()->getDecl();
271
0
      Record *BR = getOrCreateRecord(BD);
272
273
0
      if (Descriptor *Desc = GetBaseDesc(BD, BR)) {
274
0
        VirtSize += align(sizeof(InlineDescriptor));
275
0
        VirtBases.push_back({BD, VirtSize, Desc, BR});
276
0
        VirtSize += align(BR->getSize());
277
0
        continue;
278
0
      }
279
0
      return nullptr;
280
0
    }
281
0
  }
282
283
  // Reserve space for fields.
284
0
  Record::FieldList Fields;
285
0
  for (const FieldDecl *FD : RD->fields()) {
286
    // Reserve space for the field's descriptor and the offset.
287
0
    BaseSize += align(sizeof(InlineDescriptor));
288
289
    // Classify the field and add its metadata.
290
0
    QualType FT = FD->getType();
291
0
    const bool IsConst = FT.isConstQualified();
292
0
    const bool IsMutable = FD->isMutable();
293
0
    Descriptor *Desc;
294
0
    if (std::optional<PrimType> T = Ctx.classify(FT)) {
295
0
      Desc = createDescriptor(FD, *T, std::nullopt, IsConst,
296
0
                              /*isTemporary=*/false, IsMutable);
297
0
    } else {
298
0
      Desc = createDescriptor(FD, FT.getTypePtr(), std::nullopt, IsConst,
299
0
                              /*isTemporary=*/false, IsMutable);
300
0
    }
301
0
    if (!Desc)
302
0
      return nullptr;
303
0
    Fields.push_back({FD, BaseSize, Desc});
304
0
    BaseSize += align(Desc->getAllocSize());
305
0
  }
306
307
0
  Record *R = new (Allocator) Record(RD, std::move(Bases), std::move(Fields),
308
0
                                     std::move(VirtBases), VirtSize, BaseSize);
309
0
  Records[RD] = R;
310
0
  return R;
311
0
}
312
313
Descriptor *Program::createDescriptor(const DeclTy &D, const Type *Ty,
314
                                      Descriptor::MetadataSize MDSize,
315
                                      bool IsConst, bool IsTemporary,
316
0
                                      bool IsMutable, const Expr *Init) {
317
  // Classes and structures.
318
0
  if (const auto *RT = Ty->getAs<RecordType>()) {
319
0
    if (const auto *Record = getOrCreateRecord(RT->getDecl()))
320
0
      return allocateDescriptor(D, Record, MDSize, IsConst, IsTemporary,
321
0
                                IsMutable);
322
0
  }
323
324
  // Arrays.
325
0
  if (const auto ArrayType = Ty->getAsArrayTypeUnsafe()) {
326
0
    QualType ElemTy = ArrayType->getElementType();
327
    // Array of well-known bounds.
328
0
    if (auto CAT = dyn_cast<ConstantArrayType>(ArrayType)) {
329
0
      size_t NumElems = CAT->getSize().getZExtValue();
330
0
      if (std::optional<PrimType> T = Ctx.classify(ElemTy)) {
331
        // Arrays of primitives.
332
0
        unsigned ElemSize = primSize(*T);
333
0
        if (std::numeric_limits<unsigned>::max() / ElemSize <= NumElems) {
334
0
          return {};
335
0
        }
336
0
        return allocateDescriptor(D, *T, MDSize, NumElems, IsConst, IsTemporary,
337
0
                                  IsMutable);
338
0
      } else {
339
        // Arrays of composites. In this case, the array is a list of pointers,
340
        // followed by the actual elements.
341
0
        const Descriptor *ElemDesc = createDescriptor(
342
0
            D, ElemTy.getTypePtr(), std::nullopt, IsConst, IsTemporary);
343
0
        if (!ElemDesc)
344
0
          return nullptr;
345
0
        unsigned ElemSize =
346
0
            ElemDesc->getAllocSize() + sizeof(InlineDescriptor);
347
0
        if (std::numeric_limits<unsigned>::max() / ElemSize <= NumElems)
348
0
          return {};
349
0
        return allocateDescriptor(D, ElemDesc, MDSize, NumElems, IsConst,
350
0
                                  IsTemporary, IsMutable);
351
0
      }
352
0
    }
353
354
    // Array of unknown bounds - cannot be accessed and pointer arithmetic
355
    // is forbidden on pointers to such objects.
356
0
    if (isa<IncompleteArrayType>(ArrayType)) {
357
0
      if (std::optional<PrimType> T = Ctx.classify(ElemTy)) {
358
0
        return allocateDescriptor(D, *T, IsTemporary,
359
0
                                  Descriptor::UnknownSize{});
360
0
      } else {
361
0
        const Descriptor *Desc = createDescriptor(D, ElemTy.getTypePtr(),
362
0
                                                  MDSize, IsConst, IsTemporary);
363
0
        if (!Desc)
364
0
          return nullptr;
365
0
        return allocateDescriptor(D, Desc, IsTemporary,
366
0
                                  Descriptor::UnknownSize{});
367
0
      }
368
0
    }
369
0
  }
370
371
  // Atomic types.
372
0
  if (const auto *AT = Ty->getAs<AtomicType>()) {
373
0
    const Type *InnerTy = AT->getValueType().getTypePtr();
374
0
    return createDescriptor(D, InnerTy, MDSize, IsConst, IsTemporary,
375
0
                            IsMutable);
376
0
  }
377
378
  // Complex types - represented as arrays of elements.
379
0
  if (const auto *CT = Ty->getAs<ComplexType>()) {
380
0
    PrimType ElemTy = *Ctx.classify(CT->getElementType());
381
0
    return allocateDescriptor(D, ElemTy, MDSize, 2, IsConst, IsTemporary,
382
0
                              IsMutable);
383
0
  }
384
385
0
  return nullptr;
386
0
}