clang  14.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 "Opcode.h"
12 #include "Program.h"
13 #include "clang/AST/DeclCXX.h"
14 #include <type_traits>
15 
16 using namespace clang;
17 using namespace clang::interp;
18 
20 using Error = llvm::Error;
21 
23  // Do not try to compile undefined functions.
24  if (!F->isDefined(F) || (!F->hasBody() && F->willHaveBody()))
25  return nullptr;
26 
27  // Set up argument indices.
28  unsigned ParamOffset = 0;
29  SmallVector<PrimType, 8> ParamTypes;
30  llvm::DenseMap<unsigned, Function::ParamDescriptor> ParamDescriptors;
31 
32  // If the return is not a primitive, a pointer to the storage where the value
33  // is initialized in is passed as the first argument.
34  QualType Ty = F->getReturnType();
35  if (!Ty->isVoidType() && !Ctx.classify(Ty)) {
36  ParamTypes.push_back(PT_Ptr);
37  ParamOffset += align(primSize(PT_Ptr));
38  }
39 
40  // Assign descriptors to all parameters.
41  // Composite objects are lowered to pointers.
42  for (const ParmVarDecl *PD : F->parameters()) {
43  PrimType Ty;
44  if (llvm::Optional<PrimType> T = Ctx.classify(PD->getType())) {
45  Ty = *T;
46  } else {
47  Ty = PT_Ptr;
48  }
49 
50  Descriptor *Desc = P.createDescriptor(PD, Ty);
51  ParamDescriptors.insert({ParamOffset, {Ty, Desc}});
52  Params.insert({PD, ParamOffset});
53  ParamOffset += align(primSize(Ty));
54  ParamTypes.push_back(Ty);
55  }
56 
57  // Create a handle over the emitted code.
58  Function *Func = P.createFunction(F, ParamOffset, std::move(ParamTypes),
59  std::move(ParamDescriptors));
60  // Compile the function body.
61  if (!F->isConstexpr() || !visitFunc(F)) {
62  // Return a dummy function if compilation failed.
63  if (BailLocation)
64  return llvm::make_error<ByteCodeGenError>(*BailLocation);
65  else
66  return Func;
67  } else {
68  // Create scopes from descriptors.
70  for (auto &DS : Descriptors) {
71  Scopes.emplace_back(std::move(DS));
72  }
73 
74  // Set the function's code.
75  Func->setCode(NextLocalOffset, std::move(Code), std::move(SrcMap),
76  std::move(Scopes));
77  return Func;
78  }
79 }
80 
82  NextLocalOffset += sizeof(Block);
83  unsigned Location = NextLocalOffset;
84  NextLocalOffset += align(D->getAllocSize());
85  return {Location, D};
86 }
87 
89  const size_t Target = Code.size();
90  LabelOffsets.insert({Label, Target});
91  auto It = LabelRelocs.find(Label);
92  if (It != LabelRelocs.end()) {
93  for (unsigned Reloc : It->second) {
94  using namespace llvm::support;
95 
96  /// Rewrite the operand of all jumps to this label.
97  void *Location = Code.data() + Reloc - sizeof(int32_t);
98  const int32_t Offset = Target - static_cast<int64_t>(Reloc);
99  endian::write<int32_t, endianness::native, 1>(Location, Offset);
100  }
101  LabelRelocs.erase(It);
102  }
103 }
104 
105 int32_t ByteCodeEmitter::getOffset(LabelTy Label) {
106  // Compute the PC offset which the jump is relative to.
107  const int64_t Position = Code.size() + sizeof(Opcode) + sizeof(int32_t);
108 
109  // If target is known, compute jump offset.
110  auto It = LabelOffsets.find(Label);
111  if (It != LabelOffsets.end()) {
112  return It->second - Position;
113  }
114 
115  // Otherwise, record relocation and return dummy offset.
116  LabelRelocs[Label].push_back(Position);
117  return 0ull;
118 }
119 
121  if (!BailLocation)
122  BailLocation = Loc;
123  return false;
124 }
125 
126 /// Helper to write bytecode and bail out if 32-bit offsets become invalid.
127 /// Pointers will be automatically marshalled as 32-bit IDs.
128 template <typename T>
129 static std::enable_if_t<!std::is_pointer<T>::value, void>
130 emit(Program &P, std::vector<char> &Code, const T &Val, bool &Success) {
131  size_t Size = sizeof(Val);
132  if (Code.size() + Size > std::numeric_limits<unsigned>::max()) {
133  Success = false;
134  return;
135  }
136 
137  const char *Data = reinterpret_cast<const char *>(&Val);
138  Code.insert(Code.end(), Data, Data + Size);
139 }
140 
141 template <typename T>
142 static std::enable_if_t<std::is_pointer<T>::value, void>
143 emit(Program &P, std::vector<char> &Code, const T &Val, bool &Success) {
144  size_t Size = sizeof(uint32_t);
145  if (Code.size() + Size > std::numeric_limits<unsigned>::max()) {
146  Success = false;
147  return;
148  }
149 
150  uint32_t ID = P.getOrCreateNativePointer(Val);
151  const char *Data = reinterpret_cast<const char *>(&ID);
152  Code.insert(Code.end(), Data, Data + Size);
153 }
154 
155 template <typename... Tys>
156 bool ByteCodeEmitter::emitOp(Opcode Op, const Tys &... Args, const SourceInfo &SI) {
157  bool Success = true;
158 
159  /// The opcode is followed by arguments. The source info is
160  /// attached to the address after the opcode.
161  emit(P, Code, Op, Success);
162  if (SI)
163  SrcMap.emplace_back(Code.size(), SI);
164 
165  /// The initializer list forces the expression to be evaluated
166  /// for each argument in the variadic template, in order.
167  (void)std::initializer_list<int>{(emit(P, Code, Args, Success), 0)...};
168 
169  return Success;
170 }
171 
173  return emitJt(getOffset(Label), SourceInfo{});
174 }
175 
177  return emitJf(getOffset(Label), SourceInfo{});
178 }
179 
181  return emitJmp(getOffset(Label), SourceInfo{});
182 }
183 
185  emitLabel(Label);
186  return true;
187 }
188 
189 //===----------------------------------------------------------------------===//
190 // Opcode emitters
191 //===----------------------------------------------------------------------===//
192 
193 #define GET_LINK_IMPL
194 #include "Opcodes.inc"
195 #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:2537
clang::interp::align
constexpr size_t align(size_t Size)
Aligns a size to the pointer alignment.
Definition: PrimType.h:57
Error
llvm::Error Error
Definition: ByteCodeEmitter.cpp:20
clang::FunctionDecl::isConstexpr
bool isConstexpr() const
Whether this is a (C++11) constexpr function or constexpr constructor.
Definition: Decl.h:2283
Opcode.h
llvm::SmallVector< PrimType, 8 >
clang::SourceLocation
Encodes a location in the source.
Definition: SourceLocation.h:88
clang::interp::ByteCodeEmitter::createLocal
Local createLocal(Descriptor *D)
Callback for local registration.
Definition: ByteCodeEmitter.cpp:81
clang::MultiVersionKind::Target
@ Target
clang::interp::ByteCodeEmitter::emitLabel
void emitLabel(LabelTy Label)
Define a label.
Definition: ByteCodeEmitter.cpp:88
clang::QualType
A (possibly-)qualified type.
Definition: Type.h:673
clang::FunctionDecl::willHaveBody
bool willHaveBody() const
True if this function will eventually have a body, once it's fully parsed.
Definition: Decl.h:2431
clang::ParmVarDecl
Represents a parameter to a function.
Definition: Decl.h:1665
DeclCXX.h
llvm::Optional< PrimType >
clang::Type::isVoidType
bool isVoidType() const
Definition: Type.h:6955
llvm::Expected
Definition: LLVM.h:41
clang::interp::Descriptor::getAllocSize
unsigned getAllocSize() const
Returns the allocated size, including metadata.
Definition: Descriptor.h:134
clang::format::ParseError::Success
@ Success
emit
static std::enable_if_t<!std::is_pointer< T >::value, 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:130
Offset
unsigned Offset
Definition: Format.cpp:2335
clang::interp::Scope::Local
Information about a local's storage.
Definition: Function.h:35
APSInt
llvm::APSInt APSInt
Definition: ByteCodeEmitter.cpp:19
clang::interp::ByteCodeEmitter::Descriptors
llvm::SmallVector< SmallVector< Local, 8 >, 2 > Descriptors
Local descriptors.
Definition: ByteCodeEmitter.h:74
clang::interp
Definition: ASTContext.h:158
clang::interp::Program::createDescriptor
Descriptor * createDescriptor(const DeclTy &D, PrimType Type, bool IsConst=false, bool IsTemporary=false, bool IsMutable=false)
Creates a descriptor for a primitive type.
Definition: Program.h:107
clang::interp::Opcode
Opcode
Definition: Opcode.h:21
clang::interp::ByteCodeEmitter::visitFunc
virtual bool visitFunc(const FunctionDecl *E)=0
Methods implemented by the compiler.
clang::interp::Block
A memory block, either on the stack or in the heap.
Definition: InterpBlock.h:37
clang::interp::PrimType
PrimType
Enumeration of the primitive types of the VM.
Definition: PrimType.h:27
clang::interp::SourceInfo
Describes the statement/declaration an opcode was generated from.
Definition: Source.h:66
Label
std::string Label
Definition: UsingDeclarationsSorter.cpp:69
clang::FunctionDecl::hasBody
bool hasBody(const FunctionDecl *&Definition) const
Returns true if the function has a body.
Definition: Decl.cpp:2955
clang::interp::ByteCodeEmitter::LabelTy
uint32_t LabelTy
Definition: ByteCodeEmitter.h:34
P
StringRef P
Definition: ASTMatchersInternal.cpp:563
clang::interp::primSize
size_t primSize(PrimType Type)
Returns the size of a primitive type in bytes.
Definition: PrimType.cpp:17
clang::interp::ByteCodeEmitter::compileFunc
llvm::Expected< Function * > compileFunc(const FunctionDecl *F)
Compiles the function into the module.
Definition: ByteCodeEmitter.cpp:22
clang::interp::ByteCodeEmitter::Params
llvm::DenseMap< const ParmVarDecl *, unsigned > Params
Parameter indices.
Definition: ByteCodeEmitter.h:72
clang::interp::ByteCodeEmitter::fallthrough
bool fallthrough(const LabelTy &Label)
Definition: ByteCodeEmitter.cpp:184
clang::interp::ByteCodeEmitter::jumpTrue
bool jumpTrue(const LabelTy &Label)
Emits jumps.
Definition: ByteCodeEmitter.cpp:172
clang::interp::Descriptor
Describes a memory block created by an allocation site.
Definition: Descriptor.h:51
clang::Builtin::ID
ID
Definition: Builtins.h:48
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:82
clang::interp::Function
Bytecode function.
Definition: Function.h:59
clang::interp::ByteCodeEmitter::jumpFalse
bool jumpFalse(const LabelTy &Label)
Definition: ByteCodeEmitter.cpp:176
ByteCodeEmitter.h
Program.h
clang::interp::ByteCodeEmitter::jump
bool jump(const LabelTy &Label)
Definition: ByteCodeEmitter.cpp:180
clang::interp::ByteCodeEmitter::bail
bool bail(const Stmt *S)
Bails out if a given node cannot be compiled.
Definition: ByteCodeEmitter.h:58
clang::interp::PT_Ptr
@ PT_Ptr
Definition: PrimType.h:37
clang::interp::Program
The program contains and links the bytecode for all functions.
Definition: Program.h:43
clang::FunctionDecl::parameters
ArrayRef< ParmVarDecl * > parameters() const
Definition: Decl.h:2483
clang::FunctionDecl
Represents a function declaration or definition.
Definition: Decl.h:1856
clang::FunctionDecl::isDefined
bool isDefined(const FunctionDecl *&Definition, bool CheckForPendingFriendDefinition=false) const
Returns true if the function has a definition that does not need to be instantiated.
Definition: Decl.cpp:3002
clang::interp::Context::classify
llvm::Optional< PrimType > classify(QualType T)
Classifies an expression.
Definition: Context.cpp:62
Context.h