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 "ByteCodeGenError.h"
11 #include "Context.h"
12 #include "Floating.h"
13 #include "Opcode.h"
14 #include "Program.h"
15 #include "clang/AST/ASTLambda.h"
16 #include "clang/AST/DeclCXX.h"
17 #include "clang/Basic/Builtins.h"
18 #include <type_traits>
19 
20 using namespace clang;
21 using namespace clang::interp;
22 
23 Function *ByteCodeEmitter::compileFunc(const FunctionDecl *FuncDecl) {
24   // Set up argument indices.
25   unsigned ParamOffset = 0;
26   SmallVector<PrimType, 8> ParamTypes;
27   SmallVector<unsigned, 8> ParamOffsets;
28   llvm::DenseMap<unsigned, Function::ParamDescriptor> ParamDescriptors;
29 
30   // If the return is not a primitive, a pointer to the storage where the
31   // value is initialized in is passed as the first argument. See 'RVO'
32   // elsewhere in the code.
33   QualType Ty = FuncDecl->getReturnType();
34   bool HasRVO = false;
35   if (!Ty->isVoidType() && !Ctx.classify(Ty)) {
36     HasRVO = true;
37     ParamTypes.push_back(PT_Ptr);
38     ParamOffsets.push_back(ParamOffset);
39     ParamOffset += align(primSize(PT_Ptr));
40   }
41 
42   // If the function decl is a member decl, the next parameter is
43   // the 'this' pointer. This parameter is pop()ed from the
44   // InterpStack when calling the function.
45   bool HasThisPointer = false;
46   if (const auto *MD = dyn_cast<CXXMethodDecl>(FuncDecl)) {
47     if (MD->isImplicitObjectMemberFunction()) {
48       HasThisPointer = true;
49       ParamTypes.push_back(PT_Ptr);
50       ParamOffsets.push_back(ParamOffset);
51       ParamOffset += align(primSize(PT_Ptr));
52     }
53 
54     // Set up lambda capture to closure record field mapping.
55     if (isLambdaCallOperator(MD)) {
56       const Record *R = P.getOrCreateRecord(MD->getParent());
57       llvm::DenseMap<const ValueDecl *, FieldDecl *> LC;
58       FieldDecl *LTC;
59 
60       MD->getParent()->getCaptureFields(LC, LTC);
61 
62       for (auto Cap : LC) {
63         // Static lambdas cannot have any captures. If this one does,
64         // it has already been diagnosed and we can only ignore it.
65         if (MD->isStatic())
66           return nullptr;
67 
68         unsigned Offset = R->getField(Cap.second)->Offset;
69         this->LambdaCaptures[Cap.first] = {
70             Offset, Cap.second->getType()->isReferenceType()};
71       }
72       if (LTC)
73         this->LambdaThisCapture = R->getField(LTC)->Offset;
74     }
75   }
76 
77   // Assign descriptors to all parameters.
78   // Composite objects are lowered to pointers.
79   for (const ParmVarDecl *PD : FuncDecl->parameters()) {
80     std::optional<PrimType> T = Ctx.classify(PD->getType());
81     PrimType PT = T.value_or(PT_Ptr);
82     Descriptor *Desc = P.createDescriptor(PD, PT);
83     ParamDescriptors.insert({ParamOffset, {PT, Desc}});
84     Params.insert({PD, {ParamOffset, T != std::nullopt}});
85     ParamOffsets.push_back(ParamOffset);
86     ParamOffset += align(primSize(PT));
87     ParamTypes.push_back(PT);
88   }
89 
90   // Create a handle over the emitted code.
91   Function *Func = P.getFunction(FuncDecl);
92   if (!Func) {
93     bool IsUnevaluatedBuiltin = false;
94     if (unsigned BI = FuncDecl->getBuiltinID())
95       IsUnevaluatedBuiltin = Ctx.getASTContext().BuiltinInfo.isUnevaluated(BI);
96 
97     Func =
98         P.createFunction(FuncDecl, ParamOffset, std::move(ParamTypes),
99                          std::move(ParamDescriptors), std::move(ParamOffsets),
100                          HasThisPointer, HasRVO, IsUnevaluatedBuiltin);
101   }
102 
103   assert(Func);
104   // For not-yet-defined functions, we only create a Function instance and
105   // compile their body later.
106   if (!FuncDecl->isDefined()) {
107     Func->setDefined(false);
108     return Func;
109   }
110 
111   Func->setDefined(true);
112 
113   // Lambda static invokers are a special case that we emit custom code for.
114   bool IsEligibleForCompilation = false;
115   if (const auto *MD = dyn_cast<CXXMethodDecl>(FuncDecl))
116     IsEligibleForCompilation = MD->isLambdaStaticInvoker();
117   if (!IsEligibleForCompilation)
118     IsEligibleForCompilation = FuncDecl->isConstexpr();
119 
120   // Compile the function body.
121   if (!IsEligibleForCompilation || !visitFunc(FuncDecl)) {
122     Func->setIsFullyCompiled(true);
123     return Func;
124   }
125 
126   // Create scopes from descriptors.
127   llvm::SmallVector<Scope, 2> Scopes;
128   for (auto &DS : Descriptors) {
129     Scopes.emplace_back(std::move(DS));
130   }
131 
132   // Set the function's code.
133   Func->setCode(NextLocalOffset, std::move(Code), std::move(SrcMap),
134                 std::move(Scopes), FuncDecl->hasBody());
135   Func->setIsFullyCompiled(true);
136   return Func;
137 }
138 
139 Scope::Local ByteCodeEmitter::createLocal(Descriptor *D) {
140   NextLocalOffset += sizeof(Block);
141   unsigned Location = NextLocalOffset;
142   NextLocalOffset += align(D->getAllocSize());
143   return {Location, D};
144 }
145 
146 void ByteCodeEmitter::emitLabel(LabelTy Label) {
147   const size_t Target = Code.size();
148   LabelOffsets.insert({Label, Target});
149 
150   if (auto It = LabelRelocs.find(Label);
151       It != LabelRelocs.end()) {
152     for (unsigned Reloc : It->second) {
153       using namespace llvm::support;
154 
155       // Rewrite the operand of all jumps to this label.
156       void *Location = Code.data() + Reloc - align(sizeof(int32_t));
157       assert(aligned(Location));
158       const int32_t Offset = Target - static_cast<int64_t>(Reloc);
159       endian::write<int32_t, llvm::endianness::native>(Location, Offset);
160     }
161     LabelRelocs.erase(It);
162   }
163 }
164 
165 int32_t ByteCodeEmitter::getOffset(LabelTy Label) {
166   // Compute the PC offset which the jump is relative to.
167   const int64_t Position =
168       Code.size() + align(sizeof(Opcode)) + align(sizeof(int32_t));
169   assert(aligned(Position));
170 
171   // If target is known, compute jump offset.
172   if (auto It = LabelOffsets.find(Label);
173       It != LabelOffsets.end())
174     return It->second - Position;
175 
176   // Otherwise, record relocation and return dummy offset.
177   LabelRelocs[Label].push_back(Position);
178   return 0ull;
179 }
180 
181 /// Helper to write bytecode and bail out if 32-bit offsets become invalid.
182 /// Pointers will be automatically marshalled as 32-bit IDs.
183 template <typename T>
184 static void emit(Program &P, std::vector<std::byte> &Code, const T &Val,
185                  bool &Success) {
186   size_t Size;
187 
188   if constexpr (std::is_pointer_v<T>)
189     Size = sizeof(uint32_t);
190   else
191     Size = sizeof(T);
192 
193   if (Code.size() + Size > std::numeric_limits<unsigned>::max()) {
194     Success = false;
195     return;
196   }
197 
198   // Access must be aligned!
199   size_t ValPos = align(Code.size());
200   Size = align(Size);
201   assert(aligned(ValPos + Size));
202   Code.resize(ValPos + Size);
203 
204   if constexpr (!std::is_pointer_v<T>) {
205     new (Code.data() + ValPos) T(Val);
206   } else {
207     uint32_t ID = P.getOrCreateNativePointer(Val);
208     new (Code.data() + ValPos) uint32_t(ID);
209   }
210 }
211 
212 template <>
213 void emit(Program &P, std::vector<std::byte> &Code, const Floating &Val,
214           bool &Success) {
215   size_t Size = Val.bytesToSerialize();
216 
217   if (Code.size() + Size > std::numeric_limits<unsigned>::max()) {
218     Success = false;
219     return;
220   }
221 
222   // Access must be aligned!
223   size_t ValPos = align(Code.size());
224   Size = align(Size);
225   assert(aligned(ValPos + Size));
226   Code.resize(ValPos + Size);
227 
228   Val.serialize(Code.data() + ValPos);
229 }
230 
231 template <typename... Tys>
232 bool ByteCodeEmitter::emitOp(Opcode Op, const Tys &... Args, const SourceInfo &SI) {
233   bool Success = true;
234 
235   // The opcode is followed by arguments. The source info is
236   // attached to the address after the opcode.
237   emit(P, Code, Op, Success);
238   if (SI)
239     SrcMap.emplace_back(Code.size(), SI);
240 
241   // The initializer list forces the expression to be evaluated
242   // for each argument in the variadic template, in order.
243   (void)std::initializer_list<int>{(emit(P, Code, Args, Success), 0)...};
244 
245   return Success;
246 }
247 
248 bool ByteCodeEmitter::jumpTrue(const LabelTy &Label) {
249   return emitJt(getOffset(Label), SourceInfo{});
250 }
251 
252 bool ByteCodeEmitter::jumpFalse(const LabelTy &Label) {
253   return emitJf(getOffset(Label), SourceInfo{});
254 }
255 
256 bool ByteCodeEmitter::jump(const LabelTy &Label) {
257   return emitJmp(getOffset(Label), SourceInfo{});
258 }
259 
260 bool ByteCodeEmitter::fallthrough(const LabelTy &Label) {
261   emitLabel(Label);
262   return true;
263 }
264 
265 //===----------------------------------------------------------------------===//
266 // Opcode emitters
267 //===----------------------------------------------------------------------===//
268 
269 #define GET_LINK_IMPL
270 #include "Opcodes.inc"
271 #undef GET_LINK_IMPL
272