/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 |