clang 24.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 "IncrementalParser.h"
17#include "InterpreterUtils.h"
18
21#include "clang/AST/Mangle.h"
29#include "clang/Driver/Driver.h"
30#include "clang/Driver/Job.h"
31#include "clang/Driver/Tool.h"
44#include "clang/Sema/Lookup.h"
48#include "llvm/ADT/StringExtras.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/Process.h"
56#include "llvm/Support/VirtualFileSystem.h"
57#include "llvm/Support/raw_ostream.h"
58#include "llvm/TargetParser/Host.h"
59#include "llvm/TargetParser/Triple.h"
60#include "llvm/Transforms/Utils/Cloning.h" // for CloneModule
61
62#define DEBUG_TYPE "clang-repl"
63
64using namespace clang;
65// FIXME: Figure out how to unify with namespace init_convenience from
66// tools/clang-import-test/clang-import-test.cpp
67namespace {
68/// Retrieves the clang CC1 specific flags out of the compilation's jobs.
69/// \returns NULL on error.
71GetCC1Arguments(DiagnosticsEngine *Diagnostics,
72 driver::Compilation *Compilation) {
73 // We expect to get back exactly one Command job, if we didn't something
74 // failed. Extract that job from the Compilation.
75 const driver::JobList &Jobs = Compilation->getJobs();
76 if (!Jobs.size())
77 return llvm::createStringError(llvm::errc::not_supported,
78 "Driver initialization failed. "
79 "Unable to create a driver job");
80
81 // The one job we find should be to invoke clang again.
82 const driver::Command *Cmd = &*Jobs.begin();
83 if (llvm::StringRef(Cmd->getCreator().getName()) != "clang")
84 return llvm::createStringError(llvm::errc::not_supported,
85 "Driver initialization failed");
86
87 return &Cmd->getArguments();
88}
89
90// ASTReaderListener that captures the PIC level stored in a serialized AST
91// file (PCH or PCM) so the interpreter can compare it against its own.
92class PICLevelReader : public ASTReaderListener {
93 unsigned &PICLevel;
94
95public:
96 PICLevelReader(unsigned &PICLevel) : PICLevel(PICLevel) {}
97
98 bool ReadLanguageOptions(const LangOptions &LangOpts,
99 StringRef ModuleFilename, bool Complain,
100 bool AllowCompatibleDifferences) override {
101 PICLevel = LangOpts.PICLevel;
102 return false;
103 }
104};
105
106// clang-repl always compiles position-independent code (it injects -fPIC), so a
107// PCH/PCM that was built with a different PIC level is incompatible: mixing the
108// two leads to relocations that may be out of range once the JIT maps code more
109// than 2GB away. PICLevel is a "compatible" language option, so the ASTReader
110// would otherwise accept the mismatch silently. Reject it up front.
111//
112// The file is probed with its own FileManager and ModuleCache (sharing only the
113// VFS) so this read leaves the CompilerInstance's state untouched for the real
114// load performed later by ExecuteAction().
115static llvm::Error checkASTFilePICLevel(CompilerInstance &Clang,
116 StringRef Filename) {
119 std::shared_ptr<ModuleCache> ModCache = createCrossProcessModuleCache();
120 unsigned ASTPICLevel = 0;
121 PICLevelReader Reader(ASTPICLevel);
123 Filename, *FileMgr, *ModCache, Clang.getPCHContainerReader(),
124 /*FindModuleFileExtensions=*/false, Reader,
125 /*ValidateDiagnosticOptions=*/false) &&
126 ASTPICLevel != Clang.getLangOpts().PICLevel)
127 return llvm::createStringError(
128 llvm::errc::not_supported,
129 "AST file '%s' was built with PIC level %u, which is incompatible "
130 "with clang-repl's PIC level %u",
131 Filename.str().c_str(), ASTPICLevel, Clang.getLangOpts().PICLevel);
132 return llvm::Error::success();
133}
134
136CreateCI(const llvm::opt::ArgStringList &Argv) {
137 std::unique_ptr<CompilerInstance> Clang(new CompilerInstance());
138
139 // Register the support for object-file-wrapped Clang modules.
140 // FIXME: Clang should register these container operations automatically.
141 auto PCHOps = Clang->getPCHContainerOperations();
142 PCHOps->registerWriter(std::make_unique<ObjectFilePCHContainerWriter>());
143 PCHOps->registerReader(std::make_unique<ObjectFilePCHContainerReader>());
144
145 // Buffer diagnostics from argument parsing so that we can output them using
146 // a well formed diagnostic object.
147 DiagnosticOptions DiagOpts;
149 DiagnosticsEngine Diags(DiagnosticIDs::create(), DiagOpts, DiagsBuffer);
151 Clang->getInvocation(), llvm::ArrayRef(Argv.begin(), Argv.size()), Diags);
152
153 // Infer the builtin include path if unspecified.
154 if (Clang->getHeaderSearchOpts().UseBuiltinIncludes &&
155 Clang->getHeaderSearchOpts().ResourceDir.empty())
156 Clang->getHeaderSearchOpts().ResourceDir =
157 GetResourcesPath(Argv[0], nullptr);
158
159 Clang->createVirtualFileSystem();
160
161 // Create the actual diagnostics engine.
162 Clang->createDiagnostics();
163
164 DiagsBuffer->FlushDiagnostics(Clang->getDiagnostics());
165 if (!Success)
166 return llvm::createStringError(llvm::errc::not_supported,
167 "Initialization failed. "
168 "Unable to flush diagnostics");
169
170 // FIXME: Merge with CompilerInstance::ExecuteAction.
171 llvm::MemoryBuffer *MB = llvm::MemoryBuffer::getMemBuffer("").release();
172 Clang->getPreprocessorOpts().addRemappedFile("<<< inputs >>>", MB);
173
174 Clang->setTarget(TargetInfo::CreateTargetInfo(
175 Clang->getDiagnostics(), Clang->getInvocation().getTargetOpts()));
176 if (!Clang->hasTarget())
177 return llvm::createStringError(llvm::errc::not_supported,
178 "Initialization failed. "
179 "Target is missing");
180
181 Clang->getTarget().adjust(Clang->getDiagnostics(), Clang->getLangOpts(),
182 Clang->getAuxTarget());
183
184 // Don't clear the AST before backend codegen since we do codegen multiple
185 // times, reusing the same AST.
186 Clang->getCodeGenOpts().ClearASTBeforeBackend = false;
187
188 Clang->getFrontendOpts().DisableFree = false;
189 Clang->getCodeGenOpts().DisableFree = false;
190
191 // Reject any precompiled input (PCH or PCM) built with a PIC level that
192 // differs from clang-repl's own, before any Interpreter/FrontendAction is
193 // constructed. See checkASTFilePICLevel for the rationale.
194 StringRef PCHInclude = Clang->getPreprocessorOpts().ImplicitPCHInclude;
195 if (!PCHInclude.empty())
196 if (llvm::Error Err = checkASTFilePICLevel(*Clang, PCHInclude))
197 return std::move(Err);
198
199 // Explicitly loaded modules: -fmodule-file=<path> and
200 // -fmodule-file=<name>=<path>.
201 for (StringRef ModuleFile : Clang->getFrontendOpts().ModuleFiles)
202 if (llvm::Error Err = checkASTFilePICLevel(*Clang, ModuleFile))
203 return std::move(Err);
204 for (const auto &NameAndFile :
205 Clang->getHeaderSearchOpts().PrebuiltModuleFiles)
206 if (llvm::Error Err = checkASTFilePICLevel(*Clang, NameAndFile.second))
207 return std::move(Err);
208
209 return std::move(Clang);
210}
211
212static llvm::Error ExecuteIncrementalAction(CompilerInstance &CI,
213 IncrementalAction &Act) {
214 if (!CI.ExecuteAction(Act) || CI.getDiagnostics().hasErrorOccurred()) {
215 return llvm::createStringError(llvm::errc::not_supported,
216 "Failed to execute incremental action");
217 }
218 return llvm::Error::success();
219}
220
221} // anonymous namespace
222
223namespace clang {
224
226IncrementalCompilerBuilder::create(std::string TT,
227 std::vector<const char *> &ClangArgv) {
228
229 // If we don't know ClangArgv0 or the address of main() at this point, try
230 // to guess it anyway (it's possible on some platforms).
231 std::string MainExecutableName =
232 llvm::sys::fs::getMainExecutable(nullptr, nullptr);
233
234 ClangArgv.insert(ClangArgv.begin(), MainExecutableName.c_str());
235
236 // Compile as position-independent code. This prevents the frontend from
237 // marking external symbols (e.g. C++ type-info such as _ZTIPKc used for
238 // exception handling) as dso_local and emitting direct PC-relative
239 // references. JITLink can place the GOT entry near the JIT'd code, keeping
240 // the relocation in range. Without -fPIC, a direct Delta32 relocation to a
241 // host symbol may be out of range when the JIT memory is mapped more than
242 // 2GB away (as on FreeBSD), breaking tests such as
243 // Interpreter/simple-exception.cpp. Insert before user arguments so it can
244 // still be overridden. On Windows (excluding Cygwin/MinGW) an explicit
245 // -fPIC is an unsupported driver option that would drop non-x86_64 targets
246 // to PIC level 0; PIC is already the forced default there where relevant,
247 // so don't inject it.
248 llvm::Triple TargetTriple(TT);
249 if (!TargetTriple.isOSWindows() || TargetTriple.isOSCygMing())
250 ClangArgv.insert(ClangArgv.begin() + 1, "-fPIC");
251
252 // Prepending -c to force the driver to do something if no action was
253 // specified. By prepending we allow users to override the default
254 // action and use other actions in incremental mode.
255 // FIXME: Print proper driver diagnostics if the driver flags are wrong.
256 // We do C++ by default; append right after argv[0] if no "-x" given
257 ClangArgv.insert(ClangArgv.end(), "-Xclang");
258 ClangArgv.insert(ClangArgv.end(), "-fincremental-extensions");
259 ClangArgv.insert(ClangArgv.end(), "-c");
260
261 // Put a dummy C++ file on to ensure there's at least one compile job for the
262 // driver to construct.
263 ClangArgv.push_back("<<< inputs >>>");
264
265 // Buffer diagnostics from argument parsing so that we can output them using a
266 // well formed diagnostic object.
267 std::unique_ptr<DiagnosticOptions> DiagOpts =
268 CreateAndPopulateDiagOpts(ClangArgv);
269 TextDiagnosticBuffer *DiagsBuffer = new TextDiagnosticBuffer;
270 DiagnosticsEngine Diags(DiagnosticIDs::create(), *DiagOpts, DiagsBuffer);
271
272 driver::Driver Driver(/*MainBinaryName=*/ClangArgv[0], TT, Diags);
273 Driver.setCheckInputsExist(false); // the input comes from mem buffers
274 llvm::ArrayRef<const char *> RF = llvm::ArrayRef(ClangArgv);
275 std::unique_ptr<driver::Compilation> Compilation(Driver.BuildCompilation(RF));
276
277 if (CompilationCB)
278 if (auto Err = (*CompilationCB)(*Compilation.get()))
279 return std::move(Err);
280
281 if (Compilation->getArgs().hasArg(options::OPT_v))
282 Compilation->getJobs().Print(llvm::errs(), "\n", /*Quote=*/false);
283
284 auto ErrOrCC1Args = GetCC1Arguments(&Diags, Compilation.get());
285 if (auto Err = ErrOrCC1Args.takeError())
286 return std::move(Err);
287
288 return CreateCI(**ErrOrCC1Args);
289}
290
293 std::string TT = TargetTriple ? *TargetTriple : llvm::sys::getProcessTriple();
294
295 std::vector<const char *> Argv;
296 Argv.reserve(5 + 1 + UserArgs.size());
297 Argv.push_back("-xc++");
298#ifdef __EMSCRIPTEN__
299 Argv.push_back("-target");
300 Argv.push_back(TT.c_str());
301 Argv.push_back("-fvisibility=default");
302#endif
303 llvm::append_range(Argv, UserArgs);
304
305 return IncrementalCompilerBuilder::create(TT, Argv);
306}
307
309IncrementalCompilerBuilder::createOffload(OffloadType Type, bool device) {
310 const bool HipEnabled = Type == OffloadType::HIP;
311 std::vector<const char *> Argv;
312 Argv.reserve(5 + 4 + UserArgs.size());
313 Argv.push_back(HipEnabled ? "-xhip" : "-xcuda");
314 Argv.push_back(device ? "--cuda-device-only" : "--cuda-host-only");
315
316 llvm::StringRef SDKPath = HipEnabled ? RocmSDKPath : CudaSDKPath;
317 std::string SDKPathArg = HipEnabled ? "--rocm-path=" : "--cuda-path=";
318 if (!SDKPath.empty()) {
319 SDKPathArg += SDKPath;
320 Argv.push_back(SDKPathArg.c_str());
321 }
322
323 std::string ArchArg = "--offload-arch=";
324 if (!OffloadArch.empty()) {
325 ArchArg += OffloadArch;
326 Argv.push_back(ArchArg.c_str());
327 }
328
329 if (OffloadCUID.empty())
330 OffloadCUID = llvm::utohexstr(llvm::sys::Process::GetRandomNumber(),
331 /*LowerCase=*/true);
332 std::string CUIDArg = "-cuid=" + OffloadCUID;
333 Argv.push_back(CUIDArg.c_str());
334
335 llvm::append_range(Argv, UserArgs);
336
337 std::string TT = TargetTriple ? *TargetTriple : llvm::sys::getProcessTriple();
338 return IncrementalCompilerBuilder::create(TT, Argv);
339}
340
343 return IncrementalCompilerBuilder::createOffload(Type, /*device=*/true);
344}
345
348 return IncrementalCompilerBuilder::createOffload(Type, /*device=*/false);
349}
350
351Interpreter::Interpreter(std::unique_ptr<CompilerInstance> Instance,
352 llvm::Error &ErrOut,
353 std::unique_ptr<IncrementalExecutorBuilder> IEB,
354 std::unique_ptr<clang::ASTConsumer> Consumer)
355 : IncrExecutorBuilder(std::move(IEB)) {
356 CI = std::move(Instance);
357 llvm::ErrorAsOutParameter EAO(&ErrOut);
358 auto LLVMCtx = std::make_unique<llvm::LLVMContext>();
359 TSCtx = std::make_unique<llvm::orc::ThreadSafeContext>(std::move(LLVMCtx));
360
361 Act = TSCtx->withContextDo([&](llvm::LLVMContext *Ctx) {
362 return std::make_unique<IncrementalAction>(*CI, *Ctx, ErrOut, *this,
363 std::move(Consumer));
364 });
365
366 if (ErrOut)
367 return;
368
369 if (llvm::Error E = ExecuteIncrementalAction(*CI, *Act)) {
370 ErrOut = joinErrors(std::move(ErrOut), std::move(E));
371 return;
372 }
373
374 IncrParser =
375 std::make_unique<IncrementalParser>(*CI, Act.get(), ErrOut, PTUs);
376
377 if (ErrOut)
378 return;
379
380 if (Act->getCodeGen()) {
381 Act->CacheCodeGenModule();
382 // The initial PTU is filled by `-include`/`-include-pch` or by CUDA
383 // includes automatically.
384 if (!CI->getPreprocessorOpts().Includes.empty() ||
385 !CI->getPreprocessorOpts().ImplicitPCHInclude.empty()) {
386 // We can't really directly pass the CachedInCodeGenModule to the Jit
387 // because it will steal it, causing dangling references as explained in
388 // Interpreter::Execute
389 auto M = llvm::CloneModule(*Act->getCachedCodeGenModule());
390 ASTContext &C = CI->getASTContext();
391 IncrParser->RegisterPTU(C.getTranslationUnitDecl(), std::move(M));
392 }
393 if (llvm::Error Err = CreateExecutor()) {
394 ErrOut = joinErrors(std::move(ErrOut), std::move(Err));
395 return;
396 }
397 }
398
399 // Not all frontends support code-generation, e.g. ast-dump actions don't
400 if (Act->getCodeGen()) {
401 // Process the PTUs that came from initialization. For example -include will
402 // give us a header that's processed at initialization of the preprocessor.
403 for (PartialTranslationUnit &PTU : PTUs)
404 if (llvm::Error Err = Execute(PTU)) {
405 ErrOut = joinErrors(std::move(ErrOut), std::move(Err));
406 return;
407 }
408 }
409}
410
412 IncrParser.reset();
413 Act->FinalizeAction();
414 if (DeviceParser)
415 DeviceParser.reset();
416 if (DeviceAct)
417 DeviceAct->FinalizeAction();
418 if (IncrExecutor) {
419 if (llvm::Error Err = IncrExecutor->cleanUp())
420 llvm::report_fatal_error(
421 llvm::Twine("Failed to clean up IncrementalExecutor: ") +
422 toString(std::move(Err)));
423 }
424}
425
426// These better to put in a runtime header but we can't. This is because we
427// can't find the precise resource directory in unittests so we have to hard
428// code them.
429const char *const Runtimes = R"(
430 #define __CLANG_REPL__ 1
431#ifdef __cplusplus
432 #define EXTERN_C extern "C"
433 struct __clang_Interpreter_NewTag{} __ci_newtag;
434 void* operator new(__SIZE_TYPE__, void* __p, __clang_Interpreter_NewTag) noexcept;
435 template <class T, class = T (*)() /*disable for arrays*/>
436 void __clang_Interpreter_SetValueCopyArr(const T* Src, void* Placement, unsigned long Size) {
437 for (unsigned long Idx = 0; Idx < Size; ++Idx)
438 new ((void*)(((T*)Placement) + Idx), __ci_newtag) T(Src[Idx]);
439 }
440 template <class T, unsigned long N>
441 void __clang_Interpreter_SetValueCopyArr(const T (*Src)[N], void* Placement, unsigned long Size) {
442 __clang_Interpreter_SetValueCopyArr(Src[0], Placement, Size);
443 }
444#else
445 #if __STDC_VERSION__ < 199901L
446 #define CI_RESTRICT
447 #define CI_INLINE
448 #else
449 #define CI_RESTRICT restrict
450 #define CI_INLINE inline
451 #endif
452 #define EXTERN_C extern
453 EXTERN_C void *memcpy(void *CI_RESTRICT dst, const void *CI_RESTRICT src, __SIZE_TYPE__ n);
454 EXTERN_C CI_INLINE void __clang_Interpreter_SetValueCopyArr(const void* Src, void* Placement, unsigned long Size) {
455 memcpy(Placement, Src, Size);
456 }
457#endif // __cplusplus
458 EXTERN_C void *__clang_Interpreter_SetValueWithAlloc(void*, void*, void*);
459 EXTERN_C void __clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal, void *OpaqueType, ...);
460)";
461
463 std::unique_ptr<CompilerInstance> CI,
464 std::unique_ptr<IncrementalExecutorBuilder> IEB /*=nullptr*/) {
465 llvm::Error Err = llvm::Error::success();
466
467 auto Interp = std::unique_ptr<Interpreter>(new Interpreter(
468 std::move(CI), Err, std::move(IEB), /*Consumer=*/nullptr));
469 if (auto E = std::move(Err))
470 return std::move(E);
471
472 // Add runtime code and set a marker to hide it from user code. Undo will not
473 // go through that.
474 if (auto E = Interp->ParseAndExecute(Runtimes))
475 return std::move(E);
476
477 Interp->markUserCodeStart();
478
479 return std::move(Interp);
480}
481
484 std::unique_ptr<CompilerInstance> CI,
485 std::unique_ptr<CompilerInstance> DCI) {
486 // avoid writing fat binary to disk using an in-memory virtual file system
488 std::make_unique<llvm::vfs::InMemoryFileSystem>();
490 std::make_unique<llvm::vfs::OverlayFileSystem>(
491 llvm::vfs::getRealFileSystem());
492 OverlayVFS->pushOverlay(IMVFS);
493 CI->createVirtualFileSystem(OverlayVFS);
494 CI->createFileManager();
495
497 Interpreter::create(std::move(CI));
498 if (!InterpOrErr)
499 return InterpOrErr;
500
501 std::unique_ptr<Interpreter> Interp = std::move(*InterpOrErr);
502
503 llvm::Error Err = llvm::Error::success();
504
505 auto DeviceAct = Interp->TSCtx->withContextDo([&](llvm::LLVMContext *Ctx) {
506 return std::make_unique<IncrementalAction>(*DCI, *Ctx, Err, *Interp);
507 });
508
509 if (Err)
510 return std::move(Err);
511
512 Interp->DeviceAct = std::move(DeviceAct);
513
514 if (llvm::Error E = ExecuteIncrementalAction(*DCI, *Interp->DeviceAct))
515 return std::move(E);
516
517 Interp->DeviceCI = std::move(DCI);
518
519 if (Type == OffloadType::HIP) {
520 // FIXME: HIP device parsing is not supported yet; it should use an
521 // IncrementalHIPDeviceParser once one exists.
522 } else {
523 auto DeviceParser = std::make_unique<IncrementalCUDADeviceParser>(
524 *Interp->DeviceCI, *Interp->getCompilerInstance(),
525 Interp->DeviceAct.get(), IMVFS, Err, Interp->PTUs);
526
527 if (Err)
528 return std::move(Err);
529
530 Interp->DeviceParser = std::move(DeviceParser);
531 }
532
533 return std::move(Interp);
534}
535
538 return const_cast<Interpreter *>(this)->getCompilerInstance();
539}
540
542 if (!IncrExecutor) {
543 if (auto Err = CreateExecutor())
544 return std::move(Err);
545 }
546
547 return *IncrExecutor.get();
548}
549
553
557
558void Interpreter::markUserCodeStart() {
559 assert(!InitPTUSize && "We only do this once");
560 InitPTUSize = PTUs.size();
561}
562
563size_t Interpreter::getEffectivePTUSize() const {
564 assert(PTUs.size() >= InitPTUSize && "empty PTU list?");
565 return PTUs.size() - InitPTUSize;
566}
567
569Interpreter::Parse(llvm::StringRef Code) {
570 // If we have a device parser, parse it first. The generated code will be
571 // included in the host compilation
572 if (DeviceParser) {
573 llvm::Expected<TranslationUnitDecl *> DeviceTU = DeviceParser->Parse(Code);
574 if (auto E = DeviceTU.takeError())
575 return std::move(E);
576
577 DeviceParser->RegisterPTU(*DeviceTU);
578
579 llvm::Expected<llvm::StringRef> PTX = DeviceParser->GeneratePTX();
580 if (!PTX)
581 return PTX.takeError();
582
583 llvm::Error Err = DeviceParser->GenerateFatbinary();
584 if (Err)
585 return std::move(Err);
586 }
587
588 // Tell the interpreter sliently ignore unused expressions since value
589 // printing could cause it.
591 clang::diag::warn_unused_expr, diag::Severity::Ignored, SourceLocation());
592
593 llvm::Expected<TranslationUnitDecl *> TuOrErr = IncrParser->Parse(Code);
594 if (!TuOrErr)
595 return TuOrErr.takeError();
596
597 PartialTranslationUnit &LastPTU = IncrParser->RegisterPTU(*TuOrErr);
598
599 // Under -emit-llvm, print the module IR.
600 if (InitPTUSize && LastPTU.TheModule &&
601 getCompilerInstance()->getFrontendOpts().ProgramAction ==
603 LastPTU.TheModule->print(llvm::outs(), /*AAW=*/nullptr);
604
605 return LastPTU;
606}
607
609 if (IncrExecutor)
610 return llvm::make_error<llvm::StringError>("Operation failed. "
611 "Execution engine exists",
612 std::error_code());
613 if (!Act->getCodeGen())
614 return llvm::make_error<llvm::StringError>("Operation failed. "
615 "No code generator available",
616 std::error_code());
617
618 if (!IncrExecutorBuilder)
619 IncrExecutorBuilder = std::make_unique<IncrementalExecutorBuilder>();
620
621 auto ExecutorOrErr = IncrExecutorBuilder->create(*TSCtx, CI->getTarget());
622 if (ExecutorOrErr)
623 IncrExecutor = std::move(*ExecutorOrErr);
624
625 return ExecutorOrErr.takeError();
626}
627
629 assert(T.TheModule);
630 LLVM_DEBUG(
631 llvm::dbgs() << "execute-ptu "
632 << (llvm::is_contained(PTUs, T)
633 ? std::distance(PTUs.begin(), llvm::find(PTUs, T))
634 : -1)
635 << ": [TU=" << T.TUPart << ", M=" << T.TheModule.get()
636 << " (" << T.TheModule->getName() << ")]\n");
637 if (!IncrExecutor) {
638 auto Err = CreateExecutor();
639 if (Err)
640 return Err;
641 }
642 // FIXME: Add a callback to retain the llvm::Module once the JIT is done.
643 if (auto Err = IncrExecutor->addModule(T))
644 return Err;
645
646 if (auto Err = IncrExecutor->runCtors())
647 return Err;
648
649 return llvm::Error::success();
650}
651
652llvm::Error Interpreter::ParseAndExecute(llvm::StringRef Code, Value *V) {
653
654 auto PTU = Parse(Code);
655 if (!PTU)
656 return PTU.takeError();
657 if (PTU->TheModule)
658 if (llvm::Error Err = Execute(*PTU))
659 return Err;
660
661 if (LastValue.isValid()) {
662 if (!V) {
663 LastValue.dump();
664 LastValue.clear();
665 } else
666 *V = std::move(LastValue);
667 }
668 return llvm::Error::success();
669}
670
673 if (!IncrExecutor)
674 return llvm::make_error<llvm::StringError>("Operation failed. "
675 "No execution engine",
676 std::error_code());
677 llvm::StringRef MangledName = Act->getCodeGen()->GetMangledName(GD);
678 return getSymbolAddress(MangledName);
679}
680
682Interpreter::getSymbolAddress(llvm::StringRef IRName) const {
683 if (!IncrExecutor)
684 return llvm::make_error<llvm::StringError>("Operation failed. "
685 "No execution engine",
686 std::error_code());
687
688 return IncrExecutor->getSymbolAddress(IRName, IncrementalExecutor::IRName);
689}
690
693 if (!IncrExecutor)
694 return llvm::make_error<llvm::StringError>("Operation failed. "
695 "No execution engine",
696 std::error_code());
697
698 return IncrExecutor->getSymbolAddress(Name, IncrementalExecutor::LinkerName);
699}
700
701llvm::Error Interpreter::Undo(unsigned N) {
702
703 if (getEffectivePTUSize() == 0) {
704 return llvm::make_error<llvm::StringError>("Operation failed. "
705 "No input left to undo",
706 std::error_code());
707 } else if (N > getEffectivePTUSize()) {
708 return llvm::make_error<llvm::StringError>(
709 llvm::formatv(
710 "Operation failed. Wanted to undo {0} inputs, only have {1}.", N,
711 getEffectivePTUSize()),
712 std::error_code());
713 }
714
715 for (unsigned I = 0; I < N; I++) {
716 if (IncrExecutor) {
717 if (llvm::Error Err = IncrExecutor->removeModule(PTUs.back()))
718 return Err;
719 }
720
721 IncrParser->CleanUpPTU(PTUs.back().TUPart);
722 PTUs.pop_back();
723 }
724 return llvm::Error::success();
725}
726
727llvm::Error Interpreter::LoadDynamicLibrary(const char *name) {
728 auto EEOrErr = getExecutionEngine();
729 if (!EEOrErr)
730 return EEOrErr.takeError();
731
732 return EEOrErr->LoadDynamicLibrary(name);
733}
734} // end namespace clang
Defines the clang::ASTContext interface.
#define V(N, I)
Defines the clang::FileManager interface and associated types.
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:239
Abstract interface for callback invocations by the ASTReader.
Definition ASTReader.h:117
static bool readASTFileControlBlock(StringRef Filename, FileManager &FileMgr, const ModuleCache &ModCache, const PCHContainerReader &PCHContainerRdr, bool FindModuleFileExtensions, ASTReaderListener &Listener, bool ValidateDiagnosticOptions, unsigned ClientLoadCapabilities=ARR_ConfigurationMismatch|ARR_OutOfDate)
Read the control block for the named AST file.
CompilerInstance - Helper class for managing a single instance of the Clang compiler.
const PCHContainerReader & getPCHContainerReader() const
Return the appropriate PCHContainerReader depending on the current CodeGenOptions.
DiagnosticsEngine & getDiagnostics() const
Get the current diagnostics engine.
FileSystemOptions & getFileSystemOpts()
ASTContext & getASTContext() const
IntrusiveRefCntPtr< llvm::vfs::FileSystem > getVirtualFileSystemPtr() const
bool ExecuteAction(FrontendAction &Act)
ExecuteAction - Execute the provided action against the compiler's CompilerInvocation object.
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
bool hasErrorOccurred() const
Definition Diagnostic.h:891
void setSeverity(diag::kind Diag, diag::Severity Map, SourceLocation Loc)
This allows the client to specify that certain warnings are ignored.
Implements support for file system lookup, file system caching, and directory search management.
Definition FileManager.h:57
GlobalDecl - represents a global declaration.
Definition GlobalDecl.h:60
A custom action enabling the incremental processing functionality.
llvm::Expected< std::unique_ptr< CompilerInstance > > CreateCpp()
llvm::Expected< std::unique_ptr< CompilerInstance > > CreateHost(OffloadType Type)
llvm::Expected< std::unique_ptr< CompilerInstance > > CreateDevice(OffloadType Type)
llvm::Expected< IncrementalExecutor & > getExecutionEngine()
llvm::Error ParseAndExecute(llvm::StringRef Code, Value *V=nullptr)
static llvm::Expected< std::unique_ptr< Interpreter > > create(std::unique_ptr< CompilerInstance > CI, std::unique_ptr< IncrementalExecutorBuilder > IEB=nullptr)
llvm::Error CreateExecutor()
llvm::Expected< llvm::orc::ExecutorAddr > getSymbolAddress(GlobalDecl GD) const
llvm::Error LoadDynamicLibrary(const char *name)
Link a dynamic library.
llvm::Expected< PartialTranslationUnit & > Parse(llvm::StringRef Code)
llvm::Expected< llvm::orc::ExecutorAddr > getSymbolAddressFromLinkerName(llvm::StringRef LinkerName) const
static llvm::Expected< std::unique_ptr< Interpreter > > createWithDevice(OffloadType Type, std::unique_ptr< CompilerInstance > CI, std::unique_ptr< CompilerInstance > DCI)
Interpreter(std::unique_ptr< CompilerInstance > Instance, llvm::Error &Err, std::unique_ptr< IncrementalExecutorBuilder > IEB=nullptr, std::unique_ptr< clang::ASTConsumer > Consumer=nullptr)
llvm::Error Undo(unsigned N=1)
Undo N previous incremental inputs.
const CompilerInstance * getCompilerInstance() const
const ASTContext & getASTContext() const
friend class Value
llvm::Error Execute(PartialTranslationUnit &T)
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
A processor an offloading action can target.
Definition OffloadArch.h:32
Encodes a location in the source.
static TargetInfo * CreateTargetInfo(DiagnosticsEngine &Diags, TargetOptions &Opts)
Construct a target for the given options.
Definition Targets.cpp:840
void FlushDiagnostics(DiagnosticsEngine &Diags) const
FlushDiagnostics - Flush the buffered diagnostics to an given diagnostic engine.
The base class of the type hierarchy.
Definition TypeBase.h:1879
Command - An executable path/name and argument vector to execute.
Definition Job.h:107
const Tool & getCreator() const
getCreator - Return the Tool which caused the creation of this job.
Definition Job.h:199
const llvm::opt::ArgStringList & getArguments() const
Definition Job.h:243
Compilation - A set of tasks to perform for a single driver invocation.
Definition Compilation.h:46
JobList - A sequence of jobs to perform.
Definition Job.h:279
size_type size() const
Definition Job.h:305
iterator begin()
Definition Job.h:306
const char * getName() const
Definition Tool.h:48
Defines the clang::TargetInfo interface.
@ Ignored
Do not present this diagnostic, ignore it.
@ EmitLLVM
Emit a .ll file.
Top level wrappers for InstallAPI frontend operations.
std::unique_ptr< DiagnosticOptions > CreateAndPopulateDiagOpts(ArrayRef< const char * > Argv)
@ Success
Annotation was successful.
Definition Parser.h:65
std::shared_ptr< ModuleCache > createCrossProcessModuleCache()
Creates new ModuleCache backed by a file system directory that may be operated on by multiple process...
@ 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.
bool(*)(llvm::ArrayRef< const char * >, llvm::raw_ostream &, llvm::raw_ostream &, bool, bool) Driver
Definition Wasm.cpp:37
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.