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
25namespace clang {
26namespace interp {
27class Program;
28class ByteCodeEmitter;
29class Pointer;
30enum PrimType : uint32_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 /// 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
53private:
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///
77class Function final {
78public:
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
209private:
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
232private:
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
276public:
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