Coverage Report

Created: 2024-01-17 10:31

/src/llvm-project/clang/lib/AST/Interp/EvalEmitter.cpp
Line
Count
Source (jump to first uncovered line)
1
//===--- EvalEmitter.cpp - Instruction emitter for the 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 "EvalEmitter.h"
10
#include "ByteCodeGenError.h"
11
#include "Context.h"
12
#include "IntegralAP.h"
13
#include "Interp.h"
14
#include "Opcode.h"
15
#include "clang/AST/DeclCXX.h"
16
17
using namespace clang;
18
using namespace clang::interp;
19
20
EvalEmitter::EvalEmitter(Context &Ctx, Program &P, State &Parent,
21
                         InterpStack &Stk, APValue &Result)
22
0
    : Ctx(Ctx), P(P), S(Parent, P, Stk, Ctx, this), Result(Result) {
23
  // Create a dummy frame for the interpreter which does not have locals.
24
0
  S.Current =
25
0
      new InterpFrame(S, /*Func=*/nullptr, /*Caller=*/nullptr, CodePtr());
26
0
}
27
28
0
EvalEmitter::~EvalEmitter() {
29
0
  for (auto &[K, V] : Locals) {
30
0
    Block *B = reinterpret_cast<Block *>(V.get());
31
0
    if (B->isInitialized())
32
0
      B->invokeDtor();
33
0
  }
34
0
}
35
36
0
llvm::Expected<bool> EvalEmitter::interpretExpr(const Expr *E) {
37
0
  if (this->visitExpr(E))
38
0
    return true;
39
0
  if (BailLocation)
40
0
    return llvm::make_error<ByteCodeGenError>(*BailLocation);
41
0
  return false;
42
0
}
43
44
0
llvm::Expected<bool> EvalEmitter::interpretDecl(const VarDecl *VD) {
45
0
  if (this->visitDecl(VD))
46
0
    return true;
47
0
  if (BailLocation)
48
0
    return llvm::make_error<ByteCodeGenError>(*BailLocation);
49
0
  return false;
50
0
}
51
52
0
void EvalEmitter::emitLabel(LabelTy Label) {
53
0
  CurrentLabel = Label;
54
0
}
55
56
0
EvalEmitter::LabelTy EvalEmitter::getLabel() { return NextLabel++; }
57
58
0
Scope::Local EvalEmitter::createLocal(Descriptor *D) {
59
  // Allocate memory for a local.
60
0
  auto Memory = std::make_unique<char[]>(sizeof(Block) + D->getAllocSize());
61
0
  auto *B = new (Memory.get()) Block(D, /*isStatic=*/false);
62
0
  B->invokeCtor();
63
64
  // Initialize local variable inline descriptor.
65
0
  InlineDescriptor &Desc = *reinterpret_cast<InlineDescriptor *>(B->rawData());
66
0
  Desc.Desc = D;
67
0
  Desc.Offset = sizeof(InlineDescriptor);
68
0
  Desc.IsActive = true;
69
0
  Desc.IsBase = false;
70
0
  Desc.IsFieldMutable = false;
71
0
  Desc.IsConst = false;
72
0
  Desc.IsInitialized = false;
73
74
  // Register the local.
75
0
  unsigned Off = Locals.size();
76
0
  Locals.insert({Off, std::move(Memory)});
77
0
  return {Off, D};
78
0
}
79
80
0
bool EvalEmitter::bail(const SourceLocation &Loc) {
81
0
  if (!BailLocation)
82
0
    BailLocation = Loc;
83
0
  return false;
84
0
}
85
86
0
bool EvalEmitter::jumpTrue(const LabelTy &Label) {
87
0
  if (isActive()) {
88
0
    if (S.Stk.pop<bool>())
89
0
      ActiveLabel = Label;
90
0
  }
91
0
  return true;
92
0
}
93
94
0
bool EvalEmitter::jumpFalse(const LabelTy &Label) {
95
0
  if (isActive()) {
96
0
    if (!S.Stk.pop<bool>())
97
0
      ActiveLabel = Label;
98
0
  }
99
0
  return true;
100
0
}
101
102
0
bool EvalEmitter::jump(const LabelTy &Label) {
103
0
  if (isActive())
104
0
    CurrentLabel = ActiveLabel = Label;
105
0
  return true;
106
0
}
107
108
0
bool EvalEmitter::fallthrough(const LabelTy &Label) {
109
0
  if (isActive())
110
0
    ActiveLabel = Label;
111
0
  CurrentLabel = Label;
112
0
  return true;
113
0
}
114
115
0
template <PrimType OpType> bool EvalEmitter::emitRet(const SourceInfo &Info) {
116
0
  if (!isActive())
117
0
    return true;
118
0
  using T = typename PrimConv<OpType>::T;
119
0
  return ReturnValue<T>(S.Stk.pop<T>(), Result);
120
0
}
Unexecuted instantiation: bool clang::interp::EvalEmitter::emitRet<(clang::interp::PrimType)0>(clang::interp::SourceInfo const&)
Unexecuted instantiation: bool clang::interp::EvalEmitter::emitRet<(clang::interp::PrimType)1>(clang::interp::SourceInfo const&)
Unexecuted instantiation: bool clang::interp::EvalEmitter::emitRet<(clang::interp::PrimType)2>(clang::interp::SourceInfo const&)
Unexecuted instantiation: bool clang::interp::EvalEmitter::emitRet<(clang::interp::PrimType)3>(clang::interp::SourceInfo const&)
Unexecuted instantiation: bool clang::interp::EvalEmitter::emitRet<(clang::interp::PrimType)4>(clang::interp::SourceInfo const&)
Unexecuted instantiation: bool clang::interp::EvalEmitter::emitRet<(clang::interp::PrimType)5>(clang::interp::SourceInfo const&)
Unexecuted instantiation: bool clang::interp::EvalEmitter::emitRet<(clang::interp::PrimType)6>(clang::interp::SourceInfo const&)
Unexecuted instantiation: bool clang::interp::EvalEmitter::emitRet<(clang::interp::PrimType)7>(clang::interp::SourceInfo const&)
Unexecuted instantiation: bool clang::interp::EvalEmitter::emitRet<(clang::interp::PrimType)8>(clang::interp::SourceInfo const&)
Unexecuted instantiation: bool clang::interp::EvalEmitter::emitRet<(clang::interp::PrimType)9>(clang::interp::SourceInfo const&)
Unexecuted instantiation: bool clang::interp::EvalEmitter::emitRet<(clang::interp::PrimType)10>(clang::interp::SourceInfo const&)
Unexecuted instantiation: bool clang::interp::EvalEmitter::emitRet<(clang::interp::PrimType)12>(clang::interp::SourceInfo const&)
Unexecuted instantiation: bool clang::interp::EvalEmitter::emitRet<(clang::interp::PrimType)13>(clang::interp::SourceInfo const&)
Unexecuted instantiation: bool clang::interp::EvalEmitter::emitRet<(clang::interp::PrimType)11>(clang::interp::SourceInfo const&)
121
122
0
bool EvalEmitter::emitRetVoid(const SourceInfo &Info) { return true; }
123
124
0
bool EvalEmitter::emitRetValue(const SourceInfo &Info) {
125
  // Method to recursively traverse composites.
126
0
  std::function<bool(QualType, const Pointer &, APValue &)> Composite;
127
0
  Composite = [this, &Composite](QualType Ty, const Pointer &Ptr, APValue &R) {
128
0
    if (const auto *AT = Ty->getAs<AtomicType>())
129
0
      Ty = AT->getValueType();
130
131
0
    if (const auto *RT = Ty->getAs<RecordType>()) {
132
0
      const auto *Record = Ptr.getRecord();
133
0
      assert(Record && "Missing record descriptor");
134
135
0
      bool Ok = true;
136
0
      if (RT->getDecl()->isUnion()) {
137
0
        const FieldDecl *ActiveField = nullptr;
138
0
        APValue Value;
139
0
        for (const auto &F : Record->fields()) {
140
0
          const Pointer &FP = Ptr.atField(F.Offset);
141
0
          QualType FieldTy = F.Decl->getType();
142
0
          if (FP.isActive()) {
143
0
            if (std::optional<PrimType> T = Ctx.classify(FieldTy)) {
144
0
              TYPE_SWITCH(*T, Ok &= ReturnValue<T>(FP.deref<T>(), Value));
145
0
            } else {
146
0
              Ok &= Composite(FieldTy, FP, Value);
147
0
            }
148
0
            break;
149
0
          }
150
0
        }
151
0
        R = APValue(ActiveField, Value);
152
0
      } else {
153
0
        unsigned NF = Record->getNumFields();
154
0
        unsigned NB = Record->getNumBases();
155
0
        unsigned NV = Ptr.isBaseClass() ? 0 : Record->getNumVirtualBases();
156
157
0
        R = APValue(APValue::UninitStruct(), NB, NF);
158
159
0
        for (unsigned I = 0; I < NF; ++I) {
160
0
          const Record::Field *FD = Record->getField(I);
161
0
          QualType FieldTy = FD->Decl->getType();
162
0
          const Pointer &FP = Ptr.atField(FD->Offset);
163
0
          APValue &Value = R.getStructField(I);
164
165
0
          if (std::optional<PrimType> T = Ctx.classify(FieldTy)) {
166
0
            TYPE_SWITCH(*T, Ok &= ReturnValue<T>(FP.deref<T>(), Value));
167
0
          } else {
168
0
            Ok &= Composite(FieldTy, FP, Value);
169
0
          }
170
0
        }
171
172
0
        for (unsigned I = 0; I < NB; ++I) {
173
0
          const Record::Base *BD = Record->getBase(I);
174
0
          QualType BaseTy = Ctx.getASTContext().getRecordType(BD->Decl);
175
0
          const Pointer &BP = Ptr.atField(BD->Offset);
176
0
          Ok &= Composite(BaseTy, BP, R.getStructBase(I));
177
0
        }
178
179
0
        for (unsigned I = 0; I < NV; ++I) {
180
0
          const Record::Base *VD = Record->getVirtualBase(I);
181
0
          QualType VirtBaseTy = Ctx.getASTContext().getRecordType(VD->Decl);
182
0
          const Pointer &VP = Ptr.atField(VD->Offset);
183
0
          Ok &= Composite(VirtBaseTy, VP, R.getStructBase(NB + I));
184
0
        }
185
0
      }
186
0
      return Ok;
187
0
    }
188
189
0
    if (Ty->isIncompleteArrayType()) {
190
0
      R = APValue(APValue::UninitArray(), 0, 0);
191
0
      return true;
192
0
    }
193
194
0
    if (const auto *AT = Ty->getAsArrayTypeUnsafe()) {
195
0
      const size_t NumElems = Ptr.getNumElems();
196
0
      QualType ElemTy = AT->getElementType();
197
0
      R = APValue(APValue::UninitArray{}, NumElems, NumElems);
198
199
0
      bool Ok = true;
200
0
      for (unsigned I = 0; I < NumElems; ++I) {
201
0
        APValue &Slot = R.getArrayInitializedElt(I);
202
0
        const Pointer &EP = Ptr.atIndex(I);
203
0
        if (std::optional<PrimType> T = Ctx.classify(ElemTy)) {
204
0
          TYPE_SWITCH(*T, Ok &= ReturnValue<T>(EP.deref<T>(), Slot));
205
0
        } else {
206
0
          Ok &= Composite(ElemTy, EP.narrow(), Slot);
207
0
        }
208
0
      }
209
0
      return Ok;
210
0
    }
211
212
    // Complex types.
213
0
    if (const auto *CT = Ty->getAs<ComplexType>()) {
214
0
      QualType ElemTy = CT->getElementType();
215
0
      std::optional<PrimType> ElemT = Ctx.classify(ElemTy);
216
0
      assert(ElemT);
217
218
0
      if (ElemTy->isIntegerType()) {
219
0
        INT_TYPE_SWITCH(*ElemT, {
220
0
          auto V1 = Ptr.atIndex(0).deref<T>();
221
0
          auto V2 = Ptr.atIndex(1).deref<T>();
222
0
          Result = APValue(V1.toAPSInt(), V2.toAPSInt());
223
0
          return true;
224
0
        });
225
0
      } else if (ElemTy->isFloatingType()) {
226
0
        Result = APValue(Ptr.atIndex(0).deref<Floating>().getAPFloat(),
227
0
                         Ptr.atIndex(1).deref<Floating>().getAPFloat());
228
0
        return true;
229
0
      }
230
0
      return false;
231
0
    }
232
0
    llvm_unreachable("invalid value to return");
233
0
  };
234
235
  // Return the composite type.
236
0
  const auto &Ptr = S.Stk.pop<Pointer>();
237
0
  return Composite(Ptr.getType(), Ptr, Result);
238
0
}
239
240
0
bool EvalEmitter::emitGetPtrLocal(uint32_t I, const SourceInfo &Info) {
241
0
  if (!isActive())
242
0
    return true;
243
244
0
  Block *B = getLocal(I);
245
0
  S.Stk.push<Pointer>(B, sizeof(InlineDescriptor));
246
0
  return true;
247
0
}
248
249
template <PrimType OpType>
250
0
bool EvalEmitter::emitGetLocal(uint32_t I, const SourceInfo &Info) {
251
0
  if (!isActive())
252
0
    return true;
253
254
0
  using T = typename PrimConv<OpType>::T;
255
256
0
  Block *B = getLocal(I);
257
0
  S.Stk.push<T>(*reinterpret_cast<T *>(B->data()));
258
0
  return true;
259
0
}
Unexecuted instantiation: bool clang::interp::EvalEmitter::emitGetLocal<(clang::interp::PrimType)0>(unsigned int, clang::interp::SourceInfo const&)
Unexecuted instantiation: bool clang::interp::EvalEmitter::emitGetLocal<(clang::interp::PrimType)1>(unsigned int, clang::interp::SourceInfo const&)
Unexecuted instantiation: bool clang::interp::EvalEmitter::emitGetLocal<(clang::interp::PrimType)2>(unsigned int, clang::interp::SourceInfo const&)
Unexecuted instantiation: bool clang::interp::EvalEmitter::emitGetLocal<(clang::interp::PrimType)3>(unsigned int, clang::interp::SourceInfo const&)
Unexecuted instantiation: bool clang::interp::EvalEmitter::emitGetLocal<(clang::interp::PrimType)4>(unsigned int, clang::interp::SourceInfo const&)
Unexecuted instantiation: bool clang::interp::EvalEmitter::emitGetLocal<(clang::interp::PrimType)5>(unsigned int, clang::interp::SourceInfo const&)
Unexecuted instantiation: bool clang::interp::EvalEmitter::emitGetLocal<(clang::interp::PrimType)6>(unsigned int, clang::interp::SourceInfo const&)
Unexecuted instantiation: bool clang::interp::EvalEmitter::emitGetLocal<(clang::interp::PrimType)7>(unsigned int, clang::interp::SourceInfo const&)
Unexecuted instantiation: bool clang::interp::EvalEmitter::emitGetLocal<(clang::interp::PrimType)8>(unsigned int, clang::interp::SourceInfo const&)
Unexecuted instantiation: bool clang::interp::EvalEmitter::emitGetLocal<(clang::interp::PrimType)9>(unsigned int, clang::interp::SourceInfo const&)
Unexecuted instantiation: bool clang::interp::EvalEmitter::emitGetLocal<(clang::interp::PrimType)10>(unsigned int, clang::interp::SourceInfo const&)
Unexecuted instantiation: bool clang::interp::EvalEmitter::emitGetLocal<(clang::interp::PrimType)12>(unsigned int, clang::interp::SourceInfo const&)
Unexecuted instantiation: bool clang::interp::EvalEmitter::emitGetLocal<(clang::interp::PrimType)13>(unsigned int, clang::interp::SourceInfo const&)
Unexecuted instantiation: bool clang::interp::EvalEmitter::emitGetLocal<(clang::interp::PrimType)11>(unsigned int, clang::interp::SourceInfo const&)
260
261
template <PrimType OpType>
262
0
bool EvalEmitter::emitSetLocal(uint32_t I, const SourceInfo &Info) {
263
0
  if (!isActive())
264
0
    return true;
265
266
0
  using T = typename PrimConv<OpType>::T;
267
268
0
  Block *B = getLocal(I);
269
0
  *reinterpret_cast<T *>(B->data()) = S.Stk.pop<T>();
270
0
  InlineDescriptor &Desc = *reinterpret_cast<InlineDescriptor *>(B->rawData());
271
0
  Desc.IsInitialized = true;
272
273
0
  return true;
274
0
}
Unexecuted instantiation: bool clang::interp::EvalEmitter::emitSetLocal<(clang::interp::PrimType)0>(unsigned int, clang::interp::SourceInfo const&)
Unexecuted instantiation: bool clang::interp::EvalEmitter::emitSetLocal<(clang::interp::PrimType)1>(unsigned int, clang::interp::SourceInfo const&)
Unexecuted instantiation: bool clang::interp::EvalEmitter::emitSetLocal<(clang::interp::PrimType)2>(unsigned int, clang::interp::SourceInfo const&)
Unexecuted instantiation: bool clang::interp::EvalEmitter::emitSetLocal<(clang::interp::PrimType)3>(unsigned int, clang::interp::SourceInfo const&)
Unexecuted instantiation: bool clang::interp::EvalEmitter::emitSetLocal<(clang::interp::PrimType)4>(unsigned int, clang::interp::SourceInfo const&)
Unexecuted instantiation: bool clang::interp::EvalEmitter::emitSetLocal<(clang::interp::PrimType)5>(unsigned int, clang::interp::SourceInfo const&)
Unexecuted instantiation: bool clang::interp::EvalEmitter::emitSetLocal<(clang::interp::PrimType)6>(unsigned int, clang::interp::SourceInfo const&)
Unexecuted instantiation: bool clang::interp::EvalEmitter::emitSetLocal<(clang::interp::PrimType)7>(unsigned int, clang::interp::SourceInfo const&)
Unexecuted instantiation: bool clang::interp::EvalEmitter::emitSetLocal<(clang::interp::PrimType)8>(unsigned int, clang::interp::SourceInfo const&)
Unexecuted instantiation: bool clang::interp::EvalEmitter::emitSetLocal<(clang::interp::PrimType)9>(unsigned int, clang::interp::SourceInfo const&)
Unexecuted instantiation: bool clang::interp::EvalEmitter::emitSetLocal<(clang::interp::PrimType)10>(unsigned int, clang::interp::SourceInfo const&)
Unexecuted instantiation: bool clang::interp::EvalEmitter::emitSetLocal<(clang::interp::PrimType)12>(unsigned int, clang::interp::SourceInfo const&)
Unexecuted instantiation: bool clang::interp::EvalEmitter::emitSetLocal<(clang::interp::PrimType)13>(unsigned int, clang::interp::SourceInfo const&)
Unexecuted instantiation: bool clang::interp::EvalEmitter::emitSetLocal<(clang::interp::PrimType)11>(unsigned int, clang::interp::SourceInfo const&)
275
276
0
bool EvalEmitter::emitDestroy(uint32_t I, const SourceInfo &Info) {
277
0
  if (!isActive())
278
0
    return true;
279
280
0
  for (auto &Local : Descriptors[I]) {
281
0
    Block *B = getLocal(Local.Offset);
282
0
    S.deallocate(B);
283
0
  }
284
285
0
  return true;
286
0
}
287
288
//===----------------------------------------------------------------------===//
289
// Opcode evaluators
290
//===----------------------------------------------------------------------===//
291
292
#define GET_EVAL_IMPL
293
#include "Opcodes.inc"
294
#undef GET_EVAL_IMPL