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"
30#include "clang/Driver/Driver.h"
31#include "clang/Driver/Job.h"
32#include "clang/Driver/Tool.h"
42#include "clang/Lex/Pragma.h"
47#include "clang/Sema/Lookup.h"
51#include "llvm/ADT/StringExtras.h"
52#include "llvm/ADT/StringSwitch.h"
53#include "llvm/ExecutionEngine/JITSymbol.h"
54#include "llvm/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.h"
55#include "llvm/ExecutionEngine/Orc/LLJIT.h"
56#include "llvm/IR/Module.h"
57#include "llvm/Support/Errc.h"
58#include "llvm/Support/ErrorHandling.h"
59#include "llvm/Support/Process.h"
60#include "llvm/Support/VirtualFileSystem.h"
61#include "llvm/Support/raw_ostream.h"
62#include "llvm/TargetParser/Host.h"
63#include "llvm/TargetParser/Triple.h"
64#include "llvm/Transforms/Utils/Cloning.h" // for CloneModule
65
66#define DEBUG_TYPE "clang-repl"
67
68using namespace clang;
69// FIXME: Figure out how to unify with namespace init_convenience from
70// tools/clang-import-test/clang-import-test.cpp
71namespace {
72/// Retrieves the clang CC1 specific flags out of the compilation's jobs.
73/// \returns NULL on error.
75GetCC1Arguments(DiagnosticsEngine *Diagnostics,
76 driver::Compilation *Compilation) {
77 // We expect to get back exactly one Command job, if we didn't something
78 // failed. Extract that job from the Compilation.
79 const driver::JobList &Jobs = Compilation->getJobs();
80 if (!Jobs.size())
81 return llvm::createStringError(llvm::errc::not_supported,
82 "Driver initialization failed. "
83 "Unable to create a driver job");
84
85 // The driver creates one device compile job per architecture (for example if
86 // --offload-arch=native finds several GPUs). Only one can be used.
87 unsigned NumDeviceJobs = llvm::count_if(Jobs, [](const driver::Command &C) {
88 return llvm::StringRef(C.getCreator().getName()) == "clang" &&
89 llvm::is_contained(C.getArguments(),
90 llvm::StringRef("-fcuda-is-device"));
91 });
92 if (NumDeviceJobs > 1)
93 return llvm::createStringError(
94 llvm::errc::not_supported,
95 "Multiple device architectures are not supported. Pass a single "
96 "--offload-arch");
97
98 // The one job we find should be to invoke clang again.
99 const driver::Command *Cmd = &*Jobs.begin();
100 if (llvm::StringRef(Cmd->getCreator().getName()) != "clang")
101 return llvm::createStringError(llvm::errc::not_supported,
102 "Driver initialization failed");
103
104 return &Cmd->getArguments();
105}
106
107// ASTReaderListener that captures the PIC level stored in a serialized AST
108// file (PCH or PCM) so the interpreter can compare it against its own.
109class PICLevelReader : public ASTReaderListener {
110 unsigned &PICLevel;
111
112public:
113 PICLevelReader(unsigned &PICLevel) : PICLevel(PICLevel) {}
114
115 bool ReadLanguageOptions(const LangOptions &LangOpts,
116 StringRef ModuleFilename, bool Complain,
117 bool AllowCompatibleDifferences) override {
118 PICLevel = LangOpts.PICLevel;
119 return false;
120 }
121};
122
123// clang-repl always compiles position-independent code (it injects -fPIC), so a
124// PCH/PCM that was built with a different PIC level is incompatible: mixing the
125// two leads to relocations that may be out of range once the JIT maps code more
126// than 2GB away. PICLevel is a "compatible" language option, so the ASTReader
127// would otherwise accept the mismatch silently. Reject it up front.
128//
129// The file is probed with its own FileManager and ModuleCache (sharing only the
130// VFS) so this read leaves the CompilerInstance's state untouched for the real
131// load performed later by ExecuteAction().
132static llvm::Error checkASTFilePICLevel(CompilerInstance &Clang,
133 StringRef Filename) {
136 std::shared_ptr<ModuleCache> ModCache = createCrossProcessModuleCache();
137 unsigned ASTPICLevel = 0;
138 PICLevelReader Reader(ASTPICLevel);
140 Filename, *FileMgr, *ModCache, Clang.getPCHContainerReader(),
141 /*FindModuleFileExtensions=*/false, Reader,
142 /*ValidateDiagnosticOptions=*/false) &&
143 ASTPICLevel != Clang.getLangOpts().PICLevel)
144 return llvm::createStringError(
145 llvm::errc::not_supported,
146 "AST file '%s' was built with PIC level %u, which is incompatible "
147 "with clang-repl's PIC level %u",
148 Filename.str().c_str(), ASTPICLevel, Clang.getLangOpts().PICLevel);
149 return llvm::Error::success();
150}
151
153CreateCI(const llvm::opt::ArgStringList &Argv) {
154 std::unique_ptr<CompilerInstance> Clang(new CompilerInstance());
155
156 // Register the support for object-file-wrapped Clang modules.
157 // FIXME: Clang should register these container operations automatically.
158 auto PCHOps = Clang->getPCHContainerOperations();
159 PCHOps->registerWriter(std::make_unique<ObjectFilePCHContainerWriter>());
160 PCHOps->registerReader(std::make_unique<ObjectFilePCHContainerReader>());
161
162 // Buffer diagnostics from argument parsing so that we can output them using
163 // a well formed diagnostic object.
164 DiagnosticOptions DiagOpts;
166 DiagnosticsEngine Diags(DiagnosticIDs::create(), DiagOpts, DiagsBuffer);
168 Clang->getInvocation(), llvm::ArrayRef(Argv.begin(), Argv.size()), Diags);
169
170 // Infer the builtin include path if unspecified.
171 if (Clang->getHeaderSearchOpts().UseBuiltinIncludes &&
172 Clang->getHeaderSearchOpts().ResourceDir.empty())
173 Clang->getHeaderSearchOpts().ResourceDir =
174 GetResourcesPath(Argv[0], nullptr);
175
176 Clang->createVirtualFileSystem();
177
178 // Create the actual diagnostics engine.
179 Clang->createDiagnostics();
180
181 DiagsBuffer->FlushDiagnostics(Clang->getDiagnostics());
182 if (!Success)
183 return llvm::createStringError(llvm::errc::not_supported,
184 "Initialization failed. "
185 "Unable to flush diagnostics");
186
187 // FIXME: Merge with CompilerInstance::ExecuteAction.
188 llvm::MemoryBuffer *MB = llvm::MemoryBuffer::getMemBuffer("").release();
189 Clang->getPreprocessorOpts().addRemappedFile("<<< inputs >>>", MB);
190
191 Clang->setTarget(TargetInfo::CreateTargetInfo(
192 Clang->getDiagnostics(), Clang->getInvocation().getTargetOpts()));
193 if (!Clang->hasTarget())
194 return llvm::createStringError(llvm::errc::not_supported,
195 "Initialization failed. "
196 "Target is missing");
197
198 Clang->getTarget().adjust(Clang->getDiagnostics(), Clang->getLangOpts(),
199 Clang->getAuxTarget());
200
201 // Don't clear the AST before backend codegen since we do codegen multiple
202 // times, reusing the same AST.
203 Clang->getCodeGenOpts().ClearASTBeforeBackend = false;
204
205 Clang->getFrontendOpts().DisableFree = false;
206 Clang->getCodeGenOpts().DisableFree = false;
207
208 // Reject any precompiled input (PCH or PCM) built with a PIC level that
209 // differs from clang-repl's own, before any Interpreter/FrontendAction is
210 // constructed. See checkASTFilePICLevel for the rationale.
211 StringRef PCHInclude = Clang->getPreprocessorOpts().ImplicitPCHInclude;
212 if (!PCHInclude.empty())
213 if (llvm::Error Err = checkASTFilePICLevel(*Clang, PCHInclude))
214 return std::move(Err);
215
216 // Explicitly loaded modules: -fmodule-file=<path> and
217 // -fmodule-file=<name>=<path>.
218 for (StringRef ModuleFile : Clang->getFrontendOpts().ModuleFiles)
219 if (llvm::Error Err = checkASTFilePICLevel(*Clang, ModuleFile))
220 return std::move(Err);
221 for (const auto &NameAndFile :
222 Clang->getHeaderSearchOpts().PrebuiltModuleFiles)
223 if (llvm::Error Err = checkASTFilePICLevel(*Clang, NameAndFile.second))
224 return std::move(Err);
225
226 return std::move(Clang);
227}
228
229static llvm::Error ExecuteIncrementalAction(CompilerInstance &CI,
230 IncrementalAction &Act) {
231 if (!CI.ExecuteAction(Act) || CI.getDiagnostics().hasErrorOccurred()) {
232 return llvm::createStringError(llvm::errc::not_supported,
233 "Failed to execute incremental action");
234 }
235 return llvm::Error::success();
236}
237
238// '#pragma clang repl optimize(<opt>)' sets the optimization level and size
239// used to emit modules for input parsed after the pragma. <opt> is an -O flag
240// spelled without the leading dash: O0, O1, O2, O3, Os or Oz.
241struct PragmaReplHandler : public PragmaHandler {
242 Interpreter &Interp;
243
244 PragmaReplHandler(Interpreter &Interp)
245 : PragmaHandler("repl"), Interp(Interp) {}
246
247 void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
248 Token &FirstToken) override {
249 Token Tok;
251 if (Tok.isNot(tok::identifier) ||
252 !Tok.getIdentifierInfo()->isStr("optimize")) {
253 PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier)
254 << "clang repl";
255 return;
256 }
257
259 if (Tok.isNot(tok::l_paren)) {
260 PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_lparen)
261 << "clang repl optimize";
262 return;
263 }
264
266 std::string Opt = PP.getSpelling(Tok);
267 // The OptimizationLevel and OptimizeSize that each -O flag sets.
268 std::optional<std::pair<unsigned, unsigned>> Level =
269 llvm::StringSwitch<std::optional<std::pair<unsigned, unsigned>>>(Opt)
270 .Case("O0", std::pair(0U, 0U))
271 .Case("O1", std::pair(1U, 0U))
272 .Case("O2", std::pair(2U, 0U))
273 .Case("O3", std::pair(3U, 0U))
274 .Case("Os", std::pair(2U, 1U))
275 .Case("Oz", std::pair(2U, 2U))
276 .Default(std::nullopt);
277 if (!Level) {
278 PP.Diag(Tok.getLocation(), diag::warn_pragma_invalid_argument)
279 << Opt << "clang repl optimize" << /*Expected=*/true
280 << "'O0', 'O1', 'O2', 'O3', 'Os' or 'Oz'";
281 return;
282 }
283
285 if (Tok.isNot(tok::r_paren)) {
286 PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_rparen)
287 << "clang repl optimize";
288 return;
289 }
290
292 if (Tok.isNot(tok::eod)) {
293 PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
294 << "clang repl optimize";
295 return;
296 }
297
298 Interp.setOptLevel(Level->first, Level->second);
299 }
300};
301
302} // anonymous namespace
303
304namespace clang {
305
307IncrementalCompilerBuilder::create(std::string TT,
308 std::vector<const char *> &ClangArgv) {
309
310 // If we don't know ClangArgv0 or the address of main() at this point, try
311 // to guess it anyway (it's possible on some platforms).
312 std::string MainExecutableName =
313 llvm::sys::fs::getMainExecutable(nullptr, nullptr);
314
315 ClangArgv.insert(ClangArgv.begin(), MainExecutableName.c_str());
316
317 // Compile as position-independent code. This prevents the frontend from
318 // marking external symbols (e.g. C++ type-info such as _ZTIPKc used for
319 // exception handling) as dso_local and emitting direct PC-relative
320 // references. JITLink can place the GOT entry near the JIT'd code, keeping
321 // the relocation in range. Without -fPIC, a direct Delta32 relocation to a
322 // host symbol may be out of range when the JIT memory is mapped more than
323 // 2GB away (as on FreeBSD), breaking tests such as
324 // Interpreter/simple-exception.cpp. Insert before user arguments so it can
325 // still be overridden. On Windows (excluding Cygwin/MinGW) an explicit
326 // -fPIC is an unsupported driver option that would drop non-x86_64 targets
327 // to PIC level 0; PIC is already the forced default there where relevant,
328 // so don't inject it.
329 llvm::Triple TargetTriple(TT);
330 if (!TargetTriple.isOSWindows() || TargetTriple.isOSCygMing())
331 ClangArgv.insert(ClangArgv.begin() + 1, "-fPIC");
332
333 // Prepending -c to force the driver to do something if no action was
334 // specified. By prepending we allow users to override the default
335 // action and use other actions in incremental mode.
336 // FIXME: Print proper driver diagnostics if the driver flags are wrong.
337 // We do C++ by default; append right after argv[0] if no "-x" given
338 ClangArgv.insert(ClangArgv.end(), "-Xclang");
339 ClangArgv.insert(ClangArgv.end(), "-fincremental-extensions");
340 ClangArgv.insert(ClangArgv.end(), "-c");
341
342 // Put a dummy C++ file on to ensure there's at least one compile job for the
343 // driver to construct.
344 ClangArgv.push_back("<<< inputs >>>");
345
346 // Buffer diagnostics from argument parsing so that we can output them using a
347 // well formed diagnostic object.
348 std::unique_ptr<DiagnosticOptions> DiagOpts =
349 CreateAndPopulateDiagOpts(ClangArgv);
350 TextDiagnosticBuffer *DiagsBuffer = new TextDiagnosticBuffer;
351 DiagnosticsEngine Diags(DiagnosticIDs::create(), *DiagOpts, DiagsBuffer);
352
353 driver::Driver Driver(/*MainBinaryName=*/ClangArgv[0], TT, Diags);
354 Driver.setCheckInputsExist(false); // the input comes from mem buffers
355 llvm::ArrayRef<const char *> RF = llvm::ArrayRef(ClangArgv);
356 std::unique_ptr<driver::Compilation> Compilation(Driver.BuildCompilation(RF));
357
358 if (CompilationCB)
359 if (auto Err = (*CompilationCB)(*Compilation.get()))
360 return std::move(Err);
361
362 if (Compilation->getArgs().hasArg(options::OPT_v))
363 Compilation->getJobs().Print(llvm::errs(), "\n", /*Quote=*/false);
364
365 auto ErrOrCC1Args = GetCC1Arguments(&Diags, Compilation.get());
366 if (auto Err = ErrOrCC1Args.takeError())
367 return std::move(Err);
368
369 return CreateCI(**ErrOrCC1Args);
370}
371
374 std::string TT = TargetTriple ? *TargetTriple : llvm::sys::getProcessTriple();
375
376 std::vector<const char *> Argv;
377 Argv.reserve(5 + 1 + UserArgs.size());
378 Argv.push_back("-xc++");
379#ifdef __EMSCRIPTEN__
380 Argv.push_back("-target");
381 Argv.push_back(TT.c_str());
382 Argv.push_back("-fvisibility=default");
383#endif
384 llvm::append_range(Argv, UserArgs);
385
386 return IncrementalCompilerBuilder::create(TT, Argv);
387}
388
390IncrementalCompilerBuilder::createOffload(bool device, OffloadType Type) {
392 return llvm::make_error<llvm::StringError>(
393 "Detecting the device vendor is not supported yet.",
394 llvm::inconvertibleErrorCode());
395
396 const bool HipEnabled = Type == OffloadType::HIP;
397 std::vector<const char *> Argv;
398 Argv.reserve(5 + 4 + UserArgs.size());
399 Argv.push_back(HipEnabled ? "-xhip" : "-xcuda");
400 Argv.push_back(device ? "--cuda-device-only" : "--cuda-host-only");
401
402 std::string SDKPathArg = HipEnabled ? "--rocm-path=" : "--cuda-path=";
403 if (!DeviceSDKPath.empty()) {
404 SDKPathArg += DeviceSDKPath;
405 Argv.push_back(SDKPathArg.c_str());
406 }
407
408 std::string ArchArg = "--offload-arch=";
409 if (!OffloadArch.empty()) {
410 ArchArg += OffloadArch;
411 Argv.push_back(ArchArg.c_str());
412 }
413
414 if (OffloadCUID.empty())
415 OffloadCUID = llvm::utohexstr(llvm::sys::Process::GetRandomNumber(),
416 /*LowerCase=*/true);
417 std::string CUIDArg = "-cuid=" + OffloadCUID;
418 Argv.push_back(CUIDArg.c_str());
419
420 llvm::append_range(Argv, UserArgs);
421
422 std::string TT = TargetTriple ? *TargetTriple : llvm::sys::getProcessTriple();
423 return IncrementalCompilerBuilder::create(TT, Argv);
424}
425
428 return IncrementalCompilerBuilder::createOffload(/*device=*/true, Type);
429}
430
433 return IncrementalCompilerBuilder::createOffload(/*device=*/false, Type);
434}
435
436Interpreter::Interpreter(std::unique_ptr<CompilerInstance> Instance,
437 llvm::Error &ErrOut,
438 std::unique_ptr<IncrementalExecutorBuilder> IEB,
439 std::unique_ptr<clang::ASTConsumer> Consumer)
440 : IncrExecutorBuilder(std::move(IEB)) {
441 CI = std::move(Instance);
442 llvm::ErrorAsOutParameter EAO(&ErrOut);
443 auto LLVMCtx = std::make_unique<llvm::LLVMContext>();
444 TSCtx = std::make_unique<llvm::orc::ThreadSafeContext>(std::move(LLVMCtx));
445
446 // Honor -mllvm options
447 CI->parseLLVMArgs();
448
449 Act = TSCtx->withContextDo([&](llvm::LLVMContext *Ctx) {
450 return std::make_unique<IncrementalAction>(*CI, *Ctx, ErrOut, *this,
451 std::move(Consumer));
452 });
453
454 if (ErrOut)
455 return;
456
457 if (llvm::Error E = ExecuteIncrementalAction(*CI, *Act)) {
458 ErrOut = joinErrors(std::move(ErrOut), std::move(E));
459 return;
460 }
461
462 IncrParser =
463 std::make_unique<IncrementalParser>(*CI, Act.get(), ErrOut, PTUs);
464
465 if (ErrOut)
466 return;
467
468 CI->getPreprocessor().AddPragmaHandler("clang", new PragmaReplHandler(*this));
469
470 if (Act->getCodeGen()) {
471 Act->CacheCodeGenModule();
472 // The initial PTU is filled by `-include`/`-include-pch` or by CUDA
473 // includes automatically.
474 if (!CI->getPreprocessorOpts().Includes.empty() ||
475 !CI->getPreprocessorOpts().ImplicitPCHInclude.empty()) {
476 // We can't really directly pass the CachedInCodeGenModule to the Jit
477 // because it will steal it, causing dangling references as explained in
478 // Interpreter::Execute
479 auto M = llvm::CloneModule(*Act->getCachedCodeGenModule());
480 ASTContext &C = CI->getASTContext();
481 IncrParser->RegisterPTU(C.getTranslationUnitDecl(), std::move(M));
482 }
483 if (llvm::Error Err = CreateExecutor()) {
484 ErrOut = joinErrors(std::move(ErrOut), std::move(Err));
485 return;
486 }
487 }
488
489 // Not all frontends support code-generation, e.g. ast-dump actions don't
490 if (Act->getCodeGen()) {
491 // Process the PTUs that came from initialization. For example -include will
492 // give us a header that's processed at initialization of the preprocessor.
493 for (PartialTranslationUnit &PTU : PTUs)
494 if (llvm::Error Err = Execute(PTU)) {
495 ErrOut = joinErrors(std::move(ErrOut), std::move(Err));
496 return;
497 }
498 }
499}
500
502 IncrParser.reset();
503 Act->FinalizeAction();
504 if (DeviceParser)
505 DeviceParser.reset();
506 if (DeviceAct)
507 DeviceAct->FinalizeAction();
508 if (IncrExecutor) {
509 if (llvm::Error Err = IncrExecutor->cleanUp())
510 llvm::report_fatal_error(
511 llvm::Twine("Failed to clean up IncrementalExecutor: ") +
512 toString(std::move(Err)));
513 }
514}
515
516// These better to put in a runtime header but we can't. This is because we
517// can't find the precise resource directory in unittests so we have to hard
518// code them.
519const char *const Runtimes = R"(
520 #define __CLANG_REPL__ 1
521#ifdef __cplusplus
522 #define EXTERN_C extern "C"
523 struct __clang_Interpreter_NewTag{} __ci_newtag;
524 void* operator new(__SIZE_TYPE__, void* __p, __clang_Interpreter_NewTag) noexcept;
525 template <class T, class = T (*)() /*disable for arrays*/>
526 void __clang_Interpreter_SetValueCopyArr(const T* Src, void* Placement, unsigned long Size) {
527 for (unsigned long Idx = 0; Idx < Size; ++Idx)
528 new ((void*)(((T*)Placement) + Idx), __ci_newtag) T(Src[Idx]);
529 }
530 template <class T, unsigned long N>
531 void __clang_Interpreter_SetValueCopyArr(const T (*Src)[N], void* Placement, unsigned long Size) {
532 __clang_Interpreter_SetValueCopyArr(Src[0], Placement, Size);
533 }
534#else
535 #if __STDC_VERSION__ < 199901L
536 #define CI_RESTRICT
537 #define CI_INLINE
538 #else
539 #define CI_RESTRICT restrict
540 #define CI_INLINE inline
541 #endif
542 #define EXTERN_C extern
543 EXTERN_C void *memcpy(void *CI_RESTRICT dst, const void *CI_RESTRICT src, __SIZE_TYPE__ n);
544 EXTERN_C CI_INLINE void __clang_Interpreter_SetValueCopyArr(const void* Src, void* Placement, unsigned long Size) {
545 memcpy(Placement, Src, Size);
546 }
547#endif // __cplusplus
548 EXTERN_C void *__clang_Interpreter_SetValueWithAlloc(void*, void*, void*);
549 EXTERN_C void __clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal, void *OpaqueType, ...);
550)";
551
553 std::unique_ptr<CompilerInstance> CI,
554 std::unique_ptr<IncrementalExecutorBuilder> IEB /*=nullptr*/) {
555 llvm::Error Err = llvm::Error::success();
556
557 auto Interp = std::unique_ptr<Interpreter>(new Interpreter(
558 std::move(CI), Err, std::move(IEB), /*Consumer=*/nullptr));
559 if (auto E = std::move(Err))
560 return std::move(E);
561
562 // Add runtime code and set a marker to hide it from user code. Undo will not
563 // go through that.
564 if (auto E = Interp->ParseAndExecute(Runtimes))
565 return std::move(E);
566
567 Interp->markUserCodeStart();
568
569 return std::move(Interp);
570}
571
573Interpreter::createWithDevice(std::unique_ptr<CompilerInstance> CI,
574 std::unique_ptr<CompilerInstance> DCI,
577 return llvm::make_error<llvm::StringError>(
578 "Detecting the device vendor is not supported yet.",
579 llvm::inconvertibleErrorCode());
580
581 // avoid writing fat binary to disk using an in-memory virtual file system
583 std::make_unique<llvm::vfs::InMemoryFileSystem>();
585 std::make_unique<llvm::vfs::OverlayFileSystem>(
586 llvm::vfs::getRealFileSystem());
587 OverlayVFS->pushOverlay(IMVFS);
588 CI->createVirtualFileSystem(OverlayVFS);
589 CI->createFileManager();
590
592 Interpreter::create(std::move(CI));
593 if (!InterpOrErr)
594 return InterpOrErr;
595
596 std::unique_ptr<Interpreter> Interp = std::move(*InterpOrErr);
597
598 llvm::Error Err = llvm::Error::success();
599
600 auto DeviceAct = Interp->TSCtx->withContextDo([&](llvm::LLVMContext *Ctx) {
601 return std::make_unique<IncrementalAction>(*DCI, *Ctx, Err, *Interp);
602 });
603
604 if (Err)
605 return std::move(Err);
606
607 Interp->DeviceAct = std::move(DeviceAct);
608
609 if (llvm::Error E = ExecuteIncrementalAction(*DCI, *Interp->DeviceAct))
610 return std::move(E);
611
612 // Set the finalized initial device module aside, as the host path does.
613 Interp->DeviceAct->CacheCodeGenModule();
614
615 Interp->DeviceCI = std::move(DCI);
616
617 std::unique_ptr<IncrementalDeviceParser> DeviceParser;
618 if (Type == OffloadType::HIP)
619 DeviceParser = std::make_unique<IncrementalHIPDeviceParser>(
620 *Interp->DeviceCI, *Interp->getCompilerInstance(),
621 Interp->DeviceAct.get(), IMVFS, Err, Interp->PTUs);
622 else
623 DeviceParser = std::make_unique<IncrementalCUDADeviceParser>(
624 *Interp->DeviceCI, *Interp->getCompilerInstance(),
625 Interp->DeviceAct.get(), IMVFS, Err, Interp->PTUs);
626
627 if (Err)
628 return std::move(Err);
629
630 Interp->DeviceParser = std::move(DeviceParser);
631 return std::move(Interp);
632}
633
636 return const_cast<Interpreter *>(this)->getCompilerInstance();
637}
638
640 if (!IncrExecutor) {
641 if (auto Err = CreateExecutor())
642 return std::move(Err);
643 }
644
645 return *IncrExecutor.get();
646}
647
648void Interpreter::setOptLevel(unsigned OptLevel, unsigned OptSize) {
650 CGO.OptimizationLevel = OptLevel;
651 CGO.OptimizeSize = OptSize;
652 CGO.setInlining(OptLevel ? CodeGenOptions::NormalInlining
654}
655
659
663
664void Interpreter::markUserCodeStart() {
665 assert(!InitPTUSize && "We only do this once");
666 InitPTUSize = PTUs.size();
667}
668
669size_t Interpreter::getEffectivePTUSize() const {
670 assert(PTUs.size() >= InitPTUSize && "empty PTU list?");
671 return PTUs.size() - InitPTUSize;
672}
673
675Interpreter::Parse(llvm::StringRef Code) {
676 // If we have a device parser, parse it first. The generated code will be
677 // included in the host compilation
678 if (DeviceParser) {
679 llvm::Expected<TranslationUnitDecl *> DeviceTU = DeviceParser->Parse(Code);
680 if (auto E = DeviceTU.takeError())
681 return std::move(E);
682
683 PartialTranslationUnit &DevicePTU = DeviceParser->RegisterPTU(*DeviceTU);
684
685 // Under -emit-llvm, print the device module IR before it is lowered.
686 if (DevicePTU.TheModule &&
687 DeviceCI->getFrontendOpts().ProgramAction == frontend::EmitLLVM)
688 DevicePTU.TheModule->print(llvm::outs(), /*AAW=*/nullptr);
689
690 llvm::Error Err = DeviceParser->GenerateOffloadBinary();
691 if (Err)
692 return std::move(Err);
693 }
694
695 // Tell the interpreter sliently ignore unused expressions since value
696 // printing could cause it.
698 clang::diag::warn_unused_expr, diag::Severity::Ignored, SourceLocation());
699
700 llvm::Expected<TranslationUnitDecl *> TuOrErr = IncrParser->Parse(Code);
701 if (!TuOrErr)
702 return TuOrErr.takeError();
703
704 PartialTranslationUnit &LastPTU = IncrParser->RegisterPTU(*TuOrErr);
705
706 // Under -emit-llvm, print the module IR.
707 if (InitPTUSize && LastPTU.TheModule &&
708 getCompilerInstance()->getFrontendOpts().ProgramAction ==
710 LastPTU.TheModule->print(llvm::outs(), /*AAW=*/nullptr);
711
712 return LastPTU;
713}
714
716 if (IncrExecutor)
717 return llvm::make_error<llvm::StringError>("Operation failed. "
718 "Execution engine exists",
719 std::error_code());
720 if (!Act->getCodeGen())
721 return llvm::make_error<llvm::StringError>("Operation failed. "
722 "No code generator available",
723 std::error_code());
724
725 if (!IncrExecutorBuilder)
726 IncrExecutorBuilder = IncrementalExecutorBuilder::createDefault();
727
728 // Propagate mllvm args so the wasm executor can restore them after each
729 // lldMain invocation (which resets all cl options for test isolation).
730 IncrExecutorBuilder->LLVMArgs = CI->getFrontendOpts().LLVMArgs;
731
732 auto ExecutorOrErr = IncrExecutorBuilder->create(*TSCtx, CI->getTarget());
733 if (ExecutorOrErr)
734 IncrExecutor = std::move(*ExecutorOrErr);
735
736 return ExecutorOrErr.takeError();
737}
738
740 assert(T.TheModule);
741 LLVM_DEBUG(
742 llvm::dbgs() << "execute-ptu "
743 << (llvm::is_contained(PTUs, T)
744 ? std::distance(PTUs.begin(), llvm::find(PTUs, T))
745 : -1)
746 << ": [TU=" << T.TUPart << ", M=" << T.TheModule.get()
747 << " (" << T.TheModule->getName() << ")]\n");
748 if (!IncrExecutor) {
749 auto Err = CreateExecutor();
750 if (Err)
751 return Err;
752 }
753 // FIXME: Add a callback to retain the llvm::Module once the JIT is done.
754 if (auto Err = IncrExecutor->addModule(T))
755 return Err;
756
757 if (auto Err = IncrExecutor->runCtors())
758 return Err;
759
760 return llvm::Error::success();
761}
762
763llvm::Error Interpreter::ParseAndExecute(llvm::StringRef Code, Value *V) {
764
765 auto PTU = Parse(Code);
766 if (!PTU)
767 return PTU.takeError();
768 if (PTU->TheModule)
769 if (llvm::Error Err = Execute(*PTU))
770 return Err;
771
772 if (LastValue.isValid()) {
773 if (!V) {
774 LastValue.dump();
775 LastValue.clear();
776 } else
777 *V = std::move(LastValue);
778 }
779 return llvm::Error::success();
780}
781
784 if (!IncrExecutor)
785 return llvm::make_error<llvm::StringError>("Operation failed. "
786 "No execution engine",
787 std::error_code());
788 llvm::StringRef MangledName = Act->getCodeGen()->GetMangledName(GD);
789 return getSymbolAddress(MangledName);
790}
791
793Interpreter::getSymbolAddress(llvm::StringRef IRName) const {
794 if (!IncrExecutor)
795 return llvm::make_error<llvm::StringError>("Operation failed. "
796 "No execution engine",
797 std::error_code());
798
799 return IncrExecutor->getSymbolAddress(IRName, IncrementalExecutor::IRName);
800}
801
804 if (!IncrExecutor)
805 return llvm::make_error<llvm::StringError>("Operation failed. "
806 "No execution engine",
807 std::error_code());
808
809 return IncrExecutor->getSymbolAddress(Name, IncrementalExecutor::LinkerName);
810}
811
812llvm::Error Interpreter::Undo(unsigned N) {
813
814 if (getEffectivePTUSize() == 0) {
815 return llvm::make_error<llvm::StringError>("Operation failed. "
816 "No input left to undo",
817 std::error_code());
818 } else if (N > getEffectivePTUSize()) {
819 return llvm::make_error<llvm::StringError>(
820 llvm::formatv(
821 "Operation failed. Wanted to undo {0} inputs, only have {1}.", N,
822 getEffectivePTUSize()),
823 std::error_code());
824 }
825
826 for (unsigned I = 0; I < N; I++) {
827 if (IncrExecutor) {
828 if (llvm::Error Err = IncrExecutor->removeModule(PTUs.back()))
829 return Err;
830 }
831
832 IncrParser->CleanUpPTU(PTUs.back().TUPart);
833 PTUs.pop_back();
834 }
835 return llvm::Error::success();
836}
837
838llvm::Error Interpreter::LoadDynamicLibrary(const char *name) {
839 auto EEOrErr = getExecutionEngine();
840 if (!EEOrErr)
841 return EEOrErr.takeError();
842
843 return EEOrErr->LoadDynamicLibrary(name);
844}
845} // end namespace clang
Defines the clang::ASTContext interface.
#define V(N, I)
Defines the clang::FileManager interface and associated types.
Token Tok
The Token.
Defines the clang::FrontendAction interface and various convenience abstract classes (clang::ASTFront...
Defines the clang::Preprocessor interface.
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:245
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.
CodeGenOptions - Track various options which control how the code is optimized and passed to the back...
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.
CodeGenOptions & getCodeGenOpts()
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:241
bool hasErrorOccurred() const
Definition Diagnostic.h:913
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)
static std::unique_ptr< IncrementalExecutorBuilder > createDefault()
Create the default builder for the platform clangInterpreter is built for.
Provides top-level interfaces for incremental compilation and execution.
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
void setOptLevel(unsigned OptLevel, unsigned OptSize=0)
Set the optimization level and size used to emit subsequently parsed input.
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
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
static llvm::Expected< std::unique_ptr< Interpreter > > createWithDevice(std::unique_ptr< CompilerInstance > CI, std::unique_ptr< CompilerInstance > DCI, OffloadType Type=OffloadType::Detect)
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:36
PragmaHandler - Instances of this interface defined to handle the various pragmas that the language f...
Definition Pragma.h:65
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
void LexUnexpandedToken(Token &Result)
Just like Lex, but disables macro expansion of identifier tokens.
StringRef getSpelling(SourceLocation loc, SmallVectorImpl< char > &buffer, bool *invalid=nullptr) const
Return the 'spelling' of the token at the given location; does not go up to the spelling location or ...
DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID) const
Forwarding function for diagnostics.
Encodes a location in the source.
static TargetInfo * CreateTargetInfo(DiagnosticsEngine &Diags, TargetOptions &Opts)
Construct a target for the given options.
Definition Targets.cpp:842
void FlushDiagnostics(DiagnosticsEngine &Diags) const
FlushDiagnostics - Flush the buffered diagnostics to an given diagnostic engine.
Token - This structure provides full information about a lexed token.
Definition Token.h:36
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:285
size_type size() const
Definition Job.h:311
iterator begin()
Definition Job.h:312
const char * getName() const
Definition Tool.h:47
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)
OffloadType
The device language to offload to.
Definition Interpreter.h:51
@ 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:39
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.
Describes how and where the pragma was introduced.
Definition Pragma.h:51