xref: /freebsd/contrib/llvm-project/clang/lib/AST/Interp/Function.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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 
Scope(LocalVectorTy && Descriptors)47   Scope(LocalVectorTy &&Descriptors) : Descriptors(std::move(Descriptors)) {}
48 
locals()49   llvm::iterator_range<LocalVectorTy::const_iterator> locals() const {
50     return llvm::make_range(Descriptors.begin(), 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.
getFrameSize()82   unsigned getFrameSize() const { return FrameSize; }
83   /// Returns the size of the argument stack.
getArgSize()84   unsigned getArgSize() const { return ArgSize; }
85 
86   /// Returns a pointer to the start of the code.
getCodeBegin()87   CodePtr getCodeBegin() const { return Code.data(); }
88   /// Returns a pointer to the end of the code.
getCodeEnd()89   CodePtr getCodeEnd() const { return Code.data() + Code.size(); }
90 
91   /// Returns the original FunctionDecl.
getDecl()92   const FunctionDecl *getDecl() const { return F; }
93 
94   /// Returns the name of the function decl this code
95   /// was generated for.
getName()96   const std::string getName() const {
97     if (!F)
98       return "<<expr>>";
99 
100     return F->getQualifiedNameAsString();
101   }
102 
103   /// Returns the location.
getLoc()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.
hasRVO()110   bool hasRVO() const { return HasRVO; }
111 
hasNonNullAttr()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>
scopes()116   scopes() const {
117     return llvm::make_range(Scopes.begin(), Scopes.end());
118   }
119 
120   /// Range over argument types.
121   using arg_reverse_iterator =
122       SmallVectorImpl<PrimType>::const_reverse_iterator;
args_reverse()123   llvm::iterator_range<arg_reverse_iterator> args_reverse() const {
124     return llvm::reverse(ParamTypes);
125   }
126 
127   /// Returns a specific scope.
getScope(unsigned Idx)128   Scope &getScope(unsigned Idx) { return Scopes[Idx]; }
getScope(unsigned 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.
isConstexpr()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.
isConstructor()141   bool isConstructor() const { return isa<CXXConstructorDecl>(F); }
142   /// Checks if the function is a destructor.
isDestructor()143   bool isDestructor() const { return isa<CXXDestructorDecl>(F); }
144 
145   /// Returns the parent record decl, if any.
getParentDecl()146   const CXXRecordDecl *getParentDecl() const {
147     if (const auto *MD = dyn_cast<CXXMethodDecl>(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.
isLambdaStaticInvoker()154   bool isLambdaStaticInvoker() const {
155     if (const auto *MD = dyn_cast<CXXMethodDecl>(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.
isLambdaCallOperator()162   bool isLambdaCallOperator() const {
163     if (const auto *MD = dyn_cast<CXXMethodDecl>(F))
164       return clang::isLambdaCallOperator(MD);
165     return false;
166   }
167 
168   /// Checks if the function is fully done compiling.
isFullyCompiled()169   bool isFullyCompiled() const { return IsFullyCompiled; }
170 
hasThisPointer()171   bool hasThisPointer() const { return HasThisPointer; }
172 
173   /// Checks if the function already has a body attached.
hasBody()174   bool hasBody() const { return HasBody; }
175 
176   /// Checks if the function is defined.
isDefined()177   bool isDefined() const { return Defined; }
178 
isVariadic()179   bool isVariadic() const { return Variadic; }
180 
getBuiltinID()181   unsigned getBuiltinID() const { return F->getBuiltinID(); }
182 
isBuiltin()183   bool isBuiltin() const { return F->getBuiltinID() != 0; }
184 
isUnevaluatedBuiltin()185   bool isUnevaluatedBuiltin() const { return IsUnevaluatedBuiltin; }
186 
getNumParams()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.
getNumWrittenParams()191   unsigned getNumWrittenParams() const {
192     assert(getNumParams() >= (unsigned)(hasThisPointer() + hasRVO()));
193     return getNumParams() - hasThisPointer() - hasRVO();
194   }
getWrittenArgSize()195   unsigned getWrittenArgSize() const {
196     return ArgSize - (align(primSize(PT_Ptr)) * (hasThisPointer() + hasRVO()));
197   }
198 
isThisPointerExplicit()199   bool isThisPointerExplicit() const {
200     if (const auto *MD = dyn_cast<CXXMethodDecl>(F))
201       return MD->isExplicitObjectMemberFunction();
202     return false;
203   }
204 
getParamOffset(unsigned ParamIndex)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.
setCode(unsigned NewFrameSize,std::vector<std::byte> && NewCode,SourceMap && NewSrcMap,llvm::SmallVector<Scope,2> && NewScopes,bool NewHasBody)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 
setIsFullyCompiled(bool FC)229   void setIsFullyCompiled(bool FC) { IsFullyCompiled = FC; }
setDefined(bool D)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