1 //===--- EvalEmitter.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 "EvalEmitter.h"
10 #include "ByteCodeGenError.h"
11 #include "Context.h"
12 #include "IntegralAP.h"
13 #include "Interp.h"
14 #include "Opcode.h"
15 #include "clang/AST/DeclCXX.h"
16
17 using namespace clang;
18 using namespace clang::interp;
19
EvalEmitter(Context & Ctx,Program & P,State & Parent,InterpStack & Stk,APValue & Result)20 EvalEmitter::EvalEmitter(Context &Ctx, Program &P, State &Parent,
21 InterpStack &Stk, APValue &Result)
22 : Ctx(Ctx), P(P), S(Parent, P, Stk, Ctx, this), EvalResult(&Ctx) {
23 // Create a dummy frame for the interpreter which does not have locals.
24 S.Current =
25 new InterpFrame(S, /*Func=*/nullptr, /*Caller=*/nullptr, CodePtr());
26 }
27
~EvalEmitter()28 EvalEmitter::~EvalEmitter() {
29 for (auto &[K, V] : Locals) {
30 Block *B = reinterpret_cast<Block *>(V.get());
31 if (B->isInitialized())
32 B->invokeDtor();
33 }
34 }
35
interpretExpr(const Expr * E)36 EvaluationResult EvalEmitter::interpretExpr(const Expr *E) {
37 EvalResult.setSource(E);
38
39 if (!this->visitExpr(E))
40 EvalResult.setInvalid();
41
42 return std::move(this->EvalResult);
43 }
44
interpretDecl(const VarDecl * VD)45 EvaluationResult EvalEmitter::interpretDecl(const VarDecl *VD) {
46 EvalResult.setSource(VD);
47
48 if (!this->visitDecl(VD))
49 EvalResult.setInvalid();
50
51 return std::move(this->EvalResult);
52 }
53
emitLabel(LabelTy Label)54 void EvalEmitter::emitLabel(LabelTy Label) {
55 CurrentLabel = Label;
56 }
57
getLabel()58 EvalEmitter::LabelTy EvalEmitter::getLabel() { return NextLabel++; }
59
createLocal(Descriptor * D)60 Scope::Local EvalEmitter::createLocal(Descriptor *D) {
61 // Allocate memory for a local.
62 auto Memory = std::make_unique<char[]>(sizeof(Block) + D->getAllocSize());
63 auto *B = new (Memory.get()) Block(D, /*isStatic=*/false);
64 B->invokeCtor();
65
66 // Initialize local variable inline descriptor.
67 InlineDescriptor &Desc = *reinterpret_cast<InlineDescriptor *>(B->rawData());
68 Desc.Desc = D;
69 Desc.Offset = sizeof(InlineDescriptor);
70 Desc.IsActive = true;
71 Desc.IsBase = false;
72 Desc.IsFieldMutable = false;
73 Desc.IsConst = false;
74 Desc.IsInitialized = false;
75
76 // Register the local.
77 unsigned Off = Locals.size();
78 Locals.insert({Off, std::move(Memory)});
79 return {Off, D};
80 }
81
jumpTrue(const LabelTy & Label)82 bool EvalEmitter::jumpTrue(const LabelTy &Label) {
83 if (isActive()) {
84 if (S.Stk.pop<bool>())
85 ActiveLabel = Label;
86 }
87 return true;
88 }
89
jumpFalse(const LabelTy & Label)90 bool EvalEmitter::jumpFalse(const LabelTy &Label) {
91 if (isActive()) {
92 if (!S.Stk.pop<bool>())
93 ActiveLabel = Label;
94 }
95 return true;
96 }
97
jump(const LabelTy & Label)98 bool EvalEmitter::jump(const LabelTy &Label) {
99 if (isActive())
100 CurrentLabel = ActiveLabel = Label;
101 return true;
102 }
103
fallthrough(const LabelTy & Label)104 bool EvalEmitter::fallthrough(const LabelTy &Label) {
105 if (isActive())
106 ActiveLabel = Label;
107 CurrentLabel = Label;
108 return true;
109 }
110
emitRet(const SourceInfo & Info)111 template <PrimType OpType> bool EvalEmitter::emitRet(const SourceInfo &Info) {
112 if (!isActive())
113 return true;
114 using T = typename PrimConv<OpType>::T;
115 EvalResult.setValue(S.Stk.pop<T>().toAPValue());
116 return true;
117 }
118
emitRet(const SourceInfo & Info)119 template <> bool EvalEmitter::emitRet<PT_Ptr>(const SourceInfo &Info) {
120 if (!isActive())
121 return true;
122 EvalResult.setPointer(S.Stk.pop<Pointer>());
123 return true;
124 }
emitRet(const SourceInfo & Info)125 template <> bool EvalEmitter::emitRet<PT_FnPtr>(const SourceInfo &Info) {
126 if (!isActive())
127 return true;
128 EvalResult.setFunctionPointer(S.Stk.pop<FunctionPointer>());
129 return true;
130 }
131
emitRetVoid(const SourceInfo & Info)132 bool EvalEmitter::emitRetVoid(const SourceInfo &Info) {
133 EvalResult.setValid();
134 return true;
135 }
136
emitRetValue(const SourceInfo & Info)137 bool EvalEmitter::emitRetValue(const SourceInfo &Info) {
138 const auto &Ptr = S.Stk.pop<Pointer>();
139 if (std::optional<APValue> APV = Ptr.toRValue(S.getCtx())) {
140 EvalResult.setValue(*APV);
141 return true;
142 }
143
144 EvalResult.setInvalid();
145 return false;
146 }
147
emitGetPtrLocal(uint32_t I,const SourceInfo & Info)148 bool EvalEmitter::emitGetPtrLocal(uint32_t I, const SourceInfo &Info) {
149 if (!isActive())
150 return true;
151
152 Block *B = getLocal(I);
153 S.Stk.push<Pointer>(B, sizeof(InlineDescriptor));
154 return true;
155 }
156
157 template <PrimType OpType>
emitGetLocal(uint32_t I,const SourceInfo & Info)158 bool EvalEmitter::emitGetLocal(uint32_t I, const SourceInfo &Info) {
159 if (!isActive())
160 return true;
161
162 using T = typename PrimConv<OpType>::T;
163
164 Block *B = getLocal(I);
165 S.Stk.push<T>(*reinterpret_cast<T *>(B->data()));
166 return true;
167 }
168
169 template <PrimType OpType>
emitSetLocal(uint32_t I,const SourceInfo & Info)170 bool EvalEmitter::emitSetLocal(uint32_t I, const SourceInfo &Info) {
171 if (!isActive())
172 return true;
173
174 using T = typename PrimConv<OpType>::T;
175
176 Block *B = getLocal(I);
177 *reinterpret_cast<T *>(B->data()) = S.Stk.pop<T>();
178 InlineDescriptor &Desc = *reinterpret_cast<InlineDescriptor *>(B->rawData());
179 Desc.IsInitialized = true;
180
181 return true;
182 }
183
emitDestroy(uint32_t I,const SourceInfo & Info)184 bool EvalEmitter::emitDestroy(uint32_t I, const SourceInfo &Info) {
185 if (!isActive())
186 return true;
187
188 for (auto &Local : Descriptors[I]) {
189 Block *B = getLocal(Local.Offset);
190 S.deallocate(B);
191 }
192
193 return true;
194 }
195
196 //===----------------------------------------------------------------------===//
197 // Opcode evaluators
198 //===----------------------------------------------------------------------===//
199
200 #define GET_EVAL_IMPL
201 #include "Opcodes.inc"
202 #undef GET_EVAL_IMPL
203