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