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()) {
287 auto M = llvm::CloneModule(*Act->getCachedCodeGenModule());
289 IncrParser->RegisterPTU(
C.getTranslationUnitDecl(), std::move(M));
292 ErrOut = joinErrors(std::move(ErrOut), std::move(Err));
298 if (Act->getCodeGen()) {
302 if (llvm::Error Err =
Execute(PTU)) {
303 ErrOut = joinErrors(std::move(ErrOut), std::move(Err));
311 Act->FinalizeAction();
313 DeviceParser.reset();
315 DeviceAct->FinalizeAction();
317 if (llvm::Error Err = IncrExecutor->cleanUp())
318 llvm::report_fatal_error(
319 llvm::Twine(
"Failed to clean up IncrementalExecutor: ") +
328 #define __CLANG_REPL__ 1
330 #define EXTERN_C extern "C"
331 struct __clang_Interpreter_NewTag{} __ci_newtag;
332 void* operator new(__SIZE_TYPE__, void* __p, __clang_Interpreter_NewTag) noexcept;
333 template <class T, class = T (*)() /*disable for arrays*/>
334 void __clang_Interpreter_SetValueCopyArr(const T* Src, void* Placement, unsigned long Size) {
335 for (auto Idx = 0; Idx < Size; ++Idx)
336 new ((void*)(((T*)Placement) + Idx), __ci_newtag) T(Src[Idx]);
338 template <class T, unsigned long N>
339 void __clang_Interpreter_SetValueCopyArr(const T (*Src)[N], void* Placement, unsigned long Size) {
340 __clang_Interpreter_SetValueCopyArr(Src[0], Placement, Size);
343 #define EXTERN_C extern
344 EXTERN_C void *memcpy(void *restrict dst, const void *restrict src, __SIZE_TYPE__ n);
345 EXTERN_C inline void __clang_Interpreter_SetValueCopyArr(const void* Src, void* Placement, unsigned long Size) {
346 memcpy(Placement, Src, Size);
349 EXTERN_C void *__clang_Interpreter_SetValueWithAlloc(void*, void*, void*);
350 EXTERN_C void __clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal, void *OpaqueType, ...);
355 std::unique_ptr<llvm::orc::ExecutorProcessControl> EPC;
356 uint32_t childPid = -1;
363 return ResultOrErr.takeError();
364 childPid = ResultOrErr->second;
365 auto EPCOrErr = std::move(ResultOrErr->first);
366 EPC = std::move(EPCOrErr);
368#if LLVM_ON_UNIX && LLVM_ENABLE_THREADS
369 auto EPCOrErr = IncrementalExecutor::connectTCPSocket(
373 return EPCOrErr.takeError();
374 EPC = std::move(*EPCOrErr);
376 return llvm::make_error<llvm::StringError>(
377 "Out-of-process JIT over TCP is not supported on this platform",
382 std::unique_ptr<llvm::orc::LLJITBuilder> JB;
387 return JBOrErr.takeError();
388 JB = std::move(*JBOrErr);
391 return std::make_pair(std::move(JB), childPid);
399 if (!CompilerRTPath) {
400 return llvm::make_error<llvm::StringError>(
"CompilerRT path not found",
404 const std::array<const char *, 3> OrcRTLibNames = {
405 "liborc_rt.a",
"liborc_rt_osx.a",
"liborc_rt-x86_64.a"};
407 for (
const char *LibName : OrcRTLibNames) {
409 llvm::sys::path::append(CandidatePath, LibName);
411 if (llvm::sys::fs::exists(CandidatePath)) {
412 return CandidatePath.str().str();
416 return llvm::make_error<llvm::StringError>(
417 llvm::Twine(
"OrcRuntime library not found in: ") + (*CompilerRTPath),
423 llvm::Error Err = llvm::Error::success();
425 std::unique_ptr<llvm::orc::LLJITBuilder> JB;
429 const llvm::Triple &Triple = TI.
getTriple();
432 std::string BinaryName = llvm::sys::fs::getMainExecutable(
nullptr,
nullptr);
435 std::vector<const char *> Args = {
"clang",
"--version"};
436 std::unique_ptr<clang::driver::Compilation>
C(
437 Driver.BuildCompilation(Args));
439 return llvm::make_error<llvm::StringError>(
440 "Failed to create driver compilation for out-of-process JIT",
447 if (!OrcRuntimePathOrErr) {
448 return OrcRuntimePathOrErr.takeError();
455 auto Interp = std::unique_ptr<Interpreter>(
new Interpreter(
456 std::move(CI), Err, std::move(JB),
nullptr, Config));
457 if (
auto E = std::move(Err))
462 if (
auto E = Interp->ParseAndExecute(
Runtimes))
465 Interp->markUserCodeStart();
467 return std::move(Interp);
472 std::unique_ptr<CompilerInstance> DCI) {
475 std::make_unique<llvm::vfs::InMemoryFileSystem>();
477 std::make_unique<llvm::vfs::OverlayFileSystem>(
478 llvm::vfs::getRealFileSystem());
479 OverlayVFS->pushOverlay(IMVFS);
480 CI->createVirtualFileSystem(OverlayVFS);
481 CI->createFileManager();
488 std::unique_ptr<Interpreter> Interp = std::move(*InterpOrErr);
490 llvm::Error Err = llvm::Error::success();
492 auto DeviceAct = Interp->TSCtx->withContextDo([&](llvm::LLVMContext *Ctx) {
493 return std::make_unique<IncrementalAction>(*DCI, *Ctx, Err, *Interp);
497 return std::move(Err);
499 Interp->DeviceAct = std::move(DeviceAct);
501 DCI->ExecuteAction(*Interp->DeviceAct);
503 Interp->DeviceCI = std::move(DCI);
505 auto DeviceParser = std::make_unique<IncrementalCUDADeviceParser>(
506 *Interp->DeviceCI, *Interp->getCompilerInstance(),
507 Interp->DeviceAct.get(), IMVFS, Err, Interp->PTUs);
510 return std::move(Err);
512 Interp->DeviceParser = std::move(DeviceParser);
513 return std::move(Interp);
524 return std::move(Err);
527 return IncrExecutor->GetExecutionEngine();
538void Interpreter::markUserCodeStart() {
539 assert(!InitPTUSize &&
"We only do this once");
540 InitPTUSize = PTUs.size();
543size_t Interpreter::getEffectivePTUSize()
const {
544 assert(PTUs.size() >= InitPTUSize &&
"empty PTU list?");
545 return PTUs.size() - InitPTUSize;
550 return IncrExecutor->getOutOfProcessChildPid();
560 if (
auto E = DeviceTU.takeError())
563 DeviceParser->RegisterPTU(*DeviceTU);
567 return PTX.takeError();
569 llvm::Error Err = DeviceParser->GenerateFatbinary();
571 return std::move(Err);
581 return TuOrErr.takeError();
585 LastPTU.
TUPart = *TuOrErr;
587 if (std::unique_ptr<llvm::Module> M = Act->GenModule())
595 if (TT == llvm::sys::getProcessTriple())
597 return llvm::orc::JITTargetMachineBuilder::detectHost();
600 return llvm::orc::JITTargetMachineBuilder(llvm::Triple(TT));
605 std::unique_ptr<llvm::orc::ExecutorProcessControl> EPC,
606 llvm::StringRef OrcRuntimePath) {
607 const std::string &TT = EPC->getTargetTriple().getTriple();
610 return JTMB.takeError();
613 return JB.takeError();
615 (*JB)->setExecutorProcessControl(std::move(EPC));
616 (*JB)->setPlatformSetUp(
617 llvm::orc::ExecutorNativePlatform(OrcRuntimePath.str()));
619 return std::move(*JB);
624 return llvm::make_error<llvm::StringError>(
"Operation failed. "
625 "Execution engine exists",
627 if (!Act->getCodeGen())
628 return llvm::make_error<llvm::StringError>(
"Operation failed. "
629 "No code generator available",
633 llvm::Triple TargetTriple(TT);
634 bool IsWindowsTarget = TargetTriple.isOSWindows();
640 return ResOrErr.takeError();
641 JITBuilder = std::move(ResOrErr->first);
645 return llvm::make_error<llvm::StringError>(
646 "Operation failed. No LLJITBuilder for out-of-process JIT",
653 return JTMB.takeError();
655 JTMB->setCodeModel(Config.
CM);
658 return JB.takeError();
659 JITBuilder = std::move(*JB);
662 llvm::Error Err = llvm::Error::success();
665 std::unique_ptr<IncrementalExecutor> Executor;
668 Executor = std::make_unique<WasmIncrementalExecutor>(*TSCtx);
671 std::make_unique<IncrementalExecutor>(*TSCtx, *JITBuilder, Config, Err);
674 IncrExecutor = std::move(Executor);
684 llvm::dbgs() <<
"execute-ptu "
685 << (llvm::is_contained(PTUs,
T)
686 ? std::distance(PTUs.begin(), llvm::find(PTUs,
T))
688 <<
": [TU=" <<
T.TUPart <<
", M=" <<
T.TheModule.get()
689 <<
" (" <<
T.TheModule->getName() <<
")]\n");
696 if (
auto Err = IncrExecutor->addModule(
T))
699 if (
auto Err = IncrExecutor->runCtors())
702 return llvm::Error::success();
707 auto PTU =
Parse(Code);
709 return PTU.takeError();
711 if (llvm::Error Err =
Execute(*PTU))
714 if (LastValue.isValid()) {
719 *
V = std::move(LastValue);
721 return llvm::Error::success();
727 return llvm::make_error<llvm::StringError>(
"Operation failed. "
728 "No execution engine",
730 llvm::StringRef MangledName = Act->getCodeGen()->GetMangledName(GD);
737 return llvm::make_error<llvm::StringError>(
"Operation failed. "
738 "No execution engine",
747 return llvm::make_error<llvm::StringError>(
"Operation failed. "
748 "No execution engine",
756 if (getEffectivePTUSize() == 0) {
757 return llvm::make_error<llvm::StringError>(
"Operation failed. "
758 "No input left to undo",
760 }
else if (N > getEffectivePTUSize()) {
761 return llvm::make_error<llvm::StringError>(
763 "Operation failed. Wanted to undo {0} inputs, only have {1}.", N,
764 getEffectivePTUSize()),
768 for (
unsigned I = 0; I < N; I++) {
770 if (llvm::Error Err = IncrExecutor->removeModule(PTUs.back()))
774 IncrParser->CleanUpPTU(PTUs.back().TUPart);
777 return llvm::Error::success();
782 void *handle = dlopen(name, RTLD_NOW | RTLD_GLOBAL);
784 llvm::errs() << dlerror() <<
'\n';
785 return llvm::make_error<llvm::StringError>(
"Failed to load dynamic library",
786 llvm::inconvertibleErrorCode());
791 return EE.takeError();
794 std::unique_ptr<llvm::orc::EPCDynamicLibrarySearchGenerator>>
795 DLSG = llvm::orc::EPCDynamicLibrarySearchGenerator::Load(
796 EE->getExecutionSession(), name))
799 EE->getProcessSymbolsJITDylib()->addGenerator(std::move(*DLSG));
801 return DLSG.takeError();
804 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.