clang  10.0.0svn
ByteCodeExprGen.cpp
Go to the documentation of this file.
1 //===--- ByteCodeExprGen.cpp - Code generator for expressions ---*- 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 "ByteCodeExprGen.h"
10 #include "ByteCodeEmitter.h"
11 #include "ByteCodeGenError.h"
12 #include "Context.h"
13 #include "Function.h"
14 #include "PrimType.h"
15 #include "Program.h"
16 #include "State.h"
17 
18 using namespace clang;
19 using namespace clang::interp;
20 
22 template <typename T> using Expected = llvm::Expected<T>;
23 template <typename T> using Optional = llvm::Optional<T>;
24 
25 namespace clang {
26 namespace interp {
27 
28 /// Scope used to handle temporaries in toplevel variable declarations.
29 template <class Emitter> class DeclScope final : public LocalScope<Emitter> {
30 public:
32  : LocalScope<Emitter>(Ctx), Scope(Ctx->P, VD) {}
33 
34  void addExtended(const Scope::Local &Local) override {
35  return this->addLocal(Local);
36  }
37 
38 private:
40 };
41 
42 /// Scope used to handle initialization methods.
43 template <class Emitter> class OptionScope {
44 public:
46  using ChainedInitFnRef = std::function<bool(InitFnRef)>;
47 
48  /// Root constructor, compiling or discarding primitives.
49  OptionScope(ByteCodeExprGen<Emitter> *Ctx, bool NewDiscardResult)
50  : Ctx(Ctx), OldDiscardResult(Ctx->DiscardResult),
51  OldInitFn(std::move(Ctx->InitFn)) {
52  Ctx->DiscardResult = NewDiscardResult;
54  }
55 
56  /// Root constructor, setting up compilation state.
58  : Ctx(Ctx), OldDiscardResult(Ctx->DiscardResult),
59  OldInitFn(std::move(Ctx->InitFn)) {
60  Ctx->DiscardResult = true;
61  Ctx->InitFn = NewInitFn;
62  }
63 
64  /// Extends the chain of initialisation pointers.
66  : Ctx(Ctx), OldDiscardResult(Ctx->DiscardResult),
67  OldInitFn(std::move(Ctx->InitFn)) {
68  assert(OldInitFn && "missing initializer");
69  Ctx->InitFn = [this, NewInitFn] { return NewInitFn(*OldInitFn); };
70  }
71 
73  Ctx->DiscardResult = OldDiscardResult;
74  Ctx->InitFn = std::move(OldInitFn);
75  }
76 
77 private:
78  /// Parent context.
80  /// Old discard flag to restore.
81  bool OldDiscardResult;
82  /// Old pointer emitter to restore.
83  llvm::Optional<InitFnRef> OldInitFn;
84 };
85 
86 } // namespace interp
87 } // namespace clang
88 
89 template <class Emitter>
91  auto *SubExpr = CE->getSubExpr();
92  switch (CE->getCastKind()) {
93 
94  case CK_LValueToRValue: {
95  return dereference(
96  CE->getSubExpr(), DerefKind::Read,
97  [](PrimType) {
98  // Value loaded - nothing to do here.
99  return true;
100  },
101  [this, CE](PrimType T) {
102  // Pointer on stack - dereference it.
103  if (!this->emitLoadPop(T, CE))
104  return false;
105  return DiscardResult ? this->emitPop(T, CE) : true;
106  });
107  }
108 
109  case CK_ArrayToPointerDecay:
110  case CK_AtomicToNonAtomic:
111  case CK_ConstructorConversion:
112  case CK_FunctionToPointerDecay:
113  case CK_NonAtomicToAtomic:
114  case CK_NoOp:
115  case CK_UserDefinedConversion:
116  return this->Visit(SubExpr);
117 
118  case CK_ToVoid:
119  return discard(SubExpr);
120 
121  default: {
122  // TODO: implement other casts.
123  return this->bail(CE);
124  }
125  }
126 }
127 
128 template <class Emitter>
130  if (DiscardResult)
131  return true;
132 
133  auto Val = LE->getValue();
134  QualType LitTy = LE->getType();
135  if (Optional<PrimType> T = classify(LitTy))
136  return emitConst(*T, getIntWidth(LitTy), LE->getValue(), LE);
137  return this->bail(LE);
138 }
139 
140 template <class Emitter>
142  return this->Visit(PE->getSubExpr());
143 }
144 
145 template <class Emitter>
147  const Expr *LHS = BO->getLHS();
148  const Expr *RHS = BO->getRHS();
149 
150  // Deal with operations which have composite or void types.
151  switch (BO->getOpcode()) {
152  case BO_Comma:
153  if (!discard(LHS))
154  return false;
155  if (!this->Visit(RHS))
156  return false;
157  return true;
158  default:
159  break;
160  }
161 
162  // Typecheck the args.
163  Optional<PrimType> LT = classify(LHS->getType());
164  Optional<PrimType> RT = classify(RHS->getType());
165  if (!LT || !RT) {
166  return this->bail(BO);
167  }
168 
169  if (Optional<PrimType> T = classify(BO->getType())) {
170  if (!visit(LHS))
171  return false;
172  if (!visit(RHS))
173  return false;
174 
175  auto Discard = [this, T, BO](bool Result) {
176  if (!Result)
177  return false;
178  return DiscardResult ? this->emitPop(*T, BO) : true;
179  };
180 
181  switch (BO->getOpcode()) {
182  case BO_EQ:
183  return Discard(this->emitEQ(*LT, BO));
184  case BO_NE:
185  return Discard(this->emitNE(*LT, BO));
186  case BO_LT:
187  return Discard(this->emitLT(*LT, BO));
188  case BO_LE:
189  return Discard(this->emitLE(*LT, BO));
190  case BO_GT:
191  return Discard(this->emitGT(*LT, BO));
192  case BO_GE:
193  return Discard(this->emitGE(*LT, BO));
194  case BO_Sub:
195  return Discard(this->emitSub(*T, BO));
196  case BO_Add:
197  return Discard(this->emitAdd(*T, BO));
198  case BO_Mul:
199  return Discard(this->emitMul(*T, BO));
200  default:
201  return this->bail(BO);
202  }
203  }
204 
205  return this->bail(BO);
206 }
207 
208 template <class Emitter>
210  OptionScope<Emitter> Scope(this, /*discardResult=*/true);
211  return this->Visit(E);
212 }
213 
214 template <class Emitter>
216  OptionScope<Emitter> Scope(this, /*discardResult=*/false);
217  return this->Visit(E);
218 }
219 
220 template <class Emitter>
222  if (Optional<PrimType> T = classify(E->getType())) {
223  return visit(E);
224  } else {
225  return this->bail(E);
226  }
227 }
228 
229 template <class Emitter>
231  switch (T) {
232  case PT_Bool:
233  return this->emitZeroBool(E);
234  case PT_Sint8:
235  return this->emitZeroSint8(E);
236  case PT_Uint8:
237  return this->emitZeroUint8(E);
238  case PT_Sint16:
239  return this->emitZeroSint16(E);
240  case PT_Uint16:
241  return this->emitZeroUint16(E);
242  case PT_Sint32:
243  return this->emitZeroSint32(E);
244  case PT_Uint32:
245  return this->emitZeroUint32(E);
246  case PT_Sint64:
247  return this->emitZeroSint64(E);
248  case PT_Uint64:
249  return this->emitZeroUint64(E);
250  case PT_Ptr:
251  return this->emitNullPtr(E);
252  }
253  llvm_unreachable("unknown primitive type");
254 }
255 
256 template <class Emitter>
258  const Expr *LV, DerefKind AK, llvm::function_ref<bool(PrimType)> Direct,
259  llvm::function_ref<bool(PrimType)> Indirect) {
260  if (Optional<PrimType> T = classify(LV->getType())) {
261  if (!LV->refersToBitField()) {
262  // Only primitive, non bit-field types can be dereferenced directly.
263  if (auto *DE = dyn_cast<DeclRefExpr>(LV)) {
264  if (!DE->getDecl()->getType()->isReferenceType()) {
265  if (auto *PD = dyn_cast<ParmVarDecl>(DE->getDecl()))
266  return dereferenceParam(LV, *T, PD, AK, Direct, Indirect);
267  if (auto *VD = dyn_cast<VarDecl>(DE->getDecl()))
268  return dereferenceVar(LV, *T, VD, AK, Direct, Indirect);
269  }
270  }
271  }
272 
273  if (!visit(LV))
274  return false;
275  return Indirect(*T);
276  }
277 
278  return false;
279 }
280 
281 template <class Emitter>
283  const Expr *LV, PrimType T, const ParmVarDecl *PD, DerefKind AK,
284  llvm::function_ref<bool(PrimType)> Direct,
285  llvm::function_ref<bool(PrimType)> Indirect) {
286  auto It = this->Params.find(PD);
287  if (It != this->Params.end()) {
288  unsigned Idx = It->second;
289  switch (AK) {
290  case DerefKind::Read:
291  return DiscardResult ? true : this->emitGetParam(T, Idx, LV);
292 
293  case DerefKind::Write:
294  if (!Direct(T))
295  return false;
296  if (!this->emitSetParam(T, Idx, LV))
297  return false;
298  return DiscardResult ? true : this->emitGetPtrParam(Idx, LV);
299 
300  case DerefKind::ReadWrite:
301  if (!this->emitGetParam(T, Idx, LV))
302  return false;
303  if (!Direct(T))
304  return false;
305  if (!this->emitSetParam(T, Idx, LV))
306  return false;
307  return DiscardResult ? true : this->emitGetPtrParam(Idx, LV);
308  }
309  return true;
310  }
311 
312  // If the param is a pointer, we can dereference a dummy value.
313  if (!DiscardResult && T == PT_Ptr && AK == DerefKind::Read) {
314  if (auto Idx = P.getOrCreateDummy(PD))
315  return this->emitGetPtrGlobal(*Idx, PD);
316  return false;
317  }
318 
319  // Value cannot be produced - try to emit pointer and do stuff with it.
320  return visit(LV) && Indirect(T);
321 }
322 
323 template <class Emitter>
325  const Expr *LV, PrimType T, const VarDecl *VD, DerefKind AK,
326  llvm::function_ref<bool(PrimType)> Direct,
327  llvm::function_ref<bool(PrimType)> Indirect) {
328  auto It = Locals.find(VD);
329  if (It != Locals.end()) {
330  const auto &L = It->second;
331  switch (AK) {
332  case DerefKind::Read:
333  if (!this->emitGetLocal(T, L.Offset, LV))
334  return false;
335  return DiscardResult ? this->emitPop(T, LV) : true;
336 
337  case DerefKind::Write:
338  if (!Direct(T))
339  return false;
340  if (!this->emitSetLocal(T, L.Offset, LV))
341  return false;
342  return DiscardResult ? true : this->emitGetPtrLocal(L.Offset, LV);
343 
344  case DerefKind::ReadWrite:
345  if (!this->emitGetLocal(T, L.Offset, LV))
346  return false;
347  if (!Direct(T))
348  return false;
349  if (!this->emitSetLocal(T, L.Offset, LV))
350  return false;
351  return DiscardResult ? true : this->emitGetPtrLocal(L.Offset, LV);
352  }
353  } else if (auto Idx = getGlobalIdx(VD)) {
354  switch (AK) {
355  case DerefKind::Read:
356  if (!this->emitGetGlobal(T, *Idx, LV))
357  return false;
358  return DiscardResult ? this->emitPop(T, LV) : true;
359 
360  case DerefKind::Write:
361  if (!Direct(T))
362  return false;
363  if (!this->emitSetGlobal(T, *Idx, LV))
364  return false;
365  return DiscardResult ? true : this->emitGetPtrGlobal(*Idx, LV);
366 
367  case DerefKind::ReadWrite:
368  if (!this->emitGetGlobal(T, *Idx, LV))
369  return false;
370  if (!Direct(T))
371  return false;
372  if (!this->emitSetGlobal(T, *Idx, LV))
373  return false;
374  return DiscardResult ? true : this->emitGetPtrGlobal(*Idx, LV);
375  }
376  }
377 
378  // If the declaration is a constant value, emit it here even
379  // though the declaration was not evaluated in the current scope.
380  // The access mode can only be read in this case.
381  if (!DiscardResult && AK == DerefKind::Read) {
382  if (VD->hasLocalStorage() && VD->hasInit() && !VD->isConstexpr()) {
383  QualType VT = VD->getType();
384  if (VT.isConstQualified() && VT->isFundamentalType())
385  return this->Visit(VD->getInit());
386  }
387  }
388 
389  // Value cannot be produced - try to emit pointer.
390  return visit(LV) && Indirect(T);
391 }
392 
393 template <class Emitter>
394 bool ByteCodeExprGen<Emitter>::emitConst(PrimType T, unsigned NumBits,
395  const APInt &Value, const Expr *E) {
396  switch (T) {
397  case PT_Sint8:
398  return this->emitConstSint8(Value.getSExtValue(), E);
399  case PT_Uint8:
400  return this->emitConstUint8(Value.getZExtValue(), E);
401  case PT_Sint16:
402  return this->emitConstSint16(Value.getSExtValue(), E);
403  case PT_Uint16:
404  return this->emitConstUint16(Value.getZExtValue(), E);
405  case PT_Sint32:
406  return this->emitConstSint32(Value.getSExtValue(), E);
407  case PT_Uint32:
408  return this->emitConstUint32(Value.getZExtValue(), E);
409  case PT_Sint64:
410  return this->emitConstSint64(Value.getSExtValue(), E);
411  case PT_Uint64:
412  return this->emitConstUint64(Value.getZExtValue(), E);
413  case PT_Bool:
414  return this->emitConstBool(Value.getBoolValue(), E);
415  case PT_Ptr:
416  llvm_unreachable("Invalid integral type");
417  break;
418  }
419  llvm_unreachable("unknown primitive type");
420 }
421 
422 template <class Emitter>
424  PrimType Ty,
425  bool IsConst,
426  bool IsExtended) {
427  Descriptor *D = P.createDescriptor(Src, Ty, IsConst, Src.is<const Expr *>());
428  Scope::Local Local = this->createLocal(D);
429  if (auto *VD = dyn_cast_or_null<ValueDecl>(Src.dyn_cast<const Decl *>()))
430  Locals.insert({VD, Local});
431  VarScope->add(Local, IsExtended);
432  return Local.Offset;
433 }
434 
435 template <class Emitter>
438  QualType Ty;
439 
440  const ValueDecl *Key = nullptr;
441  bool IsTemporary = false;
442  if (auto *VD = dyn_cast_or_null<ValueDecl>(Src.dyn_cast<const Decl *>())) {
443  Key = VD;
444  Ty = VD->getType();
445  }
446  if (auto *E = Src.dyn_cast<const Expr *>()) {
447  IsTemporary = true;
448  Ty = E->getType();
449  }
450 
451  Descriptor *D = P.createDescriptor(Src, Ty.getTypePtr(),
452  Ty.isConstQualified(), IsTemporary);
453  if (!D)
454  return {};
455 
456  Scope::Local Local = this->createLocal(D);
457  if (Key)
458  Locals.insert({Key, Local});
459  VarScope->add(Local, IsExtended);
460  return Local.Offset;
461 }
462 
463 template <class Emitter>
465  const Expr *Init, InitFnRef InitFn) {
466  OptionScope<Emitter> Scope(this, InitFn);
467  return this->Visit(Init);
468 }
469 
470 template <class Emitter>
471 bool ByteCodeExprGen<Emitter>::getPtrVarDecl(const VarDecl *VD, const Expr *E) {
472  // Generate a pointer to the local, loading refs.
473  if (Optional<unsigned> Idx = getGlobalIdx(VD)) {
474  if (VD->getType()->isReferenceType())
475  return this->emitGetGlobalPtr(*Idx, E);
476  else
477  return this->emitGetPtrGlobal(*Idx, E);
478  }
479  return this->bail(VD);
480 }
481 
482 template <class Emitter>
485  if (VD->isConstexpr()) {
486  // Constexpr decl - it must have already been defined.
487  return P.getGlobal(VD);
488  }
489  if (!VD->hasLocalStorage()) {
490  // Not constexpr, but a global var - can have pointer taken.
492  return P.getOrCreateGlobal(VD);
493  }
494  return {};
495 }
496 
497 template <class Emitter>
499  if (auto *PT = dyn_cast<PointerType>(Ty))
500  return PT->getPointeeType()->getAs<RecordType>();
501  else
502  return Ty->getAs<RecordType>();
503 }
504 
505 template <class Emitter>
507  if (auto *RecordTy = getRecordTy(Ty)) {
508  return getRecord(RecordTy->getDecl());
509  }
510  return nullptr;
511 }
512 
513 template <class Emitter>
515  return P.getOrCreateRecord(RD);
516 }
517 
518 template <class Emitter>
520  ExprScope<Emitter> RootScope(this);
521  if (!visit(Exp))
522  return false;
523 
524  if (Optional<PrimType> T = classify(Exp))
525  return this->emitRet(*T, Exp);
526  else
527  return this->emitRetValue(Exp);
528 }
529 
530 template <class Emitter>
532  const Expr *Init = VD->getInit();
533 
534  if (Optional<unsigned> I = P.createGlobal(VD)) {
535  if (Optional<PrimType> T = classify(VD->getType())) {
536  {
537  // Primitive declarations - compute the value and set it.
538  DeclScope<Emitter> LocalScope(this, VD);
539  if (!visit(Init))
540  return false;
541  }
542 
543  // If the declaration is global, save the value for later use.
544  if (!this->emitDup(*T, VD))
545  return false;
546  if (!this->emitInitGlobal(*T, *I, VD))
547  return false;
548  return this->emitRet(*T, VD);
549  } else {
550  {
551  // Composite declarations - allocate storage and initialize it.
552  DeclScope<Emitter> LocalScope(this, VD);
553  if (!visitGlobalInitializer(Init, *I))
554  return false;
555  }
556 
557  // Return a pointer to the global.
558  if (!this->emitGetPtrGlobal(*I, VD))
559  return false;
560  return this->emitRetValue(VD);
561  }
562  }
563 
564  return this->bail(VD);
565 }
566 
567 template <class Emitter>
569  for (VariableScope<Emitter> *C = VarScope; C; C = C->getParent())
570  C->emitDestruction();
571 }
572 
573 namespace clang {
574 namespace interp {
575 
576 template class ByteCodeExprGen<ByteCodeEmitter>;
577 template class ByteCodeExprGen<EvalEmitter>;
578 
579 } // namespace interp
580 } // namespace clang
unsigned llvm::PointerUnion< const Decl *, const Expr * > DeclTy
Definition: Descriptor.h:26
Scope chain managing the variable lifetimes.
A (possibly-)qualified type.
Definition: Type.h:643
std::function< bool(InitFnRef)> ChainedInitFnRef
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee...
Definition: Type.cpp:557
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:88
Opcode getOpcode() const
Definition: Expr.h:3444
StringRef P
ParenExpr - This represents a parethesized expression, e.g.
Definition: Expr.h:1969
bool VisitCastExpr(const CastExpr *E)
Represents a variable declaration or definition.
Definition: Decl.h:827
bool visitInitializer(const Expr *E, InitFnRef GenPtr)
Compiles an initializer for a local.
const T * getAs() const
Member-template getAs<specific type>&#39;.
Definition: Type.h:6858
Represents a parameter to a function.
Definition: Decl.h:1600
bool VisitIntegerLiteral(const IntegerLiteral *E)
Represents a struct/union/class.
Definition: Decl.h:3662
bool visitDecl(const VarDecl *VD) override
Definition: Format.h:2392
bool isReferenceType() const
Definition: Type.h:6403
static llvm::Optional< DereferenceInfo > dereference(ProgramStateRef State, const FieldRegion *FR)
Dereferences FR and returns with the pointee&#39;s region, and whether it needs to be casted back to it&#39;s...
bool visit(const Expr *E)
Evaluates an expression and places result on stack.
llvm::Optional< InitFnRef > InitFn
Expression being initialized.
Expr * getSubExpr()
Definition: Expr.h:3177
Structure/Class descriptor.
Definition: Record.h:23
typename ByteCodeExprGen< Emitter >::InitFnRef InitFnRef
bool visitBool(const Expr *E)
Visits an expression and converts it to a boolean.
bool refersToBitField() const
Returns true if this expression is a gl-value that potentially refers to a bit-field.
Definition: Expr.h:446
PrimType
Enumeration of the primitive types of the VM.
Definition: PrimType.h:27
Context to manage declaration lifetimes.
Definition: Program.h:114
A builtin binary operation expression such as "x + y" or "x <= y".
Definition: Expr.h:3409
bool isConstexpr() const
Whether this variable is (C++11) constexpr.
Definition: Decl.h:1417
const Type * getTypePtr() const
Retrieves a pointer to the underlying (unqualified) type.
Definition: Type.h:6148
CastExpr - Base class for type casts, including both implicit casts (ImplicitCastExpr) and explicit c...
Definition: Expr.h:3125
Describes a memory block created by an allocation site.
Definition: Descriptor.h:51
Expression scope which tracks potentially lifetime extended temporaries which are hoisted to the pare...
bool VisitBinaryOperator(const BinaryOperator *E)
OptionScope(ByteCodeExprGen< Emitter > *Ctx, InitFnRef NewInitFn)
Root constructor, setting up compilation state.
bool discard(const Expr *E)
Evaluates an expression for side effects and discards the result.
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
Definition: Decl.h:644
This represents one expression.
Definition: Expr.h:108
bool hasLocalStorage() const
Returns true if a variable with function scope is a non-static local variable.
Definition: Decl.h:1050
Information about a local&#39;s storage.
Definition: Function.h:35
std::function< bool()> InitFnRef
QualType getType() const
Definition: Expr.h:137
void emitCleanup()
Emits scope cleanup instructions.
unsigned Offset
Offset of the local in frame.
Definition: Function.h:37
const Expr * getSubExpr() const
Definition: Expr.h:1985
OptionScope(ByteCodeExprGen< Emitter > *Ctx, ChainedInitFnRef NewInitFn)
Extends the chain of initialisation pointers.
llvm::APSInt APSInt
bool isConstQualified() const
Determine whether this type is const-qualified.
Definition: Type.h:6207
llvm::APSInt APSInt
CastKind getCastKind() const
Definition: Expr.h:3171
void addExtended(const Scope::Local &Local) override
Record * getRecord(QualType Ty)
Returns a record from a record or pointer type.
Scope used to handle temporaries in toplevel variable declarations.
llvm::APInt APInt
Definition: Integral.h:27
Scope used to handle initialization methods.
Expr * getLHS() const
Definition: Expr.h:3449
Dataflow Directional Tag Classes.
bool DiscardResult
Flag indicating if return value is to be discarded.
const Expr * getInit() const
Definition: Decl.h:1234
DeclScope(ByteCodeExprGen< Emitter > *Ctx, const VarDecl *VD)
const RecordType * getRecordTy(QualType Ty)
Returns a record type from a record or pointer type.
bool visitExpr(const Expr *E) override
llvm::APInt getValue() const
Definition: Expr.h:1405
A helper class that allows the use of isa/cast/dyncast to detect TagType objects of structs/unions/cl...
Definition: Type.h:4444
Scope for local variables.
bool VisitParenExpr(const ParenExpr *E)
Compilation context for expressions.
bool LE(InterpState &S, CodePtr OpPC)
Definition: Interp.h:240
Describes a scope block.
Definition: Function.h:32
bool isFundamentalType() const
Tests whether the type is categorized as a fundamental type.
Definition: Type.h:6354
Expr * getRHS() const
Definition: Expr.h:3451
QualType getType() const
Definition: Decl.h:655
#define true
Definition: stdbool.h:16
OptionScope(ByteCodeExprGen< Emitter > *Ctx, bool NewDiscardResult)
Root constructor, compiling or discarding primitives.
llvm::Optional< unsigned > allocateLocal(DeclTy &&Decl, bool IsExtended=false)
Allocates a space storing a local given its type.
unsigned allocateLocalPrimitive(DeclTy &&Decl, PrimType Ty, bool IsMutable, bool IsExtended=false)
Creates a local primitive value.
bool hasInit() const
Definition: Decl.cpp:2211
bool LT(InterpState &S, CodePtr OpPC)
Definition: Interp.h:233