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 make use an extended interface of the Interpreter. |
114 | // That's useful for testing and out-of-tree clients. |
115 | Interpreter(std::unique_ptr<CompilerInstance> CI, llvm::Error &Err); |
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 | // Lazily construct thev ORCv2 JITBuilder. This called when the internal |
132 | // IncrementalExecutor is created. The default implementation populates an |
133 | // in-process JIT with debugging support. Override this to configure the JIT |
134 | // engine used for execution. |
135 | virtual llvm::Expected<std::unique_ptr<llvm::orc::LLJITBuilder>> |
136 | CreateJITBuilder(CompilerInstance &CI); |
137 | |
138 | public: |
139 | virtual ~Interpreter(); |
140 | |
141 | static llvm::Expected<std::unique_ptr<Interpreter>> |
142 | create(std::unique_ptr<CompilerInstance> CI); |
143 | static llvm::Expected<std::unique_ptr<Interpreter>> |
144 | createWithCUDA(std::unique_ptr<CompilerInstance> CI, |
145 | std::unique_ptr<CompilerInstance> DCI); |
146 | const ASTContext &getASTContext() const; |
147 | ASTContext &getASTContext(); |
148 | const CompilerInstance *getCompilerInstance() const; |
149 | CompilerInstance *getCompilerInstance(); |
150 | llvm::Expected<llvm::orc::LLJIT &> getExecutionEngine(); |
151 | |
152 | llvm::Expected<PartialTranslationUnit &> Parse(llvm::StringRef Code); |
153 | llvm::Error Execute(PartialTranslationUnit &T); |
154 | llvm::Error ParseAndExecute(llvm::StringRef Code, Value *V = nullptr); |
155 | llvm::Expected<llvm::orc::ExecutorAddr> CompileDtorCall(CXXRecordDecl *CXXRD); |
156 | |
157 | /// Undo N previous incremental inputs. |
158 | llvm::Error Undo(unsigned N = 1); |
159 | |
160 | /// Link a dynamic library |
161 | llvm::Error LoadDynamicLibrary(const char *name); |
162 | |
163 | /// \returns the \c ExecutorAddr of a \c GlobalDecl. This interface uses |
164 | /// the CodeGenModule's internal mangling cache to avoid recomputing the |
165 | /// mangled name. |
166 | llvm::Expected<llvm::orc::ExecutorAddr> getSymbolAddress(GlobalDecl GD) const; |
167 | |
168 | /// \returns the \c ExecutorAddr of a given name as written in the IR. |
169 | llvm::Expected<llvm::orc::ExecutorAddr> |
170 | getSymbolAddress(llvm::StringRef IRName) const; |
171 | |
172 | /// \returns the \c ExecutorAddr of a given name as written in the object |
173 | /// file. |
174 | llvm::Expected<llvm::orc::ExecutorAddr> |
175 | getSymbolAddressFromLinkerName(llvm::StringRef LinkerName) const; |
176 | |
177 | enum InterfaceKind { NoAlloc, WithAlloc, CopyArray, NewTag }; |
178 | |
179 | const llvm::SmallVectorImpl<Expr *> &getValuePrintingInfo() const { |
180 | return ValuePrintingInfo; |
181 | } |
182 | |
183 | Expr *SynthesizeExpr(Expr *E); |
184 | |
185 | private: |
186 | size_t getEffectivePTUSize() const; |
187 | void markUserCodeStart(); |
188 | |
189 | llvm::DenseMap<CXXRecordDecl *, llvm::orc::ExecutorAddr> Dtors; |
190 | |
191 | llvm::SmallVector<Expr *, 4> ValuePrintingInfo; |
192 | }; |
193 | } // namespace clang |
194 | |
195 | #endif // LLVM_CLANG_INTERPRETER_INTERPRETER_H |
196 | |