1 | //===------ Interpreter.cpp - Incremental Compilation and Execution -------===// |
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 implements the component which performs incremental code |
10 | // compilation and execution. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #include "DeviceOffload.h" |
15 | #include "IncrementalExecutor.h" |
16 | #include "IncrementalParser.h" |
17 | #include "InterpreterUtils.h" |
18 | |
19 | #include "clang/AST/ASTContext.h" |
20 | #include "clang/AST/Mangle.h" |
21 | #include "clang/AST/TypeVisitor.h" |
22 | #include "clang/Basic/DiagnosticSema.h" |
23 | #include "clang/Basic/TargetInfo.h" |
24 | #include "clang/CodeGen/CodeGenAction.h" |
25 | #include "clang/CodeGen/ModuleBuilder.h" |
26 | #include "clang/CodeGen/ObjectFilePCHContainerOperations.h" |
27 | #include "clang/Driver/Compilation.h" |
28 | #include "clang/Driver/Driver.h" |
29 | #include "clang/Driver/Job.h" |
30 | #include "clang/Driver/Options.h" |
31 | #include "clang/Driver/Tool.h" |
32 | #include "clang/Frontend/CompilerInstance.h" |
33 | #include "clang/Frontend/TextDiagnosticBuffer.h" |
34 | #include "clang/Interpreter/Interpreter.h" |
35 | #include "clang/Interpreter/Value.h" |
36 | #include "clang/Lex/PreprocessorOptions.h" |
37 | #include "clang/Sema/Lookup.h" |
38 | #include "llvm/ExecutionEngine/JITSymbol.h" |
39 | #include "llvm/ExecutionEngine/Orc/LLJIT.h" |
40 | #include "llvm/IR/Module.h" |
41 | #include "llvm/Support/Errc.h" |
42 | #include "llvm/Support/ErrorHandling.h" |
43 | #include "llvm/Support/raw_ostream.h" |
44 | #include "llvm/TargetParser/Host.h" |
45 | using namespace clang; |
46 | |
47 | // FIXME: Figure out how to unify with namespace init_convenience from |
48 | // tools/clang-import-test/clang-import-test.cpp |
49 | namespace { |
50 | /// Retrieves the clang CC1 specific flags out of the compilation's jobs. |
51 | /// \returns NULL on error. |
52 | static llvm::Expected<const llvm::opt::ArgStringList *> |
53 | GetCC1Arguments(DiagnosticsEngine *Diagnostics, |
54 | driver::Compilation *Compilation) { |
55 | // We expect to get back exactly one Command job, if we didn't something |
56 | // failed. Extract that job from the Compilation. |
57 | const driver::JobList &Jobs = Compilation->getJobs(); |
58 | if (!Jobs.size() || !isa<driver::Command>(Val: *Jobs.begin())) |
59 | return llvm::createStringError(EC: llvm::errc::not_supported, |
60 | Msg: "Driver initialization failed. " |
61 | "Unable to create a driver job" ); |
62 | |
63 | // The one job we find should be to invoke clang again. |
64 | const driver::Command *Cmd = cast<driver::Command>(Val: &(*Jobs.begin())); |
65 | if (llvm::StringRef(Cmd->getCreator().getName()) != "clang" ) |
66 | return llvm::createStringError(EC: llvm::errc::not_supported, |
67 | Msg: "Driver initialization failed" ); |
68 | |
69 | return &Cmd->getArguments(); |
70 | } |
71 | |
72 | static llvm::Expected<std::unique_ptr<CompilerInstance>> |
73 | CreateCI(const llvm::opt::ArgStringList &Argv) { |
74 | std::unique_ptr<CompilerInstance> Clang(new CompilerInstance()); |
75 | IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); |
76 | |
77 | // Register the support for object-file-wrapped Clang modules. |
78 | // FIXME: Clang should register these container operations automatically. |
79 | auto PCHOps = Clang->getPCHContainerOperations(); |
80 | PCHOps->registerWriter(Writer: std::make_unique<ObjectFilePCHContainerWriter>()); |
81 | PCHOps->registerReader(Reader: std::make_unique<ObjectFilePCHContainerReader>()); |
82 | |
83 | // Buffer diagnostics from argument parsing so that we can output them using |
84 | // a well formed diagnostic object. |
85 | IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions(); |
86 | TextDiagnosticBuffer *DiagsBuffer = new TextDiagnosticBuffer; |
87 | DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagsBuffer); |
88 | bool Success = CompilerInvocation::CreateFromArgs( |
89 | Res&: Clang->getInvocation(), CommandLineArgs: llvm::ArrayRef(Argv.begin(), Argv.size()), Diags); |
90 | |
91 | // Infer the builtin include path if unspecified. |
92 | if (Clang->getHeaderSearchOpts().UseBuiltinIncludes && |
93 | Clang->getHeaderSearchOpts().ResourceDir.empty()) |
94 | Clang->getHeaderSearchOpts().ResourceDir = |
95 | CompilerInvocation::GetResourcesPath(Argv0: Argv[0], MainAddr: nullptr); |
96 | |
97 | // Create the actual diagnostics engine. |
98 | Clang->createDiagnostics(); |
99 | if (!Clang->hasDiagnostics()) |
100 | return llvm::createStringError(EC: llvm::errc::not_supported, |
101 | Msg: "Initialization failed. " |
102 | "Unable to create diagnostics engine" ); |
103 | |
104 | DiagsBuffer->FlushDiagnostics(Diags&: Clang->getDiagnostics()); |
105 | if (!Success) |
106 | return llvm::createStringError(EC: llvm::errc::not_supported, |
107 | Msg: "Initialization failed. " |
108 | "Unable to flush diagnostics" ); |
109 | |
110 | // FIXME: Merge with CompilerInstance::ExecuteAction. |
111 | llvm::MemoryBuffer *MB = llvm::MemoryBuffer::getMemBuffer(InputData: "" ).release(); |
112 | Clang->getPreprocessorOpts().addRemappedFile(From: "<<< inputs >>>" , To: MB); |
113 | |
114 | Clang->setTarget(TargetInfo::CreateTargetInfo( |
115 | Diags&: Clang->getDiagnostics(), Opts: Clang->getInvocation().TargetOpts)); |
116 | if (!Clang->hasTarget()) |
117 | return llvm::createStringError(EC: llvm::errc::not_supported, |
118 | Msg: "Initialization failed. " |
119 | "Target is missing" ); |
120 | |
121 | Clang->getTarget().adjust(Diags&: Clang->getDiagnostics(), Opts&: Clang->getLangOpts()); |
122 | |
123 | // Don't clear the AST before backend codegen since we do codegen multiple |
124 | // times, reusing the same AST. |
125 | Clang->getCodeGenOpts().ClearASTBeforeBackend = false; |
126 | |
127 | Clang->getFrontendOpts().DisableFree = false; |
128 | Clang->getCodeGenOpts().DisableFree = false; |
129 | return std::move(Clang); |
130 | } |
131 | |
132 | } // anonymous namespace |
133 | |
134 | llvm::Expected<std::unique_ptr<CompilerInstance>> |
135 | IncrementalCompilerBuilder::create(std::vector<const char *> &ClangArgv) { |
136 | |
137 | // If we don't know ClangArgv0 or the address of main() at this point, try |
138 | // to guess it anyway (it's possible on some platforms). |
139 | std::string MainExecutableName = |
140 | llvm::sys::fs::getMainExecutable(argv0: nullptr, MainExecAddr: nullptr); |
141 | |
142 | ClangArgv.insert(position: ClangArgv.begin(), x: MainExecutableName.c_str()); |
143 | |
144 | // Prepending -c to force the driver to do something if no action was |
145 | // specified. By prepending we allow users to override the default |
146 | // action and use other actions in incremental mode. |
147 | // FIXME: Print proper driver diagnostics if the driver flags are wrong. |
148 | // We do C++ by default; append right after argv[0] if no "-x" given |
149 | ClangArgv.insert(position: ClangArgv.end(), x: "-Xclang" ); |
150 | ClangArgv.insert(position: ClangArgv.end(), x: "-fincremental-extensions" ); |
151 | ClangArgv.insert(position: ClangArgv.end(), x: "-c" ); |
152 | |
153 | // Put a dummy C++ file on to ensure there's at least one compile job for the |
154 | // driver to construct. |
155 | ClangArgv.push_back(x: "<<< inputs >>>" ); |
156 | |
157 | // Buffer diagnostics from argument parsing so that we can output them using a |
158 | // well formed diagnostic object. |
159 | IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); |
160 | IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = |
161 | CreateAndPopulateDiagOpts(Argv: ClangArgv); |
162 | TextDiagnosticBuffer *DiagsBuffer = new TextDiagnosticBuffer; |
163 | DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagsBuffer); |
164 | |
165 | driver::Driver Driver(/*MainBinaryName=*/ClangArgv[0], |
166 | llvm::sys::getProcessTriple(), Diags); |
167 | Driver.setCheckInputsExist(false); // the input comes from mem buffers |
168 | llvm::ArrayRef<const char *> RF = llvm::ArrayRef(ClangArgv); |
169 | std::unique_ptr<driver::Compilation> Compilation(Driver.BuildCompilation(Args: RF)); |
170 | |
171 | if (Compilation->getArgs().hasArg(driver::options::OPT_v)) |
172 | Compilation->getJobs().Print(OS&: llvm::errs(), Terminator: "\n" , /*Quote=*/false); |
173 | |
174 | auto ErrOrCC1Args = GetCC1Arguments(Diagnostics: &Diags, Compilation: Compilation.get()); |
175 | if (auto Err = ErrOrCC1Args.takeError()) |
176 | return std::move(Err); |
177 | |
178 | return CreateCI(Argv: **ErrOrCC1Args); |
179 | } |
180 | |
181 | llvm::Expected<std::unique_ptr<CompilerInstance>> |
182 | IncrementalCompilerBuilder::CreateCpp() { |
183 | std::vector<const char *> Argv; |
184 | Argv.reserve(n: 5 + 1 + UserArgs.size()); |
185 | Argv.push_back(x: "-xc++" ); |
186 | Argv.insert(position: Argv.end(), first: UserArgs.begin(), last: UserArgs.end()); |
187 | |
188 | return IncrementalCompilerBuilder::create(ClangArgv&: Argv); |
189 | } |
190 | |
191 | llvm::Expected<std::unique_ptr<CompilerInstance>> |
192 | IncrementalCompilerBuilder::createCuda(bool device) { |
193 | std::vector<const char *> Argv; |
194 | Argv.reserve(n: 5 + 4 + UserArgs.size()); |
195 | |
196 | Argv.push_back(x: "-xcuda" ); |
197 | if (device) |
198 | Argv.push_back(x: "--cuda-device-only" ); |
199 | else |
200 | Argv.push_back(x: "--cuda-host-only" ); |
201 | |
202 | std::string SDKPathArg = "--cuda-path=" ; |
203 | if (!CudaSDKPath.empty()) { |
204 | SDKPathArg += CudaSDKPath; |
205 | Argv.push_back(x: SDKPathArg.c_str()); |
206 | } |
207 | |
208 | std::string ArchArg = "--offload-arch=" ; |
209 | if (!OffloadArch.empty()) { |
210 | ArchArg += OffloadArch; |
211 | Argv.push_back(x: ArchArg.c_str()); |
212 | } |
213 | |
214 | Argv.insert(position: Argv.end(), first: UserArgs.begin(), last: UserArgs.end()); |
215 | |
216 | return IncrementalCompilerBuilder::create(ClangArgv&: Argv); |
217 | } |
218 | |
219 | llvm::Expected<std::unique_ptr<CompilerInstance>> |
220 | IncrementalCompilerBuilder::CreateCudaDevice() { |
221 | return IncrementalCompilerBuilder::createCuda(device: true); |
222 | } |
223 | |
224 | llvm::Expected<std::unique_ptr<CompilerInstance>> |
225 | IncrementalCompilerBuilder::CreateCudaHost() { |
226 | return IncrementalCompilerBuilder::createCuda(device: false); |
227 | } |
228 | |
229 | Interpreter::Interpreter(std::unique_ptr<CompilerInstance> CI, |
230 | llvm::Error &Err) { |
231 | llvm::ErrorAsOutParameter EAO(&Err); |
232 | auto LLVMCtx = std::make_unique<llvm::LLVMContext>(); |
233 | TSCtx = std::make_unique<llvm::orc::ThreadSafeContext>(args: std::move(LLVMCtx)); |
234 | IncrParser = std::make_unique<IncrementalParser>(args&: *this, args: std::move(CI), |
235 | args&: *TSCtx->getContext(), args&: Err); |
236 | } |
237 | |
238 | Interpreter::~Interpreter() { |
239 | if (IncrExecutor) { |
240 | if (llvm::Error Err = IncrExecutor->cleanUp()) |
241 | llvm::report_fatal_error( |
242 | reason: llvm::Twine("Failed to clean up IncrementalExecutor: " ) + |
243 | toString(E: std::move(Err))); |
244 | } |
245 | } |
246 | |
247 | // These better to put in a runtime header but we can't. This is because we |
248 | // can't find the precise resource directory in unittests so we have to hard |
249 | // code them. |
250 | const char *const Runtimes = R"( |
251 | #ifdef __cplusplus |
252 | void *__clang_Interpreter_SetValueWithAlloc(void*, void*, void*); |
253 | void __clang_Interpreter_SetValueNoAlloc(void*, void*, void*); |
254 | void __clang_Interpreter_SetValueNoAlloc(void*, void*, void*, void*); |
255 | void __clang_Interpreter_SetValueNoAlloc(void*, void*, void*, float); |
256 | void __clang_Interpreter_SetValueNoAlloc(void*, void*, void*, double); |
257 | void __clang_Interpreter_SetValueNoAlloc(void*, void*, void*, long double); |
258 | void __clang_Interpreter_SetValueNoAlloc(void*,void*,void*,unsigned long long); |
259 | struct __clang_Interpreter_NewTag{} __ci_newtag; |
260 | void* operator new(__SIZE_TYPE__, void* __p, __clang_Interpreter_NewTag) noexcept; |
261 | template <class T, class = T (*)() /*disable for arrays*/> |
262 | void __clang_Interpreter_SetValueCopyArr(T* Src, void* Placement, unsigned long Size) { |
263 | for (auto Idx = 0; Idx < Size; ++Idx) |
264 | new ((void*)(((T*)Placement) + Idx), __ci_newtag) T(Src[Idx]); |
265 | } |
266 | template <class T, unsigned long N> |
267 | void __clang_Interpreter_SetValueCopyArr(const T (*Src)[N], void* Placement, unsigned long Size) { |
268 | __clang_Interpreter_SetValueCopyArr(Src[0], Placement, Size); |
269 | } |
270 | #endif // __cplusplus |
271 | )" ; |
272 | |
273 | llvm::Expected<std::unique_ptr<Interpreter>> |
274 | Interpreter::create(std::unique_ptr<CompilerInstance> CI) { |
275 | llvm::Error Err = llvm::Error::success(); |
276 | auto Interp = |
277 | std::unique_ptr<Interpreter>(new Interpreter(std::move(CI), Err)); |
278 | if (Err) |
279 | return std::move(Err); |
280 | |
281 | auto PTU = Interp->Parse(Code: Runtimes); |
282 | if (!PTU) |
283 | return PTU.takeError(); |
284 | |
285 | Interp->ValuePrintingInfo.resize(N: 4); |
286 | // FIXME: This is a ugly hack. Undo command checks its availability by looking |
287 | // at the size of the PTU list. However we have parsed something in the |
288 | // beginning of the REPL so we have to mark them as 'Irrevocable'. |
289 | Interp->InitPTUSize = Interp->IncrParser->getPTUs().size(); |
290 | return std::move(Interp); |
291 | } |
292 | |
293 | llvm::Expected<std::unique_ptr<Interpreter>> |
294 | Interpreter::createWithCUDA(std::unique_ptr<CompilerInstance> CI, |
295 | std::unique_ptr<CompilerInstance> DCI) { |
296 | // avoid writing fat binary to disk using an in-memory virtual file system |
297 | llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> IMVFS = |
298 | std::make_unique<llvm::vfs::InMemoryFileSystem>(); |
299 | llvm::IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> OverlayVFS = |
300 | std::make_unique<llvm::vfs::OverlayFileSystem>( |
301 | args: llvm::vfs::getRealFileSystem()); |
302 | OverlayVFS->pushOverlay(FS: IMVFS); |
303 | CI->createFileManager(VFS: OverlayVFS); |
304 | |
305 | auto Interp = Interpreter::create(CI: std::move(CI)); |
306 | if (auto E = Interp.takeError()) |
307 | return std::move(E); |
308 | |
309 | llvm::Error Err = llvm::Error::success(); |
310 | auto DeviceParser = std::make_unique<IncrementalCUDADeviceParser>( |
311 | args&: **Interp, args: std::move(DCI), args&: *(*Interp)->IncrParser.get(), |
312 | args&: *(*Interp)->TSCtx->getContext(), args&: IMVFS, args&: Err); |
313 | if (Err) |
314 | return std::move(Err); |
315 | |
316 | (*Interp)->DeviceParser = std::move(DeviceParser); |
317 | |
318 | return Interp; |
319 | } |
320 | |
321 | const CompilerInstance *Interpreter::getCompilerInstance() const { |
322 | return IncrParser->getCI(); |
323 | } |
324 | |
325 | CompilerInstance *Interpreter::getCompilerInstance() { |
326 | return IncrParser->getCI(); |
327 | } |
328 | |
329 | llvm::Expected<llvm::orc::LLJIT &> Interpreter::getExecutionEngine() { |
330 | if (!IncrExecutor) { |
331 | if (auto Err = CreateExecutor()) |
332 | return std::move(Err); |
333 | } |
334 | |
335 | return IncrExecutor->GetExecutionEngine(); |
336 | } |
337 | |
338 | ASTContext &Interpreter::getASTContext() { |
339 | return getCompilerInstance()->getASTContext(); |
340 | } |
341 | |
342 | const ASTContext &Interpreter::getASTContext() const { |
343 | return getCompilerInstance()->getASTContext(); |
344 | } |
345 | |
346 | size_t Interpreter::getEffectivePTUSize() const { |
347 | std::list<PartialTranslationUnit> &PTUs = IncrParser->getPTUs(); |
348 | assert(PTUs.size() >= InitPTUSize && "empty PTU list?" ); |
349 | return PTUs.size() - InitPTUSize; |
350 | } |
351 | |
352 | llvm::Expected<PartialTranslationUnit &> |
353 | Interpreter::Parse(llvm::StringRef Code) { |
354 | // If we have a device parser, parse it first. |
355 | // The generated code will be included in the host compilation |
356 | if (DeviceParser) { |
357 | auto DevicePTU = DeviceParser->Parse(Input: Code); |
358 | if (auto E = DevicePTU.takeError()) |
359 | return std::move(E); |
360 | } |
361 | |
362 | // Tell the interpreter sliently ignore unused expressions since value |
363 | // printing could cause it. |
364 | getCompilerInstance()->getDiagnostics().setSeverity( |
365 | clang::diag::warn_unused_expr, diag::Severity::Ignored, SourceLocation()); |
366 | return IncrParser->Parse(Input: Code); |
367 | } |
368 | |
369 | llvm::Error Interpreter::CreateExecutor() { |
370 | const clang::TargetInfo &TI = |
371 | getCompilerInstance()->getASTContext().getTargetInfo(); |
372 | llvm::Error Err = llvm::Error::success(); |
373 | auto Executor = std::make_unique<IncrementalExecutor>(args&: *TSCtx, args&: Err, args: TI); |
374 | if (!Err) |
375 | IncrExecutor = std::move(Executor); |
376 | |
377 | return Err; |
378 | } |
379 | |
380 | llvm::Error Interpreter::Execute(PartialTranslationUnit &T) { |
381 | assert(T.TheModule); |
382 | if (!IncrExecutor) { |
383 | auto Err = CreateExecutor(); |
384 | if (Err) |
385 | return Err; |
386 | } |
387 | // FIXME: Add a callback to retain the llvm::Module once the JIT is done. |
388 | if (auto Err = IncrExecutor->addModule(PTU&: T)) |
389 | return Err; |
390 | |
391 | if (auto Err = IncrExecutor->runCtors()) |
392 | return Err; |
393 | |
394 | return llvm::Error::success(); |
395 | } |
396 | |
397 | llvm::Error Interpreter::ParseAndExecute(llvm::StringRef Code, Value *V) { |
398 | |
399 | auto PTU = Parse(Code); |
400 | if (!PTU) |
401 | return PTU.takeError(); |
402 | if (PTU->TheModule) |
403 | if (llvm::Error Err = Execute(T&: *PTU)) |
404 | return Err; |
405 | |
406 | if (LastValue.isValid()) { |
407 | if (!V) { |
408 | LastValue.dump(); |
409 | LastValue.clear(); |
410 | } else |
411 | *V = std::move(LastValue); |
412 | } |
413 | return llvm::Error::success(); |
414 | } |
415 | |
416 | llvm::Expected<llvm::orc::ExecutorAddr> |
417 | Interpreter::getSymbolAddress(GlobalDecl GD) const { |
418 | if (!IncrExecutor) |
419 | return llvm::make_error<llvm::StringError>(Args: "Operation failed. " |
420 | "No execution engine" , |
421 | Args: std::error_code()); |
422 | llvm::StringRef MangledName = IncrParser->GetMangledName(GD); |
423 | return getSymbolAddress(IRName: MangledName); |
424 | } |
425 | |
426 | llvm::Expected<llvm::orc::ExecutorAddr> |
427 | Interpreter::getSymbolAddress(llvm::StringRef IRName) const { |
428 | if (!IncrExecutor) |
429 | return llvm::make_error<llvm::StringError>(Args: "Operation failed. " |
430 | "No execution engine" , |
431 | Args: std::error_code()); |
432 | |
433 | return IncrExecutor->getSymbolAddress(Name: IRName, NameKind: IncrementalExecutor::IRName); |
434 | } |
435 | |
436 | llvm::Expected<llvm::orc::ExecutorAddr> |
437 | Interpreter::getSymbolAddressFromLinkerName(llvm::StringRef Name) const { |
438 | if (!IncrExecutor) |
439 | return llvm::make_error<llvm::StringError>(Args: "Operation failed. " |
440 | "No execution engine" , |
441 | Args: std::error_code()); |
442 | |
443 | return IncrExecutor->getSymbolAddress(Name, NameKind: IncrementalExecutor::LinkerName); |
444 | } |
445 | |
446 | llvm::Error Interpreter::Undo(unsigned N) { |
447 | |
448 | std::list<PartialTranslationUnit> &PTUs = IncrParser->getPTUs(); |
449 | if (N > getEffectivePTUSize()) |
450 | return llvm::make_error<llvm::StringError>(Args: "Operation failed. " |
451 | "Too many undos" , |
452 | Args: std::error_code()); |
453 | for (unsigned I = 0; I < N; I++) { |
454 | if (IncrExecutor) { |
455 | if (llvm::Error Err = IncrExecutor->removeModule(PTU&: PTUs.back())) |
456 | return Err; |
457 | } |
458 | |
459 | IncrParser->CleanUpPTU(PTU&: PTUs.back()); |
460 | PTUs.pop_back(); |
461 | } |
462 | return llvm::Error::success(); |
463 | } |
464 | |
465 | llvm::Error Interpreter::LoadDynamicLibrary(const char *name) { |
466 | auto EE = getExecutionEngine(); |
467 | if (!EE) |
468 | return EE.takeError(); |
469 | |
470 | auto &DL = EE->getDataLayout(); |
471 | |
472 | if (auto DLSG = llvm::orc::DynamicLibrarySearchGenerator::Load( |
473 | FileName: name, GlobalPrefix: DL.getGlobalPrefix())) |
474 | EE->getMainJITDylib().addGenerator(DefGenerator: std::move(*DLSG)); |
475 | else |
476 | return DLSG.takeError(); |
477 | |
478 | return llvm::Error::success(); |
479 | } |
480 | |
481 | llvm::Expected<llvm::orc::ExecutorAddr> |
482 | Interpreter::CompileDtorCall(CXXRecordDecl *CXXRD) { |
483 | assert(CXXRD && "Cannot compile a destructor for a nullptr" ); |
484 | if (auto Dtor = Dtors.find(Val: CXXRD); Dtor != Dtors.end()) |
485 | return Dtor->getSecond(); |
486 | |
487 | if (CXXRD->hasIrrelevantDestructor()) |
488 | return llvm::orc::ExecutorAddr{}; |
489 | |
490 | CXXDestructorDecl *DtorRD = |
491 | getCompilerInstance()->getSema().LookupDestructor(Class: CXXRD); |
492 | |
493 | llvm::StringRef Name = |
494 | IncrParser->GetMangledName(GD: GlobalDecl(DtorRD, Dtor_Base)); |
495 | auto AddrOrErr = getSymbolAddress(IRName: Name); |
496 | if (!AddrOrErr) |
497 | return AddrOrErr.takeError(); |
498 | |
499 | Dtors[CXXRD] = *AddrOrErr; |
500 | return AddrOrErr; |
501 | } |
502 | |
503 | static constexpr llvm::StringRef MagicRuntimeInterface[] = { |
504 | "__clang_Interpreter_SetValueNoAlloc" , |
505 | "__clang_Interpreter_SetValueWithAlloc" , |
506 | "__clang_Interpreter_SetValueCopyArr" , "__ci_newtag" }; |
507 | |
508 | bool Interpreter::FindRuntimeInterface() { |
509 | if (llvm::all_of(Range&: ValuePrintingInfo, P: [](Expr *E) { return E != nullptr; })) |
510 | return true; |
511 | |
512 | Sema &S = getCompilerInstance()->getSema(); |
513 | ASTContext &Ctx = S.getASTContext(); |
514 | |
515 | auto LookupInterface = [&](Expr *&Interface, llvm::StringRef Name) { |
516 | LookupResult R(S, &Ctx.Idents.get(Name), SourceLocation(), |
517 | Sema::LookupOrdinaryName, Sema::ForVisibleRedeclaration); |
518 | S.LookupQualifiedName(R, Ctx.getTranslationUnitDecl()); |
519 | if (R.empty()) |
520 | return false; |
521 | |
522 | CXXScopeSpec CSS; |
523 | Interface = S.BuildDeclarationNameExpr(SS: CSS, R, /*ADL=*/NeedsADL: false).get(); |
524 | return true; |
525 | }; |
526 | |
527 | if (!LookupInterface(ValuePrintingInfo[NoAlloc], |
528 | MagicRuntimeInterface[NoAlloc])) |
529 | return false; |
530 | if (!LookupInterface(ValuePrintingInfo[WithAlloc], |
531 | MagicRuntimeInterface[WithAlloc])) |
532 | return false; |
533 | if (!LookupInterface(ValuePrintingInfo[CopyArray], |
534 | MagicRuntimeInterface[CopyArray])) |
535 | return false; |
536 | if (!LookupInterface(ValuePrintingInfo[NewTag], |
537 | MagicRuntimeInterface[NewTag])) |
538 | return false; |
539 | return true; |
540 | } |
541 | |
542 | namespace { |
543 | |
544 | class RuntimeInterfaceBuilder |
545 | : public TypeVisitor<RuntimeInterfaceBuilder, Interpreter::InterfaceKind> { |
546 | clang::Interpreter &Interp; |
547 | ASTContext &Ctx; |
548 | Sema &S; |
549 | Expr *E; |
550 | llvm::SmallVector<Expr *, 3> Args; |
551 | |
552 | public: |
553 | RuntimeInterfaceBuilder(clang::Interpreter &In, ASTContext &C, Sema &SemaRef, |
554 | Expr *VE, ArrayRef<Expr *> FixedArgs) |
555 | : Interp(In), Ctx(C), S(SemaRef), E(VE) { |
556 | // The Interpreter* parameter and the out parameter `OutVal`. |
557 | for (Expr *E : FixedArgs) |
558 | Args.push_back(Elt: E); |
559 | |
560 | // Get rid of ExprWithCleanups. |
561 | if (auto *EWC = llvm::dyn_cast_if_present<ExprWithCleanups>(Val: E)) |
562 | E = EWC->getSubExpr(); |
563 | } |
564 | |
565 | ExprResult getCall() { |
566 | QualType Ty = E->getType(); |
567 | QualType DesugaredTy = Ty.getDesugaredType(Context: Ctx); |
568 | |
569 | // For lvalue struct, we treat it as a reference. |
570 | if (DesugaredTy->isRecordType() && E->isLValue()) { |
571 | DesugaredTy = Ctx.getLValueReferenceType(T: DesugaredTy); |
572 | Ty = Ctx.getLValueReferenceType(T: Ty); |
573 | } |
574 | |
575 | Expr *TypeArg = |
576 | CStyleCastPtrExpr(S, Ctx.VoidPtrTy, (uintptr_t)Ty.getAsOpaquePtr()); |
577 | // The QualType parameter `OpaqueType`, represented as `void*`. |
578 | Args.push_back(Elt: TypeArg); |
579 | |
580 | // We push the last parameter based on the type of the Expr. Note we need |
581 | // special care for rvalue struct. |
582 | Interpreter::InterfaceKind Kind = Visit(T: &*DesugaredTy); |
583 | switch (Kind) { |
584 | case Interpreter::InterfaceKind::WithAlloc: |
585 | case Interpreter::InterfaceKind::CopyArray: { |
586 | // __clang_Interpreter_SetValueWithAlloc. |
587 | ExprResult AllocCall = S.ActOnCallExpr( |
588 | /*Scope=*/S: nullptr, |
589 | Fn: Interp.getValuePrintingInfo()[Interpreter::InterfaceKind::WithAlloc], |
590 | LParenLoc: E->getBeginLoc(), ArgExprs: Args, RParenLoc: E->getEndLoc()); |
591 | assert(!AllocCall.isInvalid() && "Can't create runtime interface call!" ); |
592 | |
593 | TypeSourceInfo *TSI = Ctx.getTrivialTypeSourceInfo(T: Ty, Loc: SourceLocation()); |
594 | |
595 | // Force CodeGen to emit destructor. |
596 | if (auto *RD = Ty->getAsCXXRecordDecl()) { |
597 | auto *Dtor = S.LookupDestructor(Class: RD); |
598 | Dtor->addAttr(UsedAttr::CreateImplicit(Ctx)); |
599 | Interp.getCompilerInstance()->getASTConsumer().HandleTopLevelDecl( |
600 | D: DeclGroupRef(Dtor)); |
601 | } |
602 | |
603 | // __clang_Interpreter_SetValueCopyArr. |
604 | if (Kind == Interpreter::InterfaceKind::CopyArray) { |
605 | const auto *ConstantArrTy = |
606 | cast<ConstantArrayType>(Val: DesugaredTy.getTypePtr()); |
607 | size_t ArrSize = Ctx.getConstantArrayElementCount(CA: ConstantArrTy); |
608 | Expr *ArrSizeExpr = IntegerLiteralExpr(C&: Ctx, Val: ArrSize); |
609 | Expr *Args[] = {E, AllocCall.get(), ArrSizeExpr}; |
610 | return S.ActOnCallExpr( |
611 | /*Scope *=*/S: nullptr, |
612 | Fn: Interp |
613 | .getValuePrintingInfo()[Interpreter::InterfaceKind::CopyArray], |
614 | LParenLoc: SourceLocation(), ArgExprs: Args, RParenLoc: SourceLocation()); |
615 | } |
616 | Expr *Args[] = { |
617 | AllocCall.get(), |
618 | Interp.getValuePrintingInfo()[Interpreter::InterfaceKind::NewTag]}; |
619 | ExprResult CXXNewCall = S.BuildCXXNew( |
620 | Range: E->getSourceRange(), |
621 | /*UseGlobal=*/true, /*PlacementLParen=*/SourceLocation(), PlacementArgs: Args, |
622 | /*PlacementRParen=*/SourceLocation(), |
623 | /*TypeIdParens=*/SourceRange(), AllocType: TSI->getType(), AllocTypeInfo: TSI, ArraySize: std::nullopt, |
624 | DirectInitRange: E->getSourceRange(), Initializer: E); |
625 | |
626 | assert(!CXXNewCall.isInvalid() && |
627 | "Can't create runtime placement new call!" ); |
628 | |
629 | return S.ActOnFinishFullExpr(Expr: CXXNewCall.get(), |
630 | /*DiscardedValue=*/false); |
631 | } |
632 | // __clang_Interpreter_SetValueNoAlloc. |
633 | case Interpreter::InterfaceKind::NoAlloc: { |
634 | return S.ActOnCallExpr( |
635 | /*Scope=*/S: nullptr, |
636 | Fn: Interp.getValuePrintingInfo()[Interpreter::InterfaceKind::NoAlloc], |
637 | LParenLoc: E->getBeginLoc(), ArgExprs: Args, RParenLoc: E->getEndLoc()); |
638 | } |
639 | default: |
640 | llvm_unreachable("Unhandled Interpreter::InterfaceKind" ); |
641 | } |
642 | } |
643 | |
644 | Interpreter::InterfaceKind VisitRecordType(const RecordType *Ty) { |
645 | return Interpreter::InterfaceKind::WithAlloc; |
646 | } |
647 | |
648 | Interpreter::InterfaceKind |
649 | VisitMemberPointerType(const MemberPointerType *Ty) { |
650 | return Interpreter::InterfaceKind::WithAlloc; |
651 | } |
652 | |
653 | Interpreter::InterfaceKind |
654 | VisitConstantArrayType(const ConstantArrayType *Ty) { |
655 | return Interpreter::InterfaceKind::CopyArray; |
656 | } |
657 | |
658 | Interpreter::InterfaceKind |
659 | VisitFunctionProtoType(const FunctionProtoType *Ty) { |
660 | HandlePtrType(Ty); |
661 | return Interpreter::InterfaceKind::NoAlloc; |
662 | } |
663 | |
664 | Interpreter::InterfaceKind VisitPointerType(const PointerType *Ty) { |
665 | HandlePtrType(Ty); |
666 | return Interpreter::InterfaceKind::NoAlloc; |
667 | } |
668 | |
669 | Interpreter::InterfaceKind VisitReferenceType(const ReferenceType *Ty) { |
670 | ExprResult AddrOfE = S.CreateBuiltinUnaryOp(OpLoc: SourceLocation(), Opc: UO_AddrOf, InputExpr: E); |
671 | assert(!AddrOfE.isInvalid() && "Can not create unary expression" ); |
672 | Args.push_back(Elt: AddrOfE.get()); |
673 | return Interpreter::InterfaceKind::NoAlloc; |
674 | } |
675 | |
676 | Interpreter::InterfaceKind VisitBuiltinType(const BuiltinType *Ty) { |
677 | if (Ty->isNullPtrType()) |
678 | Args.push_back(Elt: E); |
679 | else if (Ty->isFloatingType()) |
680 | Args.push_back(Elt: E); |
681 | else if (Ty->isIntegralOrEnumerationType()) |
682 | HandleIntegralOrEnumType(Ty); |
683 | else if (Ty->isVoidType()) { |
684 | // Do we need to still run `E`? |
685 | } |
686 | |
687 | return Interpreter::InterfaceKind::NoAlloc; |
688 | } |
689 | |
690 | Interpreter::InterfaceKind VisitEnumType(const EnumType *Ty) { |
691 | HandleIntegralOrEnumType(Ty); |
692 | return Interpreter::InterfaceKind::NoAlloc; |
693 | } |
694 | |
695 | private: |
696 | // Force cast these types to uint64 to reduce the number of overloads of |
697 | // `__clang_Interpreter_SetValueNoAlloc`. |
698 | void HandleIntegralOrEnumType(const Type *Ty) { |
699 | TypeSourceInfo *TSI = Ctx.getTrivialTypeSourceInfo(T: Ctx.UnsignedLongLongTy); |
700 | ExprResult CastedExpr = |
701 | S.BuildCStyleCastExpr(LParenLoc: SourceLocation(), Ty: TSI, RParenLoc: SourceLocation(), Op: E); |
702 | assert(!CastedExpr.isInvalid() && "Cannot create cstyle cast expr" ); |
703 | Args.push_back(Elt: CastedExpr.get()); |
704 | } |
705 | |
706 | void HandlePtrType(const Type *Ty) { |
707 | TypeSourceInfo *TSI = Ctx.getTrivialTypeSourceInfo(T: Ctx.VoidPtrTy); |
708 | ExprResult CastedExpr = |
709 | S.BuildCStyleCastExpr(LParenLoc: SourceLocation(), Ty: TSI, RParenLoc: SourceLocation(), Op: E); |
710 | assert(!CastedExpr.isInvalid() && "Can not create cstyle cast expression" ); |
711 | Args.push_back(Elt: CastedExpr.get()); |
712 | } |
713 | }; |
714 | } // namespace |
715 | |
716 | // This synthesizes a call expression to a speciall |
717 | // function that is responsible for generating the Value. |
718 | // In general, we transform: |
719 | // clang-repl> x |
720 | // To: |
721 | // // 1. If x is a built-in type like int, float. |
722 | // __clang_Interpreter_SetValueNoAlloc(ThisInterp, OpaqueValue, xQualType, x); |
723 | // // 2. If x is a struct, and a lvalue. |
724 | // __clang_Interpreter_SetValueNoAlloc(ThisInterp, OpaqueValue, xQualType, |
725 | // &x); |
726 | // // 3. If x is a struct, but a rvalue. |
727 | // new (__clang_Interpreter_SetValueWithAlloc(ThisInterp, OpaqueValue, |
728 | // xQualType)) (x); |
729 | |
730 | Expr *Interpreter::SynthesizeExpr(Expr *E) { |
731 | Sema &S = getCompilerInstance()->getSema(); |
732 | ASTContext &Ctx = S.getASTContext(); |
733 | |
734 | if (!FindRuntimeInterface()) |
735 | llvm_unreachable("We can't find the runtime iterface for pretty print!" ); |
736 | |
737 | // Create parameter `ThisInterp`. |
738 | auto *ThisInterp = CStyleCastPtrExpr(S, Ctx.VoidPtrTy, (uintptr_t)this); |
739 | |
740 | // Create parameter `OutVal`. |
741 | auto *OutValue = CStyleCastPtrExpr(S, Ctx.VoidPtrTy, (uintptr_t)&LastValue); |
742 | |
743 | // Build `__clang_Interpreter_SetValue*` call. |
744 | RuntimeInterfaceBuilder Builder(*this, Ctx, S, E, {ThisInterp, OutValue}); |
745 | |
746 | ExprResult Result = Builder.getCall(); |
747 | // It could fail, like printing an array type in C. (not supported) |
748 | if (Result.isInvalid()) |
749 | return E; |
750 | return Result.get(); |
751 | } |
752 | |
753 | // Temporary rvalue struct that need special care. |
754 | REPL_EXTERNAL_VISIBILITY void * |
755 | __clang_Interpreter_SetValueWithAlloc(void *This, void *OutVal, |
756 | void *OpaqueType) { |
757 | Value &VRef = *(Value *)OutVal; |
758 | VRef = Value(static_cast<Interpreter *>(This), OpaqueType); |
759 | return VRef.getPtr(); |
760 | } |
761 | |
762 | // Pointers, lvalue struct that can take as a reference. |
763 | REPL_EXTERNAL_VISIBILITY void |
764 | __clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal, void *OpaqueType, |
765 | void *Val) { |
766 | Value &VRef = *(Value *)OutVal; |
767 | VRef = Value(static_cast<Interpreter *>(This), OpaqueType); |
768 | VRef.setPtr(Val); |
769 | } |
770 | |
771 | REPL_EXTERNAL_VISIBILITY void |
772 | __clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal, |
773 | void *OpaqueType) { |
774 | Value &VRef = *(Value *)OutVal; |
775 | VRef = Value(static_cast<Interpreter *>(This), OpaqueType); |
776 | } |
777 | |
778 | static void SetValueDataBasedOnQualType(Value &V, unsigned long long Data) { |
779 | QualType QT = V.getType(); |
780 | if (const auto *ET = QT->getAs<EnumType>()) |
781 | QT = ET->getDecl()->getIntegerType(); |
782 | |
783 | switch (QT->castAs<BuiltinType>()->getKind()) { |
784 | default: |
785 | llvm_unreachable("unknown type kind!" ); |
786 | #define X(type, name) \ |
787 | case BuiltinType::name: \ |
788 | V.set##name(Data); \ |
789 | break; |
790 | REPL_BUILTIN_TYPES |
791 | #undef X |
792 | } |
793 | } |
794 | |
795 | REPL_EXTERNAL_VISIBILITY void |
796 | __clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal, void *OpaqueType, |
797 | unsigned long long Val) { |
798 | Value &VRef = *(Value *)OutVal; |
799 | VRef = Value(static_cast<Interpreter *>(This), OpaqueType); |
800 | SetValueDataBasedOnQualType(V&: VRef, Data: Val); |
801 | } |
802 | |
803 | REPL_EXTERNAL_VISIBILITY void |
804 | __clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal, void *OpaqueType, |
805 | float Val) { |
806 | Value &VRef = *(Value *)OutVal; |
807 | VRef = Value(static_cast<Interpreter *>(This), OpaqueType); |
808 | VRef.setFloat(Val); |
809 | } |
810 | |
811 | REPL_EXTERNAL_VISIBILITY void |
812 | __clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal, void *OpaqueType, |
813 | double Val) { |
814 | Value &VRef = *(Value *)OutVal; |
815 | VRef = Value(static_cast<Interpreter *>(This), OpaqueType); |
816 | VRef.setDouble(Val); |
817 | } |
818 | |
819 | REPL_EXTERNAL_VISIBILITY void |
820 | __clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal, void *OpaqueType, |
821 | long double Val) { |
822 | Value &VRef = *(Value *)OutVal; |
823 | VRef = Value(static_cast<Interpreter *>(This), OpaqueType); |
824 | VRef.setLongDouble(Val); |
825 | } |
826 | |
827 | // A trampoline to work around the fact that operator placement new cannot |
828 | // really be forward declared due to libc++ and libstdc++ declaration mismatch. |
829 | // FIXME: __clang_Interpreter_NewTag is ODR violation because we get the same |
830 | // definition in the interpreter runtime. We should move it in a runtime header |
831 | // which gets included by the interpreter and here. |
832 | struct __clang_Interpreter_NewTag {}; |
833 | REPL_EXTERNAL_VISIBILITY void * |
834 | operator new(size_t __sz, void *__p, __clang_Interpreter_NewTag) noexcept { |
835 | // Just forward to the standard operator placement new. |
836 | return operator new(__sz, __p); |
837 | } |
838 | |