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