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