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 "Source.h"
19 #include "Descriptor.h"
20 #include "clang/AST/ASTLambda.h"
21 #include "clang/AST/Decl.h"
22 #include "llvm/Support/raw_ostream.h"
23 
24 namespace clang {
25 namespace interp {
26 class Program;
27 class ByteCodeEmitter;
28 class Pointer;
29 enum PrimType : uint32_t;
30 
31 /// Describes a scope block.
32 ///
33 /// The block gathers all the descriptors of the locals defined in this block.
34 class Scope final {
35 public:
36   /// Information about a local's storage.
37   struct Local {
38     /// Offset of the local in frame.
39     unsigned Offset;
40     /// Descriptor of the local.
41     Descriptor *Desc;
42   };
43 
44   using LocalVectorTy = llvm::SmallVector<Local, 8>;
45 
Scope(LocalVectorTy && Descriptors)46   Scope(LocalVectorTy &&Descriptors) : Descriptors(std::move(Descriptors)) {}
47 
locals()48   llvm::iterator_range<LocalVectorTy::const_iterator> locals() const {
49     return llvm::make_range(Descriptors.begin(), Descriptors.end());
50   }
51 
52 private:
53   /// Object descriptors in this block.
54   LocalVectorTy Descriptors;
55 };
56 
57 /// Bytecode function.
58 ///
59 /// Contains links to the bytecode of the function, as well as metadata
60 /// describing all arguments and stack-local variables.
61 ///
62 /// # Calling Convention
63 ///
64 /// When calling a function, all argument values must be on the stack.
65 ///
66 /// If the function has a This pointer (i.e. hasThisPointer() returns true,
67 /// the argument values need to be preceeded by a Pointer for the This object.
68 ///
69 /// If the function uses Return Value Optimization, the arguments (and
70 /// potentially the This pointer) need to be preceeded by a Pointer pointing
71 /// to the location to construct the returned value.
72 ///
73 /// After the function has been called, it will remove all arguments,
74 /// including RVO and This pointer, from the stack.
75 ///
76 class Function final {
77 public:
78   using ParamDescriptor = std::pair<PrimType, Descriptor *>;
79 
80   /// Returns the size of the function's local stack.
getFrameSize()81   unsigned getFrameSize() const { return FrameSize; }
82   /// Returns the size of the argument stack.
getArgSize()83   unsigned getArgSize() const { return ArgSize; }
84 
85   /// Returns a pointer to the start of the code.
getCodeBegin()86   CodePtr getCodeBegin() const { return Code.data(); }
87   /// Returns a pointer to the end of the code.
getCodeEnd()88   CodePtr getCodeEnd() const { return Code.data() + Code.size(); }
89 
90   /// Returns the original FunctionDecl.
getDecl()91   const FunctionDecl *getDecl() const { return F; }
92 
93   /// Returns the name of the function decl this code
94   /// was generated for.
getName()95   const std::string getName() const {
96     if (!F)
97       return "<<expr>>";
98 
99     return F->getQualifiedNameAsString();
100   }
101 
102   /// Returns the location.
getLoc()103   SourceLocation getLoc() const { return Loc; }
104 
105   /// Returns a parameter descriptor.
106   ParamDescriptor getParamDescriptor(unsigned Offset) const;
107 
108   /// Checks if the first argument is a RVO pointer.
hasRVO()109   bool hasRVO() const { return HasRVO; }
110 
111   /// Range over the scope blocks.
112   llvm::iterator_range<llvm::SmallVector<Scope, 2>::const_iterator>
scopes()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;
args_reverse()120   llvm::iterator_range<arg_reverse_iterator> args_reverse() const {
121     return llvm::reverse(ParamTypes);
122   }
123 
124   /// Returns a specific scope.
getScope(unsigned Idx)125   Scope &getScope(unsigned Idx) { return Scopes[Idx]; }
getScope(unsigned 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.
isConstexpr()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.
isConstructor()138   bool isConstructor() const { return isa<CXXConstructorDecl>(F); }
139   /// Checks if the function is a destructor.
isDestructor()140   bool isDestructor() const { return isa<CXXDestructorDecl>(F); }
141 
142   /// Returns the parent record decl, if any.
getParentDecl()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.
isLambdaStaticInvoker()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.
isLambdaCallOperator()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.
isFullyCompiled()166   bool isFullyCompiled() const { return IsFullyCompiled; }
167 
hasThisPointer()168   bool hasThisPointer() const { return HasThisPointer; }
169 
170   /// Checks if the function already has a body attached.
hasBody()171   bool hasBody() const { return HasBody; }
172 
173   /// Checks if the function is defined.
isDefined()174   bool isDefined() const { return Defined; }
175 
isVariadic()176   bool isVariadic() const { return Variadic; }
177 
getBuiltinID()178   unsigned getBuiltinID() const { return F->getBuiltinID(); }
179 
isBuiltin()180   bool isBuiltin() const { return F->getBuiltinID() != 0; }
181 
isUnevaluatedBuiltin()182   bool isUnevaluatedBuiltin() const { return IsUnevaluatedBuiltin; }
183 
getNumParams()184   unsigned getNumParams() const { return ParamTypes.size(); }
185 
getParamOffset(unsigned ParamIndex)186   unsigned getParamOffset(unsigned ParamIndex) const {
187     return ParamOffsets[ParamIndex];
188   }
189 
190 private:
191   /// Construct a function representing an actual function.
192   Function(Program &P, const FunctionDecl *F, unsigned ArgSize,
193            llvm::SmallVectorImpl<PrimType> &&ParamTypes,
194            llvm::DenseMap<unsigned, ParamDescriptor> &&Params,
195            llvm::SmallVectorImpl<unsigned> &&ParamOffsets, bool HasThisPointer,
196            bool HasRVO, bool UnevaluatedBuiltin);
197 
198   /// Sets the code of a function.
setCode(unsigned NewFrameSize,std::vector<std::byte> && NewCode,SourceMap && NewSrcMap,llvm::SmallVector<Scope,2> && NewScopes,bool NewHasBody)199   void setCode(unsigned NewFrameSize, std::vector<std::byte> &&NewCode,
200                SourceMap &&NewSrcMap, llvm::SmallVector<Scope, 2> &&NewScopes,
201                bool NewHasBody) {
202     FrameSize = NewFrameSize;
203     Code = std::move(NewCode);
204     SrcMap = std::move(NewSrcMap);
205     Scopes = std::move(NewScopes);
206     IsValid = true;
207     HasBody = NewHasBody;
208   }
209 
setIsFullyCompiled(bool FC)210   void setIsFullyCompiled(bool FC) { IsFullyCompiled = FC; }
setDefined(bool D)211   void setDefined(bool D) { Defined = D; }
212 
213 private:
214   friend class Program;
215   friend class ByteCodeEmitter;
216 
217   /// Program reference.
218   Program &P;
219   /// Location of the executed code.
220   SourceLocation Loc;
221   /// Declaration this function was compiled from.
222   const FunctionDecl *F;
223   /// Local area size: storage + metadata.
224   unsigned FrameSize = 0;
225   /// Size of the argument stack.
226   unsigned ArgSize;
227   /// Program code.
228   std::vector<std::byte> Code;
229   /// Opcode-to-expression mapping.
230   SourceMap SrcMap;
231   /// List of block descriptors.
232   llvm::SmallVector<Scope, 2> Scopes;
233   /// List of argument types.
234   llvm::SmallVector<PrimType, 8> ParamTypes;
235   /// Map from byte offset to parameter descriptor.
236   llvm::DenseMap<unsigned, ParamDescriptor> Params;
237   /// List of parameter offsets.
238   llvm::SmallVector<unsigned, 8> ParamOffsets;
239   /// Flag to indicate if the function is valid.
240   bool IsValid = false;
241   /// Flag to indicate if the function is done being
242   /// compiled to bytecode.
243   bool IsFullyCompiled = false;
244   /// Flag indicating if this function takes the this pointer
245   /// as the first implicit argument
246   bool HasThisPointer = false;
247   /// Whether this function has Return Value Optimization, i.e.
248   /// the return value is constructed in the caller's stack frame.
249   /// This is done for functions that return non-primive values.
250   bool HasRVO = false;
251   /// If we've already compiled the function's body.
252   bool HasBody = false;
253   bool Defined = false;
254   bool Variadic = false;
255   bool IsUnevaluatedBuiltin = false;
256 
257 public:
258   /// Dumps the disassembled bytecode to \c llvm::errs().
259   void dump() const;
260   void dump(llvm::raw_ostream &OS) const;
261 };
262 
263 } // namespace interp
264 } // namespace clang
265 
266 #endif
267