clang 10.0.0git

EvalEmitter.cpp
Go to the documentation of this file.
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 "Context.h"
11 #include "Interp.h"
12 #include "Opcode.h"
13 #include "Program.h"
14 #include "clang/AST/DeclCXX.h"
15
16 using namespace clang;
17 using namespace clang::interp;
18
19 using APSInt = llvm::APSInt;
20 template <typename T> using Expected = llvm::Expected<T>;
21
22 EvalEmitter::EvalEmitter(Context &Ctx, Program &P, State &Parent,
23 InterpStack &Stk, APValue &Result)
24 : Ctx(Ctx), P(P), S(Parent, P, Stk, Ctx, this), Result(Result) {
25 // Create a dummy frame for the interpreter which does not have locals.
26 S.Current = new InterpFrame(S, nullptr, nullptr, CodePtr(), Pointer());
27 }
28
29 llvm::Expected<bool> EvalEmitter::interpretExpr(const Expr *E) {
30 if (this->visitExpr(E))
31 return true;
32 if (BailLocation)
33 return llvm::make_error<ByteCodeGenError>(*BailLocation);
34 return false;
35 }
36
37 llvm::Expected<bool> EvalEmitter::interpretDecl(const VarDecl *VD) {
38 if (this->visitDecl(VD))
39 return true;
40 if (BailLocation)
41 return llvm::make_error<ByteCodeGenError>(*BailLocation);
42 return false;
43 }
44
45 void EvalEmitter::emitLabel(LabelTy Label) {
46 CurrentLabel = Label;
47 }
48
49 EvalEmitter::LabelTy EvalEmitter::getLabel() { return NextLabel++; }
50
51 Scope::Local EvalEmitter::createLocal(Descriptor *D) {
52 // Allocate memory for a local.
53 auto Memory = std::make_unique<char[]>(sizeof(Block) + D->getAllocSize());
54 auto *B = new (Memory.get()) Block(D, /*isStatic=*/false);
55 B->invokeCtor();
56
57 // Register the local.
58 unsigned Off = Locals.size();
59 Locals.insert({Off, std::move(Memory)});
60 return {Off, D};
61 }
62
63 bool EvalEmitter::bail(const SourceLocation &Loc) {
64 if (!BailLocation)
65 BailLocation = Loc;
66 return false;
67 }
68
69 bool EvalEmitter::jumpTrue(const LabelTy &Label) {
70 if (isActive()) {
71 if (S.Stk.pop<bool>())
72 ActiveLabel = Label;
73 }
74 return true;
75 }
76
77 bool EvalEmitter::jumpFalse(const LabelTy &Label) {
78 if (isActive()) {
79 if (!S.Stk.pop<bool>())
80 ActiveLabel = Label;
81 }
82 return true;
83 }
84
85 bool EvalEmitter::jump(const LabelTy &Label) {
86 if (isActive())
87 CurrentLabel = ActiveLabel = Label;
88 return true;
89 }
90
91 bool EvalEmitter::fallthrough(const LabelTy &Label) {
92 if (isActive())
93 ActiveLabel = Label;
94 CurrentLabel = Label;
95 return true;
96 }
97
98 template <PrimType OpType> bool EvalEmitter::emitRet(const SourceInfo &Info) {
99 if (!isActive())
100 return true;
101 using T = typename PrimConv<OpType>::T;
102 return ReturnValue<T>(S.Stk.pop<T>(), Result);
103 }
104
105 bool EvalEmitter::emitRetVoid(const SourceInfo &Info) { return true; }
106
107 bool EvalEmitter::emitRetValue(const SourceInfo &Info) {
108 // Method to recursively traverse composites.
109 std::function<bool(QualType, const Pointer &, APValue &)> Composite;
110 Composite = [this, &Composite](QualType Ty, const Pointer &Ptr, APValue &R) {
111 if (auto *AT = Ty->getAs<AtomicType>())
112 Ty = AT->getValueType();
113
114 if (auto *RT = Ty->getAs<RecordType>()) {
115 auto *Record = Ptr.getRecord();
116 assert(Record && "Missing record descriptor");
117
118 bool Ok = true;
119 if (RT->getDecl()->isUnion()) {
120 const FieldDecl *ActiveField = nullptr;
121 APValue Value;
122 for (auto &F : Record->fields()) {
123 const Pointer &FP = Ptr.atField(F.Offset);
124 QualType FieldTy = F.Decl->getType();
125 if (FP.isActive()) {
126 if (llvm::Optional<PrimType> T = Ctx.classify(FieldTy)) {
127 TYPE_SWITCH(*T, Ok &= ReturnValue<T>(FP.deref<T>(), Value));
128 } else {
129 Ok &= Composite(FieldTy, FP, Value);
130 }
131 break;
132 }
133 }
134 R = APValue(ActiveField, Value);
135 } else {
136 unsigned NF = Record->getNumFields();
137 unsigned NB = Record->getNumBases();
138 unsigned NV = Ptr.isBaseClass() ? 0 : Record->getNumVirtualBases();
139
140 R = APValue(APValue::UninitStruct(), NB, NF);
141
142 for (unsigned I = 0; I < NF; ++I) {
143 const Record::Field *FD = Record->getField(I);
144 QualType FieldTy = FD->Decl->getType();
145 const Pointer &FP = Ptr.atField(FD->Offset);
146 APValue &Value = R.getStructField(I);
147
148 if (llvm::Optional<PrimType> T = Ctx.classify(FieldTy)) {
149 TYPE_SWITCH(*T, Ok &= ReturnValue<T>(FP.deref<T>(), Value));
150 } else {
151 Ok &= Composite(FieldTy, FP, Value);
152 }
153 }
154
155 for (unsigned I = 0; I < NB; ++I) {
156 const Record::Base *BD = Record->getBase(I);
157 QualType BaseTy = Ctx.getASTContext().getRecordType(BD->Decl);
158 const Pointer &BP = Ptr.atField(BD->Offset);
159 Ok &= Composite(BaseTy, BP, R.getStructBase(I));
160 }
161
162 for (unsigned I = 0; I < NV; ++I) {
163 const Record::Base *VD = Record->getVirtualBase(I);
164 QualType VirtBaseTy = Ctx.getASTContext().getRecordType(VD->Decl);
165 const Pointer &VP = Ptr.atField(VD->Offset);
166 Ok &= Composite(VirtBaseTy, VP, R.getStructBase(NB + I));
167 }
168 }
169 return Ok;
170 }
171 if (auto *AT = Ty->getAsArrayTypeUnsafe()) {
172 const size_t NumElems = Ptr.getNumElems();
173 QualType ElemTy = AT->getElementType();
174 R = APValue(APValue::UninitArray{}, NumElems, NumElems);
175
176 bool Ok = true;
177 for (unsigned I = 0; I < NumElems; ++I) {
178 APValue &Slot = R.getArrayInitializedElt(I);
179 const Pointer &EP = Ptr.atIndex(I);
180 if (llvm::Optional<PrimType> T = Ctx.classify(ElemTy)) {
181 TYPE_SWITCH(*T, Ok &= ReturnValue<T>(EP.deref<T>(), Slot));
182 } else {
183 Ok &= Composite(ElemTy, EP.narrow(), Slot);
184 }
185 }
186 return Ok;
187 }
188 llvm_unreachable("invalid value to return");
189 };
190
191 // Return the composite type.
192 const auto &Ptr = S.Stk.pop<Pointer>();
193 return Composite(Ptr.getType(), Ptr, Result);
194 }
195
196 bool EvalEmitter::emitGetPtrLocal(uint32_t I, const SourceInfo &Info) {
197 if (!isActive())
198 return true;
199
200 auto It = Locals.find(I);
201 assert(It != Locals.end() && "Missing local variable");
202 S.Stk.push<Pointer>(reinterpret_cast<Block *>(It->second.get()));
203 return true;
204 }
205
206 template <PrimType OpType>
207 bool EvalEmitter::emitGetLocal(uint32_t I, const SourceInfo &Info) {
208 if (!isActive())
209 return true;
210
211 using T = typename PrimConv<OpType>::T;
212
213 auto It = Locals.find(I);
214 assert(It != Locals.end() && "Missing local variable");
215 auto *B = reinterpret_cast<Block *>(It->second.get());
216 S.Stk.push<T>(*reinterpret_cast<T *>(B + 1));
217 return true;
218 }
219
220 template <PrimType OpType>
221 bool EvalEmitter::emitSetLocal(uint32_t I, const SourceInfo &Info) {
222 if (!isActive())
223 return true;
224
225 using T = typename PrimConv<OpType>::T;
226
227 auto It = Locals.find(I);
228 assert(It != Locals.end() && "Missing local variable");
229 auto *B = reinterpret_cast<Block *>(It->second.get());
230 *reinterpret_cast<T *>(B + 1) = S.Stk.pop<T>();
231 return true;
232 }
233
234 bool EvalEmitter::emitDestroy(uint32_t I, const SourceInfo &Info) {
235 if (!isActive())
236 return true;
237
238 for (auto &Local : Descriptors[I]) {
239 auto It = Locals.find(Local.Offset);
240 assert(It != Locals.end() && "Missing local variable");
241 S.deallocate(reinterpret_cast<Block *>(It->second.get()));
242 }
243
244 return true;
245 }
246
247 //===----------------------------------------------------------------------===//
248 // Opcode evaluators
249 //===----------------------------------------------------------------------===//
250
251 #define GET_EVAL_IMPL
252 #include "Opcodes.inc"
253 #undef GET_EVAL_IMPL
clang::interp::EvalEmitter::bail
bool bail(const Stmt *S)
Definition: EvalEmitter.h:60
Interp.h
clang::interp::Record::Base::Decl
const RecordDecl * Decl
Definition: Record.h:34
clang::QualType
A (possibly-)qualified type.
Definition: Type.h:654
clang::interp::Record::Field::Offset
unsigned Offset
Definition: Record.h:28
clang::interp::InterpState::Current
InterpFrame * Current
The current frame.
Definition: InterpState.h:104
clang::interp::PrimConv
Mapping from primitive types to their representation.
Definition: PrimType.h:41
clang::interp::CodePtr
Pointer into the code segment.
Definition: Source.h:25
clang::interp::InterpStack::push
void push(Tys &&... Args)
Constructs a value in place on the top of the stack.
Definition: InterpStack.h:30
clang::interp::InterpFrame
Frame storing local variables.
Definition: InterpFrame.h:29
clang::interp::Record::getBase
const Base * getBase(const RecordDecl *FD) const
Returns a base descriptor.
Definition: Record.cpp:36
P
StringRef P
Definition: ASTMatchersInternal.cpp:485
Value
Value
Definition: UninitializedValues.cpp:101
clang::interp::EvalEmitter::getLabel
LabelTy getLabel()
Create a label.
Definition: EvalEmitter.cpp:49
clang::VarDecl
Represents a variable declaration or definition.
Definition: Decl.h:820
clang::Type::getAs
const T * getAs() const
Member-template getAs<specific type>&#39;.
Definition: Type.h:7002
clang::interp::EvalEmitter::jumpFalse
bool jumpFalse(const LabelTy &Label)
Definition: EvalEmitter.cpp:77
clang::interp::SourceInfo
Describes the statement/declaration an opcode was generated from.
Definition: Source.h:81
clang::interp::Context
Holds all information required to evaluate constexpr code in a module.
Definition: Context.h:38
clang::interp::Pointer::atIndex
Pointer atIndex(unsigned Idx) const
Offsets a pointer inside an array.
Definition: Pointer.h:58
clang::interp::Context::classify
llvm::Optional< PrimType > classify(QualType T)
Classifies an expression.
Definition: Context.cpp:61
clang::interp::Pointer
A pointer to a memory block, live or dead.
Definition: Pointer.h:39
clang::interp::EvalEmitter::EvalEmitter
EvalEmitter(Context &Ctx, Program &P, State &Parent, InterpStack &Stk, APValue &Result)
Definition: EvalEmitter.cpp:22
llvm::Optional< PrimType >
clang::FieldDecl
Represents a member of a struct/union/class.
Definition: Decl.h:2729
clang::interp::InterpStack::pop
T pop()
Returns the value from the top of the stack and removes it.
Definition: InterpStack.h:35
clang::interp::InterpState::Stk
InterpStack & Stk
Temporary stack.
Definition: InterpState.h:100
clang::APValue::UninitStruct
Definition: APValue.h:228
clang::interp::Block
A memory block, either on the stack or in the heap.
Definition: Block.h:37
clang::interp::Record
Structure/Class descriptor.
Definition: Record.h:23
Context.h
clang::interp::Record::getNumVirtualBases
unsigned getNumVirtualBases()
Definition: Record.h:84
llvm::Expected
Definition: LLVM.h:38
clang::Type::getAsArrayTypeUnsafe
const ArrayType * getAsArrayTypeUnsafe() const
A variant of getAs<> for array types which silently discards qualifiers from the outermost type...
Definition: Type.h:7053
clang::interp::Pointer::isActive
bool isActive() const
Checks if the object is active.
Definition: Pointer.h:242
clang::interp::Descriptor
Describes a memory block created by an allocation site.
Definition: Descriptor.h:51
clang::interp::EvalEmitter::visitDecl
virtual bool visitDecl(const VarDecl *VD)=0
clang::interp::EvalEmitter::interpretDecl
llvm::Expected< bool > interpretDecl(const VarDecl *VD)
Definition: EvalEmitter.cpp:37
clang::interp::InterpStack
Stack frame storing temporaries and parameters.
Definition: InterpStack.h:22
APSInt
llvm::APSInt APSInt
Definition: EvalEmitter.cpp:19
Parent
NodeId Parent
Definition: ASTDiff.cpp:191
clang::interp::EvalEmitter::interpretExpr
llvm::Expected< bool > interpretExpr(const Expr *E)
Definition: EvalEmitter.cpp:29
clang::Expr
This represents one expression.
Definition: Expr.h:108
Label
std::string Label
Definition: UsingDeclarationsSorter.cpp:69
clang::interp::Scope::Local
Information about a local&#39;s storage.
Definition: Function.h:35
clang::interp::Record::getNumBases
unsigned getNumBases()
Definition: Record.h:76
clang::interp::Context::getASTContext
ASTContext & getASTContext() const
Returns the AST context.
Definition: Context.h:56
clang::interp::Block::invokeCtor
void invokeCtor()
Invokes the constructor.
Definition: Block.h:71
clang::interp::EvalEmitter::createLocal
Local createLocal(Descriptor *D)
Callback for registering a local.
Definition: EvalEmitter.cpp:51
clang::APValue::getStructField
APValue & getStructField(unsigned i)
Definition: APValue.h:507
clang::interp::Scope::Local::Offset
unsigned Offset
Offset of the local in frame.
Definition: Function.h:37
clang::APValue::UninitArray
Definition: APValue.h:227
clang::ASTContext::getRecordType
QualType getRecordType(const RecordDecl *Decl) const
Definition: ASTContext.cpp:4173
clang::interp::Record::getNumFields
unsigned getNumFields()
Definition: Record.h:68
clang::interp::Program
The program contains and links the bytecode for all functions.
Definition: Program.h:43
Program.h
clang::interp::Pointer::getNumElems
unsigned getNumElems() const
Returns the number of elements.
Definition: Pointer.h:260
clang::interp::EvalEmitter::LabelTy
uint32_t LabelTy
Definition: EvalEmitter.h:38
clang::APValue::getArrayInitializedElt
APValue & getArrayInitializedElt(unsigned I)
Definition: APValue.h:467
Opcode.h
clang::interp::Pointer::narrow
Pointer narrow() const
Restricts the scope of an array element pointer.
Definition: Pointer.h:76
clang::SourceLocation
Encodes a location in the source.
Definition: SourceLocation.h:86
clang::interp::Descriptor::getAllocSize
unsigned getAllocSize() const
Returns the allocated size, including metadata.
Definition: Descriptor.h:134
APSInt
llvm::APSInt APSInt
Definition: ByteCodeEmitter.cpp:18
clang::interp::EvalEmitter::emitLabel
void emitLabel(LabelTy Label)
Define a label.
Definition: EvalEmitter.cpp:45
clang::AtomicType
Definition: Type.h:6125
clang
Dataflow Directional Tag Classes.
Definition: CFGReachabilityAnalysis.h:21
clang::interp::EvalEmitter::Descriptors
llvm::SmallVector< SmallVector< Local, 8 >, 2 > Descriptors
Local descriptors.
Definition: EvalEmitter.h:81
clang::interp::EvalEmitter::fallthrough
bool fallthrough(const LabelTy &Label)
Definition: EvalEmitter.cpp:91
clang::interp::Record::fields
llvm::iterator_range< const_field_iter > fields() const
Definition: Record.h:64
clang::interp::EvalEmitter::jump
bool jump(const LabelTy &Label)
Definition: EvalEmitter.cpp:85
clang::interp::Record::Base::Offset
unsigned Offset
Definition: Record.h:35
clang::interp::InterpState::deallocate
void deallocate(Block *B)
Deallocates a pointer.
Definition: InterpState.cpp:57
clang::interp::Record::Field
Describes a record field.
Definition: Record.h:26
clang::interp::Pointer::deref
T & deref() const
Dereferences the pointer, if it&#39;s live.
Definition: Pointer.h:280
clang::interp::Pointer::atField
Pointer atField(unsigned Off) const
Creates a pointer to a field.
Definition: Pointer.h:70
clang::RecordType
A helper class that allows the use of isa/cast/dyncast to detect TagType objects of structs/unions/cl...
Definition: Type.h:4495
clang::APValue
APValue - This class implements a discriminated union of [uninitialized] [APSInt] [APFloat]...
Definition: APValue.h:115
clang::interp::Record::Field::Decl
const FieldDecl * Decl
Definition: Record.h:27
TYPE_SWITCH
#define TYPE_SWITCH(Expr, B)
Definition: PrimType.h:85
DeclCXX.h
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate.h) and friends (in DeclFriend.h).
clang::interp::State
Interface for the VM to interact with the AST walker&#39;s context.
Definition: State.h:55
clang::interp
Definition: ASTContext.h:146
clang::interp::Record::getField
const Field * getField(const FieldDecl *FD) const
Returns a field.
Definition: Record.cpp:30
clang::interp::EvalEmitter::visitExpr
virtual bool visitExpr(const Expr *E)=0
Methods implemented by the compiler.
clang::ValueDecl::getType
QualType getType() const
Definition: Decl.h:630
clang::interp::Record::getVirtualBase
const Base * getVirtualBase(const RecordDecl *RD) const
Returns a virtual base descriptor.
Definition: Record.cpp:42
clang::interp::Record::Base
Describes a base class.
Definition: Record.h:33
EvalEmitter.h
clang::interp::EvalEmitter::jumpTrue
bool jumpTrue(const LabelTy &Label)
Emits jumps.
Definition: EvalEmitter.cpp:69