1//===--- Function.h - Bytecode function 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// Defines the Function class which holds all bytecode function-specific data.
10//
11// The scope class which describes local variables is also defined here.
12//
13//===----------------------------------------------------------------------===//
14
15#ifndef LLVM_CLANG_AST_INTERP_FUNCTION_H
16#define LLVM_CLANG_AST_INTERP_FUNCTION_H
17
18#include "Descriptor.h"
19#include "Source.h"
20#include "clang/AST/Attr.h"
21#include "clang/AST/Decl.h"
22#include "clang/AST/DeclCXX.h"
23#include "llvm/ADT/PointerUnion.h"
24#include "llvm/Support/raw_ostream.h"
25
26namespace clang {
27namespace interp {
28class ByteCodeEmitter;
29class Pointer;
30enum PrimType : uint8_t;
31
32/// Describes a scope block.
33///
34/// The block gathers all the descriptors of the locals defined in this block.
35class Scope final {
36public:
37 /// Information about a local's storage.
38 struct Local {
39 /// Descriptor of the local.
40 const Descriptor *Desc;
41 /// Offset of the local in frame.
42 unsigned Offset;
43 /// If the cleanup for this local should be emitted.
44 bool EnabledByDefault = true;
45 };
46
47 using LocalVectorTy = llvm::SmallVector<Local, 8>;
48
49 Scope(LocalVectorTy &&Descriptors) : Descriptors(std::move(Descriptors)) {}
50
51 llvm::iterator_range<LocalVectorTy::const_iterator> locals() const {
52 return llvm::make_range(x: Descriptors.begin(), y: Descriptors.end());
53 }
54
55 llvm::iterator_range<LocalVectorTy::const_reverse_iterator>
56 locals_reverse() const {
57 return llvm::reverse(C: Descriptors);
58 }
59
60private:
61 /// Object descriptors in this block.
62 LocalVectorTy Descriptors;
63};
64
65using FunctionDeclTy =
66 llvm::PointerUnion<const FunctionDecl *, const BlockExpr *>;
67
68/// Bytecode function.
69///
70/// Contains links to the bytecode of the function, as well as metadata
71/// describing all arguments and stack-local variables.
72///
73/// # Calling Convention
74///
75/// When calling a function, all argument values must be on the stack.
76///
77/// If the function has a This pointer (i.e. hasThisPointer() returns true,
78/// the argument values need to be preceeded by a Pointer for the This object.
79///
80/// If the function uses Return Value Optimization, the arguments (and
81/// potentially the This pointer) need to be preceeded by a Pointer pointing
82/// to the location to construct the returned value.
83///
84/// After the function has been called, it will remove all arguments,
85/// including RVO and This pointer, from the stack.
86///
87/// The parameters saved in a clang::intepr::Function include both the
88/// instance pointer as well as the RVO pointer.
89///
90/// \verbatim
91/// Stack position when calling ─────┐
92/// this Function │
93///
94/// ┌─────┬──────┬────────┬────────┬─────┬────────────────────┐
95/// │ RVO │ This │ Param1 │ Param2 │ ... │ │
96/// └─────┴──────┴────────┴────────┴─────┴────────────────────┘
97/// \endverbatim
98class Function final {
99public:
100 enum class FunctionKind {
101 Normal,
102 Ctor,
103 CopyOrMoveCtor,
104 Dtor,
105 LambdaStaticInvoker,
106 LambdaCallOperator,
107 CopyOrMoveOperator,
108 };
109
110 struct ParamDescriptor {
111 const Descriptor *Desc;
112 /// Offset on the stack.
113 unsigned Offset;
114 /// Offset in the InterpFrame.
115 unsigned BlockOffset;
116 PrimType T;
117 ParamDescriptor(const Descriptor *Desc, unsigned Offset,
118 unsigned BlockOffset, PrimType T)
119 : Desc(Desc), Offset(Offset), BlockOffset(BlockOffset), T(T) {}
120 };
121
122 /// Returns the size of the function's local stack.
123 unsigned getFrameSize() const { return FrameSize; }
124 /// Returns the size of the argument stack.
125 unsigned getArgSize() const { return ArgSize; }
126
127 /// Returns a pointer to the start of the code.
128 CodePtr getCodeBegin() const { return Code.data(); }
129 /// Returns a pointer to the end of the code.
130 CodePtr getCodeEnd() const { return Code.data() + Code.size(); }
131
132 /// Returns the original FunctionDecl.
133 const FunctionDecl *getDecl() const {
134 return dyn_cast<const FunctionDecl *>(Val: Source);
135 }
136 const BlockExpr *getExpr() const {
137 return dyn_cast<const BlockExpr *>(Val: Source);
138 }
139
140 /// Returns the name of the function decl this code
141 /// was generated for.
142 std::string getName() const {
143 if (!Source || !getDecl())
144 return "<<expr>>";
145
146 return getDecl()->getQualifiedNameAsString();
147 }
148
149 /// Returns a parameter descriptor.
150 const ParamDescriptor &getParamDescriptor(unsigned Index) const {
151 return ParamDescriptors[Index];
152 }
153
154 /// Checks if the first argument is a RVO pointer.
155 bool hasRVO() const { return HasRVO; }
156
157 bool hasNonNullAttr() const { return getDecl()->hasAttr<NonNullAttr>(); }
158
159 /// Range over the scope blocks.
160 llvm::iterator_range<llvm::SmallVector<Scope, 2>::const_iterator>
161 scopes() const {
162 return llvm::make_range(x: Scopes.begin(), y: Scopes.end());
163 }
164
165 /// Range over argument types.
166 using arg_reverse_iterator =
167 SmallVectorImpl<ParamDescriptor>::const_reverse_iterator;
168 llvm::iterator_range<arg_reverse_iterator> args_reverse() const {
169 return llvm::reverse(C: ParamDescriptors);
170 }
171
172 /// Returns a specific scope.
173 Scope &getScope(unsigned Idx) { return Scopes[Idx]; }
174 const Scope &getScope(unsigned Idx) const { return Scopes[Idx]; }
175
176 /// Returns the source information at a given PC.
177 SourceInfo getSource(CodePtr PC) const;
178
179 /// Checks if the function is valid to call.
180 bool isValid() const { return IsValid; }
181
182 /// Checks if the function is virtual.
183 bool isVirtual() const { return Virtual; };
184 bool isImmediate() const { return Immediate; }
185 bool isConstexpr() const { return Constexpr; }
186
187 /// Checks if the function is a constructor.
188 bool isConstructor() const {
189 return Kind == FunctionKind::Ctor || Kind == FunctionKind::CopyOrMoveCtor;
190 }
191 bool isCopyOrMoveConstructor() const {
192 return Kind == FunctionKind::CopyOrMoveCtor;
193 }
194
195 /// Checks if the function is a destructor.
196 bool isDestructor() const { return Kind == FunctionKind::Dtor; }
197 /// Checks if the function is copy or move operator.
198 bool isCopyOrMoveOperator() const {
199 return Kind == FunctionKind::CopyOrMoveOperator;
200 }
201
202 /// Returns whether this function is a lambda static invoker,
203 /// which we generate custom byte code for.
204 bool isLambdaStaticInvoker() const {
205 return Kind == FunctionKind::LambdaStaticInvoker;
206 }
207
208 /// Returns whether this function is the call operator
209 /// of a lambda record decl.
210 bool isLambdaCallOperator() const {
211 return Kind == FunctionKind::LambdaCallOperator;
212 }
213
214 /// Returns the parent record decl, if any.
215 const CXXRecordDecl *getParentDecl() const {
216 if (const auto *MD = dyn_cast_if_present<CXXMethodDecl>(
217 Val: dyn_cast<const FunctionDecl *>(Val: Source)))
218 return MD->getParent();
219 return nullptr;
220 }
221
222 /// Checks if the function is fully done compiling.
223 bool isFullyCompiled() const { return IsFullyCompiled; }
224
225 bool hasThisPointer() const { return HasThisPointer; }
226 bool hasExplicitThisPointer() const {
227 return HasThisPointer && ExplicitThisPointer;
228 }
229 bool hasImplicitThisPointer() const {
230 return HasThisPointer && !ExplicitThisPointer;
231 }
232
233 /// Checks if the function already has a body attached.
234 bool hasBody() const { return HasBody; }
235
236 /// Checks if the function is defined.
237 bool isDefined() const { return Defined; }
238
239 bool isVariadic() const { return Variadic; }
240 unsigned getNumParams() const {
241 return ParamDescriptors.size() + hasThisPointer() + hasRVO();
242 }
243
244 /// Returns the number of parameter this function takes when it's called,
245 /// i.e excluding the instance pointer and the RVO pointer.
246 unsigned getNumWrittenParams() const {
247 assert(getNumParams() >= (unsigned)(hasThisPointer() + hasRVO()));
248 return ParamDescriptors.size();
249 }
250 unsigned getWrittenArgSize() const {
251 return ArgSize - (align(Size: primSize(Type: PT_Ptr)) * (hasThisPointer() + hasRVO()));
252 }
253
254private:
255 /// Construct a function representing an actual function.
256 Function(FunctionDeclTy Source, unsigned ArgSize,
257 llvm::SmallVectorImpl<ParamDescriptor> &&ParamDescriptors,
258 bool HasThisPointer, bool HasRVO, bool IsLambdaStaticInvoker);
259
260 /// Sets the code of a function.
261 void setCode(FunctionDeclTy Source, unsigned NewFrameSize,
262 llvm::SmallVector<std::byte> &&NewCode, SourceMap &&NewSrcMap,
263 llvm::SmallVector<Scope, 2> &&NewScopes, bool NewHasBody,
264 bool NewIsValid) {
265 this->Source = Source;
266 FrameSize = NewFrameSize;
267 Code = std::move(NewCode);
268 SrcMap = std::move(NewSrcMap);
269 Scopes = std::move(NewScopes);
270 IsValid = NewIsValid;
271 HasBody = NewHasBody;
272 }
273
274 void setIsFullyCompiled(bool FC) { IsFullyCompiled = FC; }
275 void setDefined(bool D) { Defined = D; }
276
277private:
278 friend class Program;
279 friend class ByteCodeEmitter;
280 friend class Context;
281
282 /// Function Kind.
283 FunctionKind Kind;
284 /// Declaration this function was compiled from.
285 FunctionDeclTy Source;
286 /// Local area size: storage + metadata.
287 unsigned FrameSize = 0;
288 /// Size of the argument stack.
289 unsigned ArgSize;
290 /// Program code.
291 llvm::SmallVector<std::byte> Code;
292 /// Opcode-to-expression mapping.
293 SourceMap SrcMap;
294 /// List of block descriptors.
295 llvm::SmallVector<Scope, 2> Scopes;
296 /// List of all parameters, including RVO and instance pointer.
297 llvm::SmallVector<ParamDescriptor> ParamDescriptors;
298 /// Flag to indicate if the function is valid.
299 LLVM_PREFERRED_TYPE(bool)
300 unsigned IsValid : 1;
301 /// Flag to indicate if the function is done being
302 /// compiled to bytecode.
303 LLVM_PREFERRED_TYPE(bool)
304 unsigned IsFullyCompiled : 1;
305 /// Flag indicating if this function takes the this pointer
306 /// as the first implicit argument
307 LLVM_PREFERRED_TYPE(bool)
308 unsigned HasThisPointer : 1;
309 LLVM_PREFERRED_TYPE(bool)
310 unsigned ExplicitThisPointer : 1;
311 /// Whether this function has Return Value Optimization, i.e.
312 /// the return value is constructed in the caller's stack frame.
313 /// This is done for functions that return non-primive values.
314 LLVM_PREFERRED_TYPE(bool)
315 unsigned HasRVO : 1;
316 /// If we've already compiled the function's body.
317 LLVM_PREFERRED_TYPE(bool)
318 unsigned HasBody : 1;
319 LLVM_PREFERRED_TYPE(bool)
320 unsigned Defined : 1;
321 LLVM_PREFERRED_TYPE(bool)
322 unsigned Variadic : 1;
323 LLVM_PREFERRED_TYPE(bool)
324 unsigned Virtual : 1;
325 LLVM_PREFERRED_TYPE(bool)
326 unsigned Immediate : 1;
327 LLVM_PREFERRED_TYPE(bool)
328 unsigned Constexpr : 1;
329
330public:
331 /// Dumps the disassembled bytecode to \c llvm::errs().
332 void dump() const { dump(PC: {}); }
333 void dump(CodePtr PC) const;
334 void dump(llvm::raw_ostream &OS, CodePtr PC = {}) const;
335};
336
337} // namespace interp
338} // namespace clang
339
340#endif
341