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(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);
397 const std::array<const char *, 3> OrcRTLibNames = {
398 "liborc_rt.a",
"liborc_rt_osx.a",
"liborc_rt-x86_64.a"};
400 auto findInDir = [&](llvm::StringRef
Base) -> std::optional<std::string> {
401 for (
const char *LibName : OrcRTLibNames) {
403 llvm::sys::path::append(CandidatePath, LibName);
404 if (llvm::sys::fs::exists(CandidatePath))
405 return std::string(CandidatePath.str());
410 std::string SearchedPaths;
413 if (
auto Found = findInDir(*CompilerRTPath))
415 SearchedPaths += *CompilerRTPath;
417 return llvm::make_error<llvm::StringError>(
"CompilerRT path not found",
421 if (std::optional<std::string> ResourceDir = TC.
getRuntimePath()) {
422 if (
auto Found = findInDir(*ResourceDir))
424 if (!SearchedPaths.empty())
425 SearchedPaths +=
"; ";
426 SearchedPaths += *ResourceDir;
428 return llvm::make_error<llvm::StringError>(
"ResourceDir path not found",
432 return llvm::make_error<llvm::StringError>(
433 llvm::Twine(
"OrcRuntime library not found in: ") + SearchedPaths,
442 const llvm::Triple &Triple = TI.
getTriple();
445 std::string BinaryName = llvm::sys::fs::getMainExecutable(
nullptr,
nullptr);
448 std::vector<const char *> Args = {
"clang",
"--version"};
449 std::unique_ptr<clang::driver::Compilation>
C(
450 Driver.BuildCompilation(Args));
452 return llvm::make_error<llvm::StringError>(
453 "Failed to create driver compilation for out-of-process JIT",
460 if (!OrcRuntimePathOrErr) {
461 return OrcRuntimePathOrErr.takeError();
468 llvm::Error Err = llvm::Error::success();
469 std::unique_ptr<llvm::orc::LLJITBuilder> JB;
471 auto Interp = std::unique_ptr<Interpreter>(
new Interpreter(
472 std::move(CI), Err, std::move(JB),
nullptr, Config));
473 if (
auto E = std::move(Err))
478 if (
auto E = Interp->ParseAndExecute(
Runtimes))
481 Interp->markUserCodeStart();
483 return std::move(Interp);
488 std::unique_ptr<CompilerInstance> DCI) {
491 std::make_unique<llvm::vfs::InMemoryFileSystem>();
493 std::make_unique<llvm::vfs::OverlayFileSystem>(
494 llvm::vfs::getRealFileSystem());
495 OverlayVFS->pushOverlay(IMVFS);
496 CI->createVirtualFileSystem(OverlayVFS);
497 CI->createFileManager();
504 std::unique_ptr<Interpreter> Interp = std::move(*InterpOrErr);
506 llvm::Error Err = llvm::Error::success();
508 auto DeviceAct = Interp->TSCtx->withContextDo([&](llvm::LLVMContext *Ctx) {
509 return std::make_unique<IncrementalAction>(*DCI, *Ctx, Err, *Interp);
513 return std::move(Err);
515 Interp->DeviceAct = std::move(DeviceAct);
517 DCI->ExecuteAction(*Interp->DeviceAct);
519 Interp->DeviceCI = std::move(DCI);
521 auto DeviceParser = std::make_unique<IncrementalCUDADeviceParser>(
522 *Interp->DeviceCI, *Interp->getCompilerInstance(),
523 Interp->DeviceAct.get(), IMVFS, Err, Interp->PTUs);
526 return std::move(Err);
528 Interp->DeviceParser = std::move(DeviceParser);
529 return std::move(Interp);
540 return std::move(Err);
543 return IncrExecutor->GetExecutionEngine();
554void Interpreter::markUserCodeStart() {
555 assert(!InitPTUSize &&
"We only do this once");
556 InitPTUSize = PTUs.size();
559size_t Interpreter::getEffectivePTUSize()
const {
560 assert(PTUs.size() >= InitPTUSize &&
"empty PTU list?");
561 return PTUs.size() - InitPTUSize;
566 return IncrExecutor->getOutOfProcessChildPid();
576 if (
auto E = DeviceTU.takeError())
579 DeviceParser->RegisterPTU(*DeviceTU);
583 return PTX.takeError();
585 llvm::Error Err = DeviceParser->GenerateFatbinary();
587 return std::move(Err);
597 return TuOrErr.takeError();
606 if (TT == llvm::sys::getProcessTriple())
608 return llvm::orc::JITTargetMachineBuilder::detectHost();
611 return llvm::orc::JITTargetMachineBuilder(llvm::Triple(TT));
616 std::unique_ptr<llvm::orc::ExecutorProcessControl> EPC,
617 llvm::StringRef OrcRuntimePath) {
618 const std::string &TT = EPC->getTargetTriple().getTriple();
621 return JTMB.takeError();
624 return JB.takeError();
626 (*JB)->setExecutorProcessControl(std::move(EPC));
627 (*JB)->setPlatformSetUp(
628 llvm::orc::ExecutorNativePlatform(OrcRuntimePath.str()));
630 return std::move(*JB);
635 return llvm::make_error<llvm::StringError>(
"Operation failed. "
636 "Execution engine exists",
638 if (!Act->getCodeGen())
639 return llvm::make_error<llvm::StringError>(
"Operation failed. "
640 "No code generator available",
644 llvm::Triple TargetTriple(TT);
645 bool IsWindowsTarget = TargetTriple.isOSWindows();
651 return ResOrErr.takeError();
652 JITBuilder = std::move(ResOrErr->first);
656 return llvm::make_error<llvm::StringError>(
657 "Operation failed. No LLJITBuilder for out-of-process JIT",
664 return JTMB.takeError();
666 JTMB->setCodeModel(Config.
CM);
669 return JB.takeError();
670 JITBuilder = std::move(*JB);
673 llvm::Error Err = llvm::Error::success();
676 std::unique_ptr<IncrementalExecutor> Executor;
679 Executor = std::make_unique<WasmIncrementalExecutor>(*TSCtx);
682 std::make_unique<IncrementalExecutor>(*TSCtx, *JITBuilder, Config, Err);
685 IncrExecutor = std::move(Executor);
695 llvm::dbgs() <<
"execute-ptu "
696 << (llvm::is_contained(PTUs,
T)
697 ? std::distance(PTUs.begin(), llvm::find(PTUs,
T))
699 <<
": [TU=" <<
T.TUPart <<
", M=" <<
T.TheModule.get()
700 <<
" (" <<
T.TheModule->getName() <<
")]\n");
707 if (
auto Err = IncrExecutor->addModule(
T))
710 if (
auto Err = IncrExecutor->runCtors())
713 return llvm::Error::success();
718 auto PTU =
Parse(Code);
720 return PTU.takeError();
722 if (llvm::Error Err =
Execute(*PTU))
725 if (LastValue.isValid()) {
730 *
V = std::move(LastValue);
732 return llvm::Error::success();
738 return llvm::make_error<llvm::StringError>(
"Operation failed. "
739 "No execution engine",
741 llvm::StringRef MangledName = Act->getCodeGen()->GetMangledName(GD);
748 return llvm::make_error<llvm::StringError>(
"Operation failed. "
749 "No execution engine",
758 return llvm::make_error<llvm::StringError>(
"Operation failed. "
759 "No execution engine",
767 if (getEffectivePTUSize() == 0) {
768 return llvm::make_error<llvm::StringError>(
"Operation failed. "
769 "No input left to undo",
771 }
else if (N > getEffectivePTUSize()) {
772 return llvm::make_error<llvm::StringError>(
774 "Operation failed. Wanted to undo {0} inputs, only have {1}.", N,
775 getEffectivePTUSize()),
779 for (
unsigned I = 0; I < N; I++) {
781 if (llvm::Error Err = IncrExecutor->removeModule(PTUs.back()))
785 IncrParser->CleanUpPTU(PTUs.back().TUPart);
788 return llvm::Error::success();
793 void *handle = dlopen(name, RTLD_NOW | RTLD_GLOBAL);
795 llvm::errs() << dlerror() <<
'\n';
796 return llvm::make_error<llvm::StringError>(
"Failed to load dynamic library",
797 llvm::inconvertibleErrorCode());
802 return EE.takeError();
805 std::unique_ptr<llvm::orc::EPCDynamicLibrarySearchGenerator>>
806 DLSG = llvm::orc::EPCDynamicLibrarySearchGenerator::Load(
807 EE->getExecutionSession(), name))
810 EE->getProcessSymbolsJITDylib()->addGenerator(std::move(*DLSG));
812 return DLSG.takeError();
815 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.