Coverage Report

Created: 2023-11-11 10:31

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/AST/Interp/ByteCodeEmitter.cpp
Line
Count
Source (jump to first uncovered line)
1
//===--- ByteCodeEmitter.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 "ByteCodeEmitter.h"
10
#include "ByteCodeGenError.h"
11
#include "Context.h"
12
#include "Floating.h"
13
#include "Opcode.h"
14
#include "Program.h"
15
#include "clang/AST/ASTLambda.h"
16
#include "clang/AST/DeclCXX.h"
17
#include <type_traits>
18
19
using namespace clang;
20
using namespace clang::interp;
21
22
Expected<Function *>
23
3.01k
ByteCodeEmitter::compileFunc(const FunctionDecl *FuncDecl) {
24
  // Set up argument indices.
25
3.01k
  unsigned ParamOffset = 0;
26
3.01k
  SmallVector<PrimType, 8> ParamTypes;
27
3.01k
  SmallVector<unsigned, 8> ParamOffsets;
28
3.01k
  llvm::DenseMap<unsigned, Function::ParamDescriptor> ParamDescriptors;
29
30
  // If the return is not a primitive, a pointer to the storage where the
31
  // value is initialized in is passed as the first argument. See 'RVO'
32
  // elsewhere in the code.
33
3.01k
  QualType Ty = FuncDecl->getReturnType();
34
3.01k
  bool HasRVO = false;
35
3.01k
  if (!Ty->isVoidType() && 
!Ctx.classify(Ty)2.47k
) {
36
96
    HasRVO = true;
37
96
    ParamTypes.push_back(PT_Ptr);
38
96
    ParamOffsets.push_back(ParamOffset);
39
96
    ParamOffset += align(primSize(PT_Ptr));
40
96
  }
41
42
  // If the function decl is a member decl, the next parameter is
43
  // the 'this' pointer. This parameter is pop()ed from the
44
  // InterpStack when calling the function.
45
3.01k
  bool HasThisPointer = false;
46
3.01k
  if (const auto *MD = dyn_cast<CXXMethodDecl>(FuncDecl)) {
47
717
    if (MD->isImplicitObjectMemberFunction()) {
48
702
      HasThisPointer = true;
49
702
      ParamTypes.push_back(PT_Ptr);
50
702
      ParamOffsets.push_back(ParamOffset);
51
702
      ParamOffset += align(primSize(PT_Ptr));
52
702
    }
53
54
    // Set up lambda capture to closure record field mapping.
55
717
    if (isLambdaCallOperator(MD)) {
56
47
      const Record *R = P.getOrCreateRecord(MD->getParent());
57
47
      llvm::DenseMap<const ValueDecl *, FieldDecl *> LC;
58
47
      FieldDecl *LTC;
59
60
47
      MD->getParent()->getCaptureFields(LC, LTC);
61
62
47
      for (auto Cap : LC) {
63
18
        unsigned Offset = R->getField(Cap.second)->Offset;
64
18
        this->LambdaCaptures[Cap.first] = {
65
18
            Offset, Cap.second->getType()->isReferenceType()};
66
18
      }
67
47
      if (LTC)
68
2
        this->LambdaThisCapture = R->getField(LTC)->Offset;
69
47
    }
70
717
  }
71
72
  // Assign descriptors to all parameters.
73
  // Composite objects are lowered to pointers.
74
3.01k
  for (const ParmVarDecl *PD : FuncDecl->parameters()) {
75
2.69k
    std::optional<PrimType> T = Ctx.classify(PD->getType());
76
2.69k
    PrimType PT = T.value_or(PT_Ptr);
77
2.69k
    Descriptor *Desc = P.createDescriptor(PD, PT);
78
2.69k
    ParamDescriptors.insert({ParamOffset, {PT, Desc}});
79
2.69k
    Params.insert({PD, {ParamOffset, T != std::nullopt}});
80
2.69k
    ParamOffsets.push_back(ParamOffset);
81
2.69k
    ParamOffset += align(primSize(PT));
82
2.69k
    ParamTypes.push_back(PT);
83
2.69k
  }
84
85
  // Create a handle over the emitted code.
86
3.01k
  Function *Func = P.getFunction(FuncDecl);
87
3.01k
  if (!Func)
88
1.69k
    Func = P.createFunction(FuncDecl, ParamOffset, std::move(ParamTypes),
89
1.69k
                            std::move(ParamDescriptors),
90
1.69k
                            std::move(ParamOffsets), HasThisPointer, HasRVO);
91
92
3.01k
  assert(Func);
93
  // For not-yet-defined functions, we only create a Function instance and
94
  // compile their body later.
95
3.01k
  if (!FuncDecl->isDefined()) {
96
1.48k
    Func->setDefined(false);
97
1.48k
    return Func;
98
1.48k
  }
99
100
1.53k
  Func->setDefined(true);
101
102
  // Lambda static invokers are a special case that we emit custom code for.
103
1.53k
  bool IsEligibleForCompilation = false;
104
1.53k
  if (const auto *MD = dyn_cast<CXXMethodDecl>(FuncDecl))
105
704
    IsEligibleForCompilation = MD->isLambdaStaticInvoker();
106
1.53k
  if (!IsEligibleForCompilation)
107
1.53k
    IsEligibleForCompilation = FuncDecl->isConstexpr();
108
109
  // Compile the function body.
110
1.53k
  if (!IsEligibleForCompilation || 
!visitFunc(FuncDecl)1.53k
) {
111
    // Return a dummy function if compilation failed.
112
24
    if (BailLocation)
113
0
      return llvm::make_error<ByteCodeGenError>(*BailLocation);
114
115
24
    Func->setIsFullyCompiled(true);
116
24
    return Func;
117
24
  }
118
119
  // Create scopes from descriptors.
120
1.51k
  llvm::SmallVector<Scope, 2> Scopes;
121
1.51k
  for (auto &DS : Descriptors) {
122
434
    Scopes.emplace_back(std::move(DS));
123
434
  }
124
125
  // Set the function's code.
126
1.51k
  Func->setCode(NextLocalOffset, std::move(Code), std::move(SrcMap),
127
1.51k
                std::move(Scopes), FuncDecl->hasBody());
128
1.51k
  Func->setIsFullyCompiled(true);
129
1.51k
  return Func;
130
1.53k
}
131
132
670
Scope::Local ByteCodeEmitter::createLocal(Descriptor *D) {
133
670
  NextLocalOffset += sizeof(Block);
134
670
  unsigned Location = NextLocalOffset;
135
670
  NextLocalOffset += align(D->getAllocSize());
136
670
  return {Location, D};
137
670
}
138
139
701
void ByteCodeEmitter::emitLabel(LabelTy Label) {
140
701
  const size_t Target = Code.size();
141
701
  LabelOffsets.insert({Label, Target});
142
143
701
  if (auto It = LabelRelocs.find(Label);
144
701
      It != LabelRelocs.end()) {
145
490
    for (unsigned Reloc : It->second) {
146
490
      using namespace llvm::support;
147
148
      // Rewrite the operand of all jumps to this label.
149
490
      void *Location = Code.data() + Reloc - align(sizeof(int32_t));
150
490
      assert(aligned(Location));
151
490
      const int32_t Offset = Target - static_cast<int64_t>(Reloc);
152
490
      endian::write<int32_t, llvm::endianness::native>(Location, Offset);
153
490
    }
154
471
    LabelRelocs.erase(It);
155
471
  }
156
701
}
157
158
559
int32_t ByteCodeEmitter::getOffset(LabelTy Label) {
159
  // Compute the PC offset which the jump is relative to.
160
559
  const int64_t Position =
161
559
      Code.size() + align(sizeof(Opcode)) + align(sizeof(int32_t));
162
559
  assert(aligned(Position));
163
164
  // If target is known, compute jump offset.
165
559
  if (auto It = LabelOffsets.find(Label);
166
559
      It != LabelOffsets.end())
167
69
    return It->second - Position;
168
169
  // Otherwise, record relocation and return dummy offset.
170
490
  LabelRelocs[Label].push_back(Position);
171
490
  return 0ull;
172
559
}
173
174
0
bool ByteCodeEmitter::bail(const SourceLocation &Loc) {
175
0
  if (!BailLocation)
176
0
    BailLocation = Loc;
177
0
  return false;
178
0
}
179
180
/// Helper to write bytecode and bail out if 32-bit offsets become invalid.
181
/// Pointers will be automatically marshalled as 32-bit IDs.
182
template <typename T>
183
static void emit(Program &P, std::vector<std::byte> &Code, const T &Val,
184
26.5k
                 bool &Success) {
185
26.5k
  size_t Size;
186
187
26.5k
  if constexpr (std::is_pointer_v<T>)
188
1.04k
    
Size0
= sizeof(uint32_t);
189
25.5k
  else
190
25.5k
    Size = sizeof(T);
191
192
26.5k
  if (Code.size() + Size > std::numeric_limits<unsigned>::max()) {
193
0
    Success = false;
194
0
    return;
195
0
  }
196
197
  // Access must be aligned!
198
26.5k
  size_t ValPos = align(Code.size());
199
26.5k
  Size = align(Size);
200
26.5k
  assert(aligned(ValPos + Size));
201
26.5k
  Code.resize(ValPos + Size);
202
203
26.5k
  if constexpr (!std::is_pointer_v<T>) 
{0
204
1.04k
    new (Code.data() + ValPos) T(Val);
205
1.04k
  } else {
206
1.04k
    uint32_t ID = P.getOrCreateNativePointer(Val);
207
1.04k
    new (Code.data() + ValPos) uint32_t(ID);
208
1.04k
  }
209
26.5k
}
ByteCodeEmitter.cpp:void emit<clang::interp::Opcode>(clang::interp::Program&, std::__1::vector<std::byte, std::__1::allocator<std::byte> >&, clang::interp::Opcode const&, bool&)
Line
Count
Source
184
17.0k
                 bool &Success) {
185
17.0k
  size_t Size;
186
187
17.0k
  if constexpr (std::is_pointer_v<T>)
188
0
    Size = sizeof(uint32_t);
189
17.0k
  else
190
17.0k
    Size = sizeof(T);
191
192
17.0k
  if (Code.size() + Size > std::numeric_limits<unsigned>::max()) {
193
0
    Success = false;
194
0
    return;
195
0
  }
196
197
  // Access must be aligned!
198
17.0k
  size_t ValPos = align(Code.size());
199
17.0k
  Size = align(Size);
200
17.0k
  assert(aligned(ValPos + Size));
201
17.0k
  Code.resize(ValPos + Size);
202
203
17.0k
  if constexpr (!std::is_pointer_v<T>) {
204
17.0k
    new (Code.data() + ValPos) T(Val);
205
17.0k
  } else {
206
17.0k
    uint32_t ID = P.getOrCreateNativePointer(Val);
207
17.0k
    new (Code.data() + ValPos) uint32_t(ID);
208
17.0k
  }
209
17.0k
}
ByteCodeEmitter.cpp:void emit<llvm::RoundingMode>(clang::interp::Program&, std::__1::vector<std::byte, std::__1::allocator<std::byte> >&, llvm::RoundingMode const&, bool&)
Line
Count
Source
184
134
                 bool &Success) {
185
134
  size_t Size;
186
187
134
  if constexpr (std::is_pointer_v<T>)
188
0
    Size = sizeof(uint32_t);
189
134
  else
190
134
    Size = sizeof(T);
191
192
134
  if (Code.size() + Size > std::numeric_limits<unsigned>::max()) {
193
0
    Success = false;
194
0
    return;
195
0
  }
196
197
  // Access must be aligned!
198
134
  size_t ValPos = align(Code.size());
199
134
  Size = align(Size);
200
134
  assert(aligned(ValPos + Size));
201
134
  Code.resize(ValPos + Size);
202
203
134
  if constexpr (!std::is_pointer_v<T>) {
204
134
    new (Code.data() + ValPos) T(Val);
205
134
  } else {
206
134
    uint32_t ID = P.getOrCreateNativePointer(Val);
207
134
    new (Code.data() + ValPos) uint32_t(ID);
208
134
  }
209
134
}
Unexecuted instantiation: ByteCodeEmitter.cpp:void emit<clang::ComparisonCategoryInfo const*>(clang::interp::Program&, std::__1::vector<std::byte, std::__1::allocator<std::byte> >&, clang::ComparisonCategoryInfo const* const&, bool&)
ByteCodeEmitter.cpp:void emit<clang::interp::Function const*>(clang::interp::Program&, std::__1::vector<std::byte, std::__1::allocator<std::byte> >&, clang::interp::Function const* const&, bool&)
Line
Count
Source
184
897
                 bool &Success) {
185
897
  size_t Size;
186
187
897
  if constexpr (std::is_pointer_v<T>)
188
897
    Size = sizeof(uint32_t);
189
897
  else
190
897
    Size = sizeof(T);
191
192
897
  if (Code.size() + Size > std::numeric_limits<unsigned>::max()) {
193
0
    Success = false;
194
0
    return;
195
0
  }
196
197
  // Access must be aligned!
198
897
  size_t ValPos = align(Code.size());
199
897
  Size = align(Size);
200
897
  assert(aligned(ValPos + Size));
201
897
  Code.resize(ValPos + Size);
202
203
897
  if constexpr (!std::is_pointer_v<T>) 
{0
204
897
    new (Code.data() + ValPos) T(Val);
205
897
  } else {
206
897
    uint32_t ID = P.getOrCreateNativePointer(Val);
207
897
    new (Code.data() + ValPos) uint32_t(ID);
208
897
  }
209
897
}
ByteCodeEmitter.cpp:void emit<clang::CallExpr const*>(clang::interp::Program&, std::__1::vector<std::byte, std::__1::allocator<std::byte> >&, clang::CallExpr const* const&, bool&)
Line
Count
Source
184
56
                 bool &Success) {
185
56
  size_t Size;
186
187
56
  if constexpr (std::is_pointer_v<T>)
188
56
    Size = sizeof(uint32_t);
189
56
  else
190
56
    Size = sizeof(T);
191
192
56
  if (Code.size() + Size > std::numeric_limits<unsigned>::max()) {
193
0
    Success = false;
194
0
    return;
195
0
  }
196
197
  // Access must be aligned!
198
56
  size_t ValPos = align(Code.size());
199
56
  Size = align(Size);
200
56
  assert(aligned(ValPos + Size));
201
56
  Code.resize(ValPos + Size);
202
203
56
  if constexpr (!std::is_pointer_v<T>) 
{0
204
56
    new (Code.data() + ValPos) T(Val);
205
56
  } else {
206
56
    uint32_t ID = P.getOrCreateNativePointer(Val);
207
56
    new (Code.data() + ValPos) uint32_t(ID);
208
56
  }
209
56
}
ByteCodeEmitter.cpp:void emit<unsigned int>(clang::interp::Program&, std::__1::vector<std::byte, std::__1::allocator<std::byte> >&, unsigned int const&, bool&)
Line
Count
Source
184
6.01k
                 bool &Success) {
185
6.01k
  size_t Size;
186
187
6.01k
  if constexpr (std::is_pointer_v<T>)
188
0
    Size = sizeof(uint32_t);
189
6.01k
  else
190
6.01k
    Size = sizeof(T);
191
192
6.01k
  if (Code.size() + Size > std::numeric_limits<unsigned>::max()) {
193
0
    Success = false;
194
0
    return;
195
0
  }
196
197
  // Access must be aligned!
198
6.01k
  size_t ValPos = align(Code.size());
199
6.01k
  Size = align(Size);
200
6.01k
  assert(aligned(ValPos + Size));
201
6.01k
  Code.resize(ValPos + Size);
202
203
6.01k
  if constexpr (!std::is_pointer_v<T>) {
204
6.01k
    new (Code.data() + ValPos) T(Val);
205
6.01k
  } else {
206
6.01k
    uint32_t ID = P.getOrCreateNativePointer(Val);
207
6.01k
    new (Code.data() + ValPos) uint32_t(ID);
208
6.01k
  }
209
6.01k
}
ByteCodeEmitter.cpp:void emit<llvm::fltSemantics const*>(clang::interp::Program&, std::__1::vector<std::byte, std::__1::allocator<std::byte> >&, llvm::fltSemantics const* const&, bool&)
Line
Count
Source
184
74
                 bool &Success) {
185
74
  size_t Size;
186
187
74
  if constexpr (std::is_pointer_v<T>)
188
74
    Size = sizeof(uint32_t);
189
74
  else
190
74
    Size = sizeof(T);
191
192
74
  if (Code.size() + Size > std::numeric_limits<unsigned>::max()) {
193
0
    Success = false;
194
0
    return;
195
0
  }
196
197
  // Access must be aligned!
198
74
  size_t ValPos = align(Code.size());
199
74
  Size = align(Size);
200
74
  assert(aligned(ValPos + Size));
201
74
  Code.resize(ValPos + Size);
202
203
74
  if constexpr (!std::is_pointer_v<T>) 
{0
204
74
    new (Code.data() + ValPos) T(Val);
205
74
  } else {
206
74
    uint32_t ID = P.getOrCreateNativePointer(Val);
207
74
    new (Code.data() + ValPos) uint32_t(ID);
208
74
  }
209
74
}
ByteCodeEmitter.cpp:void emit<bool>(clang::interp::Program&, std::__1::vector<std::byte, std::__1::allocator<std::byte> >&, bool const&, bool&)
Line
Count
Source
184
276
                 bool &Success) {
185
276
  size_t Size;
186
187
276
  if constexpr (std::is_pointer_v<T>)
188
0
    Size = sizeof(uint32_t);
189
276
  else
190
276
    Size = sizeof(T);
191
192
276
  if (Code.size() + Size > std::numeric_limits<unsigned>::max()) {
193
0
    Success = false;
194
0
    return;
195
0
  }
196
197
  // Access must be aligned!
198
276
  size_t ValPos = align(Code.size());
199
276
  Size = align(Size);
200
276
  assert(aligned(ValPos + Size));
201
276
  Code.resize(ValPos + Size);
202
203
276
  if constexpr (!std::is_pointer_v<T>) {
204
276
    new (Code.data() + ValPos) T(Val);
205
276
  } else {
206
276
    uint32_t ID = P.getOrCreateNativePointer(Val);
207
276
    new (Code.data() + ValPos) uint32_t(ID);
208
276
  }
209
276
}
ByteCodeEmitter.cpp:void emit<signed char>(clang::interp::Program&, std::__1::vector<std::byte, std::__1::allocator<std::byte> >&, signed char const&, bool&)
Line
Count
Source
184
8
                 bool &Success) {
185
8
  size_t Size;
186
187
8
  if constexpr (std::is_pointer_v<T>)
188
0
    Size = sizeof(uint32_t);
189
8
  else
190
8
    Size = sizeof(T);
191
192
8
  if (Code.size() + Size > std::numeric_limits<unsigned>::max()) {
193
0
    Success = false;
194
0
    return;
195
0
  }
196
197
  // Access must be aligned!
198
8
  size_t ValPos = align(Code.size());
199
8
  Size = align(Size);
200
8
  assert(aligned(ValPos + Size));
201
8
  Code.resize(ValPos + Size);
202
203
8
  if constexpr (!std::is_pointer_v<T>) {
204
8
    new (Code.data() + ValPos) T(Val);
205
8
  } else {
206
8
    uint32_t ID = P.getOrCreateNativePointer(Val);
207
8
    new (Code.data() + ValPos) uint32_t(ID);
208
8
  }
209
8
}
ByteCodeEmitter.cpp:void emit<short>(clang::interp::Program&, std::__1::vector<std::byte, std::__1::allocator<std::byte> >&, short const&, bool&)
Line
Count
Source
184
21
                 bool &Success) {
185
21
  size_t Size;
186
187
21
  if constexpr (std::is_pointer_v<T>)
188
0
    Size = sizeof(uint32_t);
189
21
  else
190
21
    Size = sizeof(T);
191
192
21
  if (Code.size() + Size > std::numeric_limits<unsigned>::max()) {
193
0
    Success = false;
194
0
    return;
195
0
  }
196
197
  // Access must be aligned!
198
21
  size_t ValPos = align(Code.size());
199
21
  Size = align(Size);
200
21
  assert(aligned(ValPos + Size));
201
21
  Code.resize(ValPos + Size);
202
203
21
  if constexpr (!std::is_pointer_v<T>) {
204
21
    new (Code.data() + ValPos) T(Val);
205
21
  } else {
206
21
    uint32_t ID = P.getOrCreateNativePointer(Val);
207
21
    new (Code.data() + ValPos) uint32_t(ID);
208
21
  }
209
21
}
ByteCodeEmitter.cpp:void emit<int>(clang::interp::Program&, std::__1::vector<std::byte, std::__1::allocator<std::byte> >&, int const&, bool&)
Line
Count
Source
184
1.75k
                 bool &Success) {
185
1.75k
  size_t Size;
186
187
1.75k
  if constexpr (std::is_pointer_v<T>)
188
0
    Size = sizeof(uint32_t);
189
1.75k
  else
190
1.75k
    Size = sizeof(T);
191
192
1.75k
  if (Code.size() + Size > std::numeric_limits<unsigned>::max()) {
193
0
    Success = false;
194
0
    return;
195
0
  }
196
197
  // Access must be aligned!
198
1.75k
  size_t ValPos = align(Code.size());
199
1.75k
  Size = align(Size);
200
1.75k
  assert(aligned(ValPos + Size));
201
1.75k
  Code.resize(ValPos + Size);
202
203
1.75k
  if constexpr (!std::is_pointer_v<T>) {
204
1.75k
    new (Code.data() + ValPos) T(Val);
205
1.75k
  } else {
206
1.75k
    uint32_t ID = P.getOrCreateNativePointer(Val);
207
1.75k
    new (Code.data() + ValPos) uint32_t(ID);
208
1.75k
  }
209
1.75k
}
ByteCodeEmitter.cpp:void emit<long long>(clang::interp::Program&, std::__1::vector<std::byte, std::__1::allocator<std::byte> >&, long long const&, bool&)
Line
Count
Source
184
14
                 bool &Success) {
185
14
  size_t Size;
186
187
14
  if constexpr (std::is_pointer_v<T>)
188
0
    Size = sizeof(uint32_t);
189
14
  else
190
14
    Size = sizeof(T);
191
192
14
  if (Code.size() + Size > std::numeric_limits<unsigned>::max()) {
193
0
    Success = false;
194
0
    return;
195
0
  }
196
197
  // Access must be aligned!
198
14
  size_t ValPos = align(Code.size());
199
14
  Size = align(Size);
200
14
  assert(aligned(ValPos + Size));
201
14
  Code.resize(ValPos + Size);
202
203
14
  if constexpr (!std::is_pointer_v<T>) {
204
14
    new (Code.data() + ValPos) T(Val);
205
14
  } else {
206
14
    uint32_t ID = P.getOrCreateNativePointer(Val);
207
14
    new (Code.data() + ValPos) uint32_t(ID);
208
14
  }
209
14
}
ByteCodeEmitter.cpp:void emit<unsigned char>(clang::interp::Program&, std::__1::vector<std::byte, std::__1::allocator<std::byte> >&, unsigned char const&, bool&)
Line
Count
Source
184
40
                 bool &Success) {
185
40
  size_t Size;
186
187
40
  if constexpr (std::is_pointer_v<T>)
188
0
    Size = sizeof(uint32_t);
189
40
  else
190
40
    Size = sizeof(T);
191
192
40
  if (Code.size() + Size > std::numeric_limits<unsigned>::max()) {
193
0
    Success = false;
194
0
    return;
195
0
  }
196
197
  // Access must be aligned!
198
40
  size_t ValPos = align(Code.size());
199
40
  Size = align(Size);
200
40
  assert(aligned(ValPos + Size));
201
40
  Code.resize(ValPos + Size);
202
203
40
  if constexpr (!std::is_pointer_v<T>) {
204
40
    new (Code.data() + ValPos) T(Val);
205
40
  } else {
206
40
    uint32_t ID = P.getOrCreateNativePointer(Val);
207
40
    new (Code.data() + ValPos) uint32_t(ID);
208
40
  }
209
40
}
Unexecuted instantiation: ByteCodeEmitter.cpp:void emit<unsigned short>(clang::interp::Program&, std::__1::vector<std::byte, std::__1::allocator<std::byte> >&, unsigned short const&, bool&)
ByteCodeEmitter.cpp:void emit<unsigned long long>(clang::interp::Program&, std::__1::vector<std::byte, std::__1::allocator<std::byte> >&, unsigned long long const&, bool&)
Line
Count
Source
184
149
                 bool &Success) {
185
149
  size_t Size;
186
187
149
  if constexpr (std::is_pointer_v<T>)
188
0
    Size = sizeof(uint32_t);
189
149
  else
190
149
    Size = sizeof(T);
191
192
149
  if (Code.size() + Size > std::numeric_limits<unsigned>::max()) {
193
0
    Success = false;
194
0
    return;
195
0
  }
196
197
  // Access must be aligned!
198
149
  size_t ValPos = align(Code.size());
199
149
  Size = align(Size);
200
149
  assert(aligned(ValPos + Size));
201
149
  Code.resize(ValPos + Size);
202
203
149
  if constexpr (!std::is_pointer_v<T>) {
204
149
    new (Code.data() + ValPos) T(Val);
205
149
  } else {
206
149
    uint32_t ID = P.getOrCreateNativePointer(Val);
207
149
    new (Code.data() + ValPos) uint32_t(ID);
208
149
  }
209
149
}
Unexecuted instantiation: ByteCodeEmitter.cpp:void emit<clang::RecordDecl const*>(clang::interp::Program&, std::__1::vector<std::byte, std::__1::allocator<std::byte> >&, clang::RecordDecl const* const&, bool&)
ByteCodeEmitter.cpp:void emit<clang::interp::Record::Field const*>(clang::interp::Program&, std::__1::vector<std::byte, std::__1::allocator<std::byte> >&, clang::interp::Record::Field const* const&, bool&)
Line
Count
Source
184
21
                 bool &Success) {
185
21
  size_t Size;
186
187
21
  if constexpr (std::is_pointer_v<T>)
188
21
    Size = sizeof(uint32_t);
189
21
  else
190
21
    Size = sizeof(T);
191
192
21
  if (Code.size() + Size > std::numeric_limits<unsigned>::max()) {
193
0
    Success = false;
194
0
    return;
195
0
  }
196
197
  // Access must be aligned!
198
21
  size_t ValPos = align(Code.size());
199
21
  Size = align(Size);
200
21
  assert(aligned(ValPos + Size));
201
21
  Code.resize(ValPos + Size);
202
203
21
  if constexpr (!std::is_pointer_v<T>) 
{0
204
21
    new (Code.data() + ValPos) T(Val);
205
21
  } else {
206
21
    uint32_t ID = P.getOrCreateNativePointer(Val);
207
21
    new (Code.data() + ValPos) uint32_t(ID);
208
21
  }
209
21
}
Unexecuted instantiation: ByteCodeEmitter.cpp:void emit<clang::LifetimeExtendedTemporaryDecl const*>(clang::interp::Program&, std::__1::vector<std::byte, std::__1::allocator<std::byte> >&, clang::LifetimeExtendedTemporaryDecl const* const&, bool&)
Unexecuted instantiation: ByteCodeEmitter.cpp:void emit<clang::interp::CastKind>(clang::interp::Program&, std::__1::vector<std::byte, std::__1::allocator<std::byte> >&, clang::interp::CastKind const&, bool&)
ByteCodeEmitter.cpp:void emit<clang::DeclRefExpr const*>(clang::interp::Program&, std::__1::vector<std::byte, std::__1::allocator<std::byte> >&, clang::DeclRefExpr const* const&, bool&)
Line
Count
Source
184
1
                 bool &Success) {
185
1
  size_t Size;
186
187
1
  if constexpr (std::is_pointer_v<T>)
188
1
    Size = sizeof(uint32_t);
189
1
  else
190
1
    Size = sizeof(T);
191
192
1
  if (Code.size() + Size > std::numeric_limits<unsigned>::max()) {
193
0
    Success = false;
194
0
    return;
195
0
  }
196
197
  // Access must be aligned!
198
1
  size_t ValPos = align(Code.size());
199
1
  Size = align(Size);
200
1
  assert(aligned(ValPos + Size));
201
1
  Code.resize(ValPos + Size);
202
203
1
  if constexpr (!std::is_pointer_v<T>) 
{0
204
1
    new (Code.data() + ValPos) T(Val);
205
1
  } else {
206
1
    uint32_t ID = P.getOrCreateNativePointer(Val);
207
1
    new (Code.data() + ValPos) uint32_t(ID);
208
1
  }
209
1
}
Unexecuted instantiation: ByteCodeEmitter.cpp:void emit<clang::OffsetOfExpr const*>(clang::interp::Program&, std::__1::vector<std::byte, std::__1::allocator<std::byte> >&, clang::OffsetOfExpr const* const&, bool&)
210
211
template <>
212
void emit(Program &P, std::vector<std::byte> &Code, const Floating &Val,
213
39
          bool &Success) {
214
39
  size_t Size = Val.bytesToSerialize();
215
216
39
  if (Code.size() + Size > std::numeric_limits<unsigned>::max()) {
217
0
    Success = false;
218
0
    return;
219
0
  }
220
221
  // Access must be aligned!
222
39
  size_t ValPos = align(Code.size());
223
39
  Size = align(Size);
224
39
  assert(aligned(ValPos + Size));
225
39
  Code.resize(ValPos + Size);
226
227
39
  Val.serialize(Code.data() + ValPos);
228
39
}
229
230
template <typename... Tys>
231
17.0k
bool ByteCodeEmitter::emitOp(Opcode Op, const Tys &... Args, const SourceInfo &SI) {
232
17.0k
  bool Success = true;
233
234
  // The opcode is followed by arguments. The source info is
235
  // attached to the address after the opcode.
236
17.0k
  emit(P, Code, Op, Success);
237
17.0k
  if (SI)
238
14.0k
    SrcMap.emplace_back(Code.size(), SI);
239
240
  // The initializer list forces the expression to be evaluated
241
  // for each argument in the variadic template, in order.
242
17.0k
  (void)std::initializer_list<int>{(emit(P, Code, Args, Success), 0)...};
243
244
17.0k
  return Success;
245
17.0k
}
bool clang::interp::ByteCodeEmitter::emitOp<>(clang::interp::Opcode, clang::interp::SourceInfo const&)
Line
Count
Source
231
7.72k
bool ByteCodeEmitter::emitOp(Opcode Op, const Tys &... Args, const SourceInfo &SI) {
232
7.72k
  bool Success = true;
233
234
  // The opcode is followed by arguments. The source info is
235
  // attached to the address after the opcode.
236
7.72k
  emit(P, Code, Op, Success);
237
7.72k
  if (SI)
238
5.91k
    SrcMap.emplace_back(Code.size(), SI);
239
240
  // The initializer list forces the expression to be evaluated
241
  // for each argument in the variadic template, in order.
242
7.72k
  (void)std::initializer_list<int>{(emit(P, Code, Args, Success), 0)...};
243
244
7.72k
  return Success;
245
7.72k
}
bool clang::interp::ByteCodeEmitter::emitOp<llvm::RoundingMode>(clang::interp::Opcode, llvm::RoundingMode const&, clang::interp::SourceInfo const&)
Line
Count
Source
231
60
bool ByteCodeEmitter::emitOp(Opcode Op, const Tys &... Args, const SourceInfo &SI) {
232
60
  bool Success = true;
233
234
  // The opcode is followed by arguments. The source info is
235
  // attached to the address after the opcode.
236
60
  emit(P, Code, Op, Success);
237
60
  if (SI)
238
60
    SrcMap.emplace_back(Code.size(), SI);
239
240
  // The initializer list forces the expression to be evaluated
241
  // for each argument in the variadic template, in order.
242
60
  (void)std::initializer_list<int>{(emit(P, Code, Args, Success), 0)...};
243
244
60
  return Success;
245
60
}
Unexecuted instantiation: bool clang::interp::ByteCodeEmitter::emitOp<clang::ComparisonCategoryInfo const*>(clang::interp::Opcode, clang::ComparisonCategoryInfo const* const&, clang::interp::SourceInfo const&)
bool clang::interp::ByteCodeEmitter::emitOp<clang::interp::Function const*>(clang::interp::Opcode, clang::interp::Function const* const&, clang::interp::SourceInfo const&)
Line
Count
Source
231
841
bool ByteCodeEmitter::emitOp(Opcode Op, const Tys &... Args, const SourceInfo &SI) {
232
841
  bool Success = true;
233
234
  // The opcode is followed by arguments. The source info is
235
  // attached to the address after the opcode.
236
841
  emit(P, Code, Op, Success);
237
841
  if (SI)
238
797
    SrcMap.emplace_back(Code.size(), SI);
239
240
  // The initializer list forces the expression to be evaluated
241
  // for each argument in the variadic template, in order.
242
841
  (void)std::initializer_list<int>{(emit(P, Code, Args, Success), 0)...};
243
244
841
  return Success;
245
841
}
bool clang::interp::ByteCodeEmitter::emitOp<clang::interp::Function const*, clang::CallExpr const*>(clang::interp::Opcode, clang::interp::Function const* const&, clang::CallExpr const* const&, clang::interp::SourceInfo const&)
Line
Count
Source
231
56
bool ByteCodeEmitter::emitOp(Opcode Op, const Tys &... Args, const SourceInfo &SI) {
232
56
  bool Success = true;
233
234
  // The opcode is followed by arguments. The source info is
235
  // attached to the address after the opcode.
236
56
  emit(P, Code, Op, Success);
237
56
  if (SI)
238
56
    SrcMap.emplace_back(Code.size(), SI);
239
240
  // The initializer list forces the expression to be evaluated
241
  // for each argument in the variadic template, in order.
242
56
  (void)std::initializer_list<int>{(emit(P, Code, Args, Success), 0)...};
243
244
56
  return Success;
245
56
}
bool clang::interp::ByteCodeEmitter::emitOp<unsigned int>(clang::interp::Opcode, unsigned int const&, clang::interp::SourceInfo const&)
Line
Count
Source
231
6.01k
bool ByteCodeEmitter::emitOp(Opcode Op, const Tys &... Args, const SourceInfo &SI) {
232
6.01k
  bool Success = true;
233
234
  // The opcode is followed by arguments. The source info is
235
  // attached to the address after the opcode.
236
6.01k
  emit(P, Code, Op, Success);
237
6.01k
  if (SI)
238
5.36k
    SrcMap.emplace_back(Code.size(), SI);
239
240
  // The initializer list forces the expression to be evaluated
241
  // for each argument in the variadic template, in order.
242
6.01k
  (void)std::initializer_list<int>{(emit(P, Code, Args, Success), 0)...};
243
244
6.01k
  return Success;
245
6.01k
}
bool clang::interp::ByteCodeEmitter::emitOp<llvm::fltSemantics const*, llvm::RoundingMode>(clang::interp::Opcode, llvm::fltSemantics const* const&, llvm::RoundingMode const&, clang::interp::SourceInfo const&)
Line
Count
Source
231
74
bool ByteCodeEmitter::emitOp(Opcode Op, const Tys &... Args, const SourceInfo &SI) {
232
74
  bool Success = true;
233
234
  // The opcode is followed by arguments. The source info is
235
  // attached to the address after the opcode.
236
74
  emit(P, Code, Op, Success);
237
74
  if (SI)
238
74
    SrcMap.emplace_back(Code.size(), SI);
239
240
  // The initializer list forces the expression to be evaluated
241
  // for each argument in the variadic template, in order.
242
74
  (void)std::initializer_list<int>{(emit(P, Code, Args, Success), 0)...};
243
244
74
  return Success;
245
74
}
bool clang::interp::ByteCodeEmitter::emitOp<bool>(clang::interp::Opcode, bool const&, clang::interp::SourceInfo const&)
Line
Count
Source
231
276
bool ByteCodeEmitter::emitOp(Opcode Op, const Tys &... Args, const SourceInfo &SI) {
232
276
  bool Success = true;
233
234
  // The opcode is followed by arguments. The source info is
235
  // attached to the address after the opcode.
236
276
  emit(P, Code, Op, Success);
237
276
  if (SI)
238
276
    SrcMap.emplace_back(Code.size(), SI);
239
240
  // The initializer list forces the expression to be evaluated
241
  // for each argument in the variadic template, in order.
242
276
  (void)std::initializer_list<int>{(emit(P, Code, Args, Success), 0)...};
243
244
276
  return Success;
245
276
}
bool clang::interp::ByteCodeEmitter::emitOp<clang::interp::Floating>(clang::interp::Opcode, clang::interp::Floating const&, clang::interp::SourceInfo const&)
Line
Count
Source
231
39
bool ByteCodeEmitter::emitOp(Opcode Op, const Tys &... Args, const SourceInfo &SI) {
232
39
  bool Success = true;
233
234
  // The opcode is followed by arguments. The source info is
235
  // attached to the address after the opcode.
236
39
  emit(P, Code, Op, Success);
237
39
  if (SI)
238
39
    SrcMap.emplace_back(Code.size(), SI);
239
240
  // The initializer list forces the expression to be evaluated
241
  // for each argument in the variadic template, in order.
242
39
  (void)std::initializer_list<int>{(emit(P, Code, Args, Success), 0)...};
243
244
39
  return Success;
245
39
}
bool clang::interp::ByteCodeEmitter::emitOp<signed char>(clang::interp::Opcode, signed char const&, clang::interp::SourceInfo const&)
Line
Count
Source
231
8
bool ByteCodeEmitter::emitOp(Opcode Op, const Tys &... Args, const SourceInfo &SI) {
232
8
  bool Success = true;
233
234
  // The opcode is followed by arguments. The source info is
235
  // attached to the address after the opcode.
236
8
  emit(P, Code, Op, Success);
237
8
  if (SI)
238
8
    SrcMap.emplace_back(Code.size(), SI);
239
240
  // The initializer list forces the expression to be evaluated
241
  // for each argument in the variadic template, in order.
242
8
  (void)std::initializer_list<int>{(emit(P, Code, Args, Success), 0)...};
243
244
8
  return Success;
245
8
}
bool clang::interp::ByteCodeEmitter::emitOp<short>(clang::interp::Opcode, short const&, clang::interp::SourceInfo const&)
Line
Count
Source
231
21
bool ByteCodeEmitter::emitOp(Opcode Op, const Tys &... Args, const SourceInfo &SI) {
232
21
  bool Success = true;
233
234
  // The opcode is followed by arguments. The source info is
235
  // attached to the address after the opcode.
236
21
  emit(P, Code, Op, Success);
237
21
  if (SI)
238
21
    SrcMap.emplace_back(Code.size(), SI);
239
240
  // The initializer list forces the expression to be evaluated
241
  // for each argument in the variadic template, in order.
242
21
  (void)std::initializer_list<int>{(emit(P, Code, Args, Success), 0)...};
243
244
21
  return Success;
245
21
}
bool clang::interp::ByteCodeEmitter::emitOp<int>(clang::interp::Opcode, int const&, clang::interp::SourceInfo const&)
Line
Count
Source
231
1.75k
bool ByteCodeEmitter::emitOp(Opcode Op, const Tys &... Args, const SourceInfo &SI) {
232
1.75k
  bool Success = true;
233
234
  // The opcode is followed by arguments. The source info is
235
  // attached to the address after the opcode.
236
1.75k
  emit(P, Code, Op, Success);
237
1.75k
  if (SI)
238
1.19k
    SrcMap.emplace_back(Code.size(), SI);
239
240
  // The initializer list forces the expression to be evaluated
241
  // for each argument in the variadic template, in order.
242
1.75k
  (void)std::initializer_list<int>{(emit(P, Code, Args, Success), 0)...};
243
244
1.75k
  return Success;
245
1.75k
}
bool clang::interp::ByteCodeEmitter::emitOp<long long>(clang::interp::Opcode, long long const&, clang::interp::SourceInfo const&)
Line
Count
Source
231
14
bool ByteCodeEmitter::emitOp(Opcode Op, const Tys &... Args, const SourceInfo &SI) {
232
14
  bool Success = true;
233
234
  // The opcode is followed by arguments. The source info is
235
  // attached to the address after the opcode.
236
14
  emit(P, Code, Op, Success);
237
14
  if (SI)
238
14
    SrcMap.emplace_back(Code.size(), SI);
239
240
  // The initializer list forces the expression to be evaluated
241
  // for each argument in the variadic template, in order.
242
14
  (void)std::initializer_list<int>{(emit(P, Code, Args, Success), 0)...};
243
244
14
  return Success;
245
14
}
bool clang::interp::ByteCodeEmitter::emitOp<unsigned char>(clang::interp::Opcode, unsigned char const&, clang::interp::SourceInfo const&)
Line
Count
Source
231
40
bool ByteCodeEmitter::emitOp(Opcode Op, const Tys &... Args, const SourceInfo &SI) {
232
40
  bool Success = true;
233
234
  // The opcode is followed by arguments. The source info is
235
  // attached to the address after the opcode.
236
40
  emit(P, Code, Op, Success);
237
40
  if (SI)
238
40
    SrcMap.emplace_back(Code.size(), SI);
239
240
  // The initializer list forces the expression to be evaluated
241
  // for each argument in the variadic template, in order.
242
40
  (void)std::initializer_list<int>{(emit(P, Code, Args, Success), 0)...};
243
244
40
  return Success;
245
40
}
Unexecuted instantiation: bool clang::interp::ByteCodeEmitter::emitOp<unsigned short>(clang::interp::Opcode, unsigned short const&, clang::interp::SourceInfo const&)
bool clang::interp::ByteCodeEmitter::emitOp<unsigned long long>(clang::interp::Opcode, unsigned long long const&, clang::interp::SourceInfo const&)
Line
Count
Source
231
149
bool ByteCodeEmitter::emitOp(Opcode Op, const Tys &... Args, const SourceInfo &SI) {
232
149
  bool Success = true;
233
234
  // The opcode is followed by arguments. The source info is
235
  // attached to the address after the opcode.
236
149
  emit(P, Code, Op, Success);
237
149
  if (SI)
238
137
    SrcMap.emplace_back(Code.size(), SI);
239
240
  // The initializer list forces the expression to be evaluated
241
  // for each argument in the variadic template, in order.
242
149
  (void)std::initializer_list<int>{(emit(P, Code, Args, Success), 0)...};
243
244
149
  return Success;
245
149
}
Unexecuted instantiation: bool clang::interp::ByteCodeEmitter::emitOp<clang::RecordDecl const*>(clang::interp::Opcode, clang::RecordDecl const* const&, clang::interp::SourceInfo const&)
bool clang::interp::ByteCodeEmitter::emitOp<clang::interp::Record::Field const*>(clang::interp::Opcode, clang::interp::Record::Field const* const&, clang::interp::SourceInfo const&)
Line
Count
Source
231
21
bool ByteCodeEmitter::emitOp(Opcode Op, const Tys &... Args, const SourceInfo &SI) {
232
21
  bool Success = true;
233
234
  // The opcode is followed by arguments. The source info is
235
  // attached to the address after the opcode.
236
21
  emit(P, Code, Op, Success);
237
21
  if (SI)
238
21
    SrcMap.emplace_back(Code.size(), SI);
239
240
  // The initializer list forces the expression to be evaluated
241
  // for each argument in the variadic template, in order.
242
21
  (void)std::initializer_list<int>{(emit(P, Code, Args, Success), 0)...};
243
244
21
  return Success;
245
21
}
Unexecuted instantiation: bool clang::interp::ByteCodeEmitter::emitOp<unsigned int, clang::LifetimeExtendedTemporaryDecl const*>(clang::interp::Opcode, unsigned int const&, clang::LifetimeExtendedTemporaryDecl const* const&, clang::interp::SourceInfo const&)
Unexecuted instantiation: bool clang::interp::ByteCodeEmitter::emitOp<clang::LifetimeExtendedTemporaryDecl const*>(clang::interp::Opcode, clang::LifetimeExtendedTemporaryDecl const* const&, clang::interp::SourceInfo const&)
Unexecuted instantiation: bool clang::interp::ByteCodeEmitter::emitOp<clang::interp::CastKind>(clang::interp::Opcode, clang::interp::CastKind const&, clang::interp::SourceInfo const&)
bool clang::interp::ByteCodeEmitter::emitOp<clang::DeclRefExpr const*>(clang::interp::Opcode, clang::DeclRefExpr const* const&, clang::interp::SourceInfo const&)
Line
Count
Source
231
1
bool ByteCodeEmitter::emitOp(Opcode Op, const Tys &... Args, const SourceInfo &SI) {
232
1
  bool Success = true;
233
234
  // The opcode is followed by arguments. The source info is
235
  // attached to the address after the opcode.
236
1
  emit(P, Code, Op, Success);
237
1
  if (SI)
238
1
    SrcMap.emplace_back(Code.size(), SI);
239
240
  // The initializer list forces the expression to be evaluated
241
  // for each argument in the variadic template, in order.
242
1
  (void)std::initializer_list<int>{(emit(P, Code, Args, Success), 0)...};
243
244
1
  return Success;
245
1
}
Unexecuted instantiation: bool clang::interp::ByteCodeEmitter::emitOp<clang::OffsetOfExpr const*>(clang::interp::Opcode, clang::OffsetOfExpr const* const&, clang::interp::SourceInfo const&)
246
247
40
bool ByteCodeEmitter::jumpTrue(const LabelTy &Label) {
248
40
  return emitJt(getOffset(Label), SourceInfo{});
249
40
}
250
251
268
bool ByteCodeEmitter::jumpFalse(const LabelTy &Label) {
252
268
  return emitJf(getOffset(Label), SourceInfo{});
253
268
}
254
255
251
bool ByteCodeEmitter::jump(const LabelTy &Label) {
256
251
  return emitJmp(getOffset(Label), SourceInfo{});
257
251
}
258
259
127
bool ByteCodeEmitter::fallthrough(const LabelTy &Label) {
260
127
  emitLabel(Label);
261
127
  return true;
262
127
}
263
264
//===----------------------------------------------------------------------===//
265
// Opcode emitters
266
//===----------------------------------------------------------------------===//
267
268
#define GET_LINK_IMPL
269
#include "Opcodes.inc"
270
#undef GET_LINK_IMPL