1 //===--- ByteCodeEmitter.cpp - Instruction emitter for the VM ---*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 #include "ByteCodeEmitter.h"
13 #include "clang/AST/DeclCXX.h"
15 using namespace clang;
16 using namespace clang::interp;
18 using APSInt = llvm::APSInt;
19 using Error = llvm::Error;
21 Expected<Function *> ByteCodeEmitter::compileFunc(const FunctionDecl *F) {
22 // Do not try to compile undefined functions.
23 if (!F->isDefined(F) || (!F->hasBody() && F->willHaveBody()))
26 // Set up argument indices.
27 unsigned ParamOffset = 0;
28 SmallVector<PrimType, 8> ParamTypes;
29 llvm::DenseMap<unsigned, Function::ParamDescriptor> ParamDescriptors;
31 // If the return is not a primitive, a pointer to the storage where the value
32 // is initialized in is passed as the first argument.
33 QualType Ty = F->getReturnType();
34 if (!Ty->isVoidType() && !Ctx.classify(Ty)) {
35 ParamTypes.push_back(PT_Ptr);
36 ParamOffset += align(primSize(PT_Ptr));
39 // Assign descriptors to all parameters.
40 // Composite objects are lowered to pointers.
41 for (const ParmVarDecl *PD : F->parameters()) {
43 if (llvm::Optional<PrimType> T = Ctx.classify(PD->getType())) {
49 Descriptor *Desc = P.createDescriptor(PD, Ty);
50 ParamDescriptors.insert({ParamOffset, {Ty, Desc}});
51 Params.insert({PD, ParamOffset});
52 ParamOffset += align(primSize(Ty));
53 ParamTypes.push_back(Ty);
56 // Create a handle over the emitted code.
57 Function *Func = P.createFunction(F, ParamOffset, std::move(ParamTypes),
58 std::move(ParamDescriptors));
59 // Compile the function body.
60 if (!F->isConstexpr() || !visitFunc(F)) {
61 // Return a dummy function if compilation failed.
63 return llvm::make_error<ByteCodeGenError>(*BailLocation);
67 // Create scopes from descriptors.
68 llvm::SmallVector<Scope, 2> Scopes;
69 for (auto &DS : Descriptors) {
70 Scopes.emplace_back(std::move(DS));
73 // Set the function's code.
74 Func->setCode(NextLocalOffset, std::move(Code), std::move(SrcMap),
80 Scope::Local ByteCodeEmitter::createLocal(Descriptor *D) {
81 NextLocalOffset += sizeof(Block);
82 unsigned Location = NextLocalOffset;
83 NextLocalOffset += align(D->getAllocSize());
87 void ByteCodeEmitter::emitLabel(LabelTy Label) {
88 const size_t Target = Code.size();
89 LabelOffsets.insert({Label, Target});
90 auto It = LabelRelocs.find(Label);
91 if (It != LabelRelocs.end()) {
92 for (unsigned Reloc : It->second) {
93 using namespace llvm::support;
95 /// Rewrite the operand of all jumps to this label.
96 void *Location = Code.data() + Reloc - sizeof(int32_t);
97 const int32_t Offset = Target - static_cast<int64_t>(Reloc);
98 endian::write<int32_t, endianness::native, 1>(Location, Offset);
100 LabelRelocs.erase(It);
104 int32_t ByteCodeEmitter::getOffset(LabelTy Label) {
105 // Compute the PC offset which the jump is relative to.
106 const int64_t Position = Code.size() + sizeof(Opcode) + sizeof(int32_t);
108 // If target is known, compute jump offset.
109 auto It = LabelOffsets.find(Label);
110 if (It != LabelOffsets.end()) {
111 return It->second - Position;
114 // Otherwise, record relocation and return dummy offset.
115 LabelRelocs[Label].push_back(Position);
119 bool ByteCodeEmitter::bail(const SourceLocation &Loc) {
125 template <typename... Tys>
126 bool ByteCodeEmitter::emitOp(Opcode Op, const Tys &... Args, const SourceInfo &SI) {
129 /// Helper to write bytecode and bail out if 32-bit offsets become invalid.
130 auto emit = [this, &Success](const char *Data, size_t Size) {
131 if (Code.size() + Size > std::numeric_limits<unsigned>::max()) {
135 Code.insert(Code.end(), Data, Data + Size);
138 /// The opcode is followed by arguments. The source info is
139 /// attached to the address after the opcode.
140 emit(reinterpret_cast<const char *>(&Op), sizeof(Opcode));
142 SrcMap.emplace_back(Code.size(), SI);
144 /// The initializer list forces the expression to be evaluated
145 /// for each argument in the variadic template, in order.
146 (void)std::initializer_list<int>{
147 (emit(reinterpret_cast<const char *>(&Args), sizeof(Args)), 0)...};
152 bool ByteCodeEmitter::jumpTrue(const LabelTy &Label) {
153 return emitJt(getOffset(Label), SourceInfo{});
156 bool ByteCodeEmitter::jumpFalse(const LabelTy &Label) {
157 return emitJf(getOffset(Label), SourceInfo{});
160 bool ByteCodeEmitter::jump(const LabelTy &Label) {
161 return emitJmp(getOffset(Label), SourceInfo{});
164 bool ByteCodeEmitter::fallthrough(const LabelTy &Label) {
169 //===----------------------------------------------------------------------===//
171 //===----------------------------------------------------------------------===//
173 #define GET_LINK_IMPL
174 #include "Opcodes.inc"