Thanks to visit codestin.com
Credit goes to clang.llvm.org

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` or by CUDA includes
282 // automatically.
283 if (!CI->getPreprocessorOpts().Includes.empty()) {
284 // We can't really directly pass the CachedInCodeGenModule to the Jit
285 // because it will steal it, causing dangling references as explained in
286 // Interpreter::Execute
287 auto M = llvm::CloneModule(*Act->getCachedCodeGenModule());
288 ASTContext &C = CI->getASTContext();
289 IncrParser->RegisterPTU(C.getTranslationUnitDecl(), std::move(M));
290 }
291 if (llvm::Error Err = CreateExecutor(Config)) {
292 ErrOut = joinErrors(std::move(ErrOut), std::move(Err));
293 return;
294 }
295 }
296
297 // Not all frontends support code-generation, e.g. ast-dump actions don't
298 if (Act->getCodeGen()) {
299 // Process the PTUs that came from initialization. For example -include will
300 // give us a header that's processed at initialization of the preprocessor.
301 for (PartialTranslationUnit &PTU : PTUs)
302 if (llvm::Error Err = Execute(PTU)) {
303 ErrOut = joinErrors(std::move(ErrOut), std::move(Err));
304 return;
305 }
306 }
307}
308
310 IncrParser.reset();
311 Act->FinalizeAction();
312 if (DeviceParser)
313 DeviceParser.reset();
314 if (DeviceAct)
315 DeviceAct->FinalizeAction();
316 if (IncrExecutor) {
317 if (llvm::Error Err = IncrExecutor->cleanUp())
318 llvm::report_fatal_error(
319 llvm::Twine("Failed to clean up IncrementalExecutor: ") +
320 toString(std::move(Err)));
321 }
322}
323
324// These better to put in a runtime header but we can't. This is because we
325// can't find the precise resource directory in unittests so we have to hard
326// code them.
327const char *const Runtimes = R"(
328 #define __CLANG_REPL__ 1
329#ifdef __cplusplus
330 #define EXTERN_C extern "C"
331 struct __clang_Interpreter_NewTag{} __ci_newtag;
332 void* operator new(__SIZE_TYPE__, void* __p, __clang_Interpreter_NewTag) noexcept;
333 template <class T, class = T (*)() /*disable for arrays*/>
334 void __clang_Interpreter_SetValueCopyArr(const T* Src, void* Placement, unsigned long Size) {
335 for (auto Idx = 0; Idx < Size; ++Idx)
336 new ((void*)(((T*)Placement) + Idx), __ci_newtag) T(Src[Idx]);
337 }
338 template <class T, unsigned long N>
339 void __clang_Interpreter_SetValueCopyArr(const T (*Src)[N], void* Placement, unsigned long Size) {
340 __clang_Interpreter_SetValueCopyArr(Src[0], Placement, Size);
341 }
342#else
343 #define EXTERN_C extern
344 EXTERN_C void *memcpy(void *restrict dst, const void *restrict src, __SIZE_TYPE__ n);
345 EXTERN_C inline void __clang_Interpreter_SetValueCopyArr(const void* Src, void* Placement, unsigned long Size) {
346 memcpy(Placement, Src, Size);
347 }
348#endif // __cplusplus
349 EXTERN_C void *__clang_Interpreter_SetValueWithAlloc(void*, void*, void*);
350 EXTERN_C void __clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal, void *OpaqueType, ...);
351)";
352
355 std::unique_ptr<llvm::orc::ExecutorProcessControl> EPC;
356 uint32_t childPid = -1;
357 if (!Config.OOPExecutor.empty()) {
358 // Launch an out-of-process executor locally in a child process.
359 auto ResultOrErr = IncrementalExecutor::launchExecutor(
360 Config.OOPExecutor, Config.UseSharedMemory, Config.SlabAllocateSize,
361 Config.CustomizeFork);
362 if (!ResultOrErr)
363 return ResultOrErr.takeError();
364 childPid = ResultOrErr->second;
365 auto EPCOrErr = std::move(ResultOrErr->first);
366 EPC = std::move(EPCOrErr);
367 } else if (Config.OOPExecutorConnect != "") {
368#if LLVM_ON_UNIX && LLVM_ENABLE_THREADS
369 auto EPCOrErr = IncrementalExecutor::connectTCPSocket(
370 Config.OOPExecutorConnect, Config.UseSharedMemory,
371 Config.SlabAllocateSize);
372 if (!EPCOrErr)
373 return EPCOrErr.takeError();
374 EPC = std::move(*EPCOrErr);
375#else
376 return llvm::make_error<llvm::StringError>(
377 "Out-of-process JIT over TCP is not supported on this platform",
378 std::error_code());
379#endif
380 }
381
382 std::unique_ptr<llvm::orc::LLJITBuilder> JB;
383 if (EPC) {
385 std::move(EPC), Config.OrcRuntimePath);
386 if (!JBOrErr)
387 return JBOrErr.takeError();
388 JB = std::move(*JBOrErr);
389 }
390
391 return std::make_pair(std::move(JB), childPid);
392}
393
396 std::optional<std::string> CompilerRTPath = TC.getCompilerRTPath();
397 std::optional<std::string> ResourceDir = TC.getRuntimePath();
398
399 if (!CompilerRTPath) {
400 return llvm::make_error<llvm::StringError>("CompilerRT path not found",
401 std::error_code());
402 }
403
404 const std::array<const char *, 3> OrcRTLibNames = {
405 "liborc_rt.a", "liborc_rt_osx.a", "liborc_rt-x86_64.a"};
406
407 for (const char *LibName : OrcRTLibNames) {
408 llvm::SmallString<256> CandidatePath((*CompilerRTPath).c_str());
409 llvm::sys::path::append(CandidatePath, LibName);
410
411 if (llvm::sys::fs::exists(CandidatePath)) {
412 return CandidatePath.str().str();
413 }
414 }
415
416 return llvm::make_error<llvm::StringError>(
417 llvm::Twine("OrcRuntime library not found in: ") + (*CompilerRTPath),
418 std::error_code());
419}
420
422Interpreter::create(std::unique_ptr<CompilerInstance> CI, JITConfig Config) {
423 llvm::Error Err = llvm::Error::success();
424
425 std::unique_ptr<llvm::orc::LLJITBuilder> JB;
426
427 if (Config.IsOutOfProcess) {
428 const TargetInfo &TI = CI->getTarget();
429 const llvm::Triple &Triple = TI.getTriple();
430
431 DiagnosticsEngine &Diags = CI->getDiagnostics();
432 std::string BinaryName = llvm::sys::fs::getMainExecutable(nullptr, nullptr);
433 driver::Driver Driver(BinaryName, Triple.str(), Diags);
434 // Need fake args to get the driver to create a compilation.
435 std::vector<const char *> Args = {"clang", "--version"};
436 std::unique_ptr<clang::driver::Compilation> C(
437 Driver.BuildCompilation(Args));
438 if (!C) {
439 return llvm::make_error<llvm::StringError>(
440 "Failed to create driver compilation for out-of-process JIT",
441 std::error_code());
442 }
443 if (Config.OrcRuntimePath == "") {
444 const clang::driver::ToolChain &TC = C->getDefaultToolChain();
445
446 auto OrcRuntimePathOrErr = getOrcRuntimePath(TC);
447 if (!OrcRuntimePathOrErr) {
448 return OrcRuntimePathOrErr.takeError();
449 }
450
451 Config.OrcRuntimePath = *OrcRuntimePathOrErr;
452 }
453 }
454
455 auto Interp = std::unique_ptr<Interpreter>(new Interpreter(
456 std::move(CI), Err, std::move(JB), /*Consumer=*/nullptr, Config));
457 if (auto E = std::move(Err))
458 return std::move(E);
459
460 // Add runtime code and set a marker to hide it from user code. Undo will not
461 // go through that.
462 if (auto E = Interp->ParseAndExecute(Runtimes))
463 return std::move(E);
464
465 Interp->markUserCodeStart();
466
467 return std::move(Interp);
468}
469
471Interpreter::createWithCUDA(std::unique_ptr<CompilerInstance> CI,
472 std::unique_ptr<CompilerInstance> DCI) {
473 // avoid writing fat binary to disk using an in-memory virtual file system
475 std::make_unique<llvm::vfs::InMemoryFileSystem>();
477 std::make_unique<llvm::vfs::OverlayFileSystem>(
478 llvm::vfs::getRealFileSystem());
479 OverlayVFS->pushOverlay(IMVFS);
480 CI->createVirtualFileSystem(OverlayVFS);
481 CI->createFileManager();
482
484 Interpreter::create(std::move(CI));
485 if (!InterpOrErr)
486 return InterpOrErr;
487
488 std::unique_ptr<Interpreter> Interp = std::move(*InterpOrErr);
489
490 llvm::Error Err = llvm::Error::success();
491
492 auto DeviceAct = Interp->TSCtx->withContextDo([&](llvm::LLVMContext *Ctx) {
493 return std::make_unique<IncrementalAction>(*DCI, *Ctx, Err, *Interp);
494 });
495
496 if (Err)
497 return std::move(Err);
498
499 Interp->DeviceAct = std::move(DeviceAct);
500
501 DCI->ExecuteAction(*Interp->DeviceAct);
502
503 Interp->DeviceCI = std::move(DCI);
504
505 auto DeviceParser = std::make_unique<IncrementalCUDADeviceParser>(
506 *Interp->DeviceCI, *Interp->getCompilerInstance(),
507 Interp->DeviceAct.get(), IMVFS, Err, Interp->PTUs);
508
509 if (Err)
510 return std::move(Err);
511
512 Interp->DeviceParser = std::move(DeviceParser);
513 return std::move(Interp);
514}
515
518 return const_cast<Interpreter *>(this)->getCompilerInstance();
519}
520
522 if (!IncrExecutor) {
523 if (auto Err = CreateExecutor())
524 return std::move(Err);
525 }
526
527 return IncrExecutor->GetExecutionEngine();
528}
529
533
537
538void Interpreter::markUserCodeStart() {
539 assert(!InitPTUSize && "We only do this once");
540 InitPTUSize = PTUs.size();
541}
542
543size_t Interpreter::getEffectivePTUSize() const {
544 assert(PTUs.size() >= InitPTUSize && "empty PTU list?");
545 return PTUs.size() - InitPTUSize;
546}
547
549 if (IncrExecutor)
550 return IncrExecutor->getOutOfProcessChildPid();
551 return -1;
552}
553
555Interpreter::Parse(llvm::StringRef Code) {
556 // If we have a device parser, parse it first. The generated code will be
557 // included in the host compilation
558 if (DeviceParser) {
559 llvm::Expected<TranslationUnitDecl *> DeviceTU = DeviceParser->Parse(Code);
560 if (auto E = DeviceTU.takeError())
561 return std::move(E);
562
563 DeviceParser->RegisterPTU(*DeviceTU);
564
565 llvm::Expected<llvm::StringRef> PTX = DeviceParser->GeneratePTX();
566 if (!PTX)
567 return PTX.takeError();
568
569 llvm::Error Err = DeviceParser->GenerateFatbinary();
570 if (Err)
571 return std::move(Err);
572 }
573
574 // Tell the interpreter sliently ignore unused expressions since value
575 // printing could cause it.
577 clang::diag::warn_unused_expr, diag::Severity::Ignored, SourceLocation());
578
579 llvm::Expected<TranslationUnitDecl *> TuOrErr = IncrParser->Parse(Code);
580 if (!TuOrErr)
581 return TuOrErr.takeError();
582
583 PTUs.emplace_back(PartialTranslationUnit());
584 PartialTranslationUnit &LastPTU = PTUs.back();
585 LastPTU.TUPart = *TuOrErr;
586
587 if (std::unique_ptr<llvm::Module> M = Act->GenModule())
588 LastPTU.TheModule = std::move(M);
589
590 return LastPTU;
591}
592
594createJITTargetMachineBuilder(const std::string &TT) {
595 if (TT == llvm::sys::getProcessTriple())
596 // This fails immediately if the target backend is not registered
597 return llvm::orc::JITTargetMachineBuilder::detectHost();
598
599 // If the target backend is not registered, LLJITBuilder::create() will fail
600 return llvm::orc::JITTargetMachineBuilder(llvm::Triple(TT));
601}
602
605 std::unique_ptr<llvm::orc::ExecutorProcessControl> EPC,
606 llvm::StringRef OrcRuntimePath) {
607 const std::string &TT = EPC->getTargetTriple().getTriple();
608 auto JTMB = createJITTargetMachineBuilder(TT);
609 if (!JTMB)
610 return JTMB.takeError();
611 auto JB = IncrementalExecutor::createDefaultJITBuilder(std::move(*JTMB));
612 if (!JB)
613 return JB.takeError();
614
615 (*JB)->setExecutorProcessControl(std::move(EPC));
616 (*JB)->setPlatformSetUp(
617 llvm::orc::ExecutorNativePlatform(OrcRuntimePath.str()));
618
619 return std::move(*JB);
620}
621
623 if (IncrExecutor)
624 return llvm::make_error<llvm::StringError>("Operation failed. "
625 "Execution engine exists",
626 std::error_code());
627 if (!Act->getCodeGen())
628 return llvm::make_error<llvm::StringError>("Operation failed. "
629 "No code generator available",
630 std::error_code());
631
632 const std::string &TT = getCompilerInstance()->getTargetOpts().Triple;
633 llvm::Triple TargetTriple(TT);
634 bool IsWindowsTarget = TargetTriple.isOSWindows();
635
636 if (!IsWindowsTarget && Config.IsOutOfProcess) {
637 if (!JITBuilder) {
638 auto ResOrErr = outOfProcessJITBuilder(Config);
639 if (!ResOrErr)
640 return ResOrErr.takeError();
641 JITBuilder = std::move(ResOrErr->first);
642 Config.ExecutorPID = ResOrErr->second;
643 }
644 if (!JITBuilder)
645 return llvm::make_error<llvm::StringError>(
646 "Operation failed. No LLJITBuilder for out-of-process JIT",
647 std::error_code());
648 }
649
650 if (!JITBuilder) {
651 auto JTMB = createJITTargetMachineBuilder(TT);
652 if (!JTMB)
653 return JTMB.takeError();
654 if (Config.CM)
655 JTMB->setCodeModel(Config.CM);
656 auto JB = IncrementalExecutor::createDefaultJITBuilder(std::move(*JTMB));
657 if (!JB)
658 return JB.takeError();
659 JITBuilder = std::move(*JB);
660 }
661
662 llvm::Error Err = llvm::Error::success();
663
664 // Fix: Declare Executor as the appropriate unique_ptr type
665 std::unique_ptr<IncrementalExecutor> Executor;
666
667#ifdef __EMSCRIPTEN__
668 Executor = std::make_unique<WasmIncrementalExecutor>(*TSCtx);
669#else
670 Executor =
671 std::make_unique<IncrementalExecutor>(*TSCtx, *JITBuilder, Config, Err);
672#endif
673 if (!Err)
674 IncrExecutor = std::move(Executor);
675
676 return Err;
677}
678
679void Interpreter::ResetExecutor() { IncrExecutor.reset(); }
680
682 assert(T.TheModule);
683 LLVM_DEBUG(
684 llvm::dbgs() << "execute-ptu "
685 << (llvm::is_contained(PTUs, T)
686 ? std::distance(PTUs.begin(), llvm::find(PTUs, T))
687 : -1)
688 << ": [TU=" << T.TUPart << ", M=" << T.TheModule.get()
689 << " (" << T.TheModule->getName() << ")]\n");
690 if (!IncrExecutor) {
691 auto Err = CreateExecutor();
692 if (Err)
693 return Err;
694 }
695 // FIXME: Add a callback to retain the llvm::Module once the JIT is done.
696 if (auto Err = IncrExecutor->addModule(T))
697 return Err;
698
699 if (auto Err = IncrExecutor->runCtors())
700 return Err;
701
702 return llvm::Error::success();
703}
704
705llvm::Error Interpreter::ParseAndExecute(llvm::StringRef Code, Value *V) {
706
707 auto PTU = Parse(Code);
708 if (!PTU)
709 return PTU.takeError();
710 if (PTU->TheModule)
711 if (llvm::Error Err = Execute(*PTU))
712 return Err;
713
714 if (LastValue.isValid()) {
715 if (!V) {
716 LastValue.dump();
717 LastValue.clear();
718 } else
719 *V = std::move(LastValue);
720 }
721 return llvm::Error::success();
722}
723
726 if (!IncrExecutor)
727 return llvm::make_error<llvm::StringError>("Operation failed. "
728 "No execution engine",
729 std::error_code());
730 llvm::StringRef MangledName = Act->getCodeGen()->GetMangledName(GD);
731 return getSymbolAddress(MangledName);
732}
733
735Interpreter::getSymbolAddress(llvm::StringRef IRName) const {
736 if (!IncrExecutor)
737 return llvm::make_error<llvm::StringError>("Operation failed. "
738 "No execution engine",
739 std::error_code());
740
741 return IncrExecutor->getSymbolAddress(IRName, IncrementalExecutor::IRName);
742}
743
746 if (!IncrExecutor)
747 return llvm::make_error<llvm::StringError>("Operation failed. "
748 "No execution engine",
749 std::error_code());
750
751 return IncrExecutor->getSymbolAddress(Name, IncrementalExecutor::LinkerName);
752}
753
754llvm::Error Interpreter::Undo(unsigned N) {
755
756 if (getEffectivePTUSize() == 0) {
757 return llvm::make_error<llvm::StringError>("Operation failed. "
758 "No input left to undo",
759 std::error_code());
760 } else if (N > getEffectivePTUSize()) {
761 return llvm::make_error<llvm::StringError>(
762 llvm::formatv(
763 "Operation failed. Wanted to undo {0} inputs, only have {1}.", N,
764 getEffectivePTUSize()),
765 std::error_code());
766 }
767
768 for (unsigned I = 0; I < N; I++) {
769 if (IncrExecutor) {
770 if (llvm::Error Err = IncrExecutor->removeModule(PTUs.back()))
771 return Err;
772 }
773
774 IncrParser->CleanUpPTU(PTUs.back().TUPart);
775 PTUs.pop_back();
776 }
777 return llvm::Error::success();
778}
779
780llvm::Error Interpreter::LoadDynamicLibrary(const char *name) {
781#ifdef __EMSCRIPTEN__
782 void *handle = dlopen(name, RTLD_NOW | RTLD_GLOBAL);
783 if (!handle) {
784 llvm::errs() << dlerror() << '\n';
785 return llvm::make_error<llvm::StringError>("Failed to load dynamic library",
786 llvm::inconvertibleErrorCode());
787 }
788#else
789 auto EE = getExecutionEngine();
790 if (!EE)
791 return EE.takeError();
792
793 if (llvm::Expected<
794 std::unique_ptr<llvm::orc::EPCDynamicLibrarySearchGenerator>>
795 DLSG = llvm::orc::EPCDynamicLibrarySearchGenerator::Load(
796 EE->getExecutionSession(), name))
797 // FIXME: Eventually we should put each library in its own JITDylib and
798 // turn off process symbols by default.
799 EE->getProcessSymbolsJITDylib()->addGenerator(std::move(*DLSG));
800 else
801 return DLSG.takeError();
802#endif
803
804 return llvm::Error::success();
805}
806} // 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:188
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:231
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.