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