Context.cpp revision 358851
1//===--- Context.cpp - Context for the constexpr 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 "Context.h"
10#include "ByteCodeEmitter.h"
11#include "ByteCodeExprGen.h"
12#include "ByteCodeStmtGen.h"
13#include "EvalEmitter.h"
14#include "Interp.h"
15#include "InterpFrame.h"
16#include "InterpStack.h"
17#include "PrimType.h"
18#include "Program.h"
19#include "clang/AST/Expr.h"
20
21using namespace clang;
22using namespace clang::interp;
23
24Context::Context(ASTContext &Ctx) : Ctx(Ctx), P(new Program(*this)) {}
25
26Context::~Context() {}
27
28bool Context::isPotentialConstantExpr(State &Parent, const FunctionDecl *FD) {
29  Function *Func = P->getFunction(FD);
30  if (!Func) {
31    if (auto R = ByteCodeStmtGen<ByteCodeEmitter>(*this, *P).compileFunc(FD)) {
32      Func = *R;
33    } else {
34      handleAllErrors(R.takeError(), [&Parent](ByteCodeGenError &Err) {
35        Parent.FFDiag(Err.getLoc(), diag::err_experimental_clang_interp_failed);
36      });
37      return false;
38    }
39  }
40
41  if (!Func->isConstexpr())
42    return false;
43
44  APValue Dummy;
45  return Run(Parent, Func, Dummy);
46}
47
48bool Context::evaluateAsRValue(State &Parent, const Expr *E, APValue &Result) {
49  ByteCodeExprGen<EvalEmitter> C(*this, *P, Parent, Stk, Result);
50  return Check(Parent, C.interpretExpr(E));
51}
52
53bool Context::evaluateAsInitializer(State &Parent, const VarDecl *VD,
54                                    APValue &Result) {
55  ByteCodeExprGen<EvalEmitter> C(*this, *P, Parent, Stk, Result);
56  return Check(Parent, C.interpretDecl(VD));
57}
58
59const LangOptions &Context::getLangOpts() const { return Ctx.getLangOpts(); }
60
61llvm::Optional<PrimType> Context::classify(QualType T) {
62  if (T->isReferenceType() || T->isPointerType()) {
63    return PT_Ptr;
64  }
65
66  if (T->isBooleanType())
67    return PT_Bool;
68
69  if (T->isSignedIntegerOrEnumerationType()) {
70    switch (Ctx.getIntWidth(T)) {
71    case 64:
72      return PT_Sint64;
73    case 32:
74      return PT_Sint32;
75    case 16:
76      return PT_Sint16;
77    case 8:
78      return PT_Sint8;
79    default:
80      return {};
81    }
82  }
83
84  if (T->isUnsignedIntegerOrEnumerationType()) {
85    switch (Ctx.getIntWidth(T)) {
86    case 64:
87      return PT_Uint64;
88    case 32:
89      return PT_Uint32;
90    case 16:
91      return PT_Uint16;
92    case 8:
93      return PT_Uint8;
94    default:
95      return {};
96    }
97  }
98
99  if (T->isNullPtrType())
100    return PT_Ptr;
101
102  if (auto *AT = dyn_cast<AtomicType>(T))
103    return classify(AT->getValueType());
104
105  return {};
106}
107
108unsigned Context::getCharBit() const {
109  return Ctx.getTargetInfo().getCharWidth();
110}
111
112bool Context::Run(State &Parent, Function *Func, APValue &Result) {
113  InterpState State(Parent, *P, Stk, *this);
114  State.Current = new InterpFrame(State, Func, nullptr, {}, {});
115  if (Interpret(State, Result))
116    return true;
117  Stk.clear();
118  return false;
119}
120
121bool Context::Check(State &Parent, llvm::Expected<bool> &&Flag) {
122  if (Flag)
123    return *Flag;
124  handleAllErrors(Flag.takeError(), [&Parent](ByteCodeGenError &Err) {
125    Parent.FFDiag(Err.getLoc(), diag::err_experimental_clang_interp_failed);
126  });
127  return false;
128}
129