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