Coverage Report

Created: 2023-09-30 09:22

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