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