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