clang  17.0.0git
ByteCodeEmitter.cpp
Go to the documentation of this file.
1 //===--- ByteCodeEmitter.cpp - Instruction emitter 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 #include "ByteCodeEmitter.h"
10 #include "Context.h"
11 #include "Floating.h"
12 #include "Opcode.h"
13 #include "Program.h"
14 #include "clang/AST/DeclCXX.h"
15 #include <type_traits>
16 
17 using namespace clang;
18 using namespace clang::interp;
19 
21 using Error = llvm::Error;
22 
25  // Function is not defined at all or not yet. We will
26  // create a Function instance but not compile the body. That
27  // will (maybe) happen later.
28  bool HasBody = FuncDecl->hasBody(FuncDecl);
29 
30  // Create a handle over the emitted code.
31  Function *Func = P.getFunction(FuncDecl);
32  if (!Func) {
33  // Set up argument indices.
34  unsigned ParamOffset = 0;
35  SmallVector<PrimType, 8> ParamTypes;
36  llvm::DenseMap<unsigned, Function::ParamDescriptor> ParamDescriptors;
37 
38  // If the return is not a primitive, a pointer to the storage where the
39  // value is initialized in is passed as the first argument. See 'RVO'
40  // elsewhere in the code.
41  QualType Ty = FuncDecl->getReturnType();
42  bool HasRVO = false;
43  if (!Ty->isVoidType() && !Ctx.classify(Ty)) {
44  HasRVO = true;
45  ParamTypes.push_back(PT_Ptr);
46  ParamOffset += align(primSize(PT_Ptr));
47  }
48 
49  // If the function decl is a member decl, the next parameter is
50  // the 'this' pointer. This parameter is pop()ed from the
51  // InterpStack when calling the function.
52  bool HasThisPointer = false;
53  if (const auto *MD = dyn_cast<CXXMethodDecl>(FuncDecl);
54  MD && MD->isInstance()) {
55  HasThisPointer = true;
56  ParamTypes.push_back(PT_Ptr);
57  ParamOffset += align(primSize(PT_Ptr));
58  }
59 
60  // Assign descriptors to all parameters.
61  // Composite objects are lowered to pointers.
62  for (const ParmVarDecl *PD : FuncDecl->parameters()) {
63  PrimType Ty = Ctx.classify(PD->getType()).value_or(PT_Ptr);
64  Descriptor *Desc = P.createDescriptor(PD, Ty);
65  ParamDescriptors.insert({ParamOffset, {Ty, Desc}});
66  Params.insert({PD, ParamOffset});
67  ParamOffset += align(primSize(Ty));
68  ParamTypes.push_back(Ty);
69  }
70 
71  Func =
72  P.createFunction(FuncDecl, ParamOffset, std::move(ParamTypes),
73  std::move(ParamDescriptors), HasThisPointer, HasRVO);
74  }
75 
76  assert(Func);
77  if (!HasBody)
78  return Func;
79 
80  // Compile the function body.
81  if (!FuncDecl->isConstexpr() || !visitFunc(FuncDecl)) {
82  // Return a dummy function if compilation failed.
83  if (BailLocation)
84  return llvm::make_error<ByteCodeGenError>(*BailLocation);
85  else {
86  Func->setIsFullyCompiled(true);
87  return Func;
88  }
89  } else {
90  // Create scopes from descriptors.
92  for (auto &DS : Descriptors) {
93  Scopes.emplace_back(std::move(DS));
94  }
95 
96  // Set the function's code.
97  Func->setCode(NextLocalOffset, std::move(Code), std::move(SrcMap),
98  std::move(Scopes));
99  Func->setIsFullyCompiled(true);
100  return Func;
101  }
102 }
103 
105  NextLocalOffset += sizeof(Block);
106  unsigned Location = NextLocalOffset;
107  NextLocalOffset += align(D->getAllocSize());
108  return {Location, D};
109 }
110 
112  const size_t Target = Code.size();
113  LabelOffsets.insert({Label, Target});
114  auto It = LabelRelocs.find(Label);
115  if (It != LabelRelocs.end()) {
116  for (unsigned Reloc : It->second) {
117  using namespace llvm::support;
118 
119  /// Rewrite the operand of all jumps to this label.
120  void *Location = Code.data() + Reloc - align(sizeof(int32_t));
121  assert(aligned(Location));
122  const int32_t Offset = Target - static_cast<int64_t>(Reloc);
123  endian::write<int32_t, endianness::native, 1>(Location, Offset);
124  }
125  LabelRelocs.erase(It);
126  }
127 }
128 
129 int32_t ByteCodeEmitter::getOffset(LabelTy Label) {
130  // Compute the PC offset which the jump is relative to.
131  const int64_t Position =
132  Code.size() + align(sizeof(Opcode)) + align(sizeof(int32_t));
133  assert(aligned(Position));
134 
135  // If target is known, compute jump offset.
136  auto It = LabelOffsets.find(Label);
137  if (It != LabelOffsets.end()) {
138  return It->second - Position;
139  }
140 
141  // Otherwise, record relocation and return dummy offset.
142  LabelRelocs[Label].push_back(Position);
143  return 0ull;
144 }
145 
147  if (!BailLocation)
148  BailLocation = Loc;
149  return false;
150 }
151 
152 /// Helper to write bytecode and bail out if 32-bit offsets become invalid.
153 /// Pointers will be automatically marshalled as 32-bit IDs.
154 template <typename T>
155 static void emit(Program &P, std::vector<char> &Code, const T &Val,
156  bool &Success) {
157  size_t Size;
158 
159  if constexpr (std::is_pointer_v<T>)
160  Size = sizeof(uint32_t);
161  else
162  Size = sizeof(T);
163 
164  if (Code.size() + Size > std::numeric_limits<unsigned>::max()) {
165  Success = false;
166  return;
167  }
168 
169  // Access must be aligned!
170  size_t ValPos = align(Code.size());
171  Size = align(Size);
172  assert(aligned(ValPos + Size));
173  Code.resize(ValPos + Size);
174 
175  if constexpr (!std::is_pointer_v<T>) {
176  new (Code.data() + ValPos) T(Val);
177  } else {
178  uint32_t ID = P.getOrCreateNativePointer(Val);
179  new (Code.data() + ValPos) uint32_t(ID);
180  }
181 }
182 
183 template <typename... Tys>
184 bool ByteCodeEmitter::emitOp(Opcode Op, const Tys &... Args, const SourceInfo &SI) {
185  bool Success = true;
186 
187  /// The opcode is followed by arguments. The source info is
188  /// attached to the address after the opcode.
189  emit(P, Code, Op, Success);
190  if (SI)
191  SrcMap.emplace_back(Code.size(), SI);
192 
193  /// The initializer list forces the expression to be evaluated
194  /// for each argument in the variadic template, in order.
195  (void)std::initializer_list<int>{(emit(P, Code, Args, Success), 0)...};
196 
197  return Success;
198 }
199 
201  return emitJt(getOffset(Label), SourceInfo{});
202 }
203 
205  return emitJf(getOffset(Label), SourceInfo{});
206 }
207 
209  return emitJmp(getOffset(Label), SourceInfo{});
210 }
211 
213  emitLabel(Label);
214  return true;
215 }
216 
217 //===----------------------------------------------------------------------===//
218 // Opcode emitters
219 //===----------------------------------------------------------------------===//
220 
221 #define GET_LINK_IMPL
222 #include "Opcodes.inc"
223 #undef GET_LINK_IMPL
max
__DEVICE__ int max(int __a, int __b)
Definition: __clang_cuda_math.h:196
clang::FunctionDecl::getReturnType
QualType getReturnType() const
Definition: Decl.h:2638
clang::interp::align
constexpr size_t align(size_t Size)
Aligns a size to the pointer alignment.
Definition: PrimType.h:61
Error
llvm::Error Error
Definition: ByteCodeEmitter.cpp:21
clang::FunctionDecl::isConstexpr
bool isConstexpr() const
Whether this is a (C++11) constexpr function or constexpr constructor.
Definition: Decl.h:2367
Opcode.h
llvm::SmallVector< PrimType, 8 >
clang::SourceLocation
Encodes a location in the source.
Definition: SourceLocation.h:86
clang::interp::ByteCodeEmitter::createLocal
Local createLocal(Descriptor *D)
Callback for local registration.
Definition: ByteCodeEmitter.cpp:104
clang::MultiVersionKind::Target
@ Target
clang::interp::ByteCodeEmitter::emitLabel
void emitLabel(LabelTy Label)
Define a label.
Definition: ByteCodeEmitter.cpp:111
clang::QualType
A (possibly-)qualified type.
Definition: Type.h:736
clang::ParmVarDecl
Represents a parameter to a function.
Definition: Decl.h:1724
DeclCXX.h
clang::Type::isVoidType
bool isVoidType() const
Definition: Type.h:7191
llvm::Expected
Definition: LLVM.h:41
clang::interp::Descriptor::getAllocSize
unsigned getAllocSize() const
Returns the allocated size, including metadata.
Definition: Descriptor.h:164
clang::interp::Program::getFunction
Function * getFunction(const FunctionDecl *F)
Returns a function.
Definition: Program.cpp:210
clang::format::ParseError::Success
@ Success
Offset
unsigned Offset
Definition: Format.cpp:2774
clang::interp::Scope::Local
Information about a local's storage.
Definition: Function.h:35
APSInt
llvm::APSInt APSInt
Definition: ByteCodeEmitter.cpp:20
clang::interp::ByteCodeEmitter::Descriptors
llvm::SmallVector< SmallVector< Local, 8 >, 2 > Descriptors
Local descriptors.
Definition: ByteCodeEmitter.h:74
clang::interp
Definition: ASTContext.h:128
clang::interp::Opcode
Opcode
Definition: Opcode.h:21
clang::interp::ByteCodeEmitter::visitFunc
virtual bool visitFunc(const FunctionDecl *E)=0
Methods implemented by the compiler.
emit
static void emit(Program &P, std::vector< char > &Code, const T &Val, bool &Success)
Helper to write bytecode and bail out if 32-bit offsets become invalid.
Definition: ByteCodeEmitter.cpp:155
clang::interp::Block
A memory block, either on the stack or in the heap.
Definition: InterpBlock.h:49
clang::interp::PrimType
PrimType
Enumeration of the primitive types of the VM.
Definition: PrimType.h:29
clang::interp::SourceInfo
Describes the statement/declaration an opcode was generated from.
Definition: Source.h:70
Label
std::string Label
Definition: UsingDeclarationsSorter.cpp:96
clang::FunctionDecl::hasBody
bool hasBody(const FunctionDecl *&Definition) const
Returns true if the function has a body.
Definition: Decl.cpp:3046
clang::interp::ByteCodeEmitter::LabelTy
uint32_t LabelTy
Definition: ByteCodeEmitter.h:34
P
StringRef P
Definition: ASTMatchersInternal.cpp:564
clang::interp::primSize
size_t primSize(PrimType Type)
Returns the size of a primitive type in bytes.
Definition: PrimType.cpp:20
clang::interp::ByteCodeEmitter::Params
llvm::DenseMap< const ParmVarDecl *, unsigned > Params
Parameter indices.
Definition: ByteCodeEmitter.h:72
clang::interp::Program::createDescriptor
Descriptor * createDescriptor(const DeclTy &D, PrimType Type, Descriptor::MetadataSize MDSize=std::nullopt, bool IsConst=false, bool IsTemporary=false, bool IsMutable=false)
Creates a descriptor for a primitive type.
Definition: Program.h:117
clang::interp::ByteCodeEmitter::fallthrough
bool fallthrough(const LabelTy &Label)
Definition: ByteCodeEmitter.cpp:212
clang::interp::ByteCodeEmitter::jumpTrue
bool jumpTrue(const LabelTy &Label)
Emits jumps.
Definition: ByteCodeEmitter.cpp:200
clang::interp::Descriptor
Describes a memory block created by an allocation site.
Definition: Descriptor.h:76
clang::Builtin::ID
ID
Definition: Builtins.h:64
clang
Definition: CalledOnceCheck.h:17
clang::interp::Program::createFunction
Function * createFunction(const FunctionDecl *Def, Ts &&... Args)
Creates a new function from a code range.
Definition: Program.h:96
hlsl::int64_t
long int64_t
Definition: hlsl_basic_types.h:26
clang::interp::Function
Bytecode function.
Definition: Function.h:74
clang::interp::ByteCodeEmitter::jumpFalse
bool jumpFalse(const LabelTy &Label)
Definition: ByteCodeEmitter.cpp:204
ByteCodeEmitter.h
clang::interp::ByteCodeEmitter::compileFunc
llvm::Expected< Function * > compileFunc(const FunctionDecl *FuncDecl)
Compiles the function into the module.
Definition: ByteCodeEmitter.cpp:24
Program.h
clang::interp::ByteCodeEmitter::jump
bool jump(const LabelTy &Label)
Definition: ByteCodeEmitter.cpp:208
clang::interp::ByteCodeEmitter::bail
bool bail(const Stmt *S)
Bails out if a given node cannot be compiled.
Definition: ByteCodeEmitter.h:58
Floating.h
clang::interp::PT_Ptr
@ PT_Ptr
Definition: PrimType.h:40
clang::interp::Program
The program contains and links the bytecode for all functions.
Definition: Program.h:40
clang::FunctionDecl::parameters
ArrayRef< ParmVarDecl * > parameters() const
Definition: Decl.h:2584
clang::interp::Context::classify
std::optional< PrimType > classify(QualType T) const
Classifies an expression.
Definition: Context.cpp:80
clang::FunctionDecl
Represents a function declaration or definition.
Definition: Decl.h:1917
clang::interp::aligned
constexpr bool aligned(uintptr_t Value)
Definition: PrimType.h:65
Context.h