Coverage Report

Created: 2024-01-17 10:31

/src/llvm-project/clang/lib/AST/Interp/Function.h
Line
Count
Source (jump to first uncovered line)
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
46
0
  Scope(LocalVectorTy &&Descriptors) : Descriptors(std::move(Descriptors)) {}
47
48
0
  llvm::iterator_range<LocalVectorTy::const_iterator> locals() const {
49
0
    return llvm::make_range(Descriptors.begin(), Descriptors.end());
50
0
  }
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.
81
0
  unsigned getFrameSize() const { return FrameSize; }
82
  /// Returns the size of the argument stack.
83
0
  unsigned getArgSize() const { return ArgSize; }
84
85
  /// Returns a pointer to the start of the code.
86
0
  CodePtr getCodeBegin() const { return Code.data(); }
87
  /// Returns a pointer to the end of the code.
88
0
  CodePtr getCodeEnd() const { return Code.data() + Code.size(); }
89
90
  /// Returns the original FunctionDecl.
91
0
  const FunctionDecl *getDecl() const { return F; }
92
93
  /// Returns the name of the function decl this code
94
  /// was generated for.
95
0
  const std::string getName() const {
96
0
    if (!F)
97
0
      return "<<expr>>";
98
99
0
    return F->getQualifiedNameAsString();
100
0
  }
101
102
  /// Returns the location.
103
0
  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.
109
0
  bool hasRVO() const { return HasRVO; }
110
111
  /// Range over the scope blocks.
112
  llvm::iterator_range<llvm::SmallVector<Scope, 2>::const_iterator>
113
0
  scopes() const {
114
0
    return llvm::make_range(Scopes.begin(), Scopes.end());
115
0
  }
116
117
  /// Range over argument types.
118
  using arg_reverse_iterator =
119
      SmallVectorImpl<PrimType>::const_reverse_iterator;
120
0
  llvm::iterator_range<arg_reverse_iterator> args_reverse() const {
121
0
    return llvm::reverse(ParamTypes);
122
0
  }
123
124
  /// Returns a specific scope.
125
0
  Scope &getScope(unsigned Idx) { return Scopes[Idx]; }
126
0
  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
0
  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
0
  bool isConstructor() const { return isa<CXXConstructorDecl>(F); }
139
  /// Checks if the function is a destructor.
140
0
  bool isDestructor() const { return isa<CXXDestructorDecl>(F); }
141
142
  /// Returns the parent record decl, if any.
143
0
  const CXXRecordDecl *getParentDecl() const {
144
0
    if (const auto *MD = dyn_cast<CXXMethodDecl>(F))
145
0
      return MD->getParent();
146
0
    return nullptr;
147
0
  }
148
149
  /// Returns whether this function is a lambda static invoker,
150
  /// which we generate custom byte code for.
151
0
  bool isLambdaStaticInvoker() const {
152
0
    if (const auto *MD = dyn_cast<CXXMethodDecl>(F))
153
0
      return MD->isLambdaStaticInvoker();
154
0
    return false;
155
0
  }
156
157
  /// Returns whether this function is the call operator
158
  /// of a lambda record decl.
159
0
  bool isLambdaCallOperator() const {
160
0
    if (const auto *MD = dyn_cast<CXXMethodDecl>(F))
161
0
      return clang::isLambdaCallOperator(MD);
162
0
    return false;
163
0
  }
164
165
  /// Checks if the function is fully done compiling.
166
0
  bool isFullyCompiled() const { return IsFullyCompiled; }
167
168
0
  bool hasThisPointer() const { return HasThisPointer; }
169
170
  /// Checks if the function already has a body attached.
171
0
  bool hasBody() const { return HasBody; }
172
173
  /// Checks if the function is defined.
174
0
  bool isDefined() const { return Defined; }
175
176
0
  bool isVariadic() const { return Variadic; }
177
178
0
  unsigned getBuiltinID() const { return F->getBuiltinID(); }
179
180
0
  bool isBuiltin() const { return F->getBuiltinID() != 0; }
181
182
0
  bool isUnevaluatedBuiltin() const { return IsUnevaluatedBuiltin; }
183
184
0
  unsigned getNumParams() const { return ParamTypes.size(); }
185
186
0
  unsigned getParamOffset(unsigned ParamIndex) const {
187
0
    return ParamOffsets[ParamIndex];
188
0
  }
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.
199
  void setCode(unsigned NewFrameSize, std::vector<std::byte> &&NewCode,
200
               SourceMap &&NewSrcMap, llvm::SmallVector<Scope, 2> &&NewScopes,
201
0
               bool NewHasBody) {
202
0
    FrameSize = NewFrameSize;
203
0
    Code = std::move(NewCode);
204
0
    SrcMap = std::move(NewSrcMap);
205
0
    Scopes = std::move(NewScopes);
206
0
    IsValid = true;
207
0
    HasBody = NewHasBody;
208
0
  }
209
210
0
  void setIsFullyCompiled(bool FC) { IsFullyCompiled = FC; }
211
0
  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