xref: /llvm-project/clang/lib/AST/ByteCode/Function.h (revision a07aba5d44204a7ca0d891a3da05af9960081e4c)
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 
47   Scope(LocalVectorTy &&Descriptors) : Descriptors(std::move(Descriptors)) {}
48 
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.
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 a parameter descriptor.
104   ParamDescriptor getParamDescriptor(unsigned Offset) const;
105 
106   /// Checks if the first argument is a RVO pointer.
107   bool hasRVO() const { return HasRVO; }
108 
109   bool hasNonNullAttr() const { return getDecl()->hasAttr<NonNullAttr>(); }
110 
111   /// Range over the scope blocks.
112   llvm::iterator_range<llvm::SmallVector<Scope, 2>::const_iterator>
113   scopes() const {
114     return llvm::make_range(Scopes.begin(), Scopes.end());
115   }
116 
117   /// Range over argument types.
118   using arg_reverse_iterator =
119       SmallVectorImpl<PrimType>::const_reverse_iterator;
120   llvm::iterator_range<arg_reverse_iterator> args_reverse() const {
121     return llvm::reverse(ParamTypes);
122   }
123 
124   /// Returns a specific scope.
125   Scope &getScope(unsigned Idx) { return Scopes[Idx]; }
126   const Scope &getScope(unsigned Idx) const { return Scopes[Idx]; }
127 
128   /// Returns the source information at a given PC.
129   SourceInfo getSource(CodePtr PC) const;
130 
131   /// Checks if the function is valid to call in constexpr.
132   bool isConstexpr() const { return IsValid || isLambdaStaticInvoker(); }
133 
134   /// Checks if the function is virtual.
135   bool isVirtual() const;
136 
137   /// Checks if the function is a constructor.
138   bool isConstructor() const { return isa<CXXConstructorDecl>(F); }
139   /// Checks if the function is a destructor.
140   bool isDestructor() const { return isa<CXXDestructorDecl>(F); }
141 
142   /// Returns the parent record decl, if any.
143   const CXXRecordDecl *getParentDecl() const {
144     if (const auto *MD = dyn_cast<CXXMethodDecl>(F))
145       return MD->getParent();
146     return nullptr;
147   }
148 
149   /// Returns whether this function is a lambda static invoker,
150   /// which we generate custom byte code for.
151   bool isLambdaStaticInvoker() const {
152     if (const auto *MD = dyn_cast<CXXMethodDecl>(F))
153       return MD->isLambdaStaticInvoker();
154     return false;
155   }
156 
157   /// Returns whether this function is the call operator
158   /// of a lambda record decl.
159   bool isLambdaCallOperator() const {
160     if (const auto *MD = dyn_cast<CXXMethodDecl>(F))
161       return clang::isLambdaCallOperator(MD);
162     return false;
163   }
164 
165   /// Checks if the function is fully done compiling.
166   bool isFullyCompiled() const { return IsFullyCompiled; }
167 
168   bool hasThisPointer() const { return HasThisPointer; }
169 
170   /// Checks if the function already has a body attached.
171   bool hasBody() const { return HasBody; }
172 
173   /// Checks if the function is defined.
174   bool isDefined() const { return Defined; }
175 
176   bool isVariadic() const { return Variadic; }
177 
178   unsigned getBuiltinID() const { return F->getBuiltinID(); }
179 
180   bool isBuiltin() const { return F->getBuiltinID() != 0; }
181 
182   bool isUnevaluatedBuiltin() const { return IsUnevaluatedBuiltin; }
183 
184   unsigned getNumParams() const { return ParamTypes.size(); }
185 
186   /// Returns the number of parameter this function takes when it's called,
187   /// i.e excluding the instance pointer and the RVO pointer.
188   unsigned getNumWrittenParams() const {
189     assert(getNumParams() >= (unsigned)(hasThisPointer() + hasRVO()));
190     return getNumParams() - hasThisPointer() - hasRVO();
191   }
192   unsigned getWrittenArgSize() const {
193     return ArgSize - (align(primSize(PT_Ptr)) * (hasThisPointer() + hasRVO()));
194   }
195 
196   bool isThisPointerExplicit() const {
197     if (const auto *MD = dyn_cast<CXXMethodDecl>(F))
198       return MD->isExplicitObjectMemberFunction();
199     return false;
200   }
201 
202   unsigned getParamOffset(unsigned ParamIndex) const {
203     return ParamOffsets[ParamIndex];
204   }
205 
206 private:
207   /// Construct a function representing an actual function.
208   Function(Program &P, const FunctionDecl *F, unsigned ArgSize,
209            llvm::SmallVectorImpl<PrimType> &&ParamTypes,
210            llvm::DenseMap<unsigned, ParamDescriptor> &&Params,
211            llvm::SmallVectorImpl<unsigned> &&ParamOffsets, bool HasThisPointer,
212            bool HasRVO, bool UnevaluatedBuiltin);
213 
214   /// Sets the code of a function.
215   void setCode(unsigned NewFrameSize, std::vector<std::byte> &&NewCode,
216                SourceMap &&NewSrcMap, llvm::SmallVector<Scope, 2> &&NewScopes,
217                bool NewHasBody) {
218     FrameSize = NewFrameSize;
219     Code = std::move(NewCode);
220     SrcMap = std::move(NewSrcMap);
221     Scopes = std::move(NewScopes);
222     IsValid = true;
223     HasBody = NewHasBody;
224   }
225 
226   void setIsFullyCompiled(bool FC) { IsFullyCompiled = FC; }
227   void setDefined(bool D) { Defined = D; }
228 
229 private:
230   friend class Program;
231   friend class ByteCodeEmitter;
232 
233   /// Program reference.
234   Program &P;
235   /// Declaration this function was compiled from.
236   const FunctionDecl *F;
237   /// Local area size: storage + metadata.
238   unsigned FrameSize = 0;
239   /// Size of the argument stack.
240   unsigned ArgSize;
241   /// Program code.
242   std::vector<std::byte> Code;
243   /// Opcode-to-expression mapping.
244   SourceMap SrcMap;
245   /// List of block descriptors.
246   llvm::SmallVector<Scope, 2> Scopes;
247   /// List of argument types.
248   llvm::SmallVector<PrimType, 8> ParamTypes;
249   /// Map from byte offset to parameter descriptor.
250   llvm::DenseMap<unsigned, ParamDescriptor> Params;
251   /// List of parameter offsets.
252   llvm::SmallVector<unsigned, 8> ParamOffsets;
253   /// Flag to indicate if the function is valid.
254   bool IsValid = false;
255   /// Flag to indicate if the function is done being
256   /// compiled to bytecode.
257   bool IsFullyCompiled = false;
258   /// Flag indicating if this function takes the this pointer
259   /// as the first implicit argument
260   bool HasThisPointer = false;
261   /// Whether this function has Return Value Optimization, i.e.
262   /// the return value is constructed in the caller's stack frame.
263   /// This is done for functions that return non-primive values.
264   bool HasRVO = false;
265   /// If we've already compiled the function's body.
266   bool HasBody = false;
267   bool Defined = false;
268   bool Variadic = false;
269   bool IsUnevaluatedBuiltin = false;
270 
271 public:
272   /// Dumps the disassembled bytecode to \c llvm::errs().
273   void dump() const;
274   void dump(llvm::raw_ostream &OS) const;
275 };
276 
277 } // namespace interp
278 } // namespace clang
279 
280 #endif
281