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();
118 return llvm::createStringError(llvm::errc::not_supported,
119 "Initialization failed. "
120 "Unable to flush diagnostics");
123 llvm::MemoryBuffer *MB = llvm::MemoryBuffer::getMemBuffer(
"").release();
124 Clang->getPreprocessorOpts().addRemappedFile(
"<<< inputs >>>", MB);
127 Clang->getDiagnostics(), Clang->getInvocation().getTargetOpts()));
128 if (!Clang->hasTarget())
129 return llvm::createStringError(llvm::errc::not_supported,
130 "Initialization failed. "
131 "Target is missing");
133 Clang->getTarget().adjust(Clang->getDiagnostics(), Clang->getLangOpts(),
134 Clang->getAuxTarget());
138 Clang->getCodeGenOpts().ClearASTBeforeBackend =
false;
140 Clang->getFrontendOpts().DisableFree =
false;
141 Clang->getCodeGenOpts().DisableFree =
false;
142 return std::move(Clang);
150IncrementalCompilerBuilder::create(std::string TT,
151 std::vector<const char *> &ClangArgv) {
155 std::string MainExecutableName =
156 llvm::sys::fs::getMainExecutable(
nullptr,
nullptr);
158 ClangArgv.insert(ClangArgv.begin(), MainExecutableName.c_str());
165 ClangArgv.insert(ClangArgv.end(),
"-Xclang");
166 ClangArgv.insert(ClangArgv.end(),
"-fincremental-extensions");
167 ClangArgv.insert(ClangArgv.end(),
"-c");
171 ClangArgv.push_back(
"<<< inputs >>>");
175 std::unique_ptr<DiagnosticOptions> DiagOpts =
177 TextDiagnosticBuffer *DiagsBuffer =
new TextDiagnosticBuffer;
180 driver::Driver
Driver(ClangArgv[0], TT, Diags);
181 Driver.setCheckInputsExist(
false);
182 llvm::ArrayRef<const char *> RF = llvm::ArrayRef(ClangArgv);
183 std::unique_ptr<driver::Compilation> Compilation(
Driver.BuildCompilation(RF));
185 if (Compilation->getArgs().hasArg(options::OPT_v))
186 Compilation->getJobs().Print(llvm::errs(),
"\n",
false);
188 auto ErrOrCC1Args = GetCC1Arguments(&Diags, Compilation.get());
189 if (
auto Err = ErrOrCC1Args.takeError())
190 return std::move(Err);
192 return CreateCI(**ErrOrCC1Args);
197 std::vector<const char *> Argv;
198 Argv.reserve(5 + 1 + UserArgs.size());
199 Argv.push_back(
"-xc++");
201 Argv.push_back(
"-target");
202 Argv.push_back(
"wasm32-unknown-emscripten");
203 Argv.push_back(
"-fvisibility=default");
205 llvm::append_range(Argv, UserArgs);
207 std::string TT = TargetTriple ? *TargetTriple : llvm::sys::getProcessTriple();
208 return IncrementalCompilerBuilder::create(TT, Argv);
212IncrementalCompilerBuilder::createCuda(
bool device) {
213 std::vector<const char *> Argv;
214 Argv.reserve(5 + 4 + UserArgs.size());
216 Argv.push_back(
"-xcuda");
218 Argv.push_back(
"--cuda-device-only");
220 Argv.push_back(
"--cuda-host-only");
222 std::string SDKPathArg =
"--cuda-path=";
223 if (!CudaSDKPath.empty()) {
224 SDKPathArg += CudaSDKPath;
225 Argv.push_back(SDKPathArg.c_str());
228 std::string ArchArg =
"--offload-arch=";
231 Argv.push_back(ArchArg.c_str());
234 llvm::append_range(Argv, UserArgs);
236 std::string TT = TargetTriple ? *TargetTriple : llvm::sys::getProcessTriple();
237 return IncrementalCompilerBuilder::create(TT, Argv);
242 return IncrementalCompilerBuilder::createCuda(
true);
247 return IncrementalCompilerBuilder::createCuda(
false);
252 std::unique_ptr<llvm::orc::LLJITBuilder> JITBuilder,
253 std::unique_ptr<clang::ASTConsumer> Consumer,
255 : JITBuilder(
std::move(JITBuilder)) {
256 CI = std::move(Instance);
257 llvm::ErrorAsOutParameter EAO(&ErrOut);
258 auto LLVMCtx = std::make_unique<llvm::LLVMContext>();
259 TSCtx = std::make_unique<llvm::orc::ThreadSafeContext>(std::move(LLVMCtx));
261 Act = TSCtx->withContextDo([&](llvm::LLVMContext *Ctx) {
262 return std::make_unique<IncrementalAction>(*CI, *Ctx, ErrOut, *
this,
263 std::move(Consumer));
268 CI->ExecuteAction(*Act);
271 std::make_unique<IncrementalParser>(*CI, Act.get(), ErrOut, PTUs);
276 if (Act->getCodeGen()) {
277 Act->CacheCodeGenModule();
280 if (!CI->getPreprocessorOpts().Includes.empty() ||
281 !CI->getPreprocessorOpts().ImplicitPCHInclude.empty()) {
285 auto M = llvm::CloneModule(*Act->getCachedCodeGenModule());
287 IncrParser->RegisterPTU(
C.getTranslationUnitDecl(), std::move(M));
290 ErrOut = joinErrors(std::move(ErrOut), std::move(Err));
296 if (Act->getCodeGen()) {
300 if (llvm::Error Err =
Execute(PTU)) {
301 ErrOut = joinErrors(std::move(ErrOut), std::move(Err));
309 Act->FinalizeAction();
311 DeviceParser.reset();
313 DeviceAct->FinalizeAction();
315 if (llvm::Error Err = IncrExecutor->cleanUp())
316 llvm::report_fatal_error(
317 llvm::Twine(
"Failed to clean up IncrementalExecutor: ") +
326 #define __CLANG_REPL__ 1
328 #define EXTERN_C extern "C"
329 struct __clang_Interpreter_NewTag{} __ci_newtag;
330 void* operator new(__SIZE_TYPE__, void* __p, __clang_Interpreter_NewTag) noexcept;
331 template <class T, class = T (*)() /*disable for arrays*/>
332 void __clang_Interpreter_SetValueCopyArr(const T* Src, void* Placement, unsigned long Size) {
333 for (auto Idx = 0; Idx < Size; ++Idx)
334 new ((void*)(((T*)Placement) + Idx), __ci_newtag) T(Src[Idx]);
336 template <class T, unsigned long N>
337 void __clang_Interpreter_SetValueCopyArr(const T (*Src)[N], void* Placement, unsigned long Size) {
338 __clang_Interpreter_SetValueCopyArr(Src[0], Placement, Size);
341 #define EXTERN_C extern
342 EXTERN_C void *memcpy(void *restrict dst, const void *restrict src, __SIZE_TYPE__ n);
343 EXTERN_C inline void __clang_Interpreter_SetValueCopyArr(const void* Src, void* Placement, unsigned long Size) {
344 memcpy(Placement, Src, Size);
347 EXTERN_C void *__clang_Interpreter_SetValueWithAlloc(void*, void*, void*);
348 EXTERN_C void __clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal, void *OpaqueType, ...);
353 std::unique_ptr<llvm::orc::ExecutorProcessControl> EPC;
354 uint32_t childPid = -1;
361 return ResultOrErr.takeError();
362 childPid = ResultOrErr->second;
363 auto EPCOrErr = std::move(ResultOrErr->first);
364 EPC = std::move(EPCOrErr);
366#if LLVM_ON_UNIX && LLVM_ENABLE_THREADS
367 auto EPCOrErr = IncrementalExecutor::connectTCPSocket(
371 return EPCOrErr.takeError();
372 EPC = std::move(*EPCOrErr);
374 return llvm::make_error<llvm::StringError>(
375 "Out-of-process JIT over TCP is not supported on this platform",
380 std::unique_ptr<llvm::orc::LLJITBuilder> JB;
385 return JBOrErr.takeError();
386 JB = std::move(*JBOrErr);
389 return std::make_pair(std::move(JB), childPid);
394 const std::array<const char *, 3> OrcRTLibNames = {
395 "liborc_rt.a",
"liborc_rt_osx.a",
"liborc_rt-x86_64.a"};
397 auto findInDir = [&](llvm::StringRef
Base) -> std::optional<std::string> {
398 for (
const char *LibName : OrcRTLibNames) {
400 llvm::sys::path::append(CandidatePath, LibName);
401 if (llvm::sys::fs::exists(CandidatePath))
402 return std::string(CandidatePath.str());
407 std::string SearchedPaths;
410 if (
auto Found = findInDir(*CompilerRTPath))
412 SearchedPaths += *CompilerRTPath;
414 return llvm::make_error<llvm::StringError>(
"CompilerRT path not found",
418 if (std::optional<std::string> ResourceDir = TC.
getRuntimePath()) {
419 if (
auto Found = findInDir(*ResourceDir))
421 if (!SearchedPaths.empty())
422 SearchedPaths +=
"; ";
423 SearchedPaths += *ResourceDir;
425 return llvm::make_error<llvm::StringError>(
"ResourceDir path not found",
429 return llvm::make_error<llvm::StringError>(
430 llvm::Twine(
"OrcRuntime library not found in: ") + SearchedPaths,
439 const llvm::Triple &Triple = TI.
getTriple();
442 std::string BinaryName = llvm::sys::fs::getMainExecutable(
nullptr,
nullptr);
445 std::vector<const char *> Args = {
"clang",
"--version"};
446 std::unique_ptr<clang::driver::Compilation>
C(
447 Driver.BuildCompilation(Args));
449 return llvm::make_error<llvm::StringError>(
450 "Failed to create driver compilation for out-of-process JIT",
457 if (!OrcRuntimePathOrErr) {
458 return OrcRuntimePathOrErr.takeError();
465 llvm::Error Err = llvm::Error::success();
466 std::unique_ptr<llvm::orc::LLJITBuilder> JB;
468 auto Interp = std::unique_ptr<Interpreter>(
new Interpreter(
469 std::move(CI), Err, std::move(JB),
nullptr, Config));
470 if (
auto E = std::move(Err))
475 if (
auto E = Interp->ParseAndExecute(
Runtimes))
478 Interp->markUserCodeStart();
480 return std::move(Interp);
485 std::unique_ptr<CompilerInstance> DCI) {
488 std::make_unique<llvm::vfs::InMemoryFileSystem>();
490 std::make_unique<llvm::vfs::OverlayFileSystem>(
491 llvm::vfs::getRealFileSystem());
492 OverlayVFS->pushOverlay(IMVFS);
493 CI->createVirtualFileSystem(OverlayVFS);
494 CI->createFileManager();
501 std::unique_ptr<Interpreter> Interp = std::move(*InterpOrErr);
503 llvm::Error Err = llvm::Error::success();
505 auto DeviceAct = Interp->TSCtx->withContextDo([&](llvm::LLVMContext *Ctx) {
506 return std::make_unique<IncrementalAction>(*DCI, *Ctx, Err, *Interp);
510 return std::move(Err);
512 Interp->DeviceAct = std::move(DeviceAct);
514 DCI->ExecuteAction(*Interp->DeviceAct);
516 Interp->DeviceCI = std::move(DCI);
518 auto DeviceParser = std::make_unique<IncrementalCUDADeviceParser>(
519 *Interp->DeviceCI, *Interp->getCompilerInstance(),
520 Interp->DeviceAct.get(), IMVFS, Err, Interp->PTUs);
523 return std::move(Err);
525 Interp->DeviceParser = std::move(DeviceParser);
526 return std::move(Interp);
537 return std::move(Err);
540 return IncrExecutor->GetExecutionEngine();
551void Interpreter::markUserCodeStart() {
552 assert(!InitPTUSize &&
"We only do this once");
553 InitPTUSize = PTUs.size();
556size_t Interpreter::getEffectivePTUSize()
const {
557 assert(PTUs.size() >= InitPTUSize &&
"empty PTU list?");
558 return PTUs.size() - InitPTUSize;
563 return IncrExecutor->getOutOfProcessChildPid();
573 if (
auto E = DeviceTU.takeError())
576 DeviceParser->RegisterPTU(*DeviceTU);
580 return PTX.takeError();
582 llvm::Error Err = DeviceParser->GenerateFatbinary();
584 return std::move(Err);
594 return TuOrErr.takeError();
603 if (TT == llvm::sys::getProcessTriple())
605 return llvm::orc::JITTargetMachineBuilder::detectHost();
608 return llvm::orc::JITTargetMachineBuilder(llvm::Triple(TT));
613 std::unique_ptr<llvm::orc::ExecutorProcessControl> EPC,
614 llvm::StringRef OrcRuntimePath) {
615 const std::string &TT = EPC->getTargetTriple().getTriple();
618 return JTMB.takeError();
621 return JB.takeError();
623 (*JB)->setExecutorProcessControl(std::move(EPC));
624 (*JB)->setPlatformSetUp(
625 llvm::orc::ExecutorNativePlatform(OrcRuntimePath.str()));
627 return std::move(*JB);
632 return llvm::make_error<llvm::StringError>(
"Operation failed. "
633 "Execution engine exists",
635 if (!Act->getCodeGen())
636 return llvm::make_error<llvm::StringError>(
"Operation failed. "
637 "No code generator available",
641 llvm::Triple TargetTriple(TT);
642 bool IsWindowsTarget = TargetTriple.isOSWindows();
648 return ResOrErr.takeError();
649 JITBuilder = std::move(ResOrErr->first);
653 return llvm::make_error<llvm::StringError>(
654 "Operation failed. No LLJITBuilder for out-of-process JIT",
661 return JTMB.takeError();
663 JTMB->setCodeModel(Config.
CM);
666 return JB.takeError();
667 JITBuilder = std::move(*JB);
670 llvm::Error Err = llvm::Error::success();
673 std::unique_ptr<IncrementalExecutor> Executor;
676 Executor = std::make_unique<WasmIncrementalExecutor>(*TSCtx);
679 std::make_unique<IncrementalExecutor>(*TSCtx, *JITBuilder, Config, Err);
682 IncrExecutor = std::move(Executor);
692 llvm::dbgs() <<
"execute-ptu "
693 << (llvm::is_contained(PTUs,
T)
694 ? std::distance(PTUs.begin(), llvm::find(PTUs,
T))
696 <<
": [TU=" <<
T.TUPart <<
", M=" <<
T.TheModule.get()
697 <<
" (" <<
T.TheModule->getName() <<
")]\n");
704 if (
auto Err = IncrExecutor->addModule(
T))
707 if (
auto Err = IncrExecutor->runCtors())
710 return llvm::Error::success();
715 auto PTU =
Parse(Code);
717 return PTU.takeError();
719 if (llvm::Error Err =
Execute(*PTU))
722 if (LastValue.isValid()) {
727 *
V = std::move(LastValue);
729 return llvm::Error::success();
735 return llvm::make_error<llvm::StringError>(
"Operation failed. "
736 "No execution engine",
738 llvm::StringRef MangledName = Act->getCodeGen()->GetMangledName(GD);
745 return llvm::make_error<llvm::StringError>(
"Operation failed. "
746 "No execution engine",
755 return llvm::make_error<llvm::StringError>(
"Operation failed. "
756 "No execution engine",
764 if (getEffectivePTUSize() == 0) {
765 return llvm::make_error<llvm::StringError>(
"Operation failed. "
766 "No input left to undo",
768 }
else if (N > getEffectivePTUSize()) {
769 return llvm::make_error<llvm::StringError>(
771 "Operation failed. Wanted to undo {0} inputs, only have {1}.", N,
772 getEffectivePTUSize()),
776 for (
unsigned I = 0; I < N; I++) {
778 if (llvm::Error Err = IncrExecutor->removeModule(PTUs.back()))
782 IncrParser->CleanUpPTU(PTUs.back().TUPart);
785 return llvm::Error::success();
790 void *handle = dlopen(name, RTLD_NOW | RTLD_GLOBAL);
792 llvm::errs() << dlerror() <<
'\n';
793 return llvm::make_error<llvm::StringError>(
"Failed to load dynamic library",
794 llvm::inconvertibleErrorCode());
799 return EE.takeError();
802 std::unique_ptr<llvm::orc::EPCDynamicLibrarySearchGenerator>>
803 DLSG = llvm::orc::EPCDynamicLibrarySearchGenerator::Load(
804 EE->getExecutionSession(), name))
807 EE->getProcessSymbolsJITDylib()->addGenerator(std::move(*DLSG));
809 return DLSG.takeError();
812 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.