clang  10.0.0svn
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 
20 template <typename T> using Expected = llvm::Expected<T>;
21 
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 
30  if (this->visitExpr(E))
31  return true;
32  if (BailLocation)
33  return llvm::make_error<ByteCodeGenError>(*BailLocation);
34  return false;
35 }
36 
38  if (this->visitDecl(VD))
39  return true;
40  if (BailLocation)
41  return llvm::make_error<ByteCodeGenError>(*BailLocation);
42  return false;
43 }
44 
46  CurrentLabel = Label;
47 }
48 
50 
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 
64  if (!BailLocation)
65  BailLocation = Loc;
66  return false;
67 }
68 
70  if (isActive()) {
71  if (S.Stk.pop<bool>())
72  ActiveLabel = Label;
73  }
74  return true;
75 }
76 
78  if (isActive()) {
79  if (!S.Stk.pop<bool>())
80  ActiveLabel = Label;
81  }
82  return true;
83 }
84 
86  if (isActive())
87  CurrentLabel = ActiveLabel = Label;
88  return true;
89 }
90 
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
bool bail(const Stmt *S)
Definition: EvalEmitter.h:60
const RecordDecl * Decl
Definition: Record.h:34
A (possibly-)qualified type.
Definition: Type.h:643
InterpFrame * Current
The current frame.
Definition: InterpState.h:104
Mapping from primitive types to their representation.
Definition: PrimType.h:41
Pointer into the code segment.
Definition: Source.h:25
void push(Tys &&... Args)
Constructs a value in place on the top of the stack.
Definition: InterpStack.h:30
Frame storing local variables.
Definition: InterpFrame.h:29
const Base * getBase(const RecordDecl *FD) const
Returns a base descriptor.
Definition: Record.cpp:36
StringRef P
LabelTy getLabel()
Create a label.
Definition: EvalEmitter.cpp:49
Represents a variable declaration or definition.
Definition: Decl.h:827
const T * getAs() const
Member-template getAs<specific type>&#39;.
Definition: Type.h:6858
bool jumpFalse(const LabelTy &Label)
Definition: EvalEmitter.cpp:77
Describes the statement/declaration an opcode was generated from.
Definition: Source.h:81
Holds all information required to evaluate constexpr code in a module.
Definition: Context.h:48
Pointer atIndex(unsigned Idx) const
Offsets a pointer inside an array.
Definition: Pointer.h:58
llvm::Optional< PrimType > classify(QualType T)
Classifies an expression.
Definition: Context.cpp:68
A pointer to a memory block, live or dead.
Definition: Pointer.h:39
EvalEmitter(Context &Ctx, Program &P, State &Parent, InterpStack &Stk, APValue &Result)
Definition: EvalEmitter.cpp:22
Represents a member of a struct/union/class.
Definition: Decl.h:2643
T pop()
Returns the value from the top of the stack and removes it.
Definition: InterpStack.h:35
InterpStack & Stk
Temporary stack.
Definition: InterpState.h:100
A memory block, either on the stack or in the heap.
Definition: Block.h:37
Structure/Class descriptor.
Definition: Record.h:23
unsigned getNumVirtualBases()
Definition: Record.h:84
const ArrayType * getAsArrayTypeUnsafe() const
A variant of getAs<> for array types which silently discards qualifiers from the outermost type...
Definition: Type.h:6909
bool isActive() const
Checks if the object is active.
Definition: Pointer.h:242
Describes a memory block created by an allocation site.
Definition: Descriptor.h:51
virtual bool visitDecl(const VarDecl *VD)=0
llvm::Expected< bool > interpretDecl(const VarDecl *VD)
Definition: EvalEmitter.cpp:37
Stack frame storing temporaries and parameters.
Definition: InterpStack.h:22
llvm::APSInt APSInt
Definition: EvalEmitter.cpp:19
NodeId Parent
Definition: ASTDiff.cpp:191
llvm::Expected< bool > interpretExpr(const Expr *E)
Definition: EvalEmitter.cpp:29
This represents one expression.
Definition: Expr.h:108
std::string Label
Information about a local&#39;s storage.
Definition: Function.h:35
unsigned getNumBases()
Definition: Record.h:76
ASTContext & getASTContext() const
Returns the AST context.
Definition: Context.h:68
void invokeCtor()
Invokes the constructor.
Definition: Block.h:71
Local createLocal(Descriptor *D)
Callback for registering a local.
Definition: EvalEmitter.cpp:51
APValue & getStructField(unsigned i)
Definition: APValue.h:507
unsigned Offset
Offset of the local in frame.
Definition: Function.h:37
QualType getRecordType(const RecordDecl *Decl) const
unsigned getNumFields()
Definition: Record.h:68
The program contains and links the bytecode for all functions.
Definition: Program.h:43
unsigned getNumElems() const
Returns the number of elements.
Definition: Pointer.h:260
APValue & getArrayInitializedElt(unsigned I)
Definition: APValue.h:467
Pointer narrow() const
Restricts the scope of an array element pointer.
Definition: Pointer.h:76
Encodes a location in the source.
unsigned getAllocSize() const
Returns the allocated size, including metadata.
Definition: Descriptor.h:134
llvm::APSInt APSInt
void emitLabel(LabelTy Label)
Define a label.
Definition: EvalEmitter.cpp:45
Dataflow Directional Tag Classes.
llvm::SmallVector< SmallVector< Local, 8 >, 2 > Descriptors
Local descriptors.
Definition: EvalEmitter.h:81
bool fallthrough(const LabelTy &Label)
Definition: EvalEmitter.cpp:91
llvm::iterator_range< const_field_iter > fields() const
Definition: Record.h:64
bool jump(const LabelTy &Label)
Definition: EvalEmitter.cpp:85
void deallocate(Block *B)
Deallocates a pointer.
Definition: InterpState.cpp:57
Describes a record field.
Definition: Record.h:26
T & deref() const
Dereferences the pointer, if it&#39;s live.
Definition: Pointer.h:280
Pointer atField(unsigned Off) const
Creates a pointer to a field.
Definition: Pointer.h:70
A helper class that allows the use of isa/cast/dyncast to detect TagType objects of structs/unions/cl...
Definition: Type.h:4444
APValue - This class implements a discriminated union of [uninitialized] [APSInt] [APFloat]...
Definition: APValue.h:115
const FieldDecl * Decl
Definition: Record.h:27
#define TYPE_SWITCH(Expr, B)
Definition: PrimType.h:85
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate.h) and friends (in DeclFriend.h).
Interface for the VM to interact with the AST walker&#39;s context.
Definition: State.h:55
const Field * getField(const FieldDecl *FD) const
Returns a field.
Definition: Record.cpp:30
virtual bool visitExpr(const Expr *E)=0
Methods implemented by the compiler.
QualType getType() const
Definition: Decl.h:655
const Base * getVirtualBase(const RecordDecl *RD) const
Returns a virtual base descriptor.
Definition: Record.cpp:42
Describes a base class.
Definition: Record.h:33
bool jumpTrue(const LabelTy &Label)
Emits jumps.
Definition: EvalEmitter.cpp:69