Context.cpp revision 353942
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)
25    : Ctx(Ctx), ForceInterp(getLangOpts().ForceNewConstInterp),
26      P(new Program(*this)) {}
27
28Context::~Context() {}
29
30InterpResult Context::isPotentialConstantExpr(State &Parent,
31                                              const FunctionDecl *FD) {
32  Function *Func = P->getFunction(FD);
33  if (!Func) {
34    if (auto R = ByteCodeStmtGen<ByteCodeEmitter>(*this, *P).compileFunc(FD)) {
35      Func = *R;
36    } else if (ForceInterp) {
37      handleAllErrors(R.takeError(), [&Parent](ByteCodeGenError &Err) {
38        Parent.FFDiag(Err.getLoc(), diag::err_experimental_clang_interp_failed);
39      });
40      return InterpResult::Fail;
41    } else {
42      consumeError(R.takeError());
43      return InterpResult::Bail;
44    }
45  }
46
47  if (!Func->isConstexpr())
48    return InterpResult::Fail;
49
50  APValue Dummy;
51  return Run(Parent, Func, Dummy);
52}
53
54InterpResult Context::evaluateAsRValue(State &Parent, const Expr *E,
55                                       APValue &Result) {
56  ByteCodeExprGen<EvalEmitter> C(*this, *P, Parent, Stk, Result);
57  return Check(Parent, C.interpretExpr(E));
58}
59
60InterpResult Context::evaluateAsInitializer(State &Parent, const VarDecl *VD,
61                                            APValue &Result) {
62  ByteCodeExprGen<EvalEmitter> C(*this, *P, Parent, Stk, Result);
63  return Check(Parent, C.interpretDecl(VD));
64}
65
66const LangOptions &Context::getLangOpts() const { return Ctx.getLangOpts(); }
67
68llvm::Optional<PrimType> Context::classify(QualType T) {
69  if (T->isReferenceType() || T->isPointerType()) {
70    return PT_Ptr;
71  }
72
73  if (T->isBooleanType())
74    return PT_Bool;
75
76  if (T->isSignedIntegerOrEnumerationType()) {
77    switch (Ctx.getIntWidth(T)) {
78    case 64:
79      return PT_Sint64;
80    case 32:
81      return PT_Sint32;
82    case 16:
83      return PT_Sint16;
84    case 8:
85      return PT_Sint8;
86    default:
87      return {};
88    }
89  }
90
91  if (T->isUnsignedIntegerOrEnumerationType()) {
92    switch (Ctx.getIntWidth(T)) {
93    case 64:
94      return PT_Uint64;
95    case 32:
96      return PT_Uint32;
97    case 16:
98      return PT_Uint16;
99    case 8:
100      return PT_Uint8;
101    default:
102      return {};
103    }
104  }
105
106  if (T->isNullPtrType())
107    return PT_Ptr;
108
109  if (auto *AT = dyn_cast<AtomicType>(T))
110    return classify(AT->getValueType());
111
112  return {};
113}
114
115unsigned Context::getCharBit() const {
116  return Ctx.getTargetInfo().getCharWidth();
117}
118
119InterpResult Context::Run(State &Parent, Function *Func, APValue &Result) {
120  InterpResult Flag;
121  {
122    InterpState State(Parent, *P, Stk, *this);
123    State.Current = new InterpFrame(State, Func, nullptr, {}, {});
124    if (Interpret(State, Result)) {
125      Flag = InterpResult::Success;
126    } else {
127      Flag = InterpResult::Fail;
128    }
129  }
130
131  if (Flag != InterpResult::Success)
132    Stk.clear();
133  return Flag;
134}
135
136InterpResult Context::Check(State &Parent, llvm::Expected<bool> &&R) {
137  if (R) {
138    return *R ? InterpResult::Success : InterpResult::Fail;
139  } else if (ForceInterp) {
140    handleAllErrors(R.takeError(), [&Parent](ByteCodeGenError &Err) {
141      Parent.FFDiag(Err.getLoc(), diag::err_experimental_clang_interp_failed);
142    });
143    return InterpResult::Fail;
144  } else {
145    consumeError(R.takeError());
146    return InterpResult::Bail;
147  }
148}
149