19#include "llvm/Support/VirtualFileSystem.h"
49#include "llvm/ExecutionEngine/JITSymbol.h"
50#include "llvm/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.h"
51#include "llvm/ExecutionEngine/Orc/LLJIT.h"
52#include "llvm/IR/Module.h"
53#include "llvm/Support/Errc.h"
54#include "llvm/Support/ErrorHandling.h"
55#include "llvm/Support/raw_ostream.h"
56#include "llvm/TargetParser/Host.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");
88CreateCI(
const llvm::opt::ArgStringList &Argv) {
93 auto PCHOps = Clang->getPCHContainerOperations();
94 PCHOps->registerWriter(std::make_unique<ObjectFilePCHContainerWriter>());
95 PCHOps->registerReader(std::make_unique<ObjectFilePCHContainerReader>());
103 Clang->getInvocation(),
llvm::ArrayRef(Argv.begin(), Argv.size()), Diags);
106 if (Clang->getHeaderSearchOpts().UseBuiltinIncludes &&
107 Clang->getHeaderSearchOpts().ResourceDir.empty())
108 Clang->getHeaderSearchOpts().ResourceDir =
111 Clang->createVirtualFileSystem();
114 Clang->createDiagnostics();
115 if (!Clang->hasDiagnostics())
116 return llvm::createStringError(llvm::errc::not_supported,
117 "Initialization failed. "
118 "Unable to create diagnostics engine");
122 return llvm::createStringError(llvm::errc::not_supported,
123 "Initialization failed. "
124 "Unable to flush diagnostics");
127 llvm::MemoryBuffer *MB = llvm::MemoryBuffer::getMemBuffer(
"").release();
128 Clang->getPreprocessorOpts().addRemappedFile(
"<<< inputs >>>", MB);
131 Clang->getDiagnostics(), Clang->getInvocation().getTargetOpts()));
132 if (!Clang->hasTarget())
133 return llvm::createStringError(llvm::errc::not_supported,
134 "Initialization failed. "
135 "Target is missing");
137 Clang->getTarget().adjust(Clang->getDiagnostics(), Clang->getLangOpts(),
138 Clang->getAuxTarget());
142 Clang->getCodeGenOpts().ClearASTBeforeBackend =
false;
144 Clang->getFrontendOpts().DisableFree =
false;
145 Clang->getCodeGenOpts().DisableFree =
false;
146 return std::move(Clang);
154IncrementalCompilerBuilder::create(std::string TT,
155 std::vector<const char *> &ClangArgv) {
159 std::string MainExecutableName =
160 llvm::sys::fs::getMainExecutable(
nullptr,
nullptr);
162 ClangArgv.insert(ClangArgv.begin(), MainExecutableName.c_str());
169 ClangArgv.insert(ClangArgv.end(),
"-Xclang");
170 ClangArgv.insert(ClangArgv.end(),
"-fincremental-extensions");
171 ClangArgv.insert(ClangArgv.end(),
"-c");
175 ClangArgv.push_back(
"<<< inputs >>>");
179 std::unique_ptr<DiagnosticOptions> DiagOpts =
181 TextDiagnosticBuffer *DiagsBuffer =
new TextDiagnosticBuffer;
184 driver::Driver
Driver(ClangArgv[0], TT, Diags);
185 Driver.setCheckInputsExist(
false);
186 llvm::ArrayRef<const char *> RF = llvm::ArrayRef(ClangArgv);
187 std::unique_ptr<driver::Compilation> Compilation(
Driver.BuildCompilation(RF));
189 if (Compilation->getArgs().hasArg(options::OPT_v))
190 Compilation->getJobs().Print(llvm::errs(),
"\n",
false);
192 auto ErrOrCC1Args = GetCC1Arguments(&Diags, Compilation.get());
193 if (
auto Err = ErrOrCC1Args.takeError())
194 return std::move(Err);
196 return CreateCI(**ErrOrCC1Args);
201 std::vector<const char *> Argv;
202 Argv.reserve(5 + 1 + UserArgs.size());
203 Argv.push_back(
"-xc++");
205 Argv.push_back(
"-target");
206 Argv.push_back(
"wasm32-unknown-emscripten");
207 Argv.push_back(
"-fvisibility=default");
209 llvm::append_range(Argv, UserArgs);
211 std::string TT = TargetTriple ? *TargetTriple : llvm::sys::getProcessTriple();
212 return IncrementalCompilerBuilder::create(TT, Argv);
216IncrementalCompilerBuilder::createCuda(
bool device) {
217 std::vector<const char *> Argv;
218 Argv.reserve(5 + 4 + UserArgs.size());
220 Argv.push_back(
"-xcuda");
222 Argv.push_back(
"--cuda-device-only");
224 Argv.push_back(
"--cuda-host-only");
226 std::string SDKPathArg =
"--cuda-path=";
227 if (!CudaSDKPath.empty()) {
228 SDKPathArg += CudaSDKPath;
229 Argv.push_back(SDKPathArg.c_str());
232 std::string ArchArg =
"--offload-arch=";
235 Argv.push_back(ArchArg.c_str());
238 llvm::append_range(Argv, UserArgs);
240 std::string TT = TargetTriple ? *TargetTriple : llvm::sys::getProcessTriple();
241 return IncrementalCompilerBuilder::create(TT, Argv);
246 return IncrementalCompilerBuilder::createCuda(
true);
251 return IncrementalCompilerBuilder::createCuda(
false);
256 std::unique_ptr<llvm::orc::LLJITBuilder> JITBuilder,
257 std::unique_ptr<clang::ASTConsumer> Consumer,
259 : JITBuilder(
std::move(JITBuilder)) {
260 CI = std::move(Instance);
261 llvm::ErrorAsOutParameter EAO(&ErrOut);
262 auto LLVMCtx = std::make_unique<llvm::LLVMContext>();
263 TSCtx = std::make_unique<llvm::orc::ThreadSafeContext>(std::move(LLVMCtx));
265 Act = TSCtx->withContextDo([&](llvm::LLVMContext *Ctx) {
266 return std::make_unique<IncrementalAction>(*CI, *Ctx, ErrOut, *
this,
267 std::move(Consumer));
272 CI->ExecuteAction(*Act);
275 std::make_unique<IncrementalParser>(*CI, Act.get(), ErrOut, PTUs);
280 if (Act->getCodeGen()) {
281 Act->CacheCodeGenModule();
284 if (!CI->getPreprocessorOpts().Includes.empty() ||
285 !CI->getPreprocessorOpts().ImplicitPCHInclude.empty()) {
289 auto M = llvm::CloneModule(*Act->getCachedCodeGenModule());
291 IncrParser->RegisterPTU(
C.getTranslationUnitDecl(), std::move(M));
294 ErrOut = joinErrors(std::move(ErrOut), std::move(Err));
300 if (Act->getCodeGen()) {
304 if (llvm::Error Err =
Execute(PTU)) {
305 ErrOut = joinErrors(std::move(ErrOut), std::move(Err));
313 Act->FinalizeAction();
315 DeviceParser.reset();
317 DeviceAct->FinalizeAction();
319 if (llvm::Error Err = IncrExecutor->cleanUp())
320 llvm::report_fatal_error(
321 llvm::Twine(
"Failed to clean up IncrementalExecutor: ") +
330 #define __CLANG_REPL__ 1
332 #define EXTERN_C extern "C"
333 struct __clang_Interpreter_NewTag{} __ci_newtag;
334 void* operator new(__SIZE_TYPE__, void* __p, __clang_Interpreter_NewTag) noexcept;
335 template <class T, class = T (*)() /*disable for arrays*/>
336 void __clang_Interpreter_SetValueCopyArr(const T* Src, void* Placement, unsigned long Size) {
337 for (auto Idx = 0; Idx < Size; ++Idx)
338 new ((void*)(((T*)Placement) + Idx), __ci_newtag) T(Src[Idx]);
340 template <class T, unsigned long N>
341 void __clang_Interpreter_SetValueCopyArr(const T (*Src)[N], void* Placement, unsigned long Size) {
342 __clang_Interpreter_SetValueCopyArr(Src[0], Placement, Size);
345 #define EXTERN_C extern
346 EXTERN_C void *memcpy(void *restrict dst, const void *restrict src, __SIZE_TYPE__ n);
347 EXTERN_C inline void __clang_Interpreter_SetValueCopyArr(const void* Src, void* Placement, unsigned long Size) {
348 memcpy(Placement, Src, Size);
351 EXTERN_C void *__clang_Interpreter_SetValueWithAlloc(void*, void*, void*);
352 EXTERN_C void __clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal, void *OpaqueType, ...);
357 std::unique_ptr<llvm::orc::ExecutorProcessControl> EPC;
358 uint32_t childPid = -1;
365 return ResultOrErr.takeError();
366 childPid = ResultOrErr->second;
367 auto EPCOrErr = std::move(ResultOrErr->first);
368 EPC = std::move(EPCOrErr);
370#if LLVM_ON_UNIX && LLVM_ENABLE_THREADS
371 auto EPCOrErr = IncrementalExecutor::connectTCPSocket(
375 return EPCOrErr.takeError();
376 EPC = std::move(*EPCOrErr);
378 return llvm::make_error<llvm::StringError>(
379 "Out-of-process JIT over TCP is not supported on this platform",
384 std::unique_ptr<llvm::orc::LLJITBuilder> JB;
389 return JBOrErr.takeError();
390 JB = std::move(*JBOrErr);
393 return std::make_pair(std::move(JB), childPid);
398 const std::array<const char *, 3> OrcRTLibNames = {
399 "liborc_rt.a",
"liborc_rt_osx.a",
"liborc_rt-x86_64.a"};
401 auto findInDir = [&](llvm::StringRef
Base) -> std::optional<std::string> {
402 for (
const char *LibName : OrcRTLibNames) {
404 llvm::sys::path::append(CandidatePath, LibName);
405 if (llvm::sys::fs::exists(CandidatePath))
406 return std::string(CandidatePath.str());
411 std::string SearchedPaths;
414 if (
auto Found = findInDir(*CompilerRTPath))
416 SearchedPaths += *CompilerRTPath;
418 return llvm::make_error<llvm::StringError>(
"CompilerRT path not found",
422 if (std::optional<std::string> ResourceDir = TC.
getRuntimePath()) {
423 if (
auto Found = findInDir(*ResourceDir))
425 if (!SearchedPaths.empty())
426 SearchedPaths +=
"; ";
427 SearchedPaths += *ResourceDir;
429 return llvm::make_error<llvm::StringError>(
"ResourceDir path not found",
433 return llvm::make_error<llvm::StringError>(
434 llvm::Twine(
"OrcRuntime library not found in: ") + SearchedPaths,
443 const llvm::Triple &Triple = TI.
getTriple();
446 std::string BinaryName = llvm::sys::fs::getMainExecutable(
nullptr,
nullptr);
449 std::vector<const char *> Args = {
"clang",
"--version"};
450 std::unique_ptr<clang::driver::Compilation>
C(
451 Driver.BuildCompilation(Args));
453 return llvm::make_error<llvm::StringError>(
454 "Failed to create driver compilation for out-of-process JIT",
461 if (!OrcRuntimePathOrErr) {
462 return OrcRuntimePathOrErr.takeError();
469 llvm::Error Err = llvm::Error::success();
470 std::unique_ptr<llvm::orc::LLJITBuilder> JB;
472 auto Interp = std::unique_ptr<Interpreter>(
new Interpreter(
473 std::move(CI), Err, std::move(JB),
nullptr, Config));
474 if (
auto E = std::move(Err))
479 if (
auto E = Interp->ParseAndExecute(
Runtimes))
482 Interp->markUserCodeStart();
484 return std::move(Interp);
489 std::unique_ptr<CompilerInstance> DCI) {
492 std::make_unique<llvm::vfs::InMemoryFileSystem>();
494 std::make_unique<llvm::vfs::OverlayFileSystem>(
495 llvm::vfs::getRealFileSystem());
496 OverlayVFS->pushOverlay(IMVFS);
497 CI->createVirtualFileSystem(OverlayVFS);
498 CI->createFileManager();
505 std::unique_ptr<Interpreter> Interp = std::move(*InterpOrErr);
507 llvm::Error Err = llvm::Error::success();
509 auto DeviceAct = Interp->TSCtx->withContextDo([&](llvm::LLVMContext *Ctx) {
510 return std::make_unique<IncrementalAction>(*DCI, *Ctx, Err, *Interp);
514 return std::move(Err);
516 Interp->DeviceAct = std::move(DeviceAct);
518 DCI->ExecuteAction(*Interp->DeviceAct);
520 Interp->DeviceCI = std::move(DCI);
522 auto DeviceParser = std::make_unique<IncrementalCUDADeviceParser>(
523 *Interp->DeviceCI, *Interp->getCompilerInstance(),
524 Interp->DeviceAct.get(), IMVFS, Err, Interp->PTUs);
527 return std::move(Err);
529 Interp->DeviceParser = std::move(DeviceParser);
530 return std::move(Interp);
541 return std::move(Err);
544 return IncrExecutor->GetExecutionEngine();
555void Interpreter::markUserCodeStart() {
556 assert(!InitPTUSize &&
"We only do this once");
557 InitPTUSize = PTUs.size();
560size_t Interpreter::getEffectivePTUSize()
const {
561 assert(PTUs.size() >= InitPTUSize &&
"empty PTU list?");
562 return PTUs.size() - InitPTUSize;
567 return IncrExecutor->getOutOfProcessChildPid();
577 if (
auto E = DeviceTU.takeError())
580 DeviceParser->RegisterPTU(*DeviceTU);
584 return PTX.takeError();
586 llvm::Error Err = DeviceParser->GenerateFatbinary();
588 return std::move(Err);
598 return TuOrErr.takeError();
607 if (TT == llvm::sys::getProcessTriple())
609 return llvm::orc::JITTargetMachineBuilder::detectHost();
612 return llvm::orc::JITTargetMachineBuilder(llvm::Triple(TT));
617 std::unique_ptr<llvm::orc::ExecutorProcessControl> EPC,
618 llvm::StringRef OrcRuntimePath) {
619 const std::string &TT = EPC->getTargetTriple().getTriple();
622 return JTMB.takeError();
625 return JB.takeError();
627 (*JB)->setExecutorProcessControl(std::move(EPC));
628 (*JB)->setPlatformSetUp(
629 llvm::orc::ExecutorNativePlatform(OrcRuntimePath.str()));
631 return std::move(*JB);
636 return llvm::make_error<llvm::StringError>(
"Operation failed. "
637 "Execution engine exists",
639 if (!Act->getCodeGen())
640 return llvm::make_error<llvm::StringError>(
"Operation failed. "
641 "No code generator available",
645 llvm::Triple TargetTriple(TT);
646 bool IsWindowsTarget = TargetTriple.isOSWindows();
652 return ResOrErr.takeError();
653 JITBuilder = std::move(ResOrErr->first);
657 return llvm::make_error<llvm::StringError>(
658 "Operation failed. No LLJITBuilder for out-of-process JIT",
665 return JTMB.takeError();
667 JTMB->setCodeModel(Config.
CM);
670 return JB.takeError();
671 JITBuilder = std::move(*JB);
674 llvm::Error Err = llvm::Error::success();
677 std::unique_ptr<IncrementalExecutor> Executor;
680 Executor = std::make_unique<WasmIncrementalExecutor>(*TSCtx);
683 std::make_unique<IncrementalExecutor>(*TSCtx, *JITBuilder, Config, Err);
686 IncrExecutor = std::move(Executor);
696 llvm::dbgs() <<
"execute-ptu "
697 << (llvm::is_contained(PTUs,
T)
698 ? std::distance(PTUs.begin(), llvm::find(PTUs,
T))
700 <<
": [TU=" <<
T.TUPart <<
", M=" <<
T.TheModule.get()
701 <<
" (" <<
T.TheModule->getName() <<
")]\n");
708 if (
auto Err = IncrExecutor->addModule(
T))
711 if (
auto Err = IncrExecutor->runCtors())
714 return llvm::Error::success();
719 auto PTU =
Parse(Code);
721 return PTU.takeError();
723 if (llvm::Error Err =
Execute(*PTU))
726 if (LastValue.isValid()) {
731 *
V = std::move(LastValue);
733 return llvm::Error::success();
739 return llvm::make_error<llvm::StringError>(
"Operation failed. "
740 "No execution engine",
742 llvm::StringRef MangledName = Act->getCodeGen()->GetMangledName(GD);
749 return llvm::make_error<llvm::StringError>(
"Operation failed. "
750 "No execution engine",
759 return llvm::make_error<llvm::StringError>(
"Operation failed. "
760 "No execution engine",
768 if (getEffectivePTUSize() == 0) {
769 return llvm::make_error<llvm::StringError>(
"Operation failed. "
770 "No input left to undo",
772 }
else if (N > getEffectivePTUSize()) {
773 return llvm::make_error<llvm::StringError>(
775 "Operation failed. Wanted to undo {0} inputs, only have {1}.", N,
776 getEffectivePTUSize()),
780 for (
unsigned I = 0; I < N; I++) {
782 if (llvm::Error Err = IncrExecutor->removeModule(PTUs.back()))
786 IncrParser->CleanUpPTU(PTUs.back().TUPart);
789 return llvm::Error::success();
794 void *handle = dlopen(name, RTLD_NOW | RTLD_GLOBAL);
796 llvm::errs() << dlerror() <<
'\n';
797 return llvm::make_error<llvm::StringError>(
"Failed to load dynamic library",
798 llvm::inconvertibleErrorCode());
803 return EE.takeError();
806 std::unique_ptr<llvm::orc::EPCDynamicLibrarySearchGenerator>>
807 DLSG = llvm::orc::EPCDynamicLibrarySearchGenerator::Load(
808 EE->getExecutionSession(), name))
811 EE->getProcessSymbolsJITDylib()->addGenerator(std::move(*DLSG));
813 return DLSG.takeError();
816 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 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
std::string GetResourcesPath(StringRef BinaryPath)
Get the directory where the compiler headers reside, relative to the compiler binary path BinaryPath.
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.