1950b70dcSNandor Licker //===--- ByteCodeEmitter.cpp - Instruction emitter for the VM ---*- C++ -*-===//
2950b70dcSNandor Licker //
3950b70dcSNandor Licker // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4950b70dcSNandor Licker // See https://llvm.org/LICENSE.txt for license information.
5950b70dcSNandor Licker // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6950b70dcSNandor Licker //
7950b70dcSNandor Licker //===----------------------------------------------------------------------===//
8950b70dcSNandor Licker 
9950b70dcSNandor Licker #include "ByteCodeEmitter.h"
10950b70dcSNandor Licker #include "Context.h"
11950b70dcSNandor Licker #include "Opcode.h"
12950b70dcSNandor Licker #include "Program.h"
13950b70dcSNandor Licker #include "clang/AST/DeclCXX.h"
14*40080e7eSJessica Clarke #include <type_traits>
15950b70dcSNandor Licker 
16950b70dcSNandor Licker using namespace clang;
17950b70dcSNandor Licker using namespace clang::interp;
18950b70dcSNandor Licker 
19950b70dcSNandor Licker using APSInt = llvm::APSInt;
20950b70dcSNandor Licker using Error = llvm::Error;
21950b70dcSNandor Licker 
compileFunc(const FunctionDecl * F)22950b70dcSNandor Licker Expected<Function *> ByteCodeEmitter::compileFunc(const FunctionDecl *F) {
23950b70dcSNandor Licker   // Do not try to compile undefined functions.
24950b70dcSNandor Licker   if (!F->isDefined(F) || (!F->hasBody() && F->willHaveBody()))
25950b70dcSNandor Licker     return nullptr;
26950b70dcSNandor Licker 
27950b70dcSNandor Licker   // Set up argument indices.
28950b70dcSNandor Licker   unsigned ParamOffset = 0;
29950b70dcSNandor Licker   SmallVector<PrimType, 8> ParamTypes;
30950b70dcSNandor Licker   llvm::DenseMap<unsigned, Function::ParamDescriptor> ParamDescriptors;
31950b70dcSNandor Licker 
32950b70dcSNandor Licker   // If the return is not a primitive, a pointer to the storage where the value
33950b70dcSNandor Licker   // is initialized in is passed as the first argument.
34950b70dcSNandor Licker   QualType Ty = F->getReturnType();
35950b70dcSNandor Licker   if (!Ty->isVoidType() && !Ctx.classify(Ty)) {
36950b70dcSNandor Licker     ParamTypes.push_back(PT_Ptr);
37950b70dcSNandor Licker     ParamOffset += align(primSize(PT_Ptr));
38950b70dcSNandor Licker   }
39950b70dcSNandor Licker 
40950b70dcSNandor Licker   // Assign descriptors to all parameters.
41950b70dcSNandor Licker   // Composite objects are lowered to pointers.
42950b70dcSNandor Licker   for (const ParmVarDecl *PD : F->parameters()) {
43950b70dcSNandor Licker     PrimType Ty;
44950b70dcSNandor Licker     if (llvm::Optional<PrimType> T = Ctx.classify(PD->getType())) {
45950b70dcSNandor Licker       Ty = *T;
46950b70dcSNandor Licker     } else {
47950b70dcSNandor Licker       Ty = PT_Ptr;
48950b70dcSNandor Licker     }
49950b70dcSNandor Licker 
50950b70dcSNandor Licker     Descriptor *Desc = P.createDescriptor(PD, Ty);
51950b70dcSNandor Licker     ParamDescriptors.insert({ParamOffset, {Ty, Desc}});
52950b70dcSNandor Licker     Params.insert({PD, ParamOffset});
53950b70dcSNandor Licker     ParamOffset += align(primSize(Ty));
54950b70dcSNandor Licker     ParamTypes.push_back(Ty);
55950b70dcSNandor Licker   }
56950b70dcSNandor Licker 
57950b70dcSNandor Licker   // Create a handle over the emitted code.
58950b70dcSNandor Licker   Function *Func = P.createFunction(F, ParamOffset, std::move(ParamTypes),
59950b70dcSNandor Licker                                     std::move(ParamDescriptors));
60950b70dcSNandor Licker   // Compile the function body.
61950b70dcSNandor Licker   if (!F->isConstexpr() || !visitFunc(F)) {
62950b70dcSNandor Licker     // Return a dummy function if compilation failed.
63950b70dcSNandor Licker     if (BailLocation)
64950b70dcSNandor Licker       return llvm::make_error<ByteCodeGenError>(*BailLocation);
65950b70dcSNandor Licker     else
66950b70dcSNandor Licker       return Func;
67950b70dcSNandor Licker   } else {
68950b70dcSNandor Licker     // Create scopes from descriptors.
69950b70dcSNandor Licker     llvm::SmallVector<Scope, 2> Scopes;
70950b70dcSNandor Licker     for (auto &DS : Descriptors) {
71950b70dcSNandor Licker       Scopes.emplace_back(std::move(DS));
72950b70dcSNandor Licker     }
73950b70dcSNandor Licker 
74950b70dcSNandor Licker     // Set the function's code.
75950b70dcSNandor Licker     Func->setCode(NextLocalOffset, std::move(Code), std::move(SrcMap),
76950b70dcSNandor Licker                   std::move(Scopes));
77950b70dcSNandor Licker     return Func;
78950b70dcSNandor Licker   }
79950b70dcSNandor Licker }
80950b70dcSNandor Licker 
createLocal(Descriptor * D)81950b70dcSNandor Licker Scope::Local ByteCodeEmitter::createLocal(Descriptor *D) {
82950b70dcSNandor Licker   NextLocalOffset += sizeof(Block);
83950b70dcSNandor Licker   unsigned Location = NextLocalOffset;
84950b70dcSNandor Licker   NextLocalOffset += align(D->getAllocSize());
85950b70dcSNandor Licker   return {Location, D};
86950b70dcSNandor Licker }
87950b70dcSNandor Licker 
emitLabel(LabelTy Label)88950b70dcSNandor Licker void ByteCodeEmitter::emitLabel(LabelTy Label) {
89950b70dcSNandor Licker   const size_t Target = Code.size();
90950b70dcSNandor Licker   LabelOffsets.insert({Label, Target});
91950b70dcSNandor Licker   auto It = LabelRelocs.find(Label);
92950b70dcSNandor Licker   if (It != LabelRelocs.end()) {
93950b70dcSNandor Licker     for (unsigned Reloc : It->second) {
94950b70dcSNandor Licker       using namespace llvm::support;
95950b70dcSNandor Licker 
96950b70dcSNandor Licker       /// Rewrite the operand of all jumps to this label.
97950b70dcSNandor Licker       void *Location = Code.data() + Reloc - sizeof(int32_t);
98950b70dcSNandor Licker       const int32_t Offset = Target - static_cast<int64_t>(Reloc);
99950b70dcSNandor Licker       endian::write<int32_t, endianness::native, 1>(Location, Offset);
100950b70dcSNandor Licker     }
101950b70dcSNandor Licker     LabelRelocs.erase(It);
102950b70dcSNandor Licker   }
103950b70dcSNandor Licker }
104950b70dcSNandor Licker 
getOffset(LabelTy Label)105950b70dcSNandor Licker int32_t ByteCodeEmitter::getOffset(LabelTy Label) {
106950b70dcSNandor Licker   // Compute the PC offset which the jump is relative to.
107950b70dcSNandor Licker   const int64_t Position = Code.size() + sizeof(Opcode) + sizeof(int32_t);
108950b70dcSNandor Licker 
109950b70dcSNandor Licker   // If target is known, compute jump offset.
110950b70dcSNandor Licker   auto It = LabelOffsets.find(Label);
111950b70dcSNandor Licker   if (It != LabelOffsets.end()) {
112950b70dcSNandor Licker     return It->second - Position;
113950b70dcSNandor Licker   }
114950b70dcSNandor Licker 
115950b70dcSNandor Licker   // Otherwise, record relocation and return dummy offset.
116950b70dcSNandor Licker   LabelRelocs[Label].push_back(Position);
117950b70dcSNandor Licker   return 0ull;
118950b70dcSNandor Licker }
119950b70dcSNandor Licker 
bail(const SourceLocation & Loc)120950b70dcSNandor Licker bool ByteCodeEmitter::bail(const SourceLocation &Loc) {
121950b70dcSNandor Licker   if (!BailLocation)
122950b70dcSNandor Licker     BailLocation = Loc;
123950b70dcSNandor Licker   return false;
124950b70dcSNandor Licker }
125950b70dcSNandor Licker 
126950b70dcSNandor Licker /// Helper to write bytecode and bail out if 32-bit offsets become invalid.
127*40080e7eSJessica Clarke /// Pointers will be automatically marshalled as 32-bit IDs.
128*40080e7eSJessica Clarke template <typename T>
129*40080e7eSJessica Clarke static std::enable_if_t<!std::is_pointer<T>::value, void>
emit(Program & P,std::vector<char> & Code,const T & Val,bool & Success)130*40080e7eSJessica Clarke emit(Program &P, std::vector<char> &Code, const T &Val, bool &Success) {
131*40080e7eSJessica Clarke   size_t Size = sizeof(Val);
132950b70dcSNandor Licker   if (Code.size() + Size > std::numeric_limits<unsigned>::max()) {
133950b70dcSNandor Licker     Success = false;
134950b70dcSNandor Licker     return;
135950b70dcSNandor Licker   }
136*40080e7eSJessica Clarke 
137*40080e7eSJessica Clarke   const char *Data = reinterpret_cast<const char *>(&Val);
138950b70dcSNandor Licker   Code.insert(Code.end(), Data, Data + Size);
139*40080e7eSJessica Clarke }
140*40080e7eSJessica Clarke 
141*40080e7eSJessica Clarke template <typename T>
142*40080e7eSJessica Clarke static std::enable_if_t<std::is_pointer<T>::value, void>
emit(Program & P,std::vector<char> & Code,const T & Val,bool & Success)143*40080e7eSJessica Clarke emit(Program &P, std::vector<char> &Code, const T &Val, bool &Success) {
144*40080e7eSJessica Clarke   size_t Size = sizeof(uint32_t);
145*40080e7eSJessica Clarke   if (Code.size() + Size > std::numeric_limits<unsigned>::max()) {
146*40080e7eSJessica Clarke     Success = false;
147*40080e7eSJessica Clarke     return;
148*40080e7eSJessica Clarke   }
149*40080e7eSJessica Clarke 
150*40080e7eSJessica Clarke   uint32_t ID = P.getOrCreateNativePointer(Val);
151*40080e7eSJessica Clarke   const char *Data = reinterpret_cast<const char *>(&ID);
152*40080e7eSJessica Clarke   Code.insert(Code.end(), Data, Data + Size);
153*40080e7eSJessica Clarke }
154*40080e7eSJessica Clarke 
155*40080e7eSJessica Clarke template <typename... Tys>
emitOp(Opcode Op,const Tys &...Args,const SourceInfo & SI)156*40080e7eSJessica Clarke bool ByteCodeEmitter::emitOp(Opcode Op, const Tys &... Args, const SourceInfo &SI) {
157*40080e7eSJessica Clarke   bool Success = true;
158950b70dcSNandor Licker 
159950b70dcSNandor Licker   /// The opcode is followed by arguments. The source info is
160950b70dcSNandor Licker   /// attached to the address after the opcode.
161*40080e7eSJessica Clarke   emit(P, Code, Op, Success);
162950b70dcSNandor Licker   if (SI)
163950b70dcSNandor Licker     SrcMap.emplace_back(Code.size(), SI);
164950b70dcSNandor Licker 
165950b70dcSNandor Licker   /// The initializer list forces the expression to be evaluated
166950b70dcSNandor Licker   /// for each argument in the variadic template, in order.
167*40080e7eSJessica Clarke   (void)std::initializer_list<int>{(emit(P, Code, Args, Success), 0)...};
168950b70dcSNandor Licker 
169950b70dcSNandor Licker   return Success;
170950b70dcSNandor Licker }
171950b70dcSNandor Licker 
jumpTrue(const LabelTy & Label)172950b70dcSNandor Licker bool ByteCodeEmitter::jumpTrue(const LabelTy &Label) {
173950b70dcSNandor Licker   return emitJt(getOffset(Label), SourceInfo{});
174950b70dcSNandor Licker }
175950b70dcSNandor Licker 
jumpFalse(const LabelTy & Label)176950b70dcSNandor Licker bool ByteCodeEmitter::jumpFalse(const LabelTy &Label) {
177950b70dcSNandor Licker   return emitJf(getOffset(Label), SourceInfo{});
178950b70dcSNandor Licker }
179950b70dcSNandor Licker 
jump(const LabelTy & Label)180950b70dcSNandor Licker bool ByteCodeEmitter::jump(const LabelTy &Label) {
181950b70dcSNandor Licker   return emitJmp(getOffset(Label), SourceInfo{});
182950b70dcSNandor Licker }
183950b70dcSNandor Licker 
fallthrough(const LabelTy & Label)184950b70dcSNandor Licker bool ByteCodeEmitter::fallthrough(const LabelTy &Label) {
185950b70dcSNandor Licker   emitLabel(Label);
186950b70dcSNandor Licker   return true;
187950b70dcSNandor Licker }
188950b70dcSNandor Licker 
189950b70dcSNandor Licker //===----------------------------------------------------------------------===//
190950b70dcSNandor Licker // Opcode emitters
191950b70dcSNandor Licker //===----------------------------------------------------------------------===//
192950b70dcSNandor Licker 
193950b70dcSNandor Licker #define GET_LINK_IMPL
194950b70dcSNandor Licker #include "Opcodes.inc"
195950b70dcSNandor Licker #undef GET_LINK_IMPL
196