xref: /freebsd-src/contrib/llvm-project/clang/lib/AST/Interp/EvalEmitter.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1a7dea167SDimitry Andric //===--- EvalEmitter.h - Instruction emitter for the VM ---------*- C++ -*-===//
2a7dea167SDimitry Andric //
3a7dea167SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4a7dea167SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5a7dea167SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6a7dea167SDimitry Andric //
7a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
8a7dea167SDimitry Andric //
9a7dea167SDimitry Andric // Defines the instruction emitters.
10a7dea167SDimitry Andric //
11a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
12a7dea167SDimitry Andric 
13a7dea167SDimitry Andric #ifndef LLVM_CLANG_AST_INTERP_EVALEMITTER_H
14a7dea167SDimitry Andric #define LLVM_CLANG_AST_INTERP_EVALEMITTER_H
15a7dea167SDimitry Andric 
167a6dacacSDimitry Andric #include "EvaluationResult.h"
17a7dea167SDimitry Andric #include "InterpState.h"
18a7dea167SDimitry Andric #include "PrimType.h"
19a7dea167SDimitry Andric #include "Source.h"
20a7dea167SDimitry Andric #include "llvm/Support/Error.h"
21a7dea167SDimitry Andric 
22a7dea167SDimitry Andric namespace clang {
23a7dea167SDimitry Andric namespace interp {
24a7dea167SDimitry Andric class Context;
25a7dea167SDimitry Andric class Function;
265f757f3fSDimitry Andric class InterpStack;
27a7dea167SDimitry Andric class Program;
28a7dea167SDimitry Andric enum Opcode : uint32_t;
29a7dea167SDimitry Andric 
30a7dea167SDimitry Andric /// An emitter which evaluates opcodes as they are emitted.
31a7dea167SDimitry Andric class EvalEmitter : public SourceMapper {
32a7dea167SDimitry Andric public:
33a7dea167SDimitry Andric   using LabelTy = uint32_t;
34a7dea167SDimitry Andric   using AddrTy = uintptr_t;
35a7dea167SDimitry Andric   using Local = Scope::Local;
36a7dea167SDimitry Andric 
37*0fca6ea1SDimitry Andric   EvaluationResult interpretExpr(const Expr *E,
38*0fca6ea1SDimitry Andric                                  bool ConvertResultToRValue = false);
39*0fca6ea1SDimitry Andric   EvaluationResult interpretDecl(const VarDecl *VD, bool CheckFullyInitialized);
40*0fca6ea1SDimitry Andric 
41*0fca6ea1SDimitry Andric   /// Clean up all resources.
42*0fca6ea1SDimitry Andric   void cleanup();
437a6dacacSDimitry Andric 
447a6dacacSDimitry Andric   InterpState &getState() { return S; }
45a7dea167SDimitry Andric 
46a7dea167SDimitry Andric protected:
47*0fca6ea1SDimitry Andric   EvalEmitter(Context &Ctx, Program &P, State &Parent, InterpStack &Stk);
48a7dea167SDimitry Andric 
495f757f3fSDimitry Andric   virtual ~EvalEmitter();
50a7dea167SDimitry Andric 
51a7dea167SDimitry Andric   /// Define a label.
52a7dea167SDimitry Andric   void emitLabel(LabelTy Label);
53a7dea167SDimitry Andric   /// Create a label.
54a7dea167SDimitry Andric   LabelTy getLabel();
55a7dea167SDimitry Andric 
56a7dea167SDimitry Andric   /// Methods implemented by the compiler.
57a7dea167SDimitry Andric   virtual bool visitExpr(const Expr *E) = 0;
58*0fca6ea1SDimitry Andric   virtual bool visitDeclAndReturn(const VarDecl *VD, bool ConstantContext) = 0;
59*0fca6ea1SDimitry Andric   virtual bool visitFunc(const FunctionDecl *F) = 0;
60a7dea167SDimitry Andric 
61a7dea167SDimitry Andric   /// Emits jumps.
62a7dea167SDimitry Andric   bool jumpTrue(const LabelTy &Label);
63a7dea167SDimitry Andric   bool jumpFalse(const LabelTy &Label);
64a7dea167SDimitry Andric   bool jump(const LabelTy &Label);
65a7dea167SDimitry Andric   bool fallthrough(const LabelTy &Label);
66a7dea167SDimitry Andric 
67*0fca6ea1SDimitry Andric   /// Since expressions can only jump forward, predicated execution is
68*0fca6ea1SDimitry Andric   /// used to deal with if-else statements.
69*0fca6ea1SDimitry Andric   bool isActive() const { return CurrentLabel == ActiveLabel; }
70*0fca6ea1SDimitry Andric 
71a7dea167SDimitry Andric   /// Callback for registering a local.
72a7dea167SDimitry Andric   Local createLocal(Descriptor *D);
73a7dea167SDimitry Andric 
74a7dea167SDimitry Andric   /// Returns the source location of the current opcode.
75bdd1243dSDimitry Andric   SourceInfo getSource(const Function *F, CodePtr PC) const override {
7606c3fb27SDimitry Andric     return (F && F->hasBody()) ? F->getSource(PC) : CurrentSource;
77a7dea167SDimitry Andric   }
78a7dea167SDimitry Andric 
79a7dea167SDimitry Andric   /// Parameter indices.
805f757f3fSDimitry Andric   llvm::DenseMap<const ParmVarDecl *, ParamOffset> Params;
8106c3fb27SDimitry Andric   /// Lambda captures.
825f757f3fSDimitry Andric   llvm::DenseMap<const ValueDecl *, ParamOffset> LambdaCaptures;
835f757f3fSDimitry Andric   /// Offset of the This parameter in a lambda record.
84*0fca6ea1SDimitry Andric   ParamOffset LambdaThisCapture{0, false};
85a7dea167SDimitry Andric   /// Local descriptors.
86a7dea167SDimitry Andric   llvm::SmallVector<SmallVector<Local, 8>, 2> Descriptors;
87a7dea167SDimitry Andric 
88a7dea167SDimitry Andric private:
89a7dea167SDimitry Andric   /// Current compilation context.
90a7dea167SDimitry Andric   Context &Ctx;
91a7dea167SDimitry Andric   /// Current program.
92a7dea167SDimitry Andric   Program &P;
93a7dea167SDimitry Andric   /// Callee evaluation state.
94a7dea167SDimitry Andric   InterpState S;
95a7dea167SDimitry Andric   /// Location to write the result to.
967a6dacacSDimitry Andric   EvaluationResult EvalResult;
97*0fca6ea1SDimitry Andric   /// Whether the result should be converted to an RValue.
98*0fca6ea1SDimitry Andric   bool ConvertResultToRValue = false;
99*0fca6ea1SDimitry Andric   /// Whether we should check if the result has been fully
100*0fca6ea1SDimitry Andric   /// initialized.
101*0fca6ea1SDimitry Andric   bool CheckFullyInitialized = false;
102a7dea167SDimitry Andric 
103a7dea167SDimitry Andric   /// Temporaries which require storage.
104a7dea167SDimitry Andric   llvm::DenseMap<unsigned, std::unique_ptr<char[]>> Locals;
105a7dea167SDimitry Andric 
10606c3fb27SDimitry Andric   Block *getLocal(unsigned Index) const {
10706c3fb27SDimitry Andric     auto It = Locals.find(Index);
10806c3fb27SDimitry Andric     assert(It != Locals.end() && "Missing local variable");
10906c3fb27SDimitry Andric     return reinterpret_cast<Block *>(It->second.get());
11006c3fb27SDimitry Andric   }
11106c3fb27SDimitry Andric 
112*0fca6ea1SDimitry Andric   void updateGlobalTemporaries();
113*0fca6ea1SDimitry Andric 
114a7dea167SDimitry Andric   // The emitter always tracks the current instruction and sets OpPC to a token
115a7dea167SDimitry Andric   // value which is mapped to the location of the opcode being evaluated.
116a7dea167SDimitry Andric   CodePtr OpPC;
117a7dea167SDimitry Andric   /// Location of the current instruction.
118a7dea167SDimitry Andric   SourceInfo CurrentSource;
119a7dea167SDimitry Andric 
120a7dea167SDimitry Andric   /// Next label ID to generate - first label is 1.
121a7dea167SDimitry Andric   LabelTy NextLabel = 1;
122a7dea167SDimitry Andric   /// Label being executed - 0 is the entry label.
123a7dea167SDimitry Andric   LabelTy CurrentLabel = 0;
124a7dea167SDimitry Andric   /// Active block which should be executed.
125a7dea167SDimitry Andric   LabelTy ActiveLabel = 0;
126a7dea167SDimitry Andric 
127a7dea167SDimitry Andric protected:
128a7dea167SDimitry Andric #define GET_EVAL_PROTO
129a7dea167SDimitry Andric #include "Opcodes.inc"
130a7dea167SDimitry Andric #undef GET_EVAL_PROTO
131a7dea167SDimitry Andric };
132a7dea167SDimitry Andric 
133a7dea167SDimitry Andric } // namespace interp
134a7dea167SDimitry Andric } // namespace clang
135a7dea167SDimitry Andric 
136a7dea167SDimitry Andric #endif
137