19#include "llvm/Support/VirtualFileSystem.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"
58#define DEBUG_TYPE "clang-repl"
73 return llvm::createStringError(llvm::errc::not_supported,
74 "Driver initialization failed. "
75 "Unable to create a driver job");
80 return llvm::createStringError(llvm::errc::not_supported,
81 "Driver initialization failed");
87CreateCI(
const llvm::opt::ArgStringList &Argv) {
92 auto PCHOps = Clang->getPCHContainerOperations();
93 PCHOps->registerWriter(std::make_unique<ObjectFilePCHContainerWriter>());
94 PCHOps->registerReader(std::make_unique<ObjectFilePCHContainerReader>());
102 Clang->getInvocation(),
llvm::ArrayRef(Argv.begin(), Argv.size()), Diags);
105 if (Clang->getHeaderSearchOpts().UseBuiltinIncludes &&
106 Clang->getHeaderSearchOpts().ResourceDir.empty())
107 Clang->getHeaderSearchOpts().ResourceDir =
110 Clang->createVirtualFileSystem();
113 Clang->createDiagnostics();
114 if (!Clang->hasDiagnostics())
115 return llvm::createStringError(llvm::errc::not_supported,
116 "Initialization failed. "
117 "Unable to create diagnostics engine");
121 return llvm::createStringError(llvm::errc::not_supported,
122 "Initialization failed. "
123 "Unable to flush diagnostics");
126 llvm::MemoryBuffer *MB = llvm::MemoryBuffer::getMemBuffer(
"").release();
127 Clang->getPreprocessorOpts().addRemappedFile(
"<<< inputs >>>", MB);
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");
136 Clang->getTarget().adjust(Clang->getDiagnostics(), Clang->getLangOpts(),
137 Clang->getAuxTarget());
141 Clang->getCodeGenOpts().ClearASTBeforeBackend =
false;
143 Clang->getFrontendOpts().DisableFree =
false;
144 Clang->getCodeGenOpts().DisableFree =
false;
145 return std::move(Clang);
153IncrementalCompilerBuilder::create(std::string TT,
154 std::vector<const char *> &ClangArgv) {
158 std::string MainExecutableName =
159 llvm::sys::fs::getMainExecutable(
nullptr,
nullptr);
161 ClangArgv.insert(ClangArgv.begin(), MainExecutableName.c_str());
168 ClangArgv.insert(ClangArgv.end(),
"-Xclang");
169 ClangArgv.insert(ClangArgv.end(),
"-fincremental-extensions");
170 ClangArgv.insert(ClangArgv.end(),
"-c");
174 ClangArgv.push_back(
"<<< inputs >>>");
178 std::unique_ptr<DiagnosticOptions> DiagOpts =
180 TextDiagnosticBuffer *DiagsBuffer =
new TextDiagnosticBuffer;
183 driver::Driver
Driver(ClangArgv[0], TT, Diags);
184 Driver.setCheckInputsExist(
false);
185 llvm::ArrayRef<const char *> RF = llvm::ArrayRef(ClangArgv);
186 std::unique_ptr<driver::Compilation> Compilation(
Driver.BuildCompilation(RF));
188 if (Compilation->getArgs().hasArg(driver::options::OPT_v))
189 Compilation->getJobs().Print(llvm::errs(),
"\n",
false);
191 auto ErrOrCC1Args = GetCC1Arguments(&Diags, Compilation.get());
192 if (
auto Err = ErrOrCC1Args.takeError())
193 return std::move(Err);
195 return CreateCI(**ErrOrCC1Args);
200 std::vector<const char *> Argv;
201 Argv.reserve(5 + 1 + UserArgs.size());
202 Argv.push_back(
"-xc++");
204 Argv.push_back(
"-target");
205 Argv.push_back(
"wasm32-unknown-emscripten");
206 Argv.push_back(
"-fvisibility=default");
208 llvm::append_range(Argv, UserArgs);
210 std::string TT = TargetTriple ? *TargetTriple : llvm::sys::getProcessTriple();
211 return IncrementalCompilerBuilder::create(TT, Argv);
215IncrementalCompilerBuilder::createCuda(
bool device) {
216 std::vector<const char *> Argv;
217 Argv.reserve(5 + 4 + UserArgs.size());
219 Argv.push_back(
"-xcuda");
221 Argv.push_back(
"--cuda-device-only");
223 Argv.push_back(
"--cuda-host-only");
225 std::string SDKPathArg =
"--cuda-path=";
226 if (!CudaSDKPath.empty()) {
227 SDKPathArg += CudaSDKPath;
228 Argv.push_back(SDKPathArg.c_str());
231 std::string ArchArg =
"--offload-arch=";
234 Argv.push_back(ArchArg.c_str());
237 llvm::append_range(Argv, UserArgs);
239 std::string TT = TargetTriple ? *TargetTriple : llvm::sys::getProcessTriple();
240 return IncrementalCompilerBuilder::create(TT, Argv);
245 return IncrementalCompilerBuilder::createCuda(
true);
250 return IncrementalCompilerBuilder::createCuda(
false);
255 std::unique_ptr<llvm::orc::LLJITBuilder> JITBuilder,
256 std::unique_ptr<clang::ASTConsumer> Consumer,
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));
264 Act = TSCtx->withContextDo([&](llvm::LLVMContext *Ctx) {
265 return std::make_unique<IncrementalAction>(*CI, *Ctx, ErrOut, *
this,
266 std::move(Consumer));
271 CI->ExecuteAction(*Act);
274 std::make_unique<IncrementalParser>(*CI, Act.get(), ErrOut, PTUs);
279 if (Act->getCodeGen()) {
280 Act->CacheCodeGenModule();
283 if (!CI->getPreprocessorOpts().Includes.empty() ||
284 !CI->getPreprocessorOpts().ImplicitPCHInclude.empty()) {
288 auto M = llvm::CloneModule(*Act->getCachedCodeGenModule());
290 IncrParser->RegisterPTU(
C.getTranslationUnitDecl(), std::move(M));
293 ErrOut = joinErrors(std::move(ErrOut), std::move(Err));
299 if (Act->getCodeGen()) {
303 if (llvm::Error Err =
Execute(PTU)) {
304 ErrOut = joinErrors(std::move(ErrOut), std::move(Err));
312 Act->FinalizeAction();
314 DeviceParser.reset();
316 DeviceAct->FinalizeAction();
318 if (llvm::Error Err = IncrExecutor->cleanUp())
319 llvm::report_fatal_error(
320 llvm::Twine(
"Failed to clean up IncrementalExecutor: ") +
329 #define __CLANG_REPL__ 1
331 #define EXTERN_C extern "C"
332 struct __clang_Interpreter_NewTag{} __ci_newtag;
333 void* operator new(__SIZE_TYPE__, void* __p, __clang_Interpreter_NewTag) noexcept;
334 template <class T, class = T (*)() /*disable for arrays*/>
335 void __clang_Interpreter_SetValueCopyArr(const T* Src, void* Placement, unsigned long Size) {
336 for (auto Idx = 0; Idx < Size; ++Idx)
337 new ((void*)(((T*)Placement) + Idx), __ci_newtag) T(Src[Idx]);
339 template <class T, unsigned long N>
340 void __clang_Interpreter_SetValueCopyArr(const T (*Src)[N], void* Placement, unsigned long Size) {
341 __clang_Interpreter_SetValueCopyArr(Src[0], Placement, Size);
344 #define EXTERN_C extern
345 EXTERN_C void *memcpy(void *restrict dst, const void *restrict src, __SIZE_TYPE__ n);
346 EXTERN_C inline void __clang_Interpreter_SetValueCopyArr(const void* Src, void* Placement, unsigned long Size) {
347 memcpy(Placement, Src, Size);
350 EXTERN_C void *__clang_Interpreter_SetValueWithAlloc(void*, void*, void*);
351 EXTERN_C void __clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal, void *OpaqueType, ...);
356 std::unique_ptr<llvm::orc::ExecutorProcessControl> EPC;
357 uint32_t childPid = -1;
364 return ResultOrErr.takeError();
365 childPid = ResultOrErr->second;
366 auto EPCOrErr = std::move(ResultOrErr->first);
367 EPC = std::move(EPCOrErr);
369#if LLVM_ON_UNIX && LLVM_ENABLE_THREADS
370 auto EPCOrErr = IncrementalExecutor::connectTCPSocket(
374 return EPCOrErr.takeError();
375 EPC = std::move(*EPCOrErr);
377 return llvm::make_error<llvm::StringError>(
378 "Out-of-process JIT over TCP is not supported on this platform",
383 std::unique_ptr<llvm::orc::LLJITBuilder> JB;
388 return JBOrErr.takeError();
389 JB = std::move(*JBOrErr);
392 return std::make_pair(std::move(JB), childPid);
400 if (!CompilerRTPath) {
401 return llvm::make_error<llvm::StringError>(
"CompilerRT path not found",
405 const std::array<const char *, 3> OrcRTLibNames = {
406 "liborc_rt.a",
"liborc_rt_osx.a",
"liborc_rt-x86_64.a"};
408 for (
const char *LibName : OrcRTLibNames) {
410 llvm::sys::path::append(CandidatePath, LibName);
412 if (llvm::sys::fs::exists(CandidatePath)) {
413 return CandidatePath.str().str();
417 return llvm::make_error<llvm::StringError>(
418 llvm::Twine(
"OrcRuntime library not found in: ") + (*CompilerRTPath),
424 llvm::Error Err = llvm::Error::success();
426 std::unique_ptr<llvm::orc::LLJITBuilder> JB;
430 const llvm::Triple &Triple = TI.
getTriple();
433 std::string BinaryName = llvm::sys::fs::getMainExecutable(
nullptr,
nullptr);
436 std::vector<const char *> Args = {
"clang",
"--version"};
437 std::unique_ptr<clang::driver::Compilation>
C(
438 Driver.BuildCompilation(Args));
440 return llvm::make_error<llvm::StringError>(
441 "Failed to create driver compilation for out-of-process JIT",
448 if (!OrcRuntimePathOrErr) {
449 return OrcRuntimePathOrErr.takeError();
456 auto Interp = std::unique_ptr<Interpreter>(
new Interpreter(
457 std::move(CI), Err, std::move(JB),
nullptr, Config));
458 if (
auto E = std::move(Err))
463 if (
auto E = Interp->ParseAndExecute(
Runtimes))
466 Interp->markUserCodeStart();
468 return std::move(Interp);
473 std::unique_ptr<CompilerInstance> DCI) {
476 std::make_unique<llvm::vfs::InMemoryFileSystem>();
478 std::make_unique<llvm::vfs::OverlayFileSystem>(
479 llvm::vfs::getRealFileSystem());
480 OverlayVFS->pushOverlay(IMVFS);
481 CI->createVirtualFileSystem(OverlayVFS);
482 CI->createFileManager();
489 std::unique_ptr<Interpreter> Interp = std::move(*InterpOrErr);
491 llvm::Error Err = llvm::Error::success();
493 auto DeviceAct = Interp->TSCtx->withContextDo([&](llvm::LLVMContext *Ctx) {
494 return std::make_unique<IncrementalAction>(*DCI, *Ctx, Err, *Interp);
498 return std::move(Err);
500 Interp->DeviceAct = std::move(DeviceAct);
502 DCI->ExecuteAction(*Interp->DeviceAct);
504 Interp->DeviceCI = std::move(DCI);
506 auto DeviceParser = std::make_unique<IncrementalCUDADeviceParser>(
507 *Interp->DeviceCI, *Interp->getCompilerInstance(),
508 Interp->DeviceAct.get(), IMVFS, Err, Interp->PTUs);
511 return std::move(Err);
513 Interp->DeviceParser = std::move(DeviceParser);
514 return std::move(Interp);
525 return std::move(Err);
528 return IncrExecutor->GetExecutionEngine();
539void Interpreter::markUserCodeStart() {
540 assert(!InitPTUSize &&
"We only do this once");
541 InitPTUSize = PTUs.size();
544size_t Interpreter::getEffectivePTUSize()
const {
545 assert(PTUs.size() >= InitPTUSize &&
"empty PTU list?");
546 return PTUs.size() - InitPTUSize;
551 return IncrExecutor->getOutOfProcessChildPid();
561 if (
auto E = DeviceTU.takeError())
564 DeviceParser->RegisterPTU(*DeviceTU);
568 return PTX.takeError();
570 llvm::Error Err = DeviceParser->GenerateFatbinary();
572 return std::move(Err);
582 return TuOrErr.takeError();
586 LastPTU.
TUPart = *TuOrErr;
588 if (std::unique_ptr<llvm::Module> M = Act->GenModule())
596 if (TT == llvm::sys::getProcessTriple())
598 return llvm::orc::JITTargetMachineBuilder::detectHost();
601 return llvm::orc::JITTargetMachineBuilder(llvm::Triple(TT));
606 std::unique_ptr<llvm::orc::ExecutorProcessControl> EPC,
607 llvm::StringRef OrcRuntimePath) {
608 const std::string &TT = EPC->getTargetTriple().getTriple();
611 return JTMB.takeError();
614 return JB.takeError();
616 (*JB)->setExecutorProcessControl(std::move(EPC));
617 (*JB)->setPlatformSetUp(
618 llvm::orc::ExecutorNativePlatform(OrcRuntimePath.str()));
620 return std::move(*JB);
625 return llvm::make_error<llvm::StringError>(
"Operation failed. "
626 "Execution engine exists",
628 if (!Act->getCodeGen())
629 return llvm::make_error<llvm::StringError>(
"Operation failed. "
630 "No code generator available",
634 llvm::Triple TargetTriple(TT);
635 bool IsWindowsTarget = TargetTriple.isOSWindows();
641 return ResOrErr.takeError();
642 JITBuilder = std::move(ResOrErr->first);
646 return llvm::make_error<llvm::StringError>(
647 "Operation failed. No LLJITBuilder for out-of-process JIT",
654 return JTMB.takeError();
656 JTMB->setCodeModel(Config.
CM);
659 return JB.takeError();
660 JITBuilder = std::move(*JB);
663 llvm::Error Err = llvm::Error::success();
666 std::unique_ptr<IncrementalExecutor> Executor;
669 Executor = std::make_unique<WasmIncrementalExecutor>(*TSCtx);
672 std::make_unique<IncrementalExecutor>(*TSCtx, *JITBuilder, Config, Err);
675 IncrExecutor = std::move(Executor);
685 llvm::dbgs() <<
"execute-ptu "
686 << (llvm::is_contained(PTUs,
T)
687 ? std::distance(PTUs.begin(), llvm::find(PTUs,
T))
689 <<
": [TU=" <<
T.TUPart <<
", M=" <<
T.TheModule.get()
690 <<
" (" <<
T.TheModule->getName() <<
")]\n");
697 if (
auto Err = IncrExecutor->addModule(
T))
700 if (
auto Err = IncrExecutor->runCtors())
703 return llvm::Error::success();
708 auto PTU =
Parse(Code);
710 return PTU.takeError();
712 if (llvm::Error Err =
Execute(*PTU))
715 if (LastValue.isValid()) {
720 *
V = std::move(LastValue);
722 return llvm::Error::success();
728 return llvm::make_error<llvm::StringError>(
"Operation failed. "
729 "No execution engine",
731 llvm::StringRef MangledName = Act->getCodeGen()->GetMangledName(GD);
738 return llvm::make_error<llvm::StringError>(
"Operation failed. "
739 "No execution engine",
748 return llvm::make_error<llvm::StringError>(
"Operation failed. "
749 "No execution engine",
757 if (getEffectivePTUSize() == 0) {
758 return llvm::make_error<llvm::StringError>(
"Operation failed. "
759 "No input left to undo",
761 }
else if (N > getEffectivePTUSize()) {
762 return llvm::make_error<llvm::StringError>(
764 "Operation failed. Wanted to undo {0} inputs, only have {1}.", N,
765 getEffectivePTUSize()),
769 for (
unsigned I = 0; I < N; I++) {
771 if (llvm::Error Err = IncrExecutor->removeModule(PTUs.back()))
775 IncrParser->CleanUpPTU(PTUs.back().TUPart);
778 return llvm::Error::success();
783 void *handle = dlopen(name, RTLD_NOW | RTLD_GLOBAL);
785 llvm::errs() << dlerror() <<
'\n';
786 return llvm::make_error<llvm::StringError>(
"Failed to load dynamic library",
787 llvm::inconvertibleErrorCode());
792 return EE.takeError();
795 std::unique_ptr<llvm::orc::EPCDynamicLibrarySearchGenerator>>
796 DLSG = llvm::orc::EPCDynamicLibrarySearchGenerator::Load(
797 EE->getExecutionSession(), name))
800 EE->getProcessSymbolsJITDylib()->addGenerator(std::move(*DLSG));
802 return DLSG.takeError();
805 return llvm::Error::success();
Defines the clang::ASTContext interface.
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 ...
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.
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.
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
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.
static TargetInfo * CreateTargetInfo(DiagnosticsEngine &Diags, TargetOptions &Opts)
Construct a target for the given options.
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.
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.
Driver - Encapsulate logic for constructing compilation processes from a set of gcc-driver-like comma...
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.
static llvm::Expected< llvm::orc::JITTargetMachineBuilder > createJITTargetMachineBuilder(const std::string &TT)
bool isa(CodeGen::Address addr)
std::unique_ptr< DiagnosticOptions > CreateAndPopulateDiagOpts(ArrayRef< const char * > Argv)
@ Success
Annotation was successful.
@ Parse
Parse the block; this code is always used.
const char *const Runtimes
const FunctionProtoType * T
U cast(CodeGen::Address addr)
bool(*)(llvm::ArrayRef< const char * >, llvm::raw_ostream &, llvm::raw_ostream &, bool, bool) Driver
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.
std::string OOPExecutorConnect
The class keeps track of various objects created as part of processing incremental inputs.
TranslationUnitDecl * TUPart
std::unique_ptr< llvm::Module > TheModule
The llvm IR produced for the input.