1 //===--- EvalEmitter.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 "EvalEmitter.h"
10 #include "ByteCodeGenError.h"
12 #include "IntegralAP.h"
15 #include "clang/AST/DeclCXX.h"
17 using namespace clang
;
18 using namespace clang::interp
;
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), Result(Result
) {
23 // Create a dummy frame for the interpreter which does not have locals.
25 new InterpFrame(S
, /*Func=*/nullptr, /*Caller=*/nullptr, CodePtr());
28 EvalEmitter::~EvalEmitter() {
29 for (auto &[K
, V
] : Locals
) {
30 Block
*B
= reinterpret_cast<Block
*>(V
.get());
31 if (B
->isInitialized())
36 llvm::Expected
<bool> EvalEmitter::interpretExpr(const Expr
*E
) {
37 if (this->visitExpr(E
))
40 return llvm::make_error
<ByteCodeGenError
>(*BailLocation
);
44 llvm::Expected
<bool> EvalEmitter::interpretDecl(const VarDecl
*VD
) {
45 if (this->visitDecl(VD
))
48 return llvm::make_error
<ByteCodeGenError
>(*BailLocation
);
52 void EvalEmitter::emitLabel(LabelTy Label
) {
56 EvalEmitter::LabelTy
EvalEmitter::getLabel() { return NextLabel
++; }
58 Scope::Local
EvalEmitter::createLocal(Descriptor
*D
) {
59 // Allocate memory for a local.
60 auto Memory
= std::make_unique
<char[]>(sizeof(Block
) + D
->getAllocSize());
61 auto *B
= new (Memory
.get()) Block(D
, /*isStatic=*/false);
64 // Initialize local variable inline descriptor.
65 InlineDescriptor
&Desc
= *reinterpret_cast<InlineDescriptor
*>(B
->rawData());
67 Desc
.Offset
= sizeof(InlineDescriptor
);
70 Desc
.IsFieldMutable
= false;
72 Desc
.IsInitialized
= false;
74 // Register the local.
75 unsigned Off
= Locals
.size();
76 Locals
.insert({Off
, std::move(Memory
)});
80 bool EvalEmitter::bail(const SourceLocation
&Loc
) {
86 bool EvalEmitter::jumpTrue(const LabelTy
&Label
) {
88 if (S
.Stk
.pop
<bool>())
94 bool EvalEmitter::jumpFalse(const LabelTy
&Label
) {
96 if (!S
.Stk
.pop
<bool>())
102 bool EvalEmitter::jump(const LabelTy
&Label
) {
104 CurrentLabel
= ActiveLabel
= Label
;
108 bool EvalEmitter::fallthrough(const LabelTy
&Label
) {
111 CurrentLabel
= Label
;
115 template <PrimType OpType
> bool EvalEmitter::emitRet(const SourceInfo
&Info
) {
118 using T
= typename PrimConv
<OpType
>::T
;
119 return ReturnValue
<T
>(S
.Stk
.pop
<T
>(), Result
);
122 bool EvalEmitter::emitRetVoid(const SourceInfo
&Info
) { return true; }
124 bool EvalEmitter::emitRetValue(const SourceInfo
&Info
) {
125 // Method to recursively traverse composites.
126 std::function
<bool(QualType
, const Pointer
&, APValue
&)> Composite
;
127 Composite
= [this, &Composite
](QualType Ty
, const Pointer
&Ptr
, APValue
&R
) {
128 if (const auto *AT
= Ty
->getAs
<AtomicType
>())
129 Ty
= AT
->getValueType();
131 if (const auto *RT
= Ty
->getAs
<RecordType
>()) {
132 const auto *Record
= Ptr
.getRecord();
133 assert(Record
&& "Missing record descriptor");
136 if (RT
->getDecl()->isUnion()) {
137 const FieldDecl
*ActiveField
= nullptr;
139 for (const auto &F
: Record
->fields()) {
140 const Pointer
&FP
= Ptr
.atField(F
.Offset
);
141 QualType FieldTy
= F
.Decl
->getType();
143 if (std::optional
<PrimType
> T
= Ctx
.classify(FieldTy
)) {
144 TYPE_SWITCH(*T
, Ok
&= ReturnValue
<T
>(FP
.deref
<T
>(), Value
));
146 Ok
&= Composite(FieldTy
, FP
, Value
);
151 R
= APValue(ActiveField
, Value
);
153 unsigned NF
= Record
->getNumFields();
154 unsigned NB
= Record
->getNumBases();
155 unsigned NV
= Ptr
.isBaseClass() ? 0 : Record
->getNumVirtualBases();
157 R
= APValue(APValue::UninitStruct(), NB
, NF
);
159 for (unsigned I
= 0; I
< NF
; ++I
) {
160 const Record::Field
*FD
= Record
->getField(I
);
161 QualType FieldTy
= FD
->Decl
->getType();
162 const Pointer
&FP
= Ptr
.atField(FD
->Offset
);
163 APValue
&Value
= R
.getStructField(I
);
165 if (std::optional
<PrimType
> T
= Ctx
.classify(FieldTy
)) {
166 TYPE_SWITCH(*T
, Ok
&= ReturnValue
<T
>(FP
.deref
<T
>(), Value
));
168 Ok
&= Composite(FieldTy
, FP
, Value
);
172 for (unsigned I
= 0; I
< NB
; ++I
) {
173 const Record::Base
*BD
= Record
->getBase(I
);
174 QualType BaseTy
= Ctx
.getASTContext().getRecordType(BD
->Decl
);
175 const Pointer
&BP
= Ptr
.atField(BD
->Offset
);
176 Ok
&= Composite(BaseTy
, BP
, R
.getStructBase(I
));
179 for (unsigned I
= 0; I
< NV
; ++I
) {
180 const Record::Base
*VD
= Record
->getVirtualBase(I
);
181 QualType VirtBaseTy
= Ctx
.getASTContext().getRecordType(VD
->Decl
);
182 const Pointer
&VP
= Ptr
.atField(VD
->Offset
);
183 Ok
&= Composite(VirtBaseTy
, VP
, R
.getStructBase(NB
+ I
));
189 if (Ty
->isIncompleteArrayType()) {
190 R
= APValue(APValue::UninitArray(), 0, 0);
194 if (const auto *AT
= Ty
->getAsArrayTypeUnsafe()) {
195 const size_t NumElems
= Ptr
.getNumElems();
196 QualType ElemTy
= AT
->getElementType();
197 R
= APValue(APValue::UninitArray
{}, NumElems
, NumElems
);
200 for (unsigned I
= 0; I
< NumElems
; ++I
) {
201 APValue
&Slot
= R
.getArrayInitializedElt(I
);
202 const Pointer
&EP
= Ptr
.atIndex(I
);
203 if (std::optional
<PrimType
> T
= Ctx
.classify(ElemTy
)) {
204 TYPE_SWITCH(*T
, Ok
&= ReturnValue
<T
>(EP
.deref
<T
>(), Slot
));
206 Ok
&= Composite(ElemTy
, EP
.narrow(), Slot
);
211 llvm_unreachable("invalid value to return");
214 // Return the composite type.
215 const auto &Ptr
= S
.Stk
.pop
<Pointer
>();
216 return Composite(Ptr
.getType(), Ptr
, Result
);
219 bool EvalEmitter::emitGetPtrLocal(uint32_t I
, const SourceInfo
&Info
) {
223 Block
*B
= getLocal(I
);
224 S
.Stk
.push
<Pointer
>(B
, sizeof(InlineDescriptor
));
228 template <PrimType OpType
>
229 bool EvalEmitter::emitGetLocal(uint32_t I
, const SourceInfo
&Info
) {
233 using T
= typename PrimConv
<OpType
>::T
;
235 Block
*B
= getLocal(I
);
236 S
.Stk
.push
<T
>(*reinterpret_cast<T
*>(B
->data()));
240 template <PrimType OpType
>
241 bool EvalEmitter::emitSetLocal(uint32_t I
, const SourceInfo
&Info
) {
245 using T
= typename PrimConv
<OpType
>::T
;
247 Block
*B
= getLocal(I
);
248 *reinterpret_cast<T
*>(B
->data()) = S
.Stk
.pop
<T
>();
249 InlineDescriptor
&Desc
= *reinterpret_cast<InlineDescriptor
*>(B
->rawData());
250 Desc
.IsInitialized
= true;
255 bool EvalEmitter::emitDestroy(uint32_t I
, const SourceInfo
&Info
) {
259 for (auto &Local
: Descriptors
[I
]) {
260 Block
*B
= getLocal(Local
.Offset
);
267 //===----------------------------------------------------------------------===//
269 //===----------------------------------------------------------------------===//
271 #define GET_EVAL_IMPL
272 #include "Opcodes.inc"