xref: /openbsd/gnu/llvm/clang/lib/AST/Interp/Function.h (revision 12c85518)
1e5dd7070Spatrick //===--- Function.h - Bytecode function for the VM --------------*- C++ -*-===//
2e5dd7070Spatrick //
3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information.
5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e5dd7070Spatrick //
7e5dd7070Spatrick //===----------------------------------------------------------------------===//
8e5dd7070Spatrick //
9e5dd7070Spatrick // Defines the Function class which holds all bytecode function-specific data.
10e5dd7070Spatrick //
11e5dd7070Spatrick // The scope class which describes local variables is also defined here.
12e5dd7070Spatrick //
13e5dd7070Spatrick //===----------------------------------------------------------------------===//
14e5dd7070Spatrick 
15e5dd7070Spatrick #ifndef LLVM_CLANG_AST_INTERP_FUNCTION_H
16e5dd7070Spatrick #define LLVM_CLANG_AST_INTERP_FUNCTION_H
17e5dd7070Spatrick 
18e5dd7070Spatrick #include "Pointer.h"
19e5dd7070Spatrick #include "Source.h"
20e5dd7070Spatrick #include "clang/AST/Decl.h"
21e5dd7070Spatrick #include "llvm/Support/raw_ostream.h"
22e5dd7070Spatrick 
23e5dd7070Spatrick namespace clang {
24e5dd7070Spatrick namespace interp {
25e5dd7070Spatrick class Program;
26e5dd7070Spatrick class ByteCodeEmitter;
27e5dd7070Spatrick enum PrimType : uint32_t;
28e5dd7070Spatrick 
29e5dd7070Spatrick /// Describes a scope block.
30e5dd7070Spatrick ///
31e5dd7070Spatrick /// The block gathers all the descriptors of the locals defined in this block.
32*12c85518Srobert class Scope final {
33e5dd7070Spatrick public:
34e5dd7070Spatrick   /// Information about a local's storage.
35e5dd7070Spatrick   struct Local {
36e5dd7070Spatrick     /// Offset of the local in frame.
37e5dd7070Spatrick     unsigned Offset;
38e5dd7070Spatrick     /// Descriptor of the local.
39e5dd7070Spatrick     Descriptor *Desc;
40e5dd7070Spatrick   };
41e5dd7070Spatrick 
42e5dd7070Spatrick   using LocalVectorTy = llvm::SmallVector<Local, 8>;
43e5dd7070Spatrick 
Scope(LocalVectorTy && Descriptors)44e5dd7070Spatrick   Scope(LocalVectorTy &&Descriptors) : Descriptors(std::move(Descriptors)) {}
45e5dd7070Spatrick 
locals()46*12c85518Srobert   llvm::iterator_range<LocalVectorTy::const_iterator> locals() const {
47e5dd7070Spatrick     return llvm::make_range(Descriptors.begin(), Descriptors.end());
48e5dd7070Spatrick   }
49e5dd7070Spatrick 
50e5dd7070Spatrick private:
51e5dd7070Spatrick   /// Object descriptors in this block.
52e5dd7070Spatrick   LocalVectorTy Descriptors;
53e5dd7070Spatrick };
54e5dd7070Spatrick 
55e5dd7070Spatrick /// Bytecode function.
56e5dd7070Spatrick ///
57e5dd7070Spatrick /// Contains links to the bytecode of the function, as well as metadata
58e5dd7070Spatrick /// describing all arguments and stack-local variables.
59*12c85518Srobert ///
60*12c85518Srobert /// # Calling Convention
61*12c85518Srobert ///
62*12c85518Srobert /// When calling a function, all argument values must be on the stack.
63*12c85518Srobert ///
64*12c85518Srobert /// If the function has a This pointer (i.e. hasThisPointer() returns true,
65*12c85518Srobert /// the argument values need to be preceeded by a Pointer for the This object.
66*12c85518Srobert ///
67*12c85518Srobert /// If the function uses Return Value Optimization, the arguments (and
68*12c85518Srobert /// potentially the This pointer) need to be proceeded by a Pointer pointing
69*12c85518Srobert /// to the location to construct the returned value.
70*12c85518Srobert ///
71*12c85518Srobert /// After the function has been called, it will remove all arguments,
72*12c85518Srobert /// including RVO and This pointer, from the stack.
73*12c85518Srobert ///
74*12c85518Srobert class Function final {
75e5dd7070Spatrick public:
76e5dd7070Spatrick   using ParamDescriptor = std::pair<PrimType, Descriptor *>;
77e5dd7070Spatrick 
78e5dd7070Spatrick   /// Returns the size of the function's local stack.
getFrameSize()79e5dd7070Spatrick   unsigned getFrameSize() const { return FrameSize; }
80*12c85518Srobert   /// Returns the size of the argument stack.
getArgSize()81e5dd7070Spatrick   unsigned getArgSize() const { return ArgSize; }
82e5dd7070Spatrick 
83e5dd7070Spatrick   /// Returns a pointer to the start of the code.
getCodeBegin()84*12c85518Srobert   CodePtr getCodeBegin() const { return Code.data(); }
85e5dd7070Spatrick   /// Returns a pointer to the end of the code.
getCodeEnd()86*12c85518Srobert   CodePtr getCodeEnd() const { return Code.data() + Code.size(); }
87e5dd7070Spatrick 
88e5dd7070Spatrick   /// Returns the original FunctionDecl.
getDecl()89e5dd7070Spatrick   const FunctionDecl *getDecl() const { return F; }
90e5dd7070Spatrick 
91*12c85518Srobert   /// Returns the name of the function decl this code
92*12c85518Srobert   /// was generated for.
getName()93*12c85518Srobert   const std::string getName() const { return F->getNameInfo().getAsString(); }
94*12c85518Srobert 
95*12c85518Srobert   /// Returns the location.
getLoc()96e5dd7070Spatrick   SourceLocation getLoc() const { return Loc; }
97e5dd7070Spatrick 
98e5dd7070Spatrick   /// Returns a parameter descriptor.
99e5dd7070Spatrick   ParamDescriptor getParamDescriptor(unsigned Offset) const;
100e5dd7070Spatrick 
101e5dd7070Spatrick   /// Checks if the first argument is a RVO pointer.
hasRVO()102*12c85518Srobert   bool hasRVO() const { return HasRVO; }
103e5dd7070Spatrick 
104e5dd7070Spatrick   /// Range over the scope blocks.
105*12c85518Srobert   llvm::iterator_range<llvm::SmallVector<Scope, 2>::const_iterator>
scopes()106*12c85518Srobert   scopes() const {
107e5dd7070Spatrick     return llvm::make_range(Scopes.begin(), Scopes.end());
108e5dd7070Spatrick   }
109e5dd7070Spatrick 
110e5dd7070Spatrick   /// Range over argument types.
111*12c85518Srobert   using arg_reverse_iterator =
112*12c85518Srobert       SmallVectorImpl<PrimType>::const_reverse_iterator;
args_reverse()113*12c85518Srobert   llvm::iterator_range<arg_reverse_iterator> args_reverse() const {
114*12c85518Srobert     return llvm::reverse(ParamTypes);
115e5dd7070Spatrick   }
116e5dd7070Spatrick 
117e5dd7070Spatrick   /// Returns a specific scope.
getScope(unsigned Idx)118e5dd7070Spatrick   Scope &getScope(unsigned Idx) { return Scopes[Idx]; }
getScope(unsigned Idx)119*12c85518Srobert   const Scope &getScope(unsigned Idx) const { return Scopes[Idx]; }
120e5dd7070Spatrick 
121e5dd7070Spatrick   /// Returns the source information at a given PC.
122e5dd7070Spatrick   SourceInfo getSource(CodePtr PC) const;
123e5dd7070Spatrick 
124e5dd7070Spatrick   /// Checks if the function is valid to call in constexpr.
isConstexpr()125e5dd7070Spatrick   bool isConstexpr() const { return IsValid; }
126e5dd7070Spatrick 
127e5dd7070Spatrick   /// Checks if the function is virtual.
128e5dd7070Spatrick   bool isVirtual() const;
129e5dd7070Spatrick 
130e5dd7070Spatrick   /// Checks if the function is a constructor.
isConstructor()131e5dd7070Spatrick   bool isConstructor() const { return isa<CXXConstructorDecl>(F); }
132e5dd7070Spatrick 
133*12c85518Srobert   /// Checks if the function is fully done compiling.
isFullyCompiled()134*12c85518Srobert   bool isFullyCompiled() const { return IsFullyCompiled; }
135*12c85518Srobert 
hasThisPointer()136*12c85518Srobert   bool hasThisPointer() const { return HasThisPointer; }
137*12c85518Srobert 
138*12c85518Srobert   // Checks if the funtion already has a body attached.
hasBody()139*12c85518Srobert   bool hasBody() const { return HasBody; }
140*12c85518Srobert 
getNumParams()141*12c85518Srobert   unsigned getNumParams() const { return ParamTypes.size(); }
142*12c85518Srobert 
143e5dd7070Spatrick private:
144e5dd7070Spatrick   /// Construct a function representing an actual function.
145e5dd7070Spatrick   Function(Program &P, const FunctionDecl *F, unsigned ArgSize,
146e5dd7070Spatrick            llvm::SmallVector<PrimType, 8> &&ParamTypes,
147*12c85518Srobert            llvm::DenseMap<unsigned, ParamDescriptor> &&Params,
148*12c85518Srobert            bool HasThisPointer, bool HasRVO);
149e5dd7070Spatrick 
150e5dd7070Spatrick   /// Sets the code of a function.
setCode(unsigned NewFrameSize,std::vector<char> && NewCode,SourceMap && NewSrcMap,llvm::SmallVector<Scope,2> && NewScopes)151e5dd7070Spatrick   void setCode(unsigned NewFrameSize, std::vector<char> &&NewCode, SourceMap &&NewSrcMap,
152e5dd7070Spatrick                llvm::SmallVector<Scope, 2> &&NewScopes) {
153e5dd7070Spatrick     FrameSize = NewFrameSize;
154e5dd7070Spatrick     Code = std::move(NewCode);
155e5dd7070Spatrick     SrcMap = std::move(NewSrcMap);
156e5dd7070Spatrick     Scopes = std::move(NewScopes);
157e5dd7070Spatrick     IsValid = true;
158*12c85518Srobert     HasBody = true;
159e5dd7070Spatrick   }
160e5dd7070Spatrick 
setIsFullyCompiled(bool FC)161*12c85518Srobert   void setIsFullyCompiled(bool FC) { IsFullyCompiled = FC; }
162*12c85518Srobert 
163e5dd7070Spatrick private:
164e5dd7070Spatrick   friend class Program;
165e5dd7070Spatrick   friend class ByteCodeEmitter;
166e5dd7070Spatrick 
167e5dd7070Spatrick   /// Program reference.
168e5dd7070Spatrick   Program &P;
169e5dd7070Spatrick   /// Location of the executed code.
170e5dd7070Spatrick   SourceLocation Loc;
171e5dd7070Spatrick   /// Declaration this function was compiled from.
172e5dd7070Spatrick   const FunctionDecl *F;
173e5dd7070Spatrick   /// Local area size: storage + metadata.
174*12c85518Srobert   unsigned FrameSize = 0;
175e5dd7070Spatrick   /// Size of the argument stack.
176e5dd7070Spatrick   unsigned ArgSize;
177e5dd7070Spatrick   /// Program code.
178e5dd7070Spatrick   std::vector<char> Code;
179e5dd7070Spatrick   /// Opcode-to-expression mapping.
180e5dd7070Spatrick   SourceMap SrcMap;
181e5dd7070Spatrick   /// List of block descriptors.
182e5dd7070Spatrick   llvm::SmallVector<Scope, 2> Scopes;
183e5dd7070Spatrick   /// List of argument types.
184e5dd7070Spatrick   llvm::SmallVector<PrimType, 8> ParamTypes;
185e5dd7070Spatrick   /// Map from byte offset to parameter descriptor.
186e5dd7070Spatrick   llvm::DenseMap<unsigned, ParamDescriptor> Params;
187e5dd7070Spatrick   /// Flag to indicate if the function is valid.
188e5dd7070Spatrick   bool IsValid = false;
189*12c85518Srobert   /// Flag to indicate if the function is done being
190*12c85518Srobert   /// compiled to bytecode.
191*12c85518Srobert   bool IsFullyCompiled = false;
192*12c85518Srobert   /// Flag indicating if this function takes the this pointer
193*12c85518Srobert   /// as the first implicit argument
194*12c85518Srobert   bool HasThisPointer = false;
195*12c85518Srobert   /// Whether this function has Return Value Optimization, i.e.
196*12c85518Srobert   /// the return value is constructed in the caller's stack frame.
197*12c85518Srobert   /// This is done for functions that return non-primive values.
198*12c85518Srobert   bool HasRVO = false;
199*12c85518Srobert   /// If we've already compiled the function's body.
200*12c85518Srobert   bool HasBody = false;
201e5dd7070Spatrick 
202e5dd7070Spatrick public:
203e5dd7070Spatrick   /// Dumps the disassembled bytecode to \c llvm::errs().
204e5dd7070Spatrick   void dump() const;
205e5dd7070Spatrick   void dump(llvm::raw_ostream &OS) const;
206e5dd7070Spatrick };
207e5dd7070Spatrick 
208e5dd7070Spatrick } // namespace interp
209e5dd7070Spatrick } // namespace clang
210e5dd7070Spatrick 
211e5dd7070Spatrick #endif
212