Coverage Report

Created: 2022-01-18 06:27

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/AST/Interp/ByteCodeExprGen.h
Line
Count
Source (jump to first uncovered line)
1
//===--- ByteCodeExprGen.h - Code generator for expressions -----*- 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
// Defines the constexpr bytecode compiler.
10
//
11
//===----------------------------------------------------------------------===//
12
13
#ifndef LLVM_CLANG_AST_INTERP_BYTECODEEXPRGEN_H
14
#define LLVM_CLANG_AST_INTERP_BYTECODEEXPRGEN_H
15
16
#include "ByteCodeEmitter.h"
17
#include "EvalEmitter.h"
18
#include "Pointer.h"
19
#include "PrimType.h"
20
#include "Record.h"
21
#include "clang/AST/Decl.h"
22
#include "clang/AST/Expr.h"
23
#include "clang/AST/StmtVisitor.h"
24
#include "clang/Basic/TargetInfo.h"
25
#include "llvm/ADT/Optional.h"
26
27
namespace clang {
28
class QualType;
29
30
namespace interp {
31
32
template <class Emitter> class LocalScope;
33
template <class Emitter> class RecordScope;
34
template <class Emitter> class VariableScope;
35
template <class Emitter> class DeclScope;
36
template <class Emitter> class OptionScope;
37
38
/// Compilation context for expressions.
39
template <class Emitter>
40
class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
41
                        public Emitter {
42
protected:
43
  // Emitters for opcodes of various arities.
44
  using NullaryFn = bool (ByteCodeExprGen::*)(const SourceInfo &);
45
  using UnaryFn = bool (ByteCodeExprGen::*)(PrimType, const SourceInfo &);
46
  using BinaryFn = bool (ByteCodeExprGen::*)(PrimType, PrimType,
47
                                             const SourceInfo &);
48
49
  // Aliases for types defined in the emitter.
50
  using LabelTy = typename Emitter::LabelTy;
51
  using AddrTy = typename Emitter::AddrTy;
52
53
  // Reference to a function generating the pointer of an initialized object.s
54
  using InitFnRef = std::function<bool()>;
55
56
  /// Current compilation context.
57
  Context &Ctx;
58
  /// Program to link to.
59
  Program &P;
60
61
public:
62
  /// Initializes the compiler and the backend emitter.
63
  template <typename... Tys>
64
  ByteCodeExprGen(Context &Ctx, Program &P, Tys &&... Args)
65
15
      : Emitter(Ctx, P, Args...), Ctx(Ctx), P(P) {}
clang::interp::ByteCodeExprGen<clang::interp::ByteCodeEmitter>::ByteCodeExprGen<>(clang::interp::Context&, clang::interp::Program&)
Line
Count
Source
65
2
      : Emitter(Ctx, P, Args...), Ctx(Ctx), P(P) {}
clang::interp::ByteCodeExprGen<clang::interp::EvalEmitter>::ByteCodeExprGen<clang::interp::State&, clang::interp::InterpStack&, clang::APValue&>(clang::interp::Context&, clang::interp::Program&, clang::interp::State&, clang::interp::InterpStack&, clang::APValue&)
Line
Count
Source
65
13
      : Emitter(Ctx, P, Args...), Ctx(Ctx), P(P) {}
66
67
  // Expression visitors - result returned on stack.
68
  bool VisitCastExpr(const CastExpr *E);
69
  bool VisitIntegerLiteral(const IntegerLiteral *E);
70
  bool VisitParenExpr(const ParenExpr *E);
71
  bool VisitBinaryOperator(const BinaryOperator *E);
72
73
protected:
74
  bool visitExpr(const Expr *E) override;
75
  bool visitDecl(const VarDecl *VD) override;
76
77
protected:
78
  /// Emits scope cleanup instructions.
79
  void emitCleanup();
80
81
  /// Returns a record type from a record or pointer type.
82
  const RecordType *getRecordTy(QualType Ty);
83
84
  /// Returns a record from a record or pointer type.
85
  Record *getRecord(QualType Ty);
86
  Record *getRecord(const RecordDecl *RD);
87
88
  /// Returns the size int bits of an integer.
89
1
  unsigned getIntWidth(QualType Ty) {
90
1
    auto &ASTContext = Ctx.getASTContext();
91
1
    return ASTContext.getIntWidth(Ty);
92
1
  }
clang::interp::ByteCodeExprGen<clang::interp::ByteCodeEmitter>::getIntWidth(clang::QualType)
Line
Count
Source
89
1
  unsigned getIntWidth(QualType Ty) {
90
1
    auto &ASTContext = Ctx.getASTContext();
91
1
    return ASTContext.getIntWidth(Ty);
92
1
  }
Unexecuted instantiation: clang::interp::ByteCodeExprGen<clang::interp::EvalEmitter>::getIntWidth(clang::QualType)
93
94
  /// Returns the value of CHAR_BIT.
95
0
  unsigned getCharBit() const {
96
0
    auto &ASTContext = Ctx.getASTContext();
97
0
    return ASTContext.getTargetInfo().getCharWidth();
98
0
  }
Unexecuted instantiation: clang::interp::ByteCodeExprGen<clang::interp::ByteCodeEmitter>::getCharBit() const
Unexecuted instantiation: clang::interp::ByteCodeExprGen<clang::interp::EvalEmitter>::getCharBit() const
99
100
  /// Classifies a type.
101
0
  llvm::Optional<PrimType> classify(const Expr *E) const {
102
0
    return E->isGLValue() ? PT_Ptr : classify(E->getType());
103
0
  }
Unexecuted instantiation: clang::interp::ByteCodeExprGen<clang::interp::ByteCodeEmitter>::classify(clang::Expr const*) const
Unexecuted instantiation: clang::interp::ByteCodeExprGen<clang::interp::EvalEmitter>::classify(clang::Expr const*) const
104
63
  llvm::Optional<PrimType> classify(QualType Ty) const {
105
63
    return Ctx.classify(Ty);
106
63
  }
clang::interp::ByteCodeExprGen<clang::interp::ByteCodeEmitter>::classify(clang::QualType) const
Line
Count
Source
104
23
  llvm::Optional<PrimType> classify(QualType Ty) const {
105
23
    return Ctx.classify(Ty);
106
23
  }
clang::interp::ByteCodeExprGen<clang::interp::EvalEmitter>::classify(clang::QualType) const
Line
Count
Source
104
40
  llvm::Optional<PrimType> classify(QualType Ty) const {
105
40
    return Ctx.classify(Ty);
106
40
  }
107
108
  /// Checks if a pointer needs adjustment.
109
0
  bool needsAdjust(QualType Ty) const {
110
0
    return true;
111
0
  }
Unexecuted instantiation: clang::interp::ByteCodeExprGen<clang::interp::ByteCodeEmitter>::needsAdjust(clang::QualType) const
Unexecuted instantiation: clang::interp::ByteCodeExprGen<clang::interp::EvalEmitter>::needsAdjust(clang::QualType) const
112
113
  /// Classifies a known primitive type
114
0
  PrimType classifyPrim(QualType Ty) const {
115
0
    if (auto T = classify(Ty)) {
116
0
      return *T;
117
0
    }
118
0
    llvm_unreachable("not a primitive type");
119
0
  }
Unexecuted instantiation: clang::interp::ByteCodeExprGen<clang::interp::ByteCodeEmitter>::classifyPrim(clang::QualType) const
Unexecuted instantiation: clang::interp::ByteCodeExprGen<clang::interp::EvalEmitter>::classifyPrim(clang::QualType) const
120
121
  /// Evaluates an expression for side effects and discards the result.
122
  bool discard(const Expr *E);
123
  /// Evaluates an expression and places result on stack.
124
  bool visit(const Expr *E);
125
  /// Compiles an initializer for a local.
126
  bool visitInitializer(const Expr *E, InitFnRef GenPtr);
127
128
  /// Visits an expression and converts it to a boolean.
129
  bool visitBool(const Expr *E);
130
131
  /// Visits an initializer for a local.
132
0
  bool visitLocalInitializer(const Expr *Init, unsigned I) {
133
0
    return visitInitializer(Init, [this, I, Init] {
134
0
      return this->emitGetPtrLocal(I, Init);
135
0
    });
Unexecuted instantiation: clang::interp::ByteCodeExprGen<clang::interp::ByteCodeEmitter>::visitLocalInitializer(clang::Expr const*, unsigned int)::'lambda'()::operator()() const
Unexecuted instantiation: clang::interp::ByteCodeExprGen<clang::interp::EvalEmitter>::visitLocalInitializer(clang::Expr const*, unsigned int)::'lambda'()::operator()() const
136
0
  }
Unexecuted instantiation: clang::interp::ByteCodeExprGen<clang::interp::ByteCodeEmitter>::visitLocalInitializer(clang::Expr const*, unsigned int)
Unexecuted instantiation: clang::interp::ByteCodeExprGen<clang::interp::EvalEmitter>::visitLocalInitializer(clang::Expr const*, unsigned int)
137
138
  /// Visits an initializer for a global.
139
0
  bool visitGlobalInitializer(const Expr *Init, unsigned I) {
140
0
    return visitInitializer(Init, [this, I, Init] {
141
0
      return this->emitGetPtrGlobal(I, Init);
142
0
    });
Unexecuted instantiation: clang::interp::ByteCodeExprGen<clang::interp::ByteCodeEmitter>::visitGlobalInitializer(clang::Expr const*, unsigned int)::'lambda'()::operator()() const
Unexecuted instantiation: clang::interp::ByteCodeExprGen<clang::interp::EvalEmitter>::visitGlobalInitializer(clang::Expr const*, unsigned int)::'lambda'()::operator()() const
143
0
  }
Unexecuted instantiation: clang::interp::ByteCodeExprGen<clang::interp::ByteCodeEmitter>::visitGlobalInitializer(clang::Expr const*, unsigned int)
Unexecuted instantiation: clang::interp::ByteCodeExprGen<clang::interp::EvalEmitter>::visitGlobalInitializer(clang::Expr const*, unsigned int)
144
145
  /// Visits a delegated initializer.
146
0
  bool visitThisInitializer(const Expr *I) {
147
0
    return visitInitializer(I, [this, I] { return this->emitThis(I); });
Unexecuted instantiation: clang::interp::ByteCodeExprGen<clang::interp::ByteCodeEmitter>::visitThisInitializer(clang::Expr const*)::'lambda'()::operator()() const
Unexecuted instantiation: clang::interp::ByteCodeExprGen<clang::interp::EvalEmitter>::visitThisInitializer(clang::Expr const*)::'lambda'()::operator()() const
148
0
  }
Unexecuted instantiation: clang::interp::ByteCodeExprGen<clang::interp::ByteCodeEmitter>::visitThisInitializer(clang::Expr const*)
Unexecuted instantiation: clang::interp::ByteCodeExprGen<clang::interp::EvalEmitter>::visitThisInitializer(clang::Expr const*)
149
150
  /// Creates a local primitive value.
151
  unsigned allocateLocalPrimitive(DeclTy &&Decl, PrimType Ty, bool IsMutable,
152
                                  bool IsExtended = false);
153
154
  /// Allocates a space storing a local given its type.
155
  llvm::Optional<unsigned> allocateLocal(DeclTy &&Decl,
156
                                         bool IsExtended = false);
157
158
private:
159
  friend class VariableScope<Emitter>;
160
  friend class LocalScope<Emitter>;
161
  friend class RecordScope<Emitter>;
162
  friend class DeclScope<Emitter>;
163
  friend class OptionScope<Emitter>;
164
165
  /// Emits a zero initializer.
166
  bool visitZeroInitializer(PrimType T, const Expr *E);
167
168
  enum class DerefKind {
169
    /// Value is read and pushed to stack.
170
    Read,
171
    /// Direct method generates a value which is written. Returns pointer.
172
    Write,
173
    /// Direct method receives the value, pushes mutated value. Returns pointer.
174
    ReadWrite,
175
  };
176
177
  /// Method to directly load a value. If the value can be fetched directly,
178
  /// the direct handler is called. Otherwise, a pointer is left on the stack
179
  /// and the indirect handler is expected to operate on that.
180
  bool dereference(const Expr *LV, DerefKind AK,
181
                   llvm::function_ref<bool(PrimType)> Direct,
182
                   llvm::function_ref<bool(PrimType)> Indirect);
183
  bool dereferenceParam(const Expr *LV, PrimType T, const ParmVarDecl *PD,
184
                        DerefKind AK,
185
                        llvm::function_ref<bool(PrimType)> Direct,
186
                        llvm::function_ref<bool(PrimType)> Indirect);
187
  bool dereferenceVar(const Expr *LV, PrimType T, const VarDecl *PD,
188
                      DerefKind AK, llvm::function_ref<bool(PrimType)> Direct,
189
                      llvm::function_ref<bool(PrimType)> Indirect);
190
191
  /// Emits an APInt constant.
192
  bool emitConst(PrimType T, unsigned NumBits, const llvm::APInt &Value,
193
                 const Expr *E);
194
195
  /// Emits an integer constant.
196
  template <typename T> bool emitConst(const Expr *E, T Value) {
197
    QualType Ty = E->getType();
198
    unsigned NumBits = getIntWidth(Ty);
199
    APInt WrappedValue(NumBits, Value, std::is_signed<T>::value);
200
    return emitConst(*Ctx.classify(Ty), NumBits, WrappedValue, E);
201
  }
202
203
  /// Returns a pointer to a variable declaration.
204
  bool getPtrVarDecl(const VarDecl *VD, const Expr *E);
205
206
  /// Returns the index of a global.
207
  llvm::Optional<unsigned> getGlobalIdx(const VarDecl *VD);
208
209
  /// Emits the initialized pointer.
210
0
  bool emitInitFn() {
211
0
    assert(InitFn && "missing initializer");
212
0
    return (*InitFn)();
213
0
  }
Unexecuted instantiation: clang::interp::ByteCodeExprGen<clang::interp::ByteCodeEmitter>::emitInitFn()
Unexecuted instantiation: clang::interp::ByteCodeExprGen<clang::interp::EvalEmitter>::emitInitFn()
214
215
protected:
216
  /// Variable to storage mapping.
217
  llvm::DenseMap<const ValueDecl *, Scope::Local> Locals;
218
219
  /// OpaqueValueExpr to location mapping.
220
  llvm::DenseMap<const OpaqueValueExpr *, unsigned> OpaqueExprs;
221
222
  /// Current scope.
223
  VariableScope<Emitter> *VarScope = nullptr;
224
225
  /// Current argument index.
226
  llvm::Optional<uint64_t> ArrayIndex;
227
228
  /// Flag indicating if return value is to be discarded.
229
  bool DiscardResult = false;
230
231
  /// Expression being initialized.
232
  llvm::Optional<InitFnRef> InitFn = {};
233
};
234
235
extern template class ByteCodeExprGen<ByteCodeEmitter>;
236
extern template class ByteCodeExprGen<EvalEmitter>;
237
238
/// Scope chain managing the variable lifetimes.
239
template <class Emitter> class VariableScope {
240
public:
241
23
  virtual ~VariableScope() { Ctx->VarScope = this->Parent; }
clang::interp::VariableScope<clang::interp::ByteCodeEmitter>::~VariableScope()
Line
Count
Source
241
10
  virtual ~VariableScope() { Ctx->VarScope = this->Parent; }
clang::interp::VariableScope<clang::interp::EvalEmitter>::~VariableScope()
Line
Count
Source
241
13
  virtual ~VariableScope() { Ctx->VarScope = this->Parent; }
242
243
1
  void add(const Scope::Local &Local, bool IsExtended) {
244
1
    if (IsExtended)
245
0
      this->addExtended(Local);
246
1
    else
247
1
      this->addLocal(Local);
248
1
  }
clang::interp::VariableScope<clang::interp::ByteCodeEmitter>::add(clang::interp::Scope::Local const&, bool)
Line
Count
Source
243
1
  void add(const Scope::Local &Local, bool IsExtended) {
244
1
    if (IsExtended)
245
0
      this->addExtended(Local);
246
1
    else
247
1
      this->addLocal(Local);
248
1
  }
Unexecuted instantiation: clang::interp::VariableScope<clang::interp::EvalEmitter>::add(clang::interp::Scope::Local const&, bool)
249
250
0
  virtual void addLocal(const Scope::Local &Local) {
251
0
    if (this->Parent)
252
0
      this->Parent->addLocal(Local);
253
0
  }
Unexecuted instantiation: clang::interp::VariableScope<clang::interp::ByteCodeEmitter>::addLocal(clang::interp::Scope::Local const&)
Unexecuted instantiation: clang::interp::VariableScope<clang::interp::EvalEmitter>::addLocal(clang::interp::Scope::Local const&)
254
255
0
  virtual void addExtended(const Scope::Local &Local) {
256
0
    if (this->Parent)
257
0
      this->Parent->addExtended(Local);
258
0
  }
Unexecuted instantiation: clang::interp::VariableScope<clang::interp::ByteCodeEmitter>::addExtended(clang::interp::Scope::Local const&)
Unexecuted instantiation: clang::interp::VariableScope<clang::interp::EvalEmitter>::addExtended(clang::interp::Scope::Local const&)
259
260
0
  virtual void emitDestruction() {}
Unexecuted instantiation: clang::interp::VariableScope<clang::interp::ByteCodeEmitter>::emitDestruction()
Unexecuted instantiation: clang::interp::VariableScope<clang::interp::EvalEmitter>::emitDestruction()
261
262
8
  VariableScope *getParent() { return Parent; }
clang::interp::VariableScope<clang::interp::ByteCodeEmitter>::getParent()
Line
Count
Source
262
8
  VariableScope *getParent() { return Parent; }
Unexecuted instantiation: clang::interp::VariableScope<clang::interp::EvalEmitter>::getParent()
263
264
protected:
265
  VariableScope(ByteCodeExprGen<Emitter> *Ctx)
266
23
      : Ctx(Ctx), Parent(Ctx->VarScope) {
267
23
    Ctx->VarScope = this;
268
23
  }
clang::interp::VariableScope<clang::interp::ByteCodeEmitter>::VariableScope(clang::interp::ByteCodeExprGen<clang::interp::ByteCodeEmitter>*)
Line
Count
Source
266
10
      : Ctx(Ctx), Parent(Ctx->VarScope) {
267
10
    Ctx->VarScope = this;
268
10
  }
clang::interp::VariableScope<clang::interp::EvalEmitter>::VariableScope(clang::interp::ByteCodeExprGen<clang::interp::EvalEmitter>*)
Line
Count
Source
266
13
      : Ctx(Ctx), Parent(Ctx->VarScope) {
267
13
    Ctx->VarScope = this;
268
13
  }
269
270
  /// ByteCodeExprGen instance.
271
  ByteCodeExprGen<Emitter> *Ctx;
272
  /// Link to the parent scope.
273
  VariableScope *Parent;
274
};
275
276
/// Scope for local variables.
277
///
278
/// When the scope is destroyed, instructions are emitted to tear down
279
/// all variables declared in this scope.
280
template <class Emitter> class LocalScope : public VariableScope<Emitter> {
281
public:
282
23
  LocalScope(ByteCodeExprGen<Emitter> *Ctx) : VariableScope<Emitter>(Ctx) {}
clang::interp::LocalScope<clang::interp::ByteCodeEmitter>::LocalScope(clang::interp::ByteCodeExprGen<clang::interp::ByteCodeEmitter>*)
Line
Count
Source
282
10
  LocalScope(ByteCodeExprGen<Emitter> *Ctx) : VariableScope<Emitter>(Ctx) {}
clang::interp::LocalScope<clang::interp::EvalEmitter>::LocalScope(clang::interp::ByteCodeExprGen<clang::interp::EvalEmitter>*)
Line
Count
Source
282
13
  LocalScope(ByteCodeExprGen<Emitter> *Ctx) : VariableScope<Emitter>(Ctx) {}
283
284
23
  ~LocalScope() override { this->emitDestruction(); }
clang::interp::LocalScope<clang::interp::ByteCodeEmitter>::~LocalScope()
Line
Count
Source
284
10
  ~LocalScope() override { this->emitDestruction(); }
clang::interp::LocalScope<clang::interp::EvalEmitter>::~LocalScope()
Line
Count
Source
284
13
  ~LocalScope() override { this->emitDestruction(); }
285
286
1
  void addLocal(const Scope::Local &Local) override {
287
1
    if (!Idx.hasValue()) {
288
1
      Idx = this->Ctx->Descriptors.size();
289
1
      this->Ctx->Descriptors.emplace_back();
290
1
    }
291
292
1
    this->Ctx->Descriptors[*Idx].emplace_back(Local);
293
1
  }
clang::interp::LocalScope<clang::interp::ByteCodeEmitter>::addLocal(clang::interp::Scope::Local const&)
Line
Count
Source
286
1
  void addLocal(const Scope::Local &Local) override {
287
1
    if (!Idx.hasValue()) {
288
1
      Idx = this->Ctx->Descriptors.size();
289
1
      this->Ctx->Descriptors.emplace_back();
290
1
    }
291
292
1
    this->Ctx->Descriptors[*Idx].emplace_back(Local);
293
1
  }
Unexecuted instantiation: clang::interp::LocalScope<clang::interp::EvalEmitter>::addLocal(clang::interp::Scope::Local const&)
294
295
31
  void emitDestruction() override {
296
31
    if (!Idx.hasValue())
297
30
      return;
298
1
    this->Ctx->emitDestroy(*Idx, SourceInfo{});
299
1
  }
clang::interp::LocalScope<clang::interp::ByteCodeEmitter>::emitDestruction()
Line
Count
Source
295
18
  void emitDestruction() override {
296
18
    if (!Idx.hasValue())
297
17
      return;
298
1
    this->Ctx->emitDestroy(*Idx, SourceInfo{});
299
1
  }
clang::interp::LocalScope<clang::interp::EvalEmitter>::emitDestruction()
Line
Count
Source
295
13
  void emitDestruction() override {
296
13
    if (!Idx.hasValue())
297
13
      return;
298
0
    this->Ctx->emitDestroy(*Idx, SourceInfo{});
299
0
  }
300
301
protected:
302
  /// Index of the scope in the chain.
303
  Optional<unsigned> Idx;
304
};
305
306
/// Scope for storage declared in a compound statement.
307
template <class Emitter> class BlockScope final : public LocalScope<Emitter> {
308
public:
309
7
  BlockScope(ByteCodeExprGen<Emitter> *Ctx) : LocalScope<Emitter>(Ctx) {}
310
311
0
  void addExtended(const Scope::Local &Local) override {
312
0
    llvm_unreachable("Cannot create temporaries in full scopes");
313
0
  }
314
};
315
316
/// Expression scope which tracks potentially lifetime extended
317
/// temporaries which are hoisted to the parent scope on exit.
318
template <class Emitter> class ExprScope final : public LocalScope<Emitter> {
319
public:
320
16
  ExprScope(ByteCodeExprGen<Emitter> *Ctx) : LocalScope<Emitter>(Ctx) {}
clang::interp::ExprScope<clang::interp::ByteCodeEmitter>::ExprScope(clang::interp::ByteCodeExprGen<clang::interp::ByteCodeEmitter>*)
Line
Count
Source
320
3
  ExprScope(ByteCodeExprGen<Emitter> *Ctx) : LocalScope<Emitter>(Ctx) {}
clang::interp::ExprScope<clang::interp::EvalEmitter>::ExprScope(clang::interp::ByteCodeExprGen<clang::interp::EvalEmitter>*)
Line
Count
Source
320
13
  ExprScope(ByteCodeExprGen<Emitter> *Ctx) : LocalScope<Emitter>(Ctx) {}
321
322
0
  void addExtended(const Scope::Local &Local) override {
323
0
    this->Parent->addLocal(Local);
324
0
  }
Unexecuted instantiation: clang::interp::ExprScope<clang::interp::ByteCodeEmitter>::addExtended(clang::interp::Scope::Local const&)
Unexecuted instantiation: clang::interp::ExprScope<clang::interp::EvalEmitter>::addExtended(clang::interp::Scope::Local const&)
325
};
326
327
} // namespace interp
328
} // namespace clang
329
330
#endif