1 | //===--- Interpreter.h - Incremental Compilation and Execution---*- 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 | // This file defines the component which performs incremental code |
10 | // compilation and execution. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #ifndef LLVM_CLANG_INTERPRETER_INTERPRETER_H |
15 | #define LLVM_CLANG_INTERPRETER_INTERPRETER_H |
16 | |
17 | #include "clang/AST/Decl.h" |
18 | #include "clang/AST/GlobalDecl.h" |
19 | #include "clang/Interpreter/PartialTranslationUnit.h" |
20 | #include "clang/Interpreter/Value.h" |
21 | #include "clang/Sema/Ownership.h" |
22 | |
23 | #include "llvm/ADT/DenseMap.h" |
24 | #include "llvm/ExecutionEngine/JITSymbol.h" |
25 | #include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h" |
26 | #include "llvm/Support/Error.h" |
27 | #include <memory> |
28 | #include <vector> |
29 | |
30 | namespace llvm { |
31 | namespace orc { |
32 | class LLJIT; |
33 | class LLJITBuilder; |
34 | class ThreadSafeContext; |
35 | } // namespace orc |
36 | } // namespace llvm |
37 | |
38 | namespace clang { |
39 | |
40 | class CompilerInstance; |
41 | class IncrementalExecutor; |
42 | class IncrementalParser; |
43 | |
44 | /// Create a pre-configured \c CompilerInstance for incremental processing. |
45 | class IncrementalCompilerBuilder { |
46 | public: |
47 | IncrementalCompilerBuilder() {} |
48 | |
49 | void SetCompilerArgs(const std::vector<const char *> &Args) { |
50 | UserArgs = Args; |
51 | } |
52 | |
53 | void SetTargetTriple(std::string TT) { TargetTriple = TT; } |
54 | |
55 | // General C++ |
56 | llvm::Expected<std::unique_ptr<CompilerInstance>> CreateCpp(); |
57 | |
58 | // Offload options |
59 | void SetOffloadArch(llvm::StringRef Arch) { OffloadArch = Arch; }; |
60 | |
61 | // CUDA specific |
62 | void SetCudaSDK(llvm::StringRef path) { CudaSDKPath = path; }; |
63 | |
64 | llvm::Expected<std::unique_ptr<CompilerInstance>> CreateCudaHost(); |
65 | llvm::Expected<std::unique_ptr<CompilerInstance>> CreateCudaDevice(); |
66 | |
67 | private: |
68 | static llvm::Expected<std::unique_ptr<CompilerInstance>> |
69 | create(std::string TT, std::vector<const char *> &ClangArgv); |
70 | |
71 | llvm::Expected<std::unique_ptr<CompilerInstance>> createCuda(bool device); |
72 | |
73 | std::vector<const char *> UserArgs; |
74 | std::optional<std::string> TargetTriple; |
75 | |
76 | llvm::StringRef OffloadArch; |
77 | llvm::StringRef CudaSDKPath; |
78 | }; |
79 | |
80 | /// Generate glue code between the Interpreter's built-in runtime and user code. |
81 | class RuntimeInterfaceBuilder { |
82 | public: |
83 | virtual ~RuntimeInterfaceBuilder() = default; |
84 | |
85 | using TransformExprFunction = ExprResult(RuntimeInterfaceBuilder *Builder, |
86 | Expr *, ArrayRef<Expr *>); |
87 | virtual TransformExprFunction *getPrintValueTransformer() = 0; |
88 | }; |
89 | |
90 | /// Provides top-level interfaces for incremental compilation and execution. |
91 | class Interpreter { |
92 | std::unique_ptr<llvm::orc::ThreadSafeContext> TSCtx; |
93 | std::unique_ptr<IncrementalParser> IncrParser; |
94 | std::unique_ptr<IncrementalExecutor> IncrExecutor; |
95 | std::unique_ptr<RuntimeInterfaceBuilder> RuntimeIB; |
96 | |
97 | // An optional parser for CUDA offloading |
98 | std::unique_ptr<IncrementalParser> DeviceParser; |
99 | |
100 | unsigned InitPTUSize = 0; |
101 | |
102 | // This member holds the last result of the value printing. It's a class |
103 | // member because we might want to access it after more inputs. If no value |
104 | // printing happens, it's in an invalid state. |
105 | Value LastValue; |
106 | |
107 | // Add a call to an Expr to report its result. We query the function from |
108 | // RuntimeInterfaceBuilder once and store it as a function pointer to avoid |
109 | // frequent virtual function calls. |
110 | RuntimeInterfaceBuilder::TransformExprFunction *AddPrintValueCall = nullptr; |
111 | |
112 | protected: |
113 | // Derived classes can use an extended interface of the Interpreter. |
114 | Interpreter(std::unique_ptr<CompilerInstance> CI, llvm::Error &Err, |
115 | std::unique_ptr<llvm::orc::LLJITBuilder> JITBuilder = nullptr); |
116 | |
117 | // Create the internal IncrementalExecutor, or re-create it after calling |
118 | // ResetExecutor(). |
119 | llvm::Error CreateExecutor(); |
120 | |
121 | // Delete the internal IncrementalExecutor. This causes a hard shutdown of the |
122 | // JIT engine. In particular, it doesn't run cleanup or destructors. |
123 | void ResetExecutor(); |
124 | |
125 | // Lazily construct the RuntimeInterfaceBuilder. The provided instance will be |
126 | // used for the entire lifetime of the interpreter. The default implementation |
127 | // targets the in-process __clang_Interpreter runtime. Override this to use a |
128 | // custom runtime. |
129 | virtual std::unique_ptr<RuntimeInterfaceBuilder> FindRuntimeInterface(); |
130 | |
131 | public: |
132 | virtual ~Interpreter(); |
133 | |
134 | static llvm::Expected<std::unique_ptr<Interpreter>> |
135 | create(std::unique_ptr<CompilerInstance> CI); |
136 | static llvm::Expected<std::unique_ptr<Interpreter>> |
137 | createWithCUDA(std::unique_ptr<CompilerInstance> CI, |
138 | std::unique_ptr<CompilerInstance> DCI); |
139 | const ASTContext &getASTContext() const; |
140 | ASTContext &getASTContext(); |
141 | const CompilerInstance *getCompilerInstance() const; |
142 | CompilerInstance *getCompilerInstance(); |
143 | llvm::Expected<llvm::orc::LLJIT &> getExecutionEngine(); |
144 | |
145 | llvm::Expected<PartialTranslationUnit &> Parse(llvm::StringRef Code); |
146 | llvm::Error Execute(PartialTranslationUnit &T); |
147 | llvm::Error ParseAndExecute(llvm::StringRef Code, Value *V = nullptr); |
148 | llvm::Expected<llvm::orc::ExecutorAddr> CompileDtorCall(CXXRecordDecl *CXXRD); |
149 | |
150 | /// Undo N previous incremental inputs. |
151 | llvm::Error Undo(unsigned N = 1); |
152 | |
153 | /// Link a dynamic library |
154 | llvm::Error LoadDynamicLibrary(const char *name); |
155 | |
156 | /// \returns the \c ExecutorAddr of a \c GlobalDecl. This interface uses |
157 | /// the CodeGenModule's internal mangling cache to avoid recomputing the |
158 | /// mangled name. |
159 | llvm::Expected<llvm::orc::ExecutorAddr> getSymbolAddress(GlobalDecl GD) const; |
160 | |
161 | /// \returns the \c ExecutorAddr of a given name as written in the IR. |
162 | llvm::Expected<llvm::orc::ExecutorAddr> |
163 | getSymbolAddress(llvm::StringRef IRName) const; |
164 | |
165 | /// \returns the \c ExecutorAddr of a given name as written in the object |
166 | /// file. |
167 | llvm::Expected<llvm::orc::ExecutorAddr> |
168 | getSymbolAddressFromLinkerName(llvm::StringRef LinkerName) const; |
169 | |
170 | enum InterfaceKind { NoAlloc, WithAlloc, CopyArray, NewTag }; |
171 | |
172 | const llvm::SmallVectorImpl<Expr *> &getValuePrintingInfo() const { |
173 | return ValuePrintingInfo; |
174 | } |
175 | |
176 | Expr *SynthesizeExpr(Expr *E); |
177 | |
178 | private: |
179 | size_t getEffectivePTUSize() const; |
180 | void markUserCodeStart(); |
181 | |
182 | llvm::DenseMap<CXXRecordDecl *, llvm::orc::ExecutorAddr> Dtors; |
183 | |
184 | llvm::SmallVector<Expr *, 4> ValuePrintingInfo; |
185 | |
186 | std::unique_ptr<llvm::orc::LLJITBuilder> JITBuilder; |
187 | }; |
188 | } // namespace clang |
189 | |
190 | #endif // LLVM_CLANG_INTERPRETER_INTERPRETER_H |
191 | |