Coverage Report

Created: 2020-09-22 08:39

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