clang: lib/AST/ByteCode/ByteCodeEmitter.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
18#include <type_traits>
19
20using namespace clang;
22
24
25
26
28 return nullptr;
29
30 bool IsLambdaStaticInvoker = false;
31 if (const auto *MD = dyn_cast(FuncDecl);
32 MD && MD->isLambdaStaticInvoker()) {
33
34
35
36
37
38 IsLambdaStaticInvoker = true;
39
44 assert(MD->isFunctionTemplateSpecialization() &&
45 "A generic lambda's static-invoker function must be a "
46 "template specialization");
50 void *InsertPos = nullptr;
51 const FunctionDecl *CorrespondingCallOpSpecialization =
53 assert(CorrespondingCallOpSpecialization);
54 FuncDecl = cast(CorrespondingCallOpSpecialization);
55 }
56 }
57
58
62 llvm::DenseMap<unsigned, Function::ParamDescriptor> ParamDescriptors;
63
64
65
66
68 bool HasRVO = false;
70 HasRVO = true;
71 ParamTypes.push_back(PT_Ptr);
74 }
75
76
77
78
79 bool HasThisPointer = false;
80 if (const auto *MD = dyn_cast(FuncDecl)) {
81 if (!IsLambdaStaticInvoker) {
82 HasThisPointer = MD->isInstance();
83 if (MD->isImplicitObjectMemberFunction()) {
84 ParamTypes.push_back(PT_Ptr);
87 }
88 }
89
90
92
93
94 if (!MD->getParent()->isCompleteDefinition())
95 return nullptr;
96
98 llvm::DenseMap<const ValueDecl *, FieldDecl *> LC;
100
101 MD->getParent()->getCaptureFields(LC, LTC);
102
103 for (auto Cap : LC) {
104
105
106 if (MD->isStatic())
107 return nullptr;
108
111 Offset, Cap.second->getType()->isReferenceType()};
112 }
113 if (LTC) {
118 }
119 }
120 }
121
122
123
125 std::optional T = Ctx.classify(PD->getType());
128 ParamDescriptors.insert({ParamOffset, {PT, Desc}});
132 ParamTypes.push_back(PT);
133 }
134
135
138 unsigned BuiltinID = FuncDecl->getBuiltinID();
141 std::move(ParamDescriptors), std::move(ParamOffsets),
142 HasThisPointer, HasRVO, BuiltinID);
143 }
144
145 assert(Func);
146
147
150 Func->setDefined(false);
152 }
153
154 Func->setDefined(true);
155
156
157 bool IsEligibleForCompilation = false;
158 if (const auto *MD = dyn_cast(FuncDecl))
159 IsEligibleForCompilation = MD->isLambdaStaticInvoker();
160 if (!IsEligibleForCompilation)
161 IsEligibleForCompilation =
163
164
165 if (!IsEligibleForCompilation || (FuncDecl)) {
166 Func->setIsFullyCompiled(true);
168 }
169
170
173 Scopes.emplace_back(std::move(DS));
174 }
175
176
177 Func->setCode(NextLocalOffset, std::move(Code), std::move(SrcMap),
178 std::move(Scopes), FuncDecl->hasBody());
179 Func->setIsFullyCompiled(true);
181}
182
183
184
185
186
189
193 llvm::DenseMap<unsigned, Function::ParamDescriptor> ParamDescriptors;
194
195
196
198 std::optional T = Ctx.classify(PD->getType());
201 ParamDescriptors.insert({ParamOffset, {PT, Desc}});
205 ParamTypes.push_back(PT);
206 }
207
209 return nullptr;
210
211
214 std::move(ParamDescriptors), std::move(ParamOffsets),
215 false, false,
216 false);
217
218 assert(Func);
219 Func->setDefined(true);
220
221 Func->setIsFullyCompiled(true);
223}
224
226 NextLocalOffset += sizeof(Block);
227 unsigned Location = NextLocalOffset;
228 NextLocalOffset += align(D->getAllocSize());
229 return {Location, D};
230}
231
233 const size_t Target = Code.size();
235
236 if (auto It = LabelRelocs.find(Label); It != LabelRelocs.end()) {
237 for (unsigned Reloc : It->second) {
238 using namespace llvm::support;
239
240
241 void *Location = Code.data() + Reloc - align(sizeof(int32_t));
242 assert(aligned(Location));
243 const int32_t Offset = Target - static_cast<int64_t>(Reloc);
244 endian::write<int32_t, llvm::endianness::native>(Location, Offset);
245 }
246 LabelRelocs.erase(It);
247 }
248}
249
250int32_t ByteCodeEmitter::getOffset(LabelTy Label) {
251
252 const int64_t Position =
253 Code.size() + align(sizeof(Opcode)) + align(sizeof(int32_t));
254 assert(aligned(Position));
255
256
257 if (auto It = LabelOffsets.find(Label); It != LabelOffsets.end())
258 return It->second - Position;
259
260
261 LabelRelocs[Label].push_back(Position);
262 return 0ull;
263}
264
265
266
267template
268static void emit(Program &P, std::vectorstd::byte &Code, const T &Val,
270 size_t Size;
271
272 if constexpr (std::is_pointer_v)
273 Size = sizeof(uint32_t);
274 else
275 Size = sizeof(T);
276
277 if (Code.size() + Size > std::numeric_limits::max()) {
279 return;
280 }
281
282
283 size_t ValPos = align(Code.size());
284 Size = align(Size);
285 assert(aligned(ValPos + Size));
286 Code.resize(ValPos + Size);
287
288 if constexpr (!std::is_pointer_v) {
289 new (Code.data() + ValPos) T(Val);
290 } else {
291 uint32_t ID = P.getOrCreateNativePointer(Val);
292 new (Code.data() + ValPos) uint32_t(ID);
293 }
294}
295
296
297
298template
299static void emitSerialized(std::vectorstd::byte &Code, const T &Val,
301 size_t Size = Val.bytesToSerialize();
302
303 if (Code.size() + Size > std::numeric_limits::max()) {
305 return;
306 }
307
308
309 size_t ValPos = align(Code.size());
310 Size = align(Size);
311 assert(aligned(ValPos + Size));
312 Code.resize(ValPos + Size);
313
314 Val.serialize(Code.data() + ValPos);
315}
316
317template <>
321}
322
323template <>
327}
328
329template <>
333}
334
335template <>
339}
340
341template <typename... Tys>
342bool ByteCodeEmitter::emitOp(Opcode Op, const Tys &...Args,
345
346
347
349 if (SI)
350 SrcMap.emplace_back(Code.size(), SI);
351
354}
355
358}
359
362}
363
366}
367
370 return true;
371}
372
373
374
375
376
377#define GET_LINK_IMPL
378#include "Opcodes.inc"
379#undef GET_LINK_IMPL
This file provides some common utility functions for processing Lambda related AST Constructs.
static void emit(Program &P, std::vector< std::byte > &Code, const T &Val, bool &Success)
Helper to write bytecode and bail out if 32-bit offsets become invalid.
static void emitSerialized(std::vector< std::byte > &Code, const T &Val, bool &Success)
Emits a serializable value.
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
llvm::MachO::Target Target
Represents a block literal declaration, which is like an unnamed FunctionDecl.
bool hasCaptures() const
True if this block (or its nested blocks) captures anything of local storage from its enclosing scope...
ArrayRef< ParmVarDecl * > parameters() const
BlockExpr - Adaptor class for mixing a BlockDecl with expressions.
const BlockDecl * getBlockDecl() const
Represents a static or instance method of a struct/union/class.
Represents a C++ struct/union/class.
bool isGenericLambda() const
Determine whether this class describes a generic lambda function object (i.e.
capture_const_iterator captures_end() const
capture_const_iterator captures_begin() const
CXXMethodDecl * getLambdaCallOperator() const
Retrieve the lambda call operator of the closure type if this is a closure type.
DeclContext * getParent()
getParent - Returns the containing DeclContext.
Represents a member of a struct/union/class.
const RecordDecl * getParent() const
Returns the parent of this field declaration, which is the struct in which this field is defined.
Represents a function declaration or definition.
FunctionTemplateDecl * getDescribedFunctionTemplate() const
Retrieves the function template that is described by this function declaration.
unsigned getBuiltinID(bool ConsiderWrapperFunctions=false) const
Returns a value indicating whether this function corresponds to a builtin function.
QualType getReturnType() const
ArrayRef< ParmVarDecl * > parameters() const
param_iterator param_begin()
bool isConstexpr() const
Whether this is a (C++11) constexpr function or constexpr constructor.
bool hasBody(const FunctionDecl *&Definition) const
Returns true if the function has a body.
bool isDefined(const FunctionDecl *&Definition, bool CheckForPendingFriendDefinition=false) const
Returns true if the function has a definition that does not need to be instantiated.
bool willHaveBody() const
True if this function will eventually have a body, once it's fully parsed.
Declaration of a template function.
FunctionDecl * findSpecialization(ArrayRef< TemplateArgument > Args, void *&InsertPos)
Return the specialization with the provided arguments if it exists, otherwise return the insertion po...
Represents a parameter to a function.
A (possibly-)qualified type.
A template argument list.
ArrayRef< TemplateArgument > asArray() const
Produce this as an array ref.
bool isPointerType() const
bool isReferenceType() const
A memory block, either on the stack or in the heap.
bool jump(const LabelTy &Label)
void emitLabel(LabelTy Label)
Define a label.
ParamOffset LambdaThisCapture
Offset of the This parameter in a lambda record.
llvm::DenseMap< const ParmVarDecl *, ParamOffset > Params
Parameter indices.
llvm::DenseMap< const ValueDecl *, ParamOffset > LambdaCaptures
Lambda captures.
bool fallthrough(const LabelTy &Label)
Local createLocal(Descriptor *D)
Callback for local registration.
Function * compileFunc(const FunctionDecl *FuncDecl)
Compiles the function into the module.
Function * compileObjCBlock(const BlockExpr *BE)
Compile an ObjC block, i.e.
virtual bool visitFunc(const FunctionDecl *E)=0
Methods implemented by the compiler.
bool jumpTrue(const LabelTy &Label)
Emits jumps.
bool jumpFalse(const LabelTy &Label)
llvm::SmallVector< SmallVector< Local, 8 >, 2 > Descriptors
Local descriptors.
std::optional< PrimType > classify(QualType T) const
Classifies a type.
Wrapper around fixed point types.
The program contains and links the bytecode for all functions.
Function * getFunction(const FunctionDecl *F)
Returns a function.
Descriptor * createDescriptor(const DeclTy &D, PrimType Type, Descriptor::MetadataSize MDSize=std::nullopt, bool IsConst=false, bool IsTemporary=false, bool IsMutable=false)
Creates a descriptor for a primitive type.
Function * createFunction(const FunctionDecl *Def, Ts &&...Args)
Creates a new function from a code range.
Record * getOrCreateRecord(const RecordDecl *RD)
Returns a record or creates one if it does not exist.
Structure/Class descriptor.
const Field * getField(const FieldDecl *FD) const
Returns a field.
Describes the statement/declaration an opcode was generated from.
constexpr bool aligned(uintptr_t Value)
constexpr size_t align(size_t Size)
Aligns a size to the pointer alignment.
PrimType
Enumeration of the primitive types of the VM.
size_t primSize(PrimType Type)
Returns the size of a primitive type in bytes.
The JSON file list parser is used to communicate input to InstallAPI.
bool isLambdaCallOperator(const CXXMethodDecl *MD)
const FunctionProtoType * T
@ Success
Template argument deduction was successful.
Describes a memory block created by an allocation site.
Information about a local's storage.