xref: /freebsd-src/contrib/llvm-project/clang/lib/AST/Interp/Function.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1a7dea167SDimitry Andric //===--- Function.h - Bytecode function for the VM --------------*- C++ -*-===//
2a7dea167SDimitry Andric //
3a7dea167SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4a7dea167SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5a7dea167SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6a7dea167SDimitry Andric //
7a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
8a7dea167SDimitry Andric //
9a7dea167SDimitry Andric // Defines the Function class which holds all bytecode function-specific data.
10a7dea167SDimitry Andric //
11a7dea167SDimitry Andric // The scope class which describes local variables is also defined here.
12a7dea167SDimitry Andric //
13a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
14a7dea167SDimitry Andric 
15a7dea167SDimitry Andric #ifndef LLVM_CLANG_AST_INTERP_FUNCTION_H
16a7dea167SDimitry Andric #define LLVM_CLANG_AST_INTERP_FUNCTION_H
17a7dea167SDimitry Andric 
185f757f3fSDimitry Andric #include "Descriptor.h"
19*0fca6ea1SDimitry Andric #include "Source.h"
205f757f3fSDimitry Andric #include "clang/AST/ASTLambda.h"
21*0fca6ea1SDimitry Andric #include "clang/AST/Attr.h"
22a7dea167SDimitry Andric #include "clang/AST/Decl.h"
23a7dea167SDimitry Andric #include "llvm/Support/raw_ostream.h"
24a7dea167SDimitry Andric 
25a7dea167SDimitry Andric namespace clang {
26a7dea167SDimitry Andric namespace interp {
27a7dea167SDimitry Andric class Program;
28a7dea167SDimitry Andric class ByteCodeEmitter;
295f757f3fSDimitry Andric class Pointer;
30a7dea167SDimitry Andric enum PrimType : uint32_t;
31a7dea167SDimitry Andric 
32a7dea167SDimitry Andric /// Describes a scope block.
33a7dea167SDimitry Andric ///
34a7dea167SDimitry Andric /// The block gathers all the descriptors of the locals defined in this block.
35bdd1243dSDimitry Andric class Scope final {
36a7dea167SDimitry Andric public:
37a7dea167SDimitry Andric   /// Information about a local's storage.
38a7dea167SDimitry Andric   struct Local {
39a7dea167SDimitry Andric     /// Offset of the local in frame.
40a7dea167SDimitry Andric     unsigned Offset;
41a7dea167SDimitry Andric     /// Descriptor of the local.
42a7dea167SDimitry Andric     Descriptor *Desc;
43a7dea167SDimitry Andric   };
44a7dea167SDimitry Andric 
45a7dea167SDimitry Andric   using LocalVectorTy = llvm::SmallVector<Local, 8>;
46a7dea167SDimitry Andric 
47a7dea167SDimitry Andric   Scope(LocalVectorTy &&Descriptors) : Descriptors(std::move(Descriptors)) {}
48a7dea167SDimitry Andric 
49bdd1243dSDimitry Andric   llvm::iterator_range<LocalVectorTy::const_iterator> locals() const {
50a7dea167SDimitry Andric     return llvm::make_range(Descriptors.begin(), Descriptors.end());
51a7dea167SDimitry Andric   }
52a7dea167SDimitry Andric 
53a7dea167SDimitry Andric private:
54a7dea167SDimitry Andric   /// Object descriptors in this block.
55a7dea167SDimitry Andric   LocalVectorTy Descriptors;
56a7dea167SDimitry Andric };
57a7dea167SDimitry Andric 
58a7dea167SDimitry Andric /// Bytecode function.
59a7dea167SDimitry Andric ///
60a7dea167SDimitry Andric /// Contains links to the bytecode of the function, as well as metadata
61a7dea167SDimitry Andric /// describing all arguments and stack-local variables.
62bdd1243dSDimitry Andric ///
63bdd1243dSDimitry Andric /// # Calling Convention
64bdd1243dSDimitry Andric ///
65bdd1243dSDimitry Andric /// When calling a function, all argument values must be on the stack.
66bdd1243dSDimitry Andric ///
67bdd1243dSDimitry Andric /// If the function has a This pointer (i.e. hasThisPointer() returns true,
68bdd1243dSDimitry Andric /// the argument values need to be preceeded by a Pointer for the This object.
69bdd1243dSDimitry Andric ///
70bdd1243dSDimitry Andric /// If the function uses Return Value Optimization, the arguments (and
715f757f3fSDimitry Andric /// potentially the This pointer) need to be preceeded by a Pointer pointing
72bdd1243dSDimitry Andric /// to the location to construct the returned value.
73bdd1243dSDimitry Andric ///
74bdd1243dSDimitry Andric /// After the function has been called, it will remove all arguments,
75bdd1243dSDimitry Andric /// including RVO and This pointer, from the stack.
76bdd1243dSDimitry Andric ///
77bdd1243dSDimitry Andric class Function final {
78a7dea167SDimitry Andric public:
79a7dea167SDimitry Andric   using ParamDescriptor = std::pair<PrimType, Descriptor *>;
80a7dea167SDimitry Andric 
81a7dea167SDimitry Andric   /// Returns the size of the function's local stack.
82a7dea167SDimitry Andric   unsigned getFrameSize() const { return FrameSize; }
83bdd1243dSDimitry Andric   /// Returns the size of the argument stack.
84a7dea167SDimitry Andric   unsigned getArgSize() const { return ArgSize; }
85a7dea167SDimitry Andric 
86a7dea167SDimitry Andric   /// Returns a pointer to the start of the code.
87bdd1243dSDimitry Andric   CodePtr getCodeBegin() const { return Code.data(); }
88a7dea167SDimitry Andric   /// Returns a pointer to the end of the code.
89bdd1243dSDimitry Andric   CodePtr getCodeEnd() const { return Code.data() + Code.size(); }
90a7dea167SDimitry Andric 
91a7dea167SDimitry Andric   /// Returns the original FunctionDecl.
92a7dea167SDimitry Andric   const FunctionDecl *getDecl() const { return F; }
93a7dea167SDimitry Andric 
94bdd1243dSDimitry Andric   /// Returns the name of the function decl this code
95bdd1243dSDimitry Andric   /// was generated for.
9606c3fb27SDimitry Andric   const std::string getName() const {
9706c3fb27SDimitry Andric     if (!F)
9806c3fb27SDimitry Andric       return "<<expr>>";
9906c3fb27SDimitry Andric 
10006c3fb27SDimitry Andric     return F->getQualifiedNameAsString();
10106c3fb27SDimitry Andric   }
102bdd1243dSDimitry Andric 
103349cc55cSDimitry Andric   /// Returns the location.
104a7dea167SDimitry Andric   SourceLocation getLoc() const { return Loc; }
105a7dea167SDimitry Andric 
106a7dea167SDimitry Andric   /// Returns a parameter descriptor.
107a7dea167SDimitry Andric   ParamDescriptor getParamDescriptor(unsigned Offset) const;
108a7dea167SDimitry Andric 
109a7dea167SDimitry Andric   /// Checks if the first argument is a RVO pointer.
110bdd1243dSDimitry Andric   bool hasRVO() const { return HasRVO; }
111a7dea167SDimitry Andric 
112*0fca6ea1SDimitry Andric   bool hasNonNullAttr() const { return getDecl()->hasAttr<NonNullAttr>(); }
113*0fca6ea1SDimitry Andric 
114a7dea167SDimitry Andric   /// Range over the scope blocks.
115bdd1243dSDimitry Andric   llvm::iterator_range<llvm::SmallVector<Scope, 2>::const_iterator>
116bdd1243dSDimitry Andric   scopes() const {
117a7dea167SDimitry Andric     return llvm::make_range(Scopes.begin(), Scopes.end());
118a7dea167SDimitry Andric   }
119a7dea167SDimitry Andric 
120a7dea167SDimitry Andric   /// Range over argument types.
121bdd1243dSDimitry Andric   using arg_reverse_iterator =
122bdd1243dSDimitry Andric       SmallVectorImpl<PrimType>::const_reverse_iterator;
123bdd1243dSDimitry Andric   llvm::iterator_range<arg_reverse_iterator> args_reverse() const {
124bdd1243dSDimitry Andric     return llvm::reverse(ParamTypes);
125a7dea167SDimitry Andric   }
126a7dea167SDimitry Andric 
127a7dea167SDimitry Andric   /// Returns a specific scope.
128a7dea167SDimitry Andric   Scope &getScope(unsigned Idx) { return Scopes[Idx]; }
129bdd1243dSDimitry Andric   const Scope &getScope(unsigned Idx) const { return Scopes[Idx]; }
130a7dea167SDimitry Andric 
131a7dea167SDimitry Andric   /// Returns the source information at a given PC.
132a7dea167SDimitry Andric   SourceInfo getSource(CodePtr PC) const;
133a7dea167SDimitry Andric 
134a7dea167SDimitry Andric   /// Checks if the function is valid to call in constexpr.
1355f757f3fSDimitry Andric   bool isConstexpr() const { return IsValid || isLambdaStaticInvoker(); }
136a7dea167SDimitry Andric 
137a7dea167SDimitry Andric   /// Checks if the function is virtual.
138a7dea167SDimitry Andric   bool isVirtual() const;
139a7dea167SDimitry Andric 
140a7dea167SDimitry Andric   /// Checks if the function is a constructor.
141a7dea167SDimitry Andric   bool isConstructor() const { return isa<CXXConstructorDecl>(F); }
14206c3fb27SDimitry Andric   /// Checks if the function is a destructor.
14306c3fb27SDimitry Andric   bool isDestructor() const { return isa<CXXDestructorDecl>(F); }
14406c3fb27SDimitry Andric 
14506c3fb27SDimitry Andric   /// Returns the parent record decl, if any.
14606c3fb27SDimitry Andric   const CXXRecordDecl *getParentDecl() const {
14706c3fb27SDimitry Andric     if (const auto *MD = dyn_cast<CXXMethodDecl>(F))
14806c3fb27SDimitry Andric       return MD->getParent();
14906c3fb27SDimitry Andric     return nullptr;
15006c3fb27SDimitry Andric   }
151a7dea167SDimitry Andric 
1525f757f3fSDimitry Andric   /// Returns whether this function is a lambda static invoker,
1535f757f3fSDimitry Andric   /// which we generate custom byte code for.
1545f757f3fSDimitry Andric   bool isLambdaStaticInvoker() const {
1555f757f3fSDimitry Andric     if (const auto *MD = dyn_cast<CXXMethodDecl>(F))
1565f757f3fSDimitry Andric       return MD->isLambdaStaticInvoker();
1575f757f3fSDimitry Andric     return false;
1585f757f3fSDimitry Andric   }
1595f757f3fSDimitry Andric 
1605f757f3fSDimitry Andric   /// Returns whether this function is the call operator
1615f757f3fSDimitry Andric   /// of a lambda record decl.
1625f757f3fSDimitry Andric   bool isLambdaCallOperator() const {
1635f757f3fSDimitry Andric     if (const auto *MD = dyn_cast<CXXMethodDecl>(F))
1645f757f3fSDimitry Andric       return clang::isLambdaCallOperator(MD);
1655f757f3fSDimitry Andric     return false;
1665f757f3fSDimitry Andric   }
1675f757f3fSDimitry Andric 
168bdd1243dSDimitry Andric   /// Checks if the function is fully done compiling.
169bdd1243dSDimitry Andric   bool isFullyCompiled() const { return IsFullyCompiled; }
170bdd1243dSDimitry Andric 
171bdd1243dSDimitry Andric   bool hasThisPointer() const { return HasThisPointer; }
172bdd1243dSDimitry Andric 
17306c3fb27SDimitry Andric   /// Checks if the function already has a body attached.
174bdd1243dSDimitry Andric   bool hasBody() const { return HasBody; }
175bdd1243dSDimitry Andric 
1765f757f3fSDimitry Andric   /// Checks if the function is defined.
1775f757f3fSDimitry Andric   bool isDefined() const { return Defined; }
1785f757f3fSDimitry Andric 
1795f757f3fSDimitry Andric   bool isVariadic() const { return Variadic; }
1805f757f3fSDimitry Andric 
18106c3fb27SDimitry Andric   unsigned getBuiltinID() const { return F->getBuiltinID(); }
18206c3fb27SDimitry Andric 
1835f757f3fSDimitry Andric   bool isBuiltin() const { return F->getBuiltinID() != 0; }
1845f757f3fSDimitry Andric 
1855f757f3fSDimitry Andric   bool isUnevaluatedBuiltin() const { return IsUnevaluatedBuiltin; }
1865f757f3fSDimitry Andric 
187bdd1243dSDimitry Andric   unsigned getNumParams() const { return ParamTypes.size(); }
188bdd1243dSDimitry Andric 
189*0fca6ea1SDimitry Andric   /// Returns the number of parameter this function takes when it's called,
190*0fca6ea1SDimitry Andric   /// i.e excluding the instance pointer and the RVO pointer.
191*0fca6ea1SDimitry Andric   unsigned getNumWrittenParams() const {
192*0fca6ea1SDimitry Andric     assert(getNumParams() >= (unsigned)(hasThisPointer() + hasRVO()));
193*0fca6ea1SDimitry Andric     return getNumParams() - hasThisPointer() - hasRVO();
194*0fca6ea1SDimitry Andric   }
195*0fca6ea1SDimitry Andric   unsigned getWrittenArgSize() const {
196*0fca6ea1SDimitry Andric     return ArgSize - (align(primSize(PT_Ptr)) * (hasThisPointer() + hasRVO()));
197*0fca6ea1SDimitry Andric   }
198*0fca6ea1SDimitry Andric 
199*0fca6ea1SDimitry Andric   bool isThisPointerExplicit() const {
200*0fca6ea1SDimitry Andric     if (const auto *MD = dyn_cast<CXXMethodDecl>(F))
201*0fca6ea1SDimitry Andric       return MD->isExplicitObjectMemberFunction();
202*0fca6ea1SDimitry Andric     return false;
203*0fca6ea1SDimitry Andric   }
204*0fca6ea1SDimitry Andric 
20506c3fb27SDimitry Andric   unsigned getParamOffset(unsigned ParamIndex) const {
20606c3fb27SDimitry Andric     return ParamOffsets[ParamIndex];
20706c3fb27SDimitry Andric   }
20806c3fb27SDimitry Andric 
209a7dea167SDimitry Andric private:
210a7dea167SDimitry Andric   /// Construct a function representing an actual function.
211a7dea167SDimitry Andric   Function(Program &P, const FunctionDecl *F, unsigned ArgSize,
21206c3fb27SDimitry Andric            llvm::SmallVectorImpl<PrimType> &&ParamTypes,
213bdd1243dSDimitry Andric            llvm::DenseMap<unsigned, ParamDescriptor> &&Params,
21406c3fb27SDimitry Andric            llvm::SmallVectorImpl<unsigned> &&ParamOffsets, bool HasThisPointer,
2155f757f3fSDimitry Andric            bool HasRVO, bool UnevaluatedBuiltin);
216a7dea167SDimitry Andric 
217a7dea167SDimitry Andric   /// Sets the code of a function.
21806c3fb27SDimitry Andric   void setCode(unsigned NewFrameSize, std::vector<std::byte> &&NewCode,
21906c3fb27SDimitry Andric                SourceMap &&NewSrcMap, llvm::SmallVector<Scope, 2> &&NewScopes,
22006c3fb27SDimitry Andric                bool NewHasBody) {
221a7dea167SDimitry Andric     FrameSize = NewFrameSize;
222a7dea167SDimitry Andric     Code = std::move(NewCode);
223a7dea167SDimitry Andric     SrcMap = std::move(NewSrcMap);
224a7dea167SDimitry Andric     Scopes = std::move(NewScopes);
225a7dea167SDimitry Andric     IsValid = true;
22606c3fb27SDimitry Andric     HasBody = NewHasBody;
227a7dea167SDimitry Andric   }
228a7dea167SDimitry Andric 
229bdd1243dSDimitry Andric   void setIsFullyCompiled(bool FC) { IsFullyCompiled = FC; }
2305f757f3fSDimitry Andric   void setDefined(bool D) { Defined = D; }
231bdd1243dSDimitry Andric 
232a7dea167SDimitry Andric private:
233a7dea167SDimitry Andric   friend class Program;
234a7dea167SDimitry Andric   friend class ByteCodeEmitter;
235a7dea167SDimitry Andric 
236a7dea167SDimitry Andric   /// Program reference.
237a7dea167SDimitry Andric   Program &P;
238a7dea167SDimitry Andric   /// Location of the executed code.
239a7dea167SDimitry Andric   SourceLocation Loc;
240a7dea167SDimitry Andric   /// Declaration this function was compiled from.
241a7dea167SDimitry Andric   const FunctionDecl *F;
242a7dea167SDimitry Andric   /// Local area size: storage + metadata.
243bdd1243dSDimitry Andric   unsigned FrameSize = 0;
244a7dea167SDimitry Andric   /// Size of the argument stack.
245a7dea167SDimitry Andric   unsigned ArgSize;
246a7dea167SDimitry Andric   /// Program code.
24706c3fb27SDimitry Andric   std::vector<std::byte> Code;
248a7dea167SDimitry Andric   /// Opcode-to-expression mapping.
249a7dea167SDimitry Andric   SourceMap SrcMap;
250a7dea167SDimitry Andric   /// List of block descriptors.
251a7dea167SDimitry Andric   llvm::SmallVector<Scope, 2> Scopes;
252a7dea167SDimitry Andric   /// List of argument types.
253a7dea167SDimitry Andric   llvm::SmallVector<PrimType, 8> ParamTypes;
254a7dea167SDimitry Andric   /// Map from byte offset to parameter descriptor.
255a7dea167SDimitry Andric   llvm::DenseMap<unsigned, ParamDescriptor> Params;
25606c3fb27SDimitry Andric   /// List of parameter offsets.
25706c3fb27SDimitry Andric   llvm::SmallVector<unsigned, 8> ParamOffsets;
258a7dea167SDimitry Andric   /// Flag to indicate if the function is valid.
259a7dea167SDimitry Andric   bool IsValid = false;
260bdd1243dSDimitry Andric   /// Flag to indicate if the function is done being
261bdd1243dSDimitry Andric   /// compiled to bytecode.
262bdd1243dSDimitry Andric   bool IsFullyCompiled = false;
263bdd1243dSDimitry Andric   /// Flag indicating if this function takes the this pointer
264bdd1243dSDimitry Andric   /// as the first implicit argument
265bdd1243dSDimitry Andric   bool HasThisPointer = false;
266bdd1243dSDimitry Andric   /// Whether this function has Return Value Optimization, i.e.
267bdd1243dSDimitry Andric   /// the return value is constructed in the caller's stack frame.
268bdd1243dSDimitry Andric   /// This is done for functions that return non-primive values.
269bdd1243dSDimitry Andric   bool HasRVO = false;
270bdd1243dSDimitry Andric   /// If we've already compiled the function's body.
271bdd1243dSDimitry Andric   bool HasBody = false;
2725f757f3fSDimitry Andric   bool Defined = false;
2735f757f3fSDimitry Andric   bool Variadic = false;
2745f757f3fSDimitry Andric   bool IsUnevaluatedBuiltin = false;
275a7dea167SDimitry Andric 
276a7dea167SDimitry Andric public:
277a7dea167SDimitry Andric   /// Dumps the disassembled bytecode to \c llvm::errs().
278a7dea167SDimitry Andric   void dump() const;
279a7dea167SDimitry Andric   void dump(llvm::raw_ostream &OS) const;
280a7dea167SDimitry Andric };
281a7dea167SDimitry Andric 
282a7dea167SDimitry Andric } // namespace interp
283a7dea167SDimitry Andric } // namespace clang
284a7dea167SDimitry Andric 
285a7dea167SDimitry Andric #endif
286