47#include "llvm/ExecutionEngine/JITSymbol.h"
48#include "llvm/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.h"
49#include "llvm/ExecutionEngine/Orc/LLJIT.h"
50#include "llvm/IR/Module.h"
51#include "llvm/Support/Errc.h"
52#include "llvm/Support/ErrorHandling.h"
53#include "llvm/Support/VirtualFileSystem.h"
54#include "llvm/Support/raw_ostream.h"
55#include "llvm/TargetParser/Host.h"
56#include "llvm/TargetParser/Triple.h"
57#include "llvm/Transforms/Utils/Cloning.h"
59#define DEBUG_TYPE "clang-repl"
74 return llvm::createStringError(llvm::errc::not_supported,
75 "Driver initialization failed. "
76 "Unable to create a driver job");
81 return llvm::createStringError(llvm::errc::not_supported,
82 "Driver initialization failed");
93 PICLevelReader(
unsigned &PICLevel) : PICLevel(PICLevel) {}
95 bool ReadLanguageOptions(
const LangOptions &LangOpts,
96 StringRef ModuleFilename,
bool Complain,
97 bool AllowCompatibleDifferences)
override {
98 PICLevel = LangOpts.PICLevel;
113 StringRef Filename) {
117 unsigned ASTPICLevel = 0;
118 PICLevelReader Reader(ASTPICLevel);
124 return llvm::createStringError(
125 llvm::errc::not_supported,
126 "AST file '%s' was built with PIC level %u, which is incompatible "
127 "with clang-repl's PIC level %u",
128 Filename.str().c_str(), ASTPICLevel, Clang.
getLangOpts().PICLevel);
129 return llvm::Error::success();
133CreateCI(
const llvm::opt::ArgStringList &Argv) {
138 auto PCHOps = Clang->getPCHContainerOperations();
139 PCHOps->registerWriter(std::make_unique<ObjectFilePCHContainerWriter>());
140 PCHOps->registerReader(std::make_unique<ObjectFilePCHContainerReader>());
148 Clang->getInvocation(),
llvm::ArrayRef(Argv.begin(), Argv.size()), Diags);
151 if (Clang->getHeaderSearchOpts().UseBuiltinIncludes &&
152 Clang->getHeaderSearchOpts().ResourceDir.empty())
153 Clang->getHeaderSearchOpts().ResourceDir =
156 Clang->createVirtualFileSystem();
159 Clang->createDiagnostics();
163 return llvm::createStringError(llvm::errc::not_supported,
164 "Initialization failed. "
165 "Unable to flush diagnostics");
168 llvm::MemoryBuffer *MB = llvm::MemoryBuffer::getMemBuffer(
"").release();
169 Clang->getPreprocessorOpts().addRemappedFile(
"<<< inputs >>>", MB);
172 Clang->getDiagnostics(), Clang->getInvocation().getTargetOpts()));
173 if (!Clang->hasTarget())
174 return llvm::createStringError(llvm::errc::not_supported,
175 "Initialization failed. "
176 "Target is missing");
178 Clang->getTarget().adjust(Clang->getDiagnostics(), Clang->getLangOpts(),
179 Clang->getAuxTarget());
183 Clang->getCodeGenOpts().ClearASTBeforeBackend =
false;
185 Clang->getFrontendOpts().DisableFree =
false;
186 Clang->getCodeGenOpts().DisableFree =
false;
191 StringRef PCHInclude = Clang->getPreprocessorOpts().ImplicitPCHInclude;
192 if (!PCHInclude.empty())
193 if (llvm::Error Err = checkASTFilePICLevel(*Clang, PCHInclude))
194 return std::move(Err);
198 for (StringRef ModuleFile : Clang->getFrontendOpts().ModuleFiles)
199 if (llvm::Error Err = checkASTFilePICLevel(*Clang, ModuleFile))
200 return std::move(Err);
201 for (
const auto &NameAndFile :
202 Clang->getHeaderSearchOpts().PrebuiltModuleFiles)
203 if (llvm::Error Err = checkASTFilePICLevel(*Clang, NameAndFile.second))
204 return std::move(Err);
206 return std::move(Clang);
214IncrementalCompilerBuilder::create(std::string TT,
215 std::vector<const char *> &ClangArgv) {
219 std::string MainExecutableName =
220 llvm::sys::fs::getMainExecutable(
nullptr,
nullptr);
222 ClangArgv.insert(ClangArgv.begin(), MainExecutableName.c_str());
236 llvm::Triple TargetTriple(TT);
237 if (!TargetTriple.isOSWindows() || TargetTriple.isOSCygMing())
238 ClangArgv.insert(ClangArgv.begin() + 1,
"-fPIC");
245 ClangArgv.insert(ClangArgv.end(),
"-Xclang");
246 ClangArgv.insert(ClangArgv.end(),
"-fincremental-extensions");
247 ClangArgv.insert(ClangArgv.end(),
"-c");
251 ClangArgv.push_back(
"<<< inputs >>>");
255 std::unique_ptr<DiagnosticOptions> DiagOpts =
257 TextDiagnosticBuffer *DiagsBuffer =
new TextDiagnosticBuffer;
260 driver::Driver
Driver(ClangArgv[0], TT, Diags);
261 Driver.setCheckInputsExist(
false);
262 llvm::ArrayRef<const char *> RF = llvm::ArrayRef(ClangArgv);
263 std::unique_ptr<driver::Compilation> Compilation(
Driver.BuildCompilation(RF));
266 if (
auto Err = (*CompilationCB)(*Compilation.get()))
267 return std::move(Err);
269 if (Compilation->getArgs().hasArg(options::OPT_v))
270 Compilation->getJobs().Print(llvm::errs(),
"\n",
false);
272 auto ErrOrCC1Args = GetCC1Arguments(&Diags, Compilation.get());
273 if (
auto Err = ErrOrCC1Args.takeError())
274 return std::move(Err);
276 return CreateCI(**ErrOrCC1Args);
281 std::vector<const char *> Argv;
282 Argv.reserve(5 + 1 + UserArgs.size());
283 Argv.push_back(
"-xc++");
285 Argv.push_back(
"-target");
286 Argv.push_back(
"wasm32-unknown-emscripten");
287 Argv.push_back(
"-fvisibility=default");
289 llvm::append_range(Argv, UserArgs);
291 std::string TT = TargetTriple ? *TargetTriple : llvm::sys::getProcessTriple();
292 return IncrementalCompilerBuilder::create(TT, Argv);
296IncrementalCompilerBuilder::createCuda(
bool device) {
297 std::vector<const char *> Argv;
298 Argv.reserve(5 + 4 + UserArgs.size());
300 Argv.push_back(
"-xcuda");
302 Argv.push_back(
"--cuda-device-only");
304 Argv.push_back(
"--cuda-host-only");
306 std::string SDKPathArg =
"--cuda-path=";
307 if (!CudaSDKPath.empty()) {
308 SDKPathArg += CudaSDKPath;
309 Argv.push_back(SDKPathArg.c_str());
312 std::string ArchArg =
"--offload-arch=";
315 Argv.push_back(ArchArg.c_str());
318 llvm::append_range(Argv, UserArgs);
320 std::string TT = TargetTriple ? *TargetTriple : llvm::sys::getProcessTriple();
321 return IncrementalCompilerBuilder::create(TT, Argv);
326 return IncrementalCompilerBuilder::createCuda(
true);
331 return IncrementalCompilerBuilder::createCuda(
false);
336 std::unique_ptr<IncrementalExecutorBuilder> IEB,
337 std::unique_ptr<clang::ASTConsumer> Consumer)
338 : IncrExecutorBuilder(
std::move(IEB)) {
339 CI = std::move(Instance);
340 llvm::ErrorAsOutParameter EAO(&ErrOut);
341 auto LLVMCtx = std::make_unique<llvm::LLVMContext>();
342 TSCtx = std::make_unique<llvm::orc::ThreadSafeContext>(std::move(LLVMCtx));
344 Act = TSCtx->withContextDo([&](llvm::LLVMContext *Ctx) {
345 return std::make_unique<IncrementalAction>(*CI, *Ctx, ErrOut, *
this,
346 std::move(Consumer));
352 CI->ExecuteAction(*Act);
355 std::make_unique<IncrementalParser>(*CI, Act.get(), ErrOut, PTUs);
360 if (Act->getCodeGen()) {
361 Act->CacheCodeGenModule();
364 if (!CI->getPreprocessorOpts().Includes.empty() ||
365 !CI->getPreprocessorOpts().ImplicitPCHInclude.empty()) {
369 auto M = llvm::CloneModule(*Act->getCachedCodeGenModule());
371 IncrParser->RegisterPTU(
C.getTranslationUnitDecl(), std::move(M));
374 ErrOut = joinErrors(std::move(ErrOut), std::move(Err));
380 if (Act->getCodeGen()) {
384 if (llvm::Error Err =
Execute(PTU)) {
385 ErrOut = joinErrors(std::move(ErrOut), std::move(Err));
393 Act->FinalizeAction();
395 DeviceParser.reset();
397 DeviceAct->FinalizeAction();
399 if (llvm::Error Err = IncrExecutor->cleanUp())
400 llvm::report_fatal_error(
401 llvm::Twine(
"Failed to clean up IncrementalExecutor: ") +
410 #define __CLANG_REPL__ 1
412 #define EXTERN_C extern "C"
413 struct __clang_Interpreter_NewTag{} __ci_newtag;
414 void* operator new(__SIZE_TYPE__, void* __p, __clang_Interpreter_NewTag) noexcept;
415 template <class T, class = T (*)() /*disable for arrays*/>
416 void __clang_Interpreter_SetValueCopyArr(const T* Src, void* Placement, unsigned long Size) {
417 for (unsigned long Idx = 0; Idx < Size; ++Idx)
418 new ((void*)(((T*)Placement) + Idx), __ci_newtag) T(Src[Idx]);
420 template <class T, unsigned long N>
421 void __clang_Interpreter_SetValueCopyArr(const T (*Src)[N], void* Placement, unsigned long Size) {
422 __clang_Interpreter_SetValueCopyArr(Src[0], Placement, Size);
425 #if __STDC_VERSION__ < 199901L
429 #define CI_RESTRICT restrict
430 #define CI_INLINE inline
432 #define EXTERN_C extern
433 EXTERN_C void *memcpy(void *CI_RESTRICT dst, const void *CI_RESTRICT src, __SIZE_TYPE__ n);
434 EXTERN_C CI_INLINE void __clang_Interpreter_SetValueCopyArr(const void* Src, void* Placement, unsigned long Size) {
435 memcpy(Placement, Src, Size);
438 EXTERN_C void *__clang_Interpreter_SetValueWithAlloc(void*, void*, void*);
439 EXTERN_C void __clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal, void *OpaqueType, ...);
443 std::unique_ptr<CompilerInstance> CI,
444 std::unique_ptr<IncrementalExecutorBuilder> IEB ) {
445 llvm::Error Err = llvm::Error::success();
447 auto Interp = std::unique_ptr<Interpreter>(
new Interpreter(
448 std::move(CI), Err, std::move(IEB),
nullptr));
449 if (
auto E = std::move(Err))
454 if (
auto E = Interp->ParseAndExecute(
Runtimes))
457 Interp->markUserCodeStart();
459 return std::move(Interp);
464 std::unique_ptr<CompilerInstance> DCI) {
467 std::make_unique<llvm::vfs::InMemoryFileSystem>();
469 std::make_unique<llvm::vfs::OverlayFileSystem>(
470 llvm::vfs::getRealFileSystem());
471 OverlayVFS->pushOverlay(IMVFS);
472 CI->createVirtualFileSystem(OverlayVFS);
473 CI->createFileManager();
480 std::unique_ptr<Interpreter> Interp = std::move(*InterpOrErr);
482 llvm::Error Err = llvm::Error::success();
484 auto DeviceAct = Interp->TSCtx->withContextDo([&](llvm::LLVMContext *Ctx) {
485 return std::make_unique<IncrementalAction>(*DCI, *Ctx, Err, *Interp);
489 return std::move(Err);
491 Interp->DeviceAct = std::move(DeviceAct);
493 DCI->ExecuteAction(*Interp->DeviceAct);
495 Interp->DeviceCI = std::move(DCI);
497 auto DeviceParser = std::make_unique<IncrementalCUDADeviceParser>(
498 *Interp->DeviceCI, *Interp->getCompilerInstance(),
499 Interp->DeviceAct.get(), IMVFS, Err, Interp->PTUs);
502 return std::move(Err);
504 Interp->DeviceParser = std::move(DeviceParser);
505 return std::move(Interp);
516 return std::move(Err);
519 return *IncrExecutor.get();
530void Interpreter::markUserCodeStart() {
531 assert(!InitPTUSize &&
"We only do this once");
532 InitPTUSize = PTUs.size();
535size_t Interpreter::getEffectivePTUSize()
const {
536 assert(PTUs.size() >= InitPTUSize &&
"empty PTU list?");
537 return PTUs.size() - InitPTUSize;
546 if (
auto E = DeviceTU.takeError())
549 DeviceParser->RegisterPTU(*DeviceTU);
553 return PTX.takeError();
555 llvm::Error Err = DeviceParser->GenerateFatbinary();
557 return std::move(Err);
567 return TuOrErr.takeError();
576 return llvm::make_error<llvm::StringError>(
"Operation failed. "
577 "Execution engine exists",
579 if (!Act->getCodeGen())
580 return llvm::make_error<llvm::StringError>(
"Operation failed. "
581 "No code generator available",
584 if (!IncrExecutorBuilder)
585 IncrExecutorBuilder = std::make_unique<IncrementalExecutorBuilder>();
587 auto ExecutorOrErr = IncrExecutorBuilder->create(*TSCtx, CI->getTarget());
589 IncrExecutor = std::move(*ExecutorOrErr);
591 return ExecutorOrErr.takeError();
597 llvm::dbgs() <<
"execute-ptu "
598 << (llvm::is_contained(PTUs,
T)
599 ? std::distance(PTUs.begin(), llvm::find(PTUs,
T))
601 <<
": [TU=" <<
T.TUPart <<
", M=" <<
T.TheModule.get()
602 <<
" (" <<
T.TheModule->getName() <<
")]\n");
609 if (
auto Err = IncrExecutor->addModule(
T))
612 if (
auto Err = IncrExecutor->runCtors())
615 return llvm::Error::success();
620 auto PTU =
Parse(Code);
622 return PTU.takeError();
624 if (llvm::Error Err =
Execute(*PTU))
627 if (LastValue.isValid()) {
632 *
V = std::move(LastValue);
634 return llvm::Error::success();
640 return llvm::make_error<llvm::StringError>(
"Operation failed. "
641 "No execution engine",
643 llvm::StringRef MangledName = Act->getCodeGen()->GetMangledName(GD);
650 return llvm::make_error<llvm::StringError>(
"Operation failed. "
651 "No execution engine",
660 return llvm::make_error<llvm::StringError>(
"Operation failed. "
661 "No execution engine",
669 if (getEffectivePTUSize() == 0) {
670 return llvm::make_error<llvm::StringError>(
"Operation failed. "
671 "No input left to undo",
673 }
else if (N > getEffectivePTUSize()) {
674 return llvm::make_error<llvm::StringError>(
676 "Operation failed. Wanted to undo {0} inputs, only have {1}.", N,
677 getEffectivePTUSize()),
681 for (
unsigned I = 0; I < N; I++) {
683 if (llvm::Error Err = IncrExecutor->removeModule(PTUs.back()))
687 IncrParser->CleanUpPTU(PTUs.back().TUPart);
690 return llvm::Error::success();
696 return EEOrErr.takeError();
698 return EEOrErr->LoadDynamicLibrary(name);
Defines the clang::ASTContext interface.
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 ...
Abstract interface for callback invocations by the ASTReader.
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
LangOptions & getLangOpts()
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.
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.
GlobalDecl - represents a global declaration.
llvm::Expected< std::unique_ptr< CompilerInstance > > CreateCudaHost()
llvm::Expected< std::unique_ptr< CompilerInstance > > CreateCudaDevice()
llvm::Expected< std::unique_ptr< CompilerInstance > > CreateCpp()
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.
static llvm::Expected< std::unique_ptr< Interpreter > > createWithCUDA(std::unique_ptr< CompilerInstance > CI, std::unique_ptr< CompilerInstance > DCI)
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
const ASTContext & getASTContext() const
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...
Encodes a location in the source.
static TargetInfo * CreateTargetInfo(DiagnosticsEngine &Diags, TargetOptions &Opts)
Construct a target for the given options.
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.
const Tool & getCreator() const
getCreator - Return the Tool which caused the creation of this job.
const llvm::opt::ArgStringList & getArguments() const
Compilation - A set of tasks to perform for a single driver invocation.
JobList - A sequence of jobs to perform.
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.
std::unique_ptr< DiagnosticOptions > CreateAndPopulateDiagOpts(ArrayRef< const char * > Argv)
@ Success
Annotation was successful.
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.
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
The class keeps track of various objects created as part of processing incremental inputs.