clang 22.0.0git
Interpreter.cpp
Go to the documentation of this file.
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 "IncrementalAction.h"
16#include "IncrementalExecutor.h"
17#include "IncrementalParser.h"
18#include "InterpreterUtils.h"
19#include "llvm/Support/VirtualFileSystem.h"
20#ifdef __EMSCRIPTEN__
21#include "Wasm.h"
22#include <dlfcn.h>
23#endif // __EMSCRIPTEN__
24
27#include "clang/AST/Mangle.h"
34#include "clang/Driver/Driver.h"
35#include "clang/Driver/Job.h"
36#include "clang/Driver/Tool.h"
47#include "clang/Sema/Lookup.h"
49#include "llvm/ExecutionEngine/JITSymbol.h"
50#include "llvm/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.h"
51#include "llvm/ExecutionEngine/Orc/LLJIT.h"
52#include "llvm/IR/Module.h"
53#include "llvm/Support/Errc.h"
54#include "llvm/Support/ErrorHandling.h"
55#include "llvm/Support/raw_ostream.h"
56#include "llvm/TargetParser/Host.h"
57#include "llvm/Transforms/Utils/Cloning.h" // for CloneModule
58
59#define DEBUG_TYPE "clang-repl"
60
61using namespace clang;
62// FIXME: Figure out how to unify with namespace init_convenience from
63// tools/clang-import-test/clang-import-test.cpp
64namespace {
65/// Retrieves the clang CC1 specific flags out of the compilation's jobs.
66/// \returns NULL on error.
68GetCC1Arguments(DiagnosticsEngine *Diagnostics,
69 driver::Compilation *Compilation) {
70 // We expect to get back exactly one Command job, if we didn't something
71 // failed. Extract that job from the Compilation.
72 const driver::JobList &Jobs = Compilation->getJobs();
73 if (!Jobs.size() || !isa<driver::Command>(*Jobs.begin()))
74 return llvm::createStringError(llvm::errc::not_supported,
75 "Driver initialization failed. "
76 "Unable to create a driver job");
77
78 // The one job we find should be to invoke clang again.
79 const driver::Command *Cmd = cast<driver::Command>(&(*Jobs.begin()));
80 if (llvm::StringRef(Cmd->getCreator().getName()) != "clang")
81 return llvm::createStringError(llvm::errc::not_supported,
82 "Driver initialization failed");
83
84 return &Cmd->getArguments();
85}
86
88CreateCI(const llvm::opt::ArgStringList &Argv) {
89 std::unique_ptr<CompilerInstance> Clang(new CompilerInstance());
90
91 // Register the support for object-file-wrapped Clang modules.
92 // FIXME: Clang should register these container operations automatically.
93 auto PCHOps = Clang->getPCHContainerOperations();
94 PCHOps->registerWriter(std::make_unique<ObjectFilePCHContainerWriter>());
95 PCHOps->registerReader(std::make_unique<ObjectFilePCHContainerReader>());
96
97 // Buffer diagnostics from argument parsing so that we can output them using
98 // a well formed diagnostic object.
99 DiagnosticOptions DiagOpts;
101 DiagnosticsEngine Diags(DiagnosticIDs::create(), DiagOpts, DiagsBuffer);
103 Clang->getInvocation(), llvm::ArrayRef(Argv.begin(), Argv.size()), Diags);
104
105 // Infer the builtin include path if unspecified.
106 if (Clang->getHeaderSearchOpts().UseBuiltinIncludes &&
107 Clang->getHeaderSearchOpts().ResourceDir.empty())
108 Clang->getHeaderSearchOpts().ResourceDir =
109 GetResourcesPath(Argv[0], nullptr);
110
111 Clang->createVirtualFileSystem();
112
113 // Create the actual diagnostics engine.
114 Clang->createDiagnostics();
115
116 DiagsBuffer->FlushDiagnostics(Clang->getDiagnostics());
117 if (!Success)
118 return llvm::createStringError(llvm::errc::not_supported,
119 "Initialization failed. "
120 "Unable to flush diagnostics");
121
122 // FIXME: Merge with CompilerInstance::ExecuteAction.
123 llvm::MemoryBuffer *MB = llvm::MemoryBuffer::getMemBuffer("").release();
124 Clang->getPreprocessorOpts().addRemappedFile("<<< inputs >>>", MB);
125
126 Clang->setTarget(TargetInfo::CreateTargetInfo(
127 Clang->getDiagnostics(), Clang->getInvocation().getTargetOpts()));
128 if (!Clang->hasTarget())
129 return llvm::createStringError(llvm::errc::not_supported,
130 "Initialization failed. "
131 "Target is missing");
132
133 Clang->getTarget().adjust(Clang->getDiagnostics(), Clang->getLangOpts(),
134 Clang->getAuxTarget());
135
136 // Don't clear the AST before backend codegen since we do codegen multiple
137 // times, reusing the same AST.
138 Clang->getCodeGenOpts().ClearASTBeforeBackend = false;
139
140 Clang->getFrontendOpts().DisableFree = false;
141 Clang->getCodeGenOpts().DisableFree = false;
142 return std::move(Clang);
143}
144
145} // anonymous namespace
146
147namespace clang {
148
150IncrementalCompilerBuilder::create(std::string TT,
151 std::vector<const char *> &ClangArgv) {
152
153 // If we don't know ClangArgv0 or the address of main() at this point, try
154 // to guess it anyway (it's possible on some platforms).
155 std::string MainExecutableName =
156 llvm::sys::fs::getMainExecutable(nullptr, nullptr);
157
158 ClangArgv.insert(ClangArgv.begin(), MainExecutableName.c_str());
159
160 // Prepending -c to force the driver to do something if no action was
161 // specified. By prepending we allow users to override the default
162 // action and use other actions in incremental mode.
163 // FIXME: Print proper driver diagnostics if the driver flags are wrong.
164 // We do C++ by default; append right after argv[0] if no "-x" given
165 ClangArgv.insert(ClangArgv.end(), "-Xclang");
166 ClangArgv.insert(ClangArgv.end(), "-fincremental-extensions");
167 ClangArgv.insert(ClangArgv.end(), "-c");
168
169 // Put a dummy C++ file on to ensure there's at least one compile job for the
170 // driver to construct.
171 ClangArgv.push_back("<<< inputs >>>");
172
173 // Buffer diagnostics from argument parsing so that we can output them using a
174 // well formed diagnostic object.
175 std::unique_ptr<DiagnosticOptions> DiagOpts =
176 CreateAndPopulateDiagOpts(ClangArgv);
177 TextDiagnosticBuffer *DiagsBuffer = new TextDiagnosticBuffer;
178 DiagnosticsEngine Diags(DiagnosticIDs::create(), *DiagOpts, DiagsBuffer);
179
180 driver::Driver Driver(/*MainBinaryName=*/ClangArgv[0], TT, Diags);
181 Driver.setCheckInputsExist(false); // the input comes from mem buffers
182 llvm::ArrayRef<const char *> RF = llvm::ArrayRef(ClangArgv);
183 std::unique_ptr<driver::Compilation> Compilation(Driver.BuildCompilation(RF));
184
185 if (Compilation->getArgs().hasArg(options::OPT_v))
186 Compilation->getJobs().Print(llvm::errs(), "\n", /*Quote=*/false);
187
188 auto ErrOrCC1Args = GetCC1Arguments(&Diags, Compilation.get());
189 if (auto Err = ErrOrCC1Args.takeError())
190 return std::move(Err);
191
192 return CreateCI(**ErrOrCC1Args);
193}
194
197 std::vector<const char *> Argv;
198 Argv.reserve(5 + 1 + UserArgs.size());
199 Argv.push_back("-xc++");
200#ifdef __EMSCRIPTEN__
201 Argv.push_back("-target");
202 Argv.push_back("wasm32-unknown-emscripten");
203 Argv.push_back("-fvisibility=default");
204#endif
205 llvm::append_range(Argv, UserArgs);
206
207 std::string TT = TargetTriple ? *TargetTriple : llvm::sys::getProcessTriple();
208 return IncrementalCompilerBuilder::create(TT, Argv);
209}
210
212IncrementalCompilerBuilder::createCuda(bool device) {
213 std::vector<const char *> Argv;
214 Argv.reserve(5 + 4 + UserArgs.size());
215
216 Argv.push_back("-xcuda");
217 if (device)
218 Argv.push_back("--cuda-device-only");
219 else
220 Argv.push_back("--cuda-host-only");
221
222 std::string SDKPathArg = "--cuda-path=";
223 if (!CudaSDKPath.empty()) {
224 SDKPathArg += CudaSDKPath;
225 Argv.push_back(SDKPathArg.c_str());
226 }
227
228 std::string ArchArg = "--offload-arch=";
229 if (!OffloadArch.empty()) {
230 ArchArg += OffloadArch;
231 Argv.push_back(ArchArg.c_str());
232 }
233
234 llvm::append_range(Argv, UserArgs);
235
236 std::string TT = TargetTriple ? *TargetTriple : llvm::sys::getProcessTriple();
237 return IncrementalCompilerBuilder::create(TT, Argv);
238}
239
242 return IncrementalCompilerBuilder::createCuda(true);
243}
244
247 return IncrementalCompilerBuilder::createCuda(false);
248}
249
250Interpreter::Interpreter(std::unique_ptr<CompilerInstance> Instance,
251 llvm::Error &ErrOut,
252 std::unique_ptr<llvm::orc::LLJITBuilder> JITBuilder,
253 std::unique_ptr<clang::ASTConsumer> Consumer,
254 JITConfig Config)
255 : JITBuilder(std::move(JITBuilder)) {
256 CI = std::move(Instance);
257 llvm::ErrorAsOutParameter EAO(&ErrOut);
258 auto LLVMCtx = std::make_unique<llvm::LLVMContext>();
259 TSCtx = std::make_unique<llvm::orc::ThreadSafeContext>(std::move(LLVMCtx));
260
261 Act = TSCtx->withContextDo([&](llvm::LLVMContext *Ctx) {
262 return std::make_unique<IncrementalAction>(*CI, *Ctx, ErrOut, *this,
263 std::move(Consumer));
264 });
265
266 if (ErrOut)
267 return;
268 CI->ExecuteAction(*Act);
269
270 IncrParser =
271 std::make_unique<IncrementalParser>(*CI, Act.get(), ErrOut, PTUs);
272
273 if (ErrOut)
274 return;
275
276 if (Act->getCodeGen()) {
277 Act->CacheCodeGenModule();
278 // The initial PTU is filled by `-include`/`-include-pch` or by CUDA
279 // includes automatically.
280 if (!CI->getPreprocessorOpts().Includes.empty() ||
281 !CI->getPreprocessorOpts().ImplicitPCHInclude.empty()) {
282 // We can't really directly pass the CachedInCodeGenModule to the Jit
283 // because it will steal it, causing dangling references as explained in
284 // Interpreter::Execute
285 auto M = llvm::CloneModule(*Act->getCachedCodeGenModule());
286 ASTContext &C = CI->getASTContext();
287 IncrParser->RegisterPTU(C.getTranslationUnitDecl(), std::move(M));
288 }
289 if (llvm::Error Err = CreateExecutor(Config)) {
290 ErrOut = joinErrors(std::move(ErrOut), std::move(Err));
291 return;
292 }
293 }
294
295 // Not all frontends support code-generation, e.g. ast-dump actions don't
296 if (Act->getCodeGen()) {
297 // Process the PTUs that came from initialization. For example -include will
298 // give us a header that's processed at initialization of the preprocessor.
299 for (PartialTranslationUnit &PTU : PTUs)
300 if (llvm::Error Err = Execute(PTU)) {
301 ErrOut = joinErrors(std::move(ErrOut), std::move(Err));
302 return;
303 }
304 }
305}
306
308 IncrParser.reset();
309 Act->FinalizeAction();
310 if (DeviceParser)
311 DeviceParser.reset();
312 if (DeviceAct)
313 DeviceAct->FinalizeAction();
314 if (IncrExecutor) {
315 if (llvm::Error Err = IncrExecutor->cleanUp())
316 llvm::report_fatal_error(
317 llvm::Twine("Failed to clean up IncrementalExecutor: ") +
318 toString(std::move(Err)));
319 }
320}
321
322// These better to put in a runtime header but we can't. This is because we
323// can't find the precise resource directory in unittests so we have to hard
324// code them.
325const char *const Runtimes = R"(
326 #define __CLANG_REPL__ 1
327#ifdef __cplusplus
328 #define EXTERN_C extern "C"
329 struct __clang_Interpreter_NewTag{} __ci_newtag;
330 void* operator new(__SIZE_TYPE__, void* __p, __clang_Interpreter_NewTag) noexcept;
331 template <class T, class = T (*)() /*disable for arrays*/>
332 void __clang_Interpreter_SetValueCopyArr(const T* Src, void* Placement, unsigned long Size) {
333 for (auto Idx = 0; Idx < Size; ++Idx)
334 new ((void*)(((T*)Placement) + Idx), __ci_newtag) T(Src[Idx]);
335 }
336 template <class T, unsigned long N>
337 void __clang_Interpreter_SetValueCopyArr(const T (*Src)[N], void* Placement, unsigned long Size) {
338 __clang_Interpreter_SetValueCopyArr(Src[0], Placement, Size);
339 }
340#else
341 #define EXTERN_C extern
342 EXTERN_C void *memcpy(void *restrict dst, const void *restrict src, __SIZE_TYPE__ n);
343 EXTERN_C inline void __clang_Interpreter_SetValueCopyArr(const void* Src, void* Placement, unsigned long Size) {
344 memcpy(Placement, Src, Size);
345 }
346#endif // __cplusplus
347 EXTERN_C void *__clang_Interpreter_SetValueWithAlloc(void*, void*, void*);
348 EXTERN_C void __clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal, void *OpaqueType, ...);
349)";
350
353 std::unique_ptr<llvm::orc::ExecutorProcessControl> EPC;
354 uint32_t childPid = -1;
355 if (!Config.OOPExecutor.empty()) {
356 // Launch an out-of-process executor locally in a child process.
357 auto ResultOrErr = IncrementalExecutor::launchExecutor(
358 Config.OOPExecutor, Config.UseSharedMemory, Config.SlabAllocateSize,
359 Config.CustomizeFork);
360 if (!ResultOrErr)
361 return ResultOrErr.takeError();
362 childPid = ResultOrErr->second;
363 auto EPCOrErr = std::move(ResultOrErr->first);
364 EPC = std::move(EPCOrErr);
365 } else if (Config.OOPExecutorConnect != "") {
366#if LLVM_ON_UNIX && LLVM_ENABLE_THREADS
367 auto EPCOrErr = IncrementalExecutor::connectTCPSocket(
368 Config.OOPExecutorConnect, Config.UseSharedMemory,
369 Config.SlabAllocateSize);
370 if (!EPCOrErr)
371 return EPCOrErr.takeError();
372 EPC = std::move(*EPCOrErr);
373#else
374 return llvm::make_error<llvm::StringError>(
375 "Out-of-process JIT over TCP is not supported on this platform",
376 std::error_code());
377#endif
378 }
379
380 std::unique_ptr<llvm::orc::LLJITBuilder> JB;
381 if (EPC) {
383 std::move(EPC), Config.OrcRuntimePath);
384 if (!JBOrErr)
385 return JBOrErr.takeError();
386 JB = std::move(*JBOrErr);
387 }
388
389 return std::make_pair(std::move(JB), childPid);
390}
391
394 const std::array<const char *, 3> OrcRTLibNames = {
395 "liborc_rt.a", "liborc_rt_osx.a", "liborc_rt-x86_64.a"};
396
397 auto findInDir = [&](llvm::StringRef Base) -> std::optional<std::string> {
398 for (const char *LibName : OrcRTLibNames) {
399 llvm::SmallString<256> CandidatePath(Base);
400 llvm::sys::path::append(CandidatePath, LibName);
401 if (llvm::sys::fs::exists(CandidatePath))
402 return std::string(CandidatePath.str());
403 }
404 return std::nullopt;
405 };
406
407 std::string SearchedPaths;
408
409 if (std::optional<std::string> CompilerRTPath = TC.getCompilerRTPath()) {
410 if (auto Found = findInDir(*CompilerRTPath))
411 return *Found;
412 SearchedPaths += *CompilerRTPath;
413 } else {
414 return llvm::make_error<llvm::StringError>("CompilerRT path not found",
415 std::error_code());
416 }
417
418 if (std::optional<std::string> ResourceDir = TC.getRuntimePath()) {
419 if (auto Found = findInDir(*ResourceDir))
420 return *Found;
421 if (!SearchedPaths.empty())
422 SearchedPaths += "; ";
423 SearchedPaths += *ResourceDir;
424 } else {
425 return llvm::make_error<llvm::StringError>("ResourceDir path not found",
426 std::error_code());
427 }
428
429 return llvm::make_error<llvm::StringError>(
430 llvm::Twine("OrcRuntime library not found in: ") + SearchedPaths,
431 std::error_code());
432}
433
435Interpreter::create(std::unique_ptr<CompilerInstance> CI, JITConfig Config) {
436
437 if (Config.IsOutOfProcess) {
438 const TargetInfo &TI = CI->getTarget();
439 const llvm::Triple &Triple = TI.getTriple();
440
441 DiagnosticsEngine &Diags = CI->getDiagnostics();
442 std::string BinaryName = llvm::sys::fs::getMainExecutable(nullptr, nullptr);
443 driver::Driver Driver(BinaryName, Triple.str(), Diags);
444 // Need fake args to get the driver to create a compilation.
445 std::vector<const char *> Args = {"clang", "--version"};
446 std::unique_ptr<clang::driver::Compilation> C(
447 Driver.BuildCompilation(Args));
448 if (!C) {
449 return llvm::make_error<llvm::StringError>(
450 "Failed to create driver compilation for out-of-process JIT",
451 std::error_code());
452 }
453 if (Config.OrcRuntimePath == "") {
454 const clang::driver::ToolChain &TC = C->getDefaultToolChain();
455
456 auto OrcRuntimePathOrErr = getOrcRuntimePath(TC);
457 if (!OrcRuntimePathOrErr) {
458 return OrcRuntimePathOrErr.takeError();
459 }
460
461 Config.OrcRuntimePath = *OrcRuntimePathOrErr;
462 }
463 }
464
465 llvm::Error Err = llvm::Error::success();
466 std::unique_ptr<llvm::orc::LLJITBuilder> JB;
467
468 auto Interp = std::unique_ptr<Interpreter>(new Interpreter(
469 std::move(CI), Err, std::move(JB), /*Consumer=*/nullptr, Config));
470 if (auto E = std::move(Err))
471 return std::move(E);
472
473 // Add runtime code and set a marker to hide it from user code. Undo will not
474 // go through that.
475 if (auto E = Interp->ParseAndExecute(Runtimes))
476 return std::move(E);
477
478 Interp->markUserCodeStart();
479
480 return std::move(Interp);
481}
482
484Interpreter::createWithCUDA(std::unique_ptr<CompilerInstance> CI,
485 std::unique_ptr<CompilerInstance> DCI) {
486 // avoid writing fat binary to disk using an in-memory virtual file system
488 std::make_unique<llvm::vfs::InMemoryFileSystem>();
490 std::make_unique<llvm::vfs::OverlayFileSystem>(
491 llvm::vfs::getRealFileSystem());
492 OverlayVFS->pushOverlay(IMVFS);
493 CI->createVirtualFileSystem(OverlayVFS);
494 CI->createFileManager();
495
497 Interpreter::create(std::move(CI));
498 if (!InterpOrErr)
499 return InterpOrErr;
500
501 std::unique_ptr<Interpreter> Interp = std::move(*InterpOrErr);
502
503 llvm::Error Err = llvm::Error::success();
504
505 auto DeviceAct = Interp->TSCtx->withContextDo([&](llvm::LLVMContext *Ctx) {
506 return std::make_unique<IncrementalAction>(*DCI, *Ctx, Err, *Interp);
507 });
508
509 if (Err)
510 return std::move(Err);
511
512 Interp->DeviceAct = std::move(DeviceAct);
513
514 DCI->ExecuteAction(*Interp->DeviceAct);
515
516 Interp->DeviceCI = std::move(DCI);
517
518 auto DeviceParser = std::make_unique<IncrementalCUDADeviceParser>(
519 *Interp->DeviceCI, *Interp->getCompilerInstance(),
520 Interp->DeviceAct.get(), IMVFS, Err, Interp->PTUs);
521
522 if (Err)
523 return std::move(Err);
524
525 Interp->DeviceParser = std::move(DeviceParser);
526 return std::move(Interp);
527}
528
531 return const_cast<Interpreter *>(this)->getCompilerInstance();
532}
533
535 if (!IncrExecutor) {
536 if (auto Err = CreateExecutor())
537 return std::move(Err);
538 }
539
540 return IncrExecutor->GetExecutionEngine();
541}
542
546
550
551void Interpreter::markUserCodeStart() {
552 assert(!InitPTUSize && "We only do this once");
553 InitPTUSize = PTUs.size();
554}
555
556size_t Interpreter::getEffectivePTUSize() const {
557 assert(PTUs.size() >= InitPTUSize && "empty PTU list?");
558 return PTUs.size() - InitPTUSize;
559}
560
562 if (IncrExecutor)
563 return IncrExecutor->getOutOfProcessChildPid();
564 return -1;
565}
566
568Interpreter::Parse(llvm::StringRef Code) {
569 // If we have a device parser, parse it first. The generated code will be
570 // included in the host compilation
571 if (DeviceParser) {
572 llvm::Expected<TranslationUnitDecl *> DeviceTU = DeviceParser->Parse(Code);
573 if (auto E = DeviceTU.takeError())
574 return std::move(E);
575
576 DeviceParser->RegisterPTU(*DeviceTU);
577
578 llvm::Expected<llvm::StringRef> PTX = DeviceParser->GeneratePTX();
579 if (!PTX)
580 return PTX.takeError();
581
582 llvm::Error Err = DeviceParser->GenerateFatbinary();
583 if (Err)
584 return std::move(Err);
585 }
586
587 // Tell the interpreter sliently ignore unused expressions since value
588 // printing could cause it.
590 clang::diag::warn_unused_expr, diag::Severity::Ignored, SourceLocation());
591
592 llvm::Expected<TranslationUnitDecl *> TuOrErr = IncrParser->Parse(Code);
593 if (!TuOrErr)
594 return TuOrErr.takeError();
595
596 PartialTranslationUnit &LastPTU = IncrParser->RegisterPTU(*TuOrErr);
597
598 return LastPTU;
599}
600
602createJITTargetMachineBuilder(const std::string &TT) {
603 if (TT == llvm::sys::getProcessTriple())
604 // This fails immediately if the target backend is not registered
605 return llvm::orc::JITTargetMachineBuilder::detectHost();
606
607 // If the target backend is not registered, LLJITBuilder::create() will fail
608 return llvm::orc::JITTargetMachineBuilder(llvm::Triple(TT));
609}
610
613 std::unique_ptr<llvm::orc::ExecutorProcessControl> EPC,
614 llvm::StringRef OrcRuntimePath) {
615 const std::string &TT = EPC->getTargetTriple().getTriple();
616 auto JTMB = createJITTargetMachineBuilder(TT);
617 if (!JTMB)
618 return JTMB.takeError();
619 auto JB = IncrementalExecutor::createDefaultJITBuilder(std::move(*JTMB));
620 if (!JB)
621 return JB.takeError();
622
623 (*JB)->setExecutorProcessControl(std::move(EPC));
624 (*JB)->setPlatformSetUp(
625 llvm::orc::ExecutorNativePlatform(OrcRuntimePath.str()));
626
627 return std::move(*JB);
628}
629
631 if (IncrExecutor)
632 return llvm::make_error<llvm::StringError>("Operation failed. "
633 "Execution engine exists",
634 std::error_code());
635 if (!Act->getCodeGen())
636 return llvm::make_error<llvm::StringError>("Operation failed. "
637 "No code generator available",
638 std::error_code());
639
640 const std::string &TT = getCompilerInstance()->getTargetOpts().Triple;
641 llvm::Triple TargetTriple(TT);
642 bool IsWindowsTarget = TargetTriple.isOSWindows();
643
644 if (!IsWindowsTarget && Config.IsOutOfProcess) {
645 if (!JITBuilder) {
646 auto ResOrErr = outOfProcessJITBuilder(Config);
647 if (!ResOrErr)
648 return ResOrErr.takeError();
649 JITBuilder = std::move(ResOrErr->first);
650 Config.ExecutorPID = ResOrErr->second;
651 }
652 if (!JITBuilder)
653 return llvm::make_error<llvm::StringError>(
654 "Operation failed. No LLJITBuilder for out-of-process JIT",
655 std::error_code());
656 }
657
658 if (!JITBuilder) {
659 auto JTMB = createJITTargetMachineBuilder(TT);
660 if (!JTMB)
661 return JTMB.takeError();
662 if (Config.CM)
663 JTMB->setCodeModel(Config.CM);
664 auto JB = IncrementalExecutor::createDefaultJITBuilder(std::move(*JTMB));
665 if (!JB)
666 return JB.takeError();
667 JITBuilder = std::move(*JB);
668 }
669
670 llvm::Error Err = llvm::Error::success();
671
672 // Fix: Declare Executor as the appropriate unique_ptr type
673 std::unique_ptr<IncrementalExecutor> Executor;
674
675#ifdef __EMSCRIPTEN__
676 Executor = std::make_unique<WasmIncrementalExecutor>(*TSCtx);
677#else
678 Executor =
679 std::make_unique<IncrementalExecutor>(*TSCtx, *JITBuilder, Config, Err);
680#endif
681 if (!Err)
682 IncrExecutor = std::move(Executor);
683
684 return Err;
685}
686
687void Interpreter::ResetExecutor() { IncrExecutor.reset(); }
688
690 assert(T.TheModule);
691 LLVM_DEBUG(
692 llvm::dbgs() << "execute-ptu "
693 << (llvm::is_contained(PTUs, T)
694 ? std::distance(PTUs.begin(), llvm::find(PTUs, T))
695 : -1)
696 << ": [TU=" << T.TUPart << ", M=" << T.TheModule.get()
697 << " (" << T.TheModule->getName() << ")]\n");
698 if (!IncrExecutor) {
699 auto Err = CreateExecutor();
700 if (Err)
701 return Err;
702 }
703 // FIXME: Add a callback to retain the llvm::Module once the JIT is done.
704 if (auto Err = IncrExecutor->addModule(T))
705 return Err;
706
707 if (auto Err = IncrExecutor->runCtors())
708 return Err;
709
710 return llvm::Error::success();
711}
712
713llvm::Error Interpreter::ParseAndExecute(llvm::StringRef Code, Value *V) {
714
715 auto PTU = Parse(Code);
716 if (!PTU)
717 return PTU.takeError();
718 if (PTU->TheModule)
719 if (llvm::Error Err = Execute(*PTU))
720 return Err;
721
722 if (LastValue.isValid()) {
723 if (!V) {
724 LastValue.dump();
725 LastValue.clear();
726 } else
727 *V = std::move(LastValue);
728 }
729 return llvm::Error::success();
730}
731
734 if (!IncrExecutor)
735 return llvm::make_error<llvm::StringError>("Operation failed. "
736 "No execution engine",
737 std::error_code());
738 llvm::StringRef MangledName = Act->getCodeGen()->GetMangledName(GD);
739 return getSymbolAddress(MangledName);
740}
741
743Interpreter::getSymbolAddress(llvm::StringRef IRName) const {
744 if (!IncrExecutor)
745 return llvm::make_error<llvm::StringError>("Operation failed. "
746 "No execution engine",
747 std::error_code());
748
749 return IncrExecutor->getSymbolAddress(IRName, IncrementalExecutor::IRName);
750}
751
754 if (!IncrExecutor)
755 return llvm::make_error<llvm::StringError>("Operation failed. "
756 "No execution engine",
757 std::error_code());
758
759 return IncrExecutor->getSymbolAddress(Name, IncrementalExecutor::LinkerName);
760}
761
762llvm::Error Interpreter::Undo(unsigned N) {
763
764 if (getEffectivePTUSize() == 0) {
765 return llvm::make_error<llvm::StringError>("Operation failed. "
766 "No input left to undo",
767 std::error_code());
768 } else if (N > getEffectivePTUSize()) {
769 return llvm::make_error<llvm::StringError>(
770 llvm::formatv(
771 "Operation failed. Wanted to undo {0} inputs, only have {1}.", N,
772 getEffectivePTUSize()),
773 std::error_code());
774 }
775
776 for (unsigned I = 0; I < N; I++) {
777 if (IncrExecutor) {
778 if (llvm::Error Err = IncrExecutor->removeModule(PTUs.back()))
779 return Err;
780 }
781
782 IncrParser->CleanUpPTU(PTUs.back().TUPart);
783 PTUs.pop_back();
784 }
785 return llvm::Error::success();
786}
787
788llvm::Error Interpreter::LoadDynamicLibrary(const char *name) {
789#ifdef __EMSCRIPTEN__
790 void *handle = dlopen(name, RTLD_NOW | RTLD_GLOBAL);
791 if (!handle) {
792 llvm::errs() << dlerror() << '\n';
793 return llvm::make_error<llvm::StringError>("Failed to load dynamic library",
794 llvm::inconvertibleErrorCode());
795 }
796#else
797 auto EE = getExecutionEngine();
798 if (!EE)
799 return EE.takeError();
800
801 if (llvm::Expected<
802 std::unique_ptr<llvm::orc::EPCDynamicLibrarySearchGenerator>>
803 DLSG = llvm::orc::EPCDynamicLibrarySearchGenerator::Load(
804 EE->getExecutionSession(), name))
805 // FIXME: Eventually we should put each library in its own JITDylib and
806 // turn off process symbols by default.
807 EE->getProcessSymbolsJITDylib()->addGenerator(std::move(*DLSG));
808 else
809 return DLSG.takeError();
810#endif
811
812 return llvm::Error::success();
813}
814} // end namespace clang
Defines the clang::ASTContext interface.
#define V(N, I)
Defines the clang::FrontendAction interface and various convenience abstract classes (clang::ASTFront...
static std::string toString(const clang::SanitizerSet &Sanitizers)
Produce a string containing comma-separated names of sanitizers in Sanitizers set.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition ASTContext.h:220
CompilerInstance - Helper class for managing a single instance of the Clang compiler.
DiagnosticsEngine & getDiagnostics() const
Get the current diagnostics engine.
ASTContext & getASTContext() const
TargetOptions & getTargetOpts()
static bool CreateFromArgs(CompilerInvocation &Res, ArrayRef< const char * > CommandLineArgs, DiagnosticsEngine &Diags, const char *Argv0=nullptr)
Create a compiler invocation from a list of input options.
static llvm::IntrusiveRefCntPtr< DiagnosticIDs > create()
Options for controlling the compiler diagnostics engine.
Concrete class used by the front-end to report problems and issues.
Definition Diagnostic.h:232
void setSeverity(diag::kind Diag, diag::Severity Map, SourceLocation Loc)
This allows the client to specify that certain warnings are ignored.
GlobalDecl - represents a global declaration.
Definition GlobalDecl.h:57
llvm::Expected< std::unique_ptr< CompilerInstance > > CreateCudaHost()
llvm::Expected< std::unique_ptr< CompilerInstance > > CreateCudaDevice()
llvm::Expected< std::unique_ptr< CompilerInstance > > CreateCpp()
static llvm::Expected< std::pair< std::unique_ptr< llvm::orc::SimpleRemoteEPC >, uint32_t > > launchExecutor(llvm::StringRef ExecutablePath, bool UseSharedMemory, unsigned SlabAllocateSize, std::function< void()> CustomizeFork=nullptr)
static llvm::Expected< std::unique_ptr< llvm::orc::LLJITBuilder > > createDefaultJITBuilder(llvm::orc::JITTargetMachineBuilder JTMB)
llvm::Error ParseAndExecute(llvm::StringRef Code, Value *V=nullptr)
uint32_t getOutOfProcessExecutorPID() const
llvm::Expected< llvm::orc::ExecutorAddr > getSymbolAddress(GlobalDecl GD) const
static llvm::Expected< std::pair< std::unique_ptr< llvm::orc::LLJITBuilder >, uint32_t > > outOfProcessJITBuilder(JITConfig Config)
llvm::Error LoadDynamicLibrary(const char *name)
Link a dynamic library.
static llvm::Expected< std::unique_ptr< Interpreter > > createWithCUDA(std::unique_ptr< CompilerInstance > CI, std::unique_ptr< CompilerInstance > DCI)
llvm::Error CreateExecutor(JITConfig Config=JITConfig())
llvm::Expected< PartialTranslationUnit & > Parse(llvm::StringRef Code)
llvm::Expected< llvm::orc::ExecutorAddr > getSymbolAddressFromLinkerName(llvm::StringRef LinkerName) const
llvm::Error Undo(unsigned N=1)
Undo N previous incremental inputs.
const CompilerInstance * getCompilerInstance() const
static llvm::Expected< std::unique_ptr< llvm::orc::LLJITBuilder > > createLLJITBuilder(std::unique_ptr< llvm::orc::ExecutorProcessControl > EPC, llvm::StringRef OrcRuntimePath)
static llvm::Expected< std::string > getOrcRuntimePath(const driver::ToolChain &TC)
const ASTContext & getASTContext() const
friend class Value
Definition Interpreter.h:92
llvm::Expected< llvm::orc::LLJIT & > getExecutionEngine()
static llvm::Expected< std::unique_ptr< Interpreter > > create(std::unique_ptr< CompilerInstance > CI, JITConfig Config={})
llvm::Error Execute(PartialTranslationUnit &T)
Interpreter(std::unique_ptr< CompilerInstance > Instance, llvm::Error &Err, std::unique_ptr< llvm::orc::LLJITBuilder > JITBuilder=nullptr, std::unique_ptr< clang::ASTConsumer > Consumer=nullptr, JITConfig Config=JITConfig())
Encodes a location in the source.
Exposes information about the current target.
Definition TargetInfo.h:226
static TargetInfo * CreateTargetInfo(DiagnosticsEngine &Diags, TargetOptions &Opts)
Construct a target for the given options.
Definition Targets.cpp:792
const llvm::Triple & getTriple() const
Returns the target triple of the primary target.
std::string Triple
The name of the target triple to compile for.
void FlushDiagnostics(DiagnosticsEngine &Diags) const
FlushDiagnostics - Flush the buffered diagnostics to an given diagnostic engine.
Command - An executable path/name and argument vector to execute.
Definition Job.h:106
const Tool & getCreator() const
getCreator - Return the Tool which caused the creation of this job.
Definition Job.h:191
const llvm::opt::ArgStringList & getArguments() const
Definition Job.h:224
Compilation - A set of tasks to perform for a single driver invocation.
Definition Compilation.h:45
Driver - Encapsulate logic for constructing compilation processes from a set of gcc-driver-like comma...
Definition Driver.h:99
JobList - A sequence of jobs to perform.
Definition Job.h:260
size_type size() const
Definition Job.h:283
iterator begin()
Definition Job.h:284
ToolChain - Access to tools for a single platform.
Definition ToolChain.h:92
virtual std::string getCompilerRTPath() const
std::optional< std::string > getRuntimePath() const
const char * getName() const
Definition Tool.h:48
Defines the clang::TargetInfo interface.
@ Ignored
Do not present this diagnostic, ignore it.
The JSON file list parser is used to communicate input to InstallAPI.
static llvm::Expected< llvm::orc::JITTargetMachineBuilder > createJITTargetMachineBuilder(const std::string &TT)
bool isa(CodeGen::Address addr)
Definition Address.h:330
std::unique_ptr< DiagnosticOptions > CreateAndPopulateDiagOpts(ArrayRef< const char * > Argv)
@ Success
Annotation was successful.
Definition Parser.h:65
@ Parse
Parse the block; this code is always used.
Definition Parser.h:137
const char *const Runtimes
const FunctionProtoType * T
std::string GetResourcesPath(StringRef BinaryPath)
Get the directory where the compiler headers reside, relative to the compiler binary path BinaryPath.
U cast(CodeGen::Address addr)
Definition Address.h:327
bool(*)(llvm::ArrayRef< const char * >, llvm::raw_ostream &, llvm::raw_ostream &, bool, bool) Driver
Definition Wasm.cpp:35
uint32_t ExecutorPID
PID of the out-of-process JIT executor.
std::function< void()> CustomizeFork
Custom lambda to be executed inside child process/executor.
bool IsOutOfProcess
Indicates whether out-of-process JIT execution is enabled.
std::string OrcRuntimePath
Path to the ORC runtime library.
std::optional< llvm::CodeModel::Model > CM
An optional code model to provide to the JITTargetMachineBuilder.
unsigned SlabAllocateSize
Representing the slab allocation size for memory management in kb.
bool UseSharedMemory
Indicates whether to use shared memory for communication.
std::string OOPExecutor
Path to the out-of-process JIT executor.
The class keeps track of various objects created as part of processing incremental inputs.