xref: /freebsd/contrib/llvm-project/clang/lib/AST/Interp/Context.cpp (revision 9dba64be9536c28e4800e06512b7f29b43ade345)
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 
21 using namespace clang;
22 using namespace clang::interp;
23 
24 Context::Context(ASTContext &Ctx)
25     : Ctx(Ctx), ForceInterp(getLangOpts().ForceNewConstInterp),
26       P(new Program(*this)) {}
27 
28 Context::~Context() {}
29 
30 InterpResult 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 
54 InterpResult 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 
60 InterpResult 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 
66 const LangOptions &Context::getLangOpts() const { return Ctx.getLangOpts(); }
67 
68 llvm::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 
115 unsigned Context::getCharBit() const {
116   return Ctx.getTargetInfo().getCharWidth();
117 }
118 
119 InterpResult 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 
136 InterpResult 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