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