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