https://github.com/jameshu15869 updated https://github.com/llvm/llvm-project/pull/79936
>From 5efb122bc1d3b732bd58eb636ec770dfc572611f Mon Sep 17 00:00:00 2001 From: James Hu <jhudson15...@gmail.com> Date: Sun, 28 Jan 2024 20:01:20 -0500 Subject: [PATCH 1/7] [clang-repl][ORC] Add support for out-of-process execution on ELF --- clang/include/clang/Interpreter/Interpreter.h | 10 + clang/lib/Interpreter/IncrementalExecutor.cpp | 29 +++ clang/lib/Interpreter/IncrementalExecutor.h | 3 + clang/lib/Interpreter/Interpreter.cpp | 41 +++- clang/test/Interpreter/code-undo.cpp | 1 + clang/test/Interpreter/const.cpp | 1 + clang/test/Interpreter/execute-stmts.cpp | 1 + clang/test/Interpreter/execute-weak.cpp | 1 + clang/test/Interpreter/global-dtor.cpp | 1 + clang/test/Interpreter/incremental-mode.cpp | 1 + clang/test/Interpreter/inline-virtual.cpp | 1 + clang/test/Interpreter/lambda.cpp | 1 + clang/test/Interpreter/multiline.cpp | 1 + clang/test/Interpreter/sanity.c | 4 + clang/tools/clang-repl/CMakeLists.txt | 1 + clang/tools/clang-repl/ClangRepl.cpp | 220 ++++++++++++++++++ compiler-rt/lib/orc/dlfcn_wrapper.cpp | 14 ++ compiler-rt/lib/orc/elfnix_platform.cpp | 39 ++++ compiler-rt/lib/orc/elfnix_platform.h | 1 + .../ExecutionEngine/Orc/ELFNixPlatform.cpp | 10 +- llvm/lib/ExecutionEngine/Orc/LLJIT.cpp | 21 +- 21 files changed, 392 insertions(+), 10 deletions(-) diff --git a/clang/include/clang/Interpreter/Interpreter.h b/clang/include/clang/Interpreter/Interpreter.h index 43573fb1a4b89..314beb7b72dac 100644 --- a/clang/include/clang/Interpreter/Interpreter.h +++ b/clang/include/clang/Interpreter/Interpreter.h @@ -21,6 +21,7 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ExecutionEngine/JITSymbol.h" +#include "llvm/ExecutionEngine/Orc/ExecutorProcessControl.h" #include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h" #include "llvm/Support/Error.h" #include <memory> @@ -81,6 +82,11 @@ class Interpreter { // An optional parser for CUDA offloading std::unique_ptr<IncrementalParser> DeviceParser; + // An optional parameter for an out-of-process executor + std::unique_ptr<llvm::orc::ExecutorProcessControl> EPC; + + llvm::StringRef OrcRuntimePath; + Interpreter(std::unique_ptr<CompilerInstance> CI, llvm::Error &Err); llvm::Error CreateExecutor(); @@ -98,6 +104,10 @@ class Interpreter { static llvm::Expected<std::unique_ptr<Interpreter>> createWithCUDA(std::unique_ptr<CompilerInstance> CI, std::unique_ptr<CompilerInstance> DCI); + static llvm::Expected<std::unique_ptr<Interpreter>> + createWithOutOfProcessExecutor( + std::unique_ptr<CompilerInstance> CI, + std::unique_ptr<llvm::orc::ExecutorProcessControl> EI, llvm::StringRef OrcRuntimePath); const ASTContext &getASTContext() const; ASTContext &getASTContext(); const CompilerInstance *getCompilerInstance() const; diff --git a/clang/lib/Interpreter/IncrementalExecutor.cpp b/clang/lib/Interpreter/IncrementalExecutor.cpp index 40bcef94797d4..30b24caa4a594 100644 --- a/clang/lib/Interpreter/IncrementalExecutor.cpp +++ b/clang/lib/Interpreter/IncrementalExecutor.cpp @@ -63,6 +63,35 @@ IncrementalExecutor::IncrementalExecutor(llvm::orc::ThreadSafeContext &TSC, } } +IncrementalExecutor::IncrementalExecutor( + llvm::orc::ThreadSafeContext &TSC, llvm::Error &Err, + const clang::TargetInfo &TI, + std::unique_ptr<llvm::orc::ExecutorProcessControl> EPC, llvm::StringRef OrcRuntimePath) + : TSCtx(TSC) { + using namespace llvm::orc; + llvm::ErrorAsOutParameter EAO(&Err); + + auto JTMB = JITTargetMachineBuilder(TI.getTriple()); + JTMB.addFeatures(TI.getTargetOpts().Features); + LLJITBuilder Builder; + Builder.setJITTargetMachineBuilder(JTMB); + Builder.setPrePlatformSetup([](LLJIT &J) { + // Try to enable debugging of JIT'd code (only works with JITLink for + // ELF and MachO). + consumeError(enableDebuggerSupport(J)); + return llvm::Error::success(); + }); + Builder.setExecutorProcessControl(std::move(EPC)); + Builder.setPlatformSetUp(llvm::orc::ExecutorNativePlatform(OrcRuntimePath.str())); + + if (auto JitOrErr = Builder.create()) { + Jit = std::move(*JitOrErr); + } else { + Err = JitOrErr.takeError(); + return; + } +} + IncrementalExecutor::~IncrementalExecutor() {} llvm::Error IncrementalExecutor::addModule(PartialTranslationUnit &PTU) { diff --git a/clang/lib/Interpreter/IncrementalExecutor.h b/clang/lib/Interpreter/IncrementalExecutor.h index dd0a210a06141..a73ba9035182c 100644 --- a/clang/lib/Interpreter/IncrementalExecutor.h +++ b/clang/lib/Interpreter/IncrementalExecutor.h @@ -46,6 +46,9 @@ class IncrementalExecutor { IncrementalExecutor(llvm::orc::ThreadSafeContext &TSC, llvm::Error &Err, const clang::TargetInfo &TI); + IncrementalExecutor(llvm::orc::ThreadSafeContext &TSC, llvm::Error &Err, + const clang::TargetInfo &TI, + std::unique_ptr<llvm::orc::ExecutorProcessControl> EPC, llvm::StringRef OrcRuntimePath); ~IncrementalExecutor(); llvm::Error addModule(PartialTranslationUnit &PTU); diff --git a/clang/lib/Interpreter/Interpreter.cpp b/clang/lib/Interpreter/Interpreter.cpp index 7968c62cbd3e7..50d1ddbfcf07b 100644 --- a/clang/lib/Interpreter/Interpreter.cpp +++ b/clang/lib/Interpreter/Interpreter.cpp @@ -36,6 +36,7 @@ #include "clang/Lex/PreprocessorOptions.h" #include "clang/Sema/Lookup.h" #include "llvm/ExecutionEngine/JITSymbol.h" +#include "llvm/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.h" #include "llvm/ExecutionEngine/Orc/LLJIT.h" #include "llvm/IR/Module.h" #include "llvm/Support/Errc.h" @@ -242,6 +243,15 @@ Interpreter::~Interpreter() { llvm::Twine("Failed to clean up IncrementalExecutor: ") + toString(std::move(Err))); } + + if (EPC) { + if (auto Err = EPC->disconnect()) { + llvm::report_fatal_error( + llvm::Twine("Failed to clean up EPC (IncrementalExecutor has not yet " + "been created): ") + + toString(std::move(Err))); + } + } } // These better to put in a runtime header but we can't. This is because we @@ -315,6 +325,20 @@ Interpreter::createWithCUDA(std::unique_ptr<CompilerInstance> CI, return Interp; } + +llvm::Expected<std::unique_ptr<Interpreter>> +Interpreter::createWithOutOfProcessExecutor( + std::unique_ptr<CompilerInstance> CI, + std::unique_ptr<llvm::orc::ExecutorProcessControl> EI, llvm::StringRef OrcRuntimePath) { + auto Interp = create(std::move(CI)); + if (auto E = Interp.takeError()) { + return std::move(E); + } + (*Interp)->EPC = std::move(EI); + (*Interp)->OrcRuntimePath = OrcRuntimePath; + return Interp; +} + const CompilerInstance *Interpreter::getCompilerInstance() const { return IncrParser->getCI(); } @@ -363,7 +387,13 @@ llvm::Error Interpreter::CreateExecutor() { const clang::TargetInfo &TI = getCompilerInstance()->getASTContext().getTargetInfo(); llvm::Error Err = llvm::Error::success(); - auto Executor = std::make_unique<IncrementalExecutor>(*TSCtx, Err, TI); + std::unique_ptr<IncrementalExecutor> Executor; + if (EPC) { + Executor = + std::make_unique<IncrementalExecutor>(*TSCtx, Err, TI, std::move(EPC), OrcRuntimePath); + } else { + Executor = std::make_unique<IncrementalExecutor>(*TSCtx, Err, TI); + } if (!Err) IncrExecutor = std::move(Executor); @@ -460,13 +490,8 @@ llvm::Error Interpreter::LoadDynamicLibrary(const char *name) { if (!EE) return EE.takeError(); - auto &DL = EE->getDataLayout(); - - if (auto DLSG = llvm::orc::DynamicLibrarySearchGenerator::Load( - name, DL.getGlobalPrefix())) - EE->getMainJITDylib().addGenerator(std::move(*DLSG)); - else - return DLSG.takeError(); + if (auto DLSG = llvm::orc::EPCDynamicLibrarySearchGenerator::Load( + EE->getExecutionSession(), name)) return llvm::Error::success(); } diff --git a/clang/test/Interpreter/code-undo.cpp b/clang/test/Interpreter/code-undo.cpp index 83ade0ec9158b..6a4b99fde2899 100644 --- a/clang/test/Interpreter/code-undo.cpp +++ b/clang/test/Interpreter/code-undo.cpp @@ -1,5 +1,6 @@ // UNSUPPORTED: system-aix // RUN: cat %s | clang-repl | FileCheck %s +// RUN: cat %s | clang-repl -oop-executor | FileCheck %s extern "C" int printf(const char *, ...); int x1 = 0; int x2 = 42; diff --git a/clang/test/Interpreter/const.cpp b/clang/test/Interpreter/const.cpp index 4b6ce65e3643e..b4aa3ef9d87ee 100644 --- a/clang/test/Interpreter/const.cpp +++ b/clang/test/Interpreter/const.cpp @@ -3,6 +3,7 @@ // XFAIL: system-windows // RUN: cat %s | clang-repl | FileCheck %s +// RUN: cat %s | clang-repl -oop-executor | FileCheck %s // RUN: cat %s | clang-repl -Xcc -O2 | FileCheck %s extern "C" int printf(const char*, ...); diff --git a/clang/test/Interpreter/execute-stmts.cpp b/clang/test/Interpreter/execute-stmts.cpp index 2d4c17e0c91e6..defd128683e64 100644 --- a/clang/test/Interpreter/execute-stmts.cpp +++ b/clang/test/Interpreter/execute-stmts.cpp @@ -1,6 +1,7 @@ // REQUIRES: host-supports-jit // UNSUPPORTED: system-aix // RUN: cat %s | clang-repl -Xcc -Xclang -Xcc -verify | FileCheck %s +// RUN: cat %s | clang-repl -oop-executor -Xcc -Xclang -Xcc -verify | FileCheck %s // RUN: %clang_cc1 -verify -fincremental-extensions -emit-llvm -o - %s \ // RUN: | FileCheck --check-prefix=CODEGEN-CHECK %s diff --git a/clang/test/Interpreter/execute-weak.cpp b/clang/test/Interpreter/execute-weak.cpp index 85fa5d276f5f4..75e58e5e2c295 100644 --- a/clang/test/Interpreter/execute-weak.cpp +++ b/clang/test/Interpreter/execute-weak.cpp @@ -1,5 +1,6 @@ // UNSUPPORTED: system-aix, system-windows // RUN: cat %s | clang-repl | FileCheck %s +// RUN: cat %s | clang-repl -oop-executor | FileCheck %s extern "C" int printf(const char *, ...); int __attribute__((weak)) bar() { return 42; } diff --git a/clang/test/Interpreter/global-dtor.cpp b/clang/test/Interpreter/global-dtor.cpp index 1f241d9f19317..2a01cdb4d8c7b 100644 --- a/clang/test/Interpreter/global-dtor.cpp +++ b/clang/test/Interpreter/global-dtor.cpp @@ -4,6 +4,7 @@ // Tests that a global destructor is ran on platforms with gnu exception support. // // RUN: cat %s | clang-repl | FileCheck %s +// RUN: cat %s | clang-repl -oop-executor | FileCheck %s extern "C" int printf(const char *, ...); diff --git a/clang/test/Interpreter/incremental-mode.cpp b/clang/test/Interpreter/incremental-mode.cpp index e6350d237ef57..54153b74b2d83 100644 --- a/clang/test/Interpreter/incremental-mode.cpp +++ b/clang/test/Interpreter/incremental-mode.cpp @@ -1,3 +1,4 @@ // RUN: clang-repl -Xcc -E // RUN: clang-repl -Xcc -emit-llvm +// RUN: clang-repl -oop-executor -Xcc -E // expected-no-diagnostics diff --git a/clang/test/Interpreter/inline-virtual.cpp b/clang/test/Interpreter/inline-virtual.cpp index 79ab8ed337ffe..557ba47a68356 100644 --- a/clang/test/Interpreter/inline-virtual.cpp +++ b/clang/test/Interpreter/inline-virtual.cpp @@ -4,6 +4,7 @@ // We disable RTTI to avoid problems on Windows for non-RTTI builds of LLVM // where the JIT cannot find ??_7type_info@@6B@. // RUN: cat %s | clang-repl -Xcc -fno-rtti | FileCheck %s +// RUN: cat %s | clang-repl -oop-executor -Xcc -fno-rtti | FileCheck %s // RUN: cat %s | clang-repl -Xcc -fno-rtti -Xcc -O2 | FileCheck %s extern "C" int printf(const char *, ...); diff --git a/clang/test/Interpreter/lambda.cpp b/clang/test/Interpreter/lambda.cpp index df75274a050b2..fa926925d7eda 100644 --- a/clang/test/Interpreter/lambda.cpp +++ b/clang/test/Interpreter/lambda.cpp @@ -1,6 +1,7 @@ // REQUIRES: host-supports-jit // UNSUPPORTED: system-aix // RUN: cat %s | clang-repl | FileCheck %s +// RUN: cat %s | clang-repl -oop-executor | FileCheck %s // RUN: cat %s | clang-repl -Xcc -O2 | FileCheck %s extern "C" int printf(const char *, ...); diff --git a/clang/test/Interpreter/multiline.cpp b/clang/test/Interpreter/multiline.cpp index 054e61a7e3d62..797a6cdba1361 100644 --- a/clang/test/Interpreter/multiline.cpp +++ b/clang/test/Interpreter/multiline.cpp @@ -1,6 +1,7 @@ // REQUIRES: host-supports-jit // UNSUPPORTED: system-aix // RUN: cat %s | clang-repl | FileCheck %s +// RUN: cat %s | clang-repl -oop-executor | FileCheck %s extern "C" int printf(const char*,...); int i = \ diff --git a/clang/test/Interpreter/sanity.c b/clang/test/Interpreter/sanity.c index 8893a12f9216a..85f44558f5b6a 100644 --- a/clang/test/Interpreter/sanity.c +++ b/clang/test/Interpreter/sanity.c @@ -2,6 +2,10 @@ // RUN: clang-repl -Xcc -fno-color-diagnostics -Xcc -Xclang -Xcc -ast-dump \ // RUN: -Xcc -Xclang -Xcc -ast-dump-filter -Xcc -Xclang -Xcc Test 2>&1| \ // RUN: FileCheck %s +// RUN: cat %s | \ +// RUN: clang-repl -oop-executor -Xcc -fno-color-diagnostics -Xcc -Xclang -Xcc -ast-dump \ +// RUN: -Xcc -Xclang -Xcc -ast-dump-filter -Xcc -Xclang -Xcc Test 2>&1| \ +// RUN: FileCheck %s int TestVar = 12; // CHECK: Dumping TestVar: diff --git a/clang/tools/clang-repl/CMakeLists.txt b/clang/tools/clang-repl/CMakeLists.txt index 2ccbe292fd49e..d33d0273f6abb 100644 --- a/clang/tools/clang-repl/CMakeLists.txt +++ b/clang/tools/clang-repl/CMakeLists.txt @@ -4,6 +4,7 @@ set( LLVM_LINK_COMPONENTS LineEditor Option OrcJIT + OrcShared Support ) diff --git a/clang/tools/clang-repl/ClangRepl.cpp b/clang/tools/clang-repl/ClangRepl.cpp index 5663c2c5a6c92..b79f3a4dff5be 100644 --- a/clang/tools/clang-repl/ClangRepl.cpp +++ b/clang/tools/clang-repl/ClangRepl.cpp @@ -16,13 +16,20 @@ #include "clang/Interpreter/CodeCompletion.h" #include "clang/Interpreter/Interpreter.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ExecutionEngine/Orc/ExecutorProcessControl.h" #include "llvm/ExecutionEngine/Orc/LLJIT.h" +#include "llvm/ExecutionEngine/Orc/SimpleRemoteEPC.h" #include "llvm/LineEditor/LineEditor.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/ManagedStatic.h" // llvm_shutdown #include "llvm/Support/Signals.h" #include "llvm/Support/TargetSelect.h" +#include <netdb.h> #include <optional> +#include <sys/socket.h> +#include <sys/types.h> +#include <unistd.h> // Disable LSan for this test. // FIXME: Re-enable once we can assume GCC 13.2 or higher. @@ -45,6 +52,20 @@ static llvm::cl::opt<bool> OptHostSupportsJit("host-supports-jit", static llvm::cl::list<std::string> OptInputs(llvm::cl::Positional, llvm::cl::desc("[code to run]")); +static llvm::cl::OptionCategory OOPCategory("Out-of-process Execution Options"); +static llvm::cl::opt<std::string> OutOfProcessExecutor( + "oop-executor", + llvm::cl::desc("Launch an out-of-process executor to run code"), + llvm::cl::ValueOptional, llvm::cl::cat(OOPCategory)); +static llvm::cl::opt<std::string> OutOfProcessExecutorConnect( + "oop-executor-connect", + llvm::cl::desc("Connect to an out-of-process executor via TCP"), + llvm::cl::cat(OOPCategory)); +static llvm::cl::opt<std::string> OrcRuntimePath( + "orc-runtime", + llvm::cl::desc("Path to the ORC runtime"), + llvm::cl::cat(OOPCategory)); + static void LLVMErrorHandler(void *UserData, const char *Message, bool GenCrashDiag) { auto &Diags = *static_cast<clang::DiagnosticsEngine *>(UserData); @@ -143,6 +164,193 @@ ReplListCompleter::operator()(llvm::StringRef Buffer, size_t Pos, return Comps; } +static llvm::Error sanitizeArguments(const char *ArgV0) { + // Only one of -oop-executor and -oop-executor-connect can be used. + if (!!OutOfProcessExecutor.getNumOccurrences() && + !!OutOfProcessExecutorConnect.getNumOccurrences()) + return llvm::make_error<llvm::StringError>( + "Only one of -" + OutOfProcessExecutor.ArgStr + " and -" + + OutOfProcessExecutorConnect.ArgStr + " can be specified", + llvm::inconvertibleErrorCode()); + + // If -oop-executor was used but no value was specified then use a sensible + // default. + if (!!OutOfProcessExecutor.getNumOccurrences() && + OutOfProcessExecutor.empty()) { + llvm::SmallString<256> OOPExecutorPath(llvm::sys::fs::getMainExecutable( + ArgV0, reinterpret_cast<void *>(&sanitizeArguments))); + llvm::sys::path::remove_filename(OOPExecutorPath); + llvm::sys::path::append(OOPExecutorPath, "llvm-jitlink-executor"); + OutOfProcessExecutor = OOPExecutorPath.str().str(); + } + + // Out-of-process executors must run with the ORC runtime for destructor support. + if (OrcRuntimePath.empty() && (OutOfProcessExecutor.getNumOccurrences() || OutOfProcessExecutorConnect.getNumOccurrences())) { + llvm::SmallString<256> OrcPath(llvm::sys::fs::getMainExecutable( + ArgV0, reinterpret_cast<void *>(&sanitizeArguments))); + llvm::sys::path::remove_filename(OrcPath); // Remove clang-repl filename. + llvm::sys::path::remove_filename(OrcPath); // Remove ./bin directory. + llvm::sys::path::append(OrcPath, "lib/clang/18/lib/x86_64-unknown-linux-gnu/liborc_rt.a"); + OrcRuntimePath = OrcPath.str().str(); + } + + return llvm::Error::success(); +} + +static llvm::Expected<std::unique_ptr<llvm::orc::ExecutorProcessControl>> +launchExecutor() { + constexpr int ReadEnd = 0; + constexpr int WriteEnd = 1; + + // Pipe FDs. + int ToExecutor[2]; + int FromExecutor[2]; + + pid_t ChildPID; + + // Create pipes to/from the executor.. + if (pipe(ToExecutor) != 0 || pipe(FromExecutor) != 0) + return llvm::make_error<llvm::StringError>( + "Unable to create pipe for executor", llvm::inconvertibleErrorCode()); + + ChildPID = fork(); + + if (ChildPID == 0) { + // In the child... + + // Close the parent ends of the pipes + close(ToExecutor[WriteEnd]); + close(FromExecutor[ReadEnd]); + + // Execute the child process. + std::unique_ptr<char[]> ExecutorPath, FDSpecifier; + { + ExecutorPath = std::make_unique<char[]>(OutOfProcessExecutor.size() + 1); + strcpy(ExecutorPath.get(), OutOfProcessExecutor.data()); + + std::string FDSpecifierStr("filedescs="); + FDSpecifierStr += llvm::utostr(ToExecutor[ReadEnd]); + FDSpecifierStr += ','; + FDSpecifierStr += llvm::utostr(FromExecutor[WriteEnd]); + FDSpecifier = std::make_unique<char[]>(FDSpecifierStr.size() + 1); + strcpy(FDSpecifier.get(), FDSpecifierStr.c_str()); + } + + char *const Args[] = {ExecutorPath.get(), FDSpecifier.get(), nullptr}; + int RC = execvp(ExecutorPath.get(), Args); + if (RC != 0) { + llvm::errs() << "unable to launch out-of-process executor \"" + << ExecutorPath.get() << "\"\n"; + exit(1); + } + } + // else we're the parent... + + // Close the child ends of the pipes + close(ToExecutor[ReadEnd]); + close(FromExecutor[WriteEnd]); + + auto S = llvm::orc::SimpleRemoteEPC::Setup(); + + return llvm::orc::SimpleRemoteEPC::Create< + llvm::orc::FDSimpleRemoteEPCTransport>( + std::make_unique<llvm::orc::DynamicThreadPoolTaskDispatcher>(), + std::move(S), FromExecutor[ReadEnd], ToExecutor[WriteEnd]); +} + +#if LLVM_ON_UNIX && LLVM_ENABLE_THREADS +static llvm::Error createTCPSocketError(llvm::Twine Details) { + return llvm::make_error<llvm::StringError>( + formatv("Failed to connect TCP socket '{0}': {1}", + OutOfProcessExecutorConnect, Details), + llvm::inconvertibleErrorCode()); +} + +static llvm::Expected<int> connectTCPSocket(std::string Host, + std::string PortStr) { + addrinfo *AI; + addrinfo Hints{}; + Hints.ai_family = AF_INET; + Hints.ai_socktype = SOCK_STREAM; + Hints.ai_flags = AI_NUMERICSERV; + + if (int EC = getaddrinfo(Host.c_str(), PortStr.c_str(), &Hints, &AI)) + return createTCPSocketError("Address resolution failed (" + + llvm::StringRef(gai_strerror(EC)) + ")"); + + // Cycle through the returned addrinfo structures and connect to the first + // reachable endpoint. + int SockFD; + addrinfo *Server; + for (Server = AI; Server != nullptr; Server = Server->ai_next) { + // socket might fail, e.g. if the address family is not supported. Skip to + // the next addrinfo structure in such a case. + if ((SockFD = socket(AI->ai_family, AI->ai_socktype, AI->ai_protocol)) < 0) + continue; + + // If connect returns null, we exit the loop with a working socket. + if (connect(SockFD, Server->ai_addr, Server->ai_addrlen) == 0) + break; + + close(SockFD); + } + freeaddrinfo(AI); + + // If we reached the end of the loop without connecting to a valid endpoint, + // dump the last error that was logged in socket() or connect(). + if (Server == nullptr) + return createTCPSocketError(std::strerror(errno)); + + return SockFD; +} +#endif + +static llvm::Expected<std::unique_ptr<llvm::orc::ExecutorProcessControl>> +connectToExecutor() { +#ifndef LLVM_ON_UNIX + // FIXME: Add TCP support for Windows. + return llvm::make_error<StringError>( + "-" + OutOfProcessExecutorConnect.ArgStr + + " not supported on non-unix platforms", + inconvertibleErrorCode()); +#elif !LLVM_ENABLE_THREADS + // Out of process mode using SimpleRemoteEPC depends on threads. + return llvm::make_error<StringError>( + "-" + OutOfProcessExecutorConnect.ArgStr + + " requires threads, but LLVM was built with " + "LLVM_ENABLE_THREADS=Off", + inconvertibleErrorCode()); +#else + + llvm::StringRef Host, PortStr; + std::tie(Host, PortStr) = + llvm::StringRef(OutOfProcessExecutorConnect).split(':'); + if (Host.empty()) + return createTCPSocketError("Host name for -" + + OutOfProcessExecutorConnect.ArgStr + + " can not be empty"); + if (PortStr.empty()) + return createTCPSocketError("Port number in -" + + OutOfProcessExecutorConnect.ArgStr + + " can not be empty"); + int Port = 0; + if (PortStr.getAsInteger(10, Port)) + return createTCPSocketError("Port number '" + PortStr + + "' is not a valid integer"); + + llvm::Expected<int> SockFD = connectTCPSocket(Host.str(), PortStr.str()); + if (!SockFD) + return SockFD.takeError(); + + auto S = llvm::orc::SimpleRemoteEPC::Setup(); + + return llvm::orc::SimpleRemoteEPC::Create< + llvm::orc::FDSimpleRemoteEPCTransport>( + std::make_unique<llvm::orc::DynamicThreadPoolTaskDispatcher>(), + std::move(S), *SockFD, *SockFD); +#endif +} + llvm::ExitOnError ExitOnErr; int main(int argc, const char **argv) { ExitOnErr.setBanner("clang-repl: "); @@ -205,6 +413,8 @@ int main(int argc, const char **argv) { if (CudaEnabled) DeviceCI->LoadRequestedPlugins(); + ExitOnErr(sanitizeArguments(argv[0])); + std::unique_ptr<clang::Interpreter> Interp; if (CudaEnabled) { @@ -217,6 +427,16 @@ int main(int argc, const char **argv) { auto CudaRuntimeLibPath = CudaPath + "/lib/libcudart.so"; ExitOnErr(Interp->LoadDynamicLibrary(CudaRuntimeLibPath.c_str())); } + } else if (OutOfProcessExecutor.getNumOccurrences()) { + // Create an instance of llvm-jitlink-executor in a separate process. + auto oopExecutor = ExitOnErr(launchExecutor()); + Interp = ExitOnErr(clang::Interpreter::createWithOutOfProcessExecutor( + std::move(CI), std::move(oopExecutor), OrcRuntimePath)); + } else if (OutOfProcessExecutorConnect.getNumOccurrences()) { + /// If -oop-executor-connect is passed then connect to the executor. + auto REPC = ExitOnErr(connectToExecutor()); + Interp = ExitOnErr(clang::Interpreter::createWithOutOfProcessExecutor( + std::move(CI), std::move(REPC), OrcRuntimePath)); } else Interp = ExitOnErr(clang::Interpreter::create(std::move(CI))); diff --git a/compiler-rt/lib/orc/dlfcn_wrapper.cpp b/compiler-rt/lib/orc/dlfcn_wrapper.cpp index ece63da2cb48e..a8b207d27157e 100644 --- a/compiler-rt/lib/orc/dlfcn_wrapper.cpp +++ b/compiler-rt/lib/orc/dlfcn_wrapper.cpp @@ -20,6 +20,7 @@ using namespace __orc_rt; extern "C" const char *__orc_rt_jit_dlerror(); extern "C" void *__orc_rt_jit_dlopen(const char *path, int mode); +extern "C" void *__orc_rt_jit_dlupdate(const char *path, int mode); extern "C" int __orc_rt_jit_dlclose(void *dso_handle); ORC_RT_INTERFACE orc_rt_CWrapperFunctionResult @@ -41,6 +42,19 @@ __orc_rt_jit_dlopen_wrapper(const char *ArgData, size_t ArgSize) { .release(); } +ORC_RT_INTERFACE orc_rt_CWrapperFunctionResult +__orc_rt_jit_dlupdate_wrapper(const char *ArgData, size_t ArgSize) { + return WrapperFunction<SPSExecutorAddr(SPSString, int32_t)>::handle( + ArgData, ArgSize, + [](const std::string &Path, int32_t mode) { + return ExecutorAddr::fromPtr( + __orc_rt_jit_dlupdate(Path.c_str(), mode)); + }) + .release(); +} + + + ORC_RT_INTERFACE orc_rt_CWrapperFunctionResult __orc_rt_jit_dlclose_wrapper(const char *ArgData, size_t ArgSize) { return WrapperFunction<int32_t(SPSExecutorAddr)>::handle( diff --git a/compiler-rt/lib/orc/elfnix_platform.cpp b/compiler-rt/lib/orc/elfnix_platform.cpp index c087e71038f95..6f9fdb670f558 100644 --- a/compiler-rt/lib/orc/elfnix_platform.cpp +++ b/compiler-rt/lib/orc/elfnix_platform.cpp @@ -116,6 +116,7 @@ class ELFNixPlatformRuntimeState { const char *dlerror(); void *dlopen(std::string_view Name, int Mode); + void *dlupdate(std::string_view Name, int Mode); int dlclose(void *DSOHandle); void *dlsym(void *DSOHandle, std::string_view Symbol); @@ -142,6 +143,7 @@ class ELFNixPlatformRuntimeState { Expected<ELFNixJITDylibInitializerSequence> getJITDylibInitializersByName(std::string_view Path); Expected<void *> dlopenInitialize(std::string_view Path, int Mode); + Expected<void *> dlupdateInitialize(std::string_view Path, int Mode); Error initializeJITDylib(ELFNixJITDylibInitializers &MOJDIs); static ELFNixPlatformRuntimeState *MOPS; @@ -237,6 +239,18 @@ void *ELFNixPlatformRuntimeState::dlopen(std::string_view Path, int Mode) { return *H; } +void *ELFNixPlatformRuntimeState::dlupdate(std::string_view Path, int Mode) { + std::lock_guard<std::recursive_mutex> Lock(JDStatesMutex); + + auto H = dlupdateInitialize(Path, Mode); + if (!H) { + DLFcnError = toString(H.takeError()); + return nullptr; + } + + return *H; +} + int ELFNixPlatformRuntimeState::dlclose(void *DSOHandle) { runAtExits(DSOHandle); return 0; @@ -401,6 +415,27 @@ ELFNixPlatformRuntimeState::dlopenInitialize(std::string_view Path, int Mode) { return JDS->Header; } +Expected<void *> +ELFNixPlatformRuntimeState::dlupdateInitialize(std::string_view Path, + int Mode) { + auto InitSeq = getJITDylibInitializersByName(Path); + if (!InitSeq) + return InitSeq.takeError(); + + // Init sequences can be empty becaue we are (possibly) reinitializing + if (InitSeq->empty()) + return getJITDylibStateByName(Path)->Header; + + for (auto &MOJDIs : *InitSeq) + if (auto Err = initializeJITDylib(MOJDIs)) + return std::move(Err); + + auto *JDS = getJITDylibStateByHeaderAddr( + InitSeq->back().DSOHandleAddress.toPtr<void *>()); + assert(JDS && "Missing state entry for JD"); + return JDS->Header; +} + long getPriority(const std::string &name) { auto pos = name.find_last_not_of("0123456789"); if (pos == name.size() - 1) @@ -583,6 +618,10 @@ void *__orc_rt_elfnix_jit_dlopen(const char *path, int mode) { return ELFNixPlatformRuntimeState::get().dlopen(path, mode); } +void *__orc_rt_elfnix_jit_dlupdate(const char *path, int mode) { + return ELFNixPlatformRuntimeState::get().dlupdate(path, mode); +} + int __orc_rt_elfnix_jit_dlclose(void *dso_handle) { return ELFNixPlatformRuntimeState::get().dlclose(dso_handle); } diff --git a/compiler-rt/lib/orc/elfnix_platform.h b/compiler-rt/lib/orc/elfnix_platform.h index e0ee9591dfc62..569a3cfb5e11b 100644 --- a/compiler-rt/lib/orc/elfnix_platform.h +++ b/compiler-rt/lib/orc/elfnix_platform.h @@ -25,6 +25,7 @@ ORC_RT_INTERFACE void __orc_rt_elfnix_cxa_finalize(void *dso_handle); // dlfcn functions. ORC_RT_INTERFACE const char *__orc_rt_elfnix_jit_dlerror(); ORC_RT_INTERFACE void *__orc_rt_elfnix_jit_dlopen(const char *path, int mode); +ORC_RT_INTERFACE void *__orc_rt_elfnix_jit_dlupdate(const char *path, int mode); ORC_RT_INTERFACE int __orc_rt_elfnix_jit_dlclose(void *dso_handle); ORC_RT_INTERFACE void *__orc_rt_elfnix_jit_dlsym(void *dso_handle, const char *symbol); diff --git a/llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp b/llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp index 2b6c4b9e7f431..b32d9d4c1046d 100644 --- a/llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp +++ b/llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp @@ -237,6 +237,7 @@ ELFNixPlatform::standardRuntimeUtilityAliases() { {"__orc_rt_run_program", "__orc_rt_elfnix_run_program"}, {"__orc_rt_jit_dlerror", "__orc_rt_elfnix_jit_dlerror"}, {"__orc_rt_jit_dlopen", "__orc_rt_elfnix_jit_dlopen"}, + {"__orc_rt_jit_dlupdate", "__orc_rt_elfnix_jit_dlupdate"}, {"__orc_rt_jit_dlclose", "__orc_rt_elfnix_jit_dlclose"}, {"__orc_rt_jit_dlsym", "__orc_rt_elfnix_jit_dlsym"}, {"__orc_rt_log_error", "__orc_rt_log_error_to_stderr"}}; @@ -544,10 +545,17 @@ Error ELFNixPlatform::registerInitInfo( auto SearchOrder = JD.withLinkOrderDo([](const JITDylibSearchOrder &SO) { return SO; }); - if (auto Err = ES.lookup(SearchOrder, DSOHandleSymbol).takeError()) + auto SymOrErr = ES.lookup(SearchOrder, DSOHandleSymbol); + if (auto Err = SymOrErr.takeError()) { return Err; + } Lock.lock(); + // We can allow reinitialization by reinserting the handles to each + // JITDylib into InitSeqs. + InitSeqs.insert(std::make_pair( + &JD, + ELFNixJITDylibInitializers(JD.getName(), (*SymOrErr).getAddress()))); I = InitSeqs.find(&JD); assert(I != InitSeqs.end() && "Entry missing after header symbol lookup?"); diff --git a/llvm/lib/ExecutionEngine/Orc/LLJIT.cpp b/llvm/lib/ExecutionEngine/Orc/LLJIT.cpp index 1a4251353e2da..54030c83b7eb0 100644 --- a/llvm/lib/ExecutionEngine/Orc/LLJIT.cpp +++ b/llvm/lib/ExecutionEngine/Orc/LLJIT.cpp @@ -105,9 +105,18 @@ class ORCPlatformSupport : public LLJIT::PlatformSupport { auto MainSearchOrder = J.getMainJITDylib().withLinkOrderDo( [](const JITDylibSearchOrder &SO) { return SO; }); + std::string WrapperToCall = "__orc_rt_jit_dlopen_wrapper"; + auto Triple = ES.getTargetTriple(); + if (Triple.isOSBinFormatELF()) { + WrapperToCall = FirstInitialization ? "__orc_rt_jit_dlopen_wrapper" : "__orc_rt_jit_dlupdate_wrapper"; + if (FirstInitialization) { + FirstInitialization = false; + } + } + if (auto WrapperAddr = ES.lookup(MainSearchOrder, - J.mangleAndIntern("__orc_rt_jit_dlopen_wrapper"))) { + J.mangleAndIntern(WrapperToCall))) { return ES.callSPSWrapper<SPSDLOpenSig>(WrapperAddr->getAddress(), DSOHandles[&JD], JD.getName(), int32_t(ORC_RT_RTLD_LAZY)); @@ -143,6 +152,7 @@ class ORCPlatformSupport : public LLJIT::PlatformSupport { private: orc::LLJIT &J; DenseMap<orc::JITDylib *, orc::ExecutorAddr> DSOHandles; + bool FirstInitialization = true; // Used to track if reinitialization is needed for ELF }; class GenericLLVMIRPlatformSupport; @@ -1109,6 +1119,15 @@ Expected<JITDylibSP> ExecutorNativePlatform::operator()(LLJIT &J) { auto &ES = J.getExecutionSession(); auto &PlatformJD = ES.createBareJITDylib("<Platform>"); + + // Required to help out-of-process executors find definitions for setting + // up the ORC platform + if (auto DylibSearchGeneratorOrErr = + llvm::orc::EPCDynamicLibrarySearchGenerator::GetForTargetProcess( + ES)) { + PlatformJD.addGenerator(std::move(*DylibSearchGeneratorOrErr)); + } + PlatformJD.addToLinkOrder(*ProcessSymbolsJD); J.setPlatformSupport(std::make_unique<ORCPlatformSupport>(J)); >From 246d0373e7ed35803f1200213a5415360b1787ab Mon Sep 17 00:00:00 2001 From: James Hu <jhudson15...@gmail.com> Date: Mon, 29 Jan 2024 21:17:29 -0500 Subject: [PATCH 2/7] [clang-repl] Add ELF-only test and checks --- clang/test/Interpreter/code-undo.cpp | 1 - clang/test/Interpreter/const.cpp | 1 - clang/test/Interpreter/execute-stmts.cpp | 1 - clang/test/Interpreter/execute-weak.cpp | 1 - clang/test/Interpreter/global-dtor.cpp | 1 - clang/test/Interpreter/incremental-mode.cpp | 1 - clang/test/Interpreter/inline-virtual.cpp | 1 - clang/test/Interpreter/lambda.cpp | 1 - clang/test/Interpreter/multiline.cpp | 1 - clang/test/Interpreter/out-of-process.cpp | 70 +++++++++++++++++++++ clang/test/Interpreter/sanity.c | 4 -- clang/tools/clang-repl/CMakeLists.txt | 1 + clang/tools/clang-repl/ClangRepl.cpp | 20 ++++-- 13 files changed, 86 insertions(+), 18 deletions(-) create mode 100644 clang/test/Interpreter/out-of-process.cpp diff --git a/clang/test/Interpreter/code-undo.cpp b/clang/test/Interpreter/code-undo.cpp index 6a4b99fde2899..83ade0ec9158b 100644 --- a/clang/test/Interpreter/code-undo.cpp +++ b/clang/test/Interpreter/code-undo.cpp @@ -1,6 +1,5 @@ // UNSUPPORTED: system-aix // RUN: cat %s | clang-repl | FileCheck %s -// RUN: cat %s | clang-repl -oop-executor | FileCheck %s extern "C" int printf(const char *, ...); int x1 = 0; int x2 = 42; diff --git a/clang/test/Interpreter/const.cpp b/clang/test/Interpreter/const.cpp index b4aa3ef9d87ee..4b6ce65e3643e 100644 --- a/clang/test/Interpreter/const.cpp +++ b/clang/test/Interpreter/const.cpp @@ -3,7 +3,6 @@ // XFAIL: system-windows // RUN: cat %s | clang-repl | FileCheck %s -// RUN: cat %s | clang-repl -oop-executor | FileCheck %s // RUN: cat %s | clang-repl -Xcc -O2 | FileCheck %s extern "C" int printf(const char*, ...); diff --git a/clang/test/Interpreter/execute-stmts.cpp b/clang/test/Interpreter/execute-stmts.cpp index defd128683e64..2d4c17e0c91e6 100644 --- a/clang/test/Interpreter/execute-stmts.cpp +++ b/clang/test/Interpreter/execute-stmts.cpp @@ -1,7 +1,6 @@ // REQUIRES: host-supports-jit // UNSUPPORTED: system-aix // RUN: cat %s | clang-repl -Xcc -Xclang -Xcc -verify | FileCheck %s -// RUN: cat %s | clang-repl -oop-executor -Xcc -Xclang -Xcc -verify | FileCheck %s // RUN: %clang_cc1 -verify -fincremental-extensions -emit-llvm -o - %s \ // RUN: | FileCheck --check-prefix=CODEGEN-CHECK %s diff --git a/clang/test/Interpreter/execute-weak.cpp b/clang/test/Interpreter/execute-weak.cpp index 75e58e5e2c295..85fa5d276f5f4 100644 --- a/clang/test/Interpreter/execute-weak.cpp +++ b/clang/test/Interpreter/execute-weak.cpp @@ -1,6 +1,5 @@ // UNSUPPORTED: system-aix, system-windows // RUN: cat %s | clang-repl | FileCheck %s -// RUN: cat %s | clang-repl -oop-executor | FileCheck %s extern "C" int printf(const char *, ...); int __attribute__((weak)) bar() { return 42; } diff --git a/clang/test/Interpreter/global-dtor.cpp b/clang/test/Interpreter/global-dtor.cpp index 2a01cdb4d8c7b..1f241d9f19317 100644 --- a/clang/test/Interpreter/global-dtor.cpp +++ b/clang/test/Interpreter/global-dtor.cpp @@ -4,7 +4,6 @@ // Tests that a global destructor is ran on platforms with gnu exception support. // // RUN: cat %s | clang-repl | FileCheck %s -// RUN: cat %s | clang-repl -oop-executor | FileCheck %s extern "C" int printf(const char *, ...); diff --git a/clang/test/Interpreter/incremental-mode.cpp b/clang/test/Interpreter/incremental-mode.cpp index 54153b74b2d83..e6350d237ef57 100644 --- a/clang/test/Interpreter/incremental-mode.cpp +++ b/clang/test/Interpreter/incremental-mode.cpp @@ -1,4 +1,3 @@ // RUN: clang-repl -Xcc -E // RUN: clang-repl -Xcc -emit-llvm -// RUN: clang-repl -oop-executor -Xcc -E // expected-no-diagnostics diff --git a/clang/test/Interpreter/inline-virtual.cpp b/clang/test/Interpreter/inline-virtual.cpp index 557ba47a68356..79ab8ed337ffe 100644 --- a/clang/test/Interpreter/inline-virtual.cpp +++ b/clang/test/Interpreter/inline-virtual.cpp @@ -4,7 +4,6 @@ // We disable RTTI to avoid problems on Windows for non-RTTI builds of LLVM // where the JIT cannot find ??_7type_info@@6B@. // RUN: cat %s | clang-repl -Xcc -fno-rtti | FileCheck %s -// RUN: cat %s | clang-repl -oop-executor -Xcc -fno-rtti | FileCheck %s // RUN: cat %s | clang-repl -Xcc -fno-rtti -Xcc -O2 | FileCheck %s extern "C" int printf(const char *, ...); diff --git a/clang/test/Interpreter/lambda.cpp b/clang/test/Interpreter/lambda.cpp index fa926925d7eda..df75274a050b2 100644 --- a/clang/test/Interpreter/lambda.cpp +++ b/clang/test/Interpreter/lambda.cpp @@ -1,7 +1,6 @@ // REQUIRES: host-supports-jit // UNSUPPORTED: system-aix // RUN: cat %s | clang-repl | FileCheck %s -// RUN: cat %s | clang-repl -oop-executor | FileCheck %s // RUN: cat %s | clang-repl -Xcc -O2 | FileCheck %s extern "C" int printf(const char *, ...); diff --git a/clang/test/Interpreter/multiline.cpp b/clang/test/Interpreter/multiline.cpp index 797a6cdba1361..054e61a7e3d62 100644 --- a/clang/test/Interpreter/multiline.cpp +++ b/clang/test/Interpreter/multiline.cpp @@ -1,7 +1,6 @@ // REQUIRES: host-supports-jit // UNSUPPORTED: system-aix // RUN: cat %s | clang-repl | FileCheck %s -// RUN: cat %s | clang-repl -oop-executor | FileCheck %s extern "C" int printf(const char*,...); int i = \ diff --git a/clang/test/Interpreter/out-of-process.cpp b/clang/test/Interpreter/out-of-process.cpp new file mode 100644 index 0000000000000..19db924cb32f1 --- /dev/null +++ b/clang/test/Interpreter/out-of-process.cpp @@ -0,0 +1,70 @@ +// REQUIRES: host-supports-jit, x86_64-linux +// RUN: cat %s | clang-repl | FileCheck %s +// RUN: cat %s | clang-repl -oop-executor | FileCheck %s + +extern "C" int printf(const char *, ...); + +// Test code undo. +int x1 = 0; +int x2 = 42; +%undo +int x2 = 24; +auto r1 = printf("x1 = %d\n", x1); +// CHECK: x1 = 0 +auto r2 = printf("x2 = %d\n", x2); +// CHECK-NEXT: x2 = 24 +int foo() { return 1; } +%undo +int foo() { return 2; } +auto r3 = printf("foo() = %d\n", foo()); +// CHECK-NEXT: foo() = 2 +inline int bar() { return 42;} +auto r4 = bar(); +%undo +auto r5 = bar(); + +// Test weak execution. +int __attribute__((weak)) weak_bar() { return 42; } +auto r6 = printf("bar() = %d\n", weak_bar()); +// CHECK: bar() = 42 +int a = 12; +static __typeof(a) b __attribute__((__weakref__("a"))); +int c = b; + +// Test dynamic libraries. +extern "C" int ultimate_answer; +extern "C" int calculate_answer(); +%lib libdynamic-library-test.so +printf("Return value: %d\n", calculate_answer()); +// CHECK: Return value: 5 +printf("Variable: %d\n", ultimate_answer); +// CHECK-NEXT: Variable: 42 + +// Test lambdas. +auto l1 = []() { printf("ONE\n"); return 42; }; +auto l2 = []() { printf("TWO\n"); return 17; }; +auto lambda_r1 = l1(); +// CHECK: ONE +auto lambda_r2 = l2(); +// CHECK: TWO +auto lambda_r3 = l2(); +// CHECK: TWO + +// Test multiline. +int i = \ + 12; +printf("i=%d\n", i); +// CHECK: i=12 +void f(int x) \ +{ \ + printf("x=\ + %d", x); \ +} +f(i); +// CHECK: x=12 + +// Test global destructor. +struct D { float f = 1.0; D *m = nullptr; D(){} ~D() { printf("D[f=%f, m=0x%llx]\n", f, reinterpret_cast<unsigned long long>(m)); }} d; +// CHECK: D[f=1.000000, m=0x0] + +%quit \ No newline at end of file diff --git a/clang/test/Interpreter/sanity.c b/clang/test/Interpreter/sanity.c index 85f44558f5b6a..8893a12f9216a 100644 --- a/clang/test/Interpreter/sanity.c +++ b/clang/test/Interpreter/sanity.c @@ -2,10 +2,6 @@ // RUN: clang-repl -Xcc -fno-color-diagnostics -Xcc -Xclang -Xcc -ast-dump \ // RUN: -Xcc -Xclang -Xcc -ast-dump-filter -Xcc -Xclang -Xcc Test 2>&1| \ // RUN: FileCheck %s -// RUN: cat %s | \ -// RUN: clang-repl -oop-executor -Xcc -fno-color-diagnostics -Xcc -Xclang -Xcc -ast-dump \ -// RUN: -Xcc -Xclang -Xcc -ast-dump-filter -Xcc -Xclang -Xcc Test 2>&1| \ -// RUN: FileCheck %s int TestVar = 12; // CHECK: Dumping TestVar: diff --git a/clang/tools/clang-repl/CMakeLists.txt b/clang/tools/clang-repl/CMakeLists.txt index d33d0273f6abb..adf4ea4180cba 100644 --- a/clang/tools/clang-repl/CMakeLists.txt +++ b/clang/tools/clang-repl/CMakeLists.txt @@ -6,6 +6,7 @@ set( LLVM_LINK_COMPONENTS OrcJIT OrcShared Support + TargetParser ) add_clang_tool(clang-repl diff --git a/clang/tools/clang-repl/ClangRepl.cpp b/clang/tools/clang-repl/ClangRepl.cpp index b79f3a4dff5be..1c43e7b503646 100644 --- a/clang/tools/clang-repl/ClangRepl.cpp +++ b/clang/tools/clang-repl/ClangRepl.cpp @@ -25,6 +25,7 @@ #include "llvm/Support/ManagedStatic.h" // llvm_shutdown #include "llvm/Support/Signals.h" #include "llvm/Support/TargetSelect.h" +#include "llvm/TargetParser/Host.h" #include <netdb.h> #include <optional> #include <sys/socket.h> @@ -52,7 +53,8 @@ static llvm::cl::opt<bool> OptHostSupportsJit("host-supports-jit", static llvm::cl::list<std::string> OptInputs(llvm::cl::Positional, llvm::cl::desc("[code to run]")); -static llvm::cl::OptionCategory OOPCategory("Out-of-process Execution Options"); +static llvm::cl::OptionCategory OOPCategory( + "Out-of-process Execution Options (Only available on ELF/Linux)"); static llvm::cl::opt<std::string> OutOfProcessExecutor( "oop-executor", llvm::cl::desc("Launch an out-of-process executor to run code"), @@ -164,7 +166,15 @@ ReplListCompleter::operator()(llvm::StringRef Buffer, size_t Pos, return Comps; } -static llvm::Error sanitizeArguments(const char *ArgV0) { +static llvm::Error sanitizeOopArguments(const char *ArgV0) { + llvm::Triple SystemTriple(llvm::sys::getProcessTriple()); + if ((OutOfProcessExecutor.getNumOccurrences() || + OutOfProcessExecutorConnect.getNumOccurrences()) && + (!SystemTriple.isOSBinFormatELF())) + return llvm::make_error<llvm::StringError>( + "Out-process-executors are currently only supported on ELF", + llvm::inconvertibleErrorCode()); + // Only one of -oop-executor and -oop-executor-connect can be used. if (!!OutOfProcessExecutor.getNumOccurrences() && !!OutOfProcessExecutorConnect.getNumOccurrences()) @@ -178,7 +188,7 @@ static llvm::Error sanitizeArguments(const char *ArgV0) { if (!!OutOfProcessExecutor.getNumOccurrences() && OutOfProcessExecutor.empty()) { llvm::SmallString<256> OOPExecutorPath(llvm::sys::fs::getMainExecutable( - ArgV0, reinterpret_cast<void *>(&sanitizeArguments))); + ArgV0, reinterpret_cast<void *>(&sanitizeOopArguments))); llvm::sys::path::remove_filename(OOPExecutorPath); llvm::sys::path::append(OOPExecutorPath, "llvm-jitlink-executor"); OutOfProcessExecutor = OOPExecutorPath.str().str(); @@ -187,7 +197,7 @@ static llvm::Error sanitizeArguments(const char *ArgV0) { // Out-of-process executors must run with the ORC runtime for destructor support. if (OrcRuntimePath.empty() && (OutOfProcessExecutor.getNumOccurrences() || OutOfProcessExecutorConnect.getNumOccurrences())) { llvm::SmallString<256> OrcPath(llvm::sys::fs::getMainExecutable( - ArgV0, reinterpret_cast<void *>(&sanitizeArguments))); + ArgV0, reinterpret_cast<void *>(&sanitizeOopArguments))); llvm::sys::path::remove_filename(OrcPath); // Remove clang-repl filename. llvm::sys::path::remove_filename(OrcPath); // Remove ./bin directory. llvm::sys::path::append(OrcPath, "lib/clang/18/lib/x86_64-unknown-linux-gnu/liborc_rt.a"); @@ -413,7 +423,7 @@ int main(int argc, const char **argv) { if (CudaEnabled) DeviceCI->LoadRequestedPlugins(); - ExitOnErr(sanitizeArguments(argv[0])); + ExitOnErr(sanitizeOopArguments(argv[0])); std::unique_ptr<clang::Interpreter> Interp; >From c7dbe9ae97083478a8183abf297e5fdffc828916 Mon Sep 17 00:00:00 2001 From: James Hu <jhudson15...@gmail.com> Date: Mon, 29 Jan 2024 21:18:21 -0500 Subject: [PATCH 3/7] [clang-repl] Add trailing whitespace --- clang/test/Interpreter/out-of-process.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/test/Interpreter/out-of-process.cpp b/clang/test/Interpreter/out-of-process.cpp index 19db924cb32f1..39ae1442f1b13 100644 --- a/clang/test/Interpreter/out-of-process.cpp +++ b/clang/test/Interpreter/out-of-process.cpp @@ -67,4 +67,4 @@ f(i); struct D { float f = 1.0; D *m = nullptr; D(){} ~D() { printf("D[f=%f, m=0x%llx]\n", f, reinterpret_cast<unsigned long long>(m)); }} d; // CHECK: D[f=1.000000, m=0x0] -%quit \ No newline at end of file +%quit >From 158cc5ec91bf085ec9914de26a1554606a1e3338 Mon Sep 17 00:00:00 2001 From: James Hu <jhudson15...@gmail.com> Date: Mon, 29 Jan 2024 21:59:46 -0500 Subject: [PATCH 4/7] [clang-repl] Refactor reinitialization check and reorganize tests --- clang/lib/Interpreter/Interpreter.cpp | 3 +++ clang/test/Interpreter/dynamic-library.cpp | 1 + clang/test/Interpreter/out-of-process.cpp | 9 --------- llvm/lib/ExecutionEngine/Orc/LLJIT.cpp | 13 ++++++++----- 4 files changed, 12 insertions(+), 14 deletions(-) diff --git a/clang/lib/Interpreter/Interpreter.cpp b/clang/lib/Interpreter/Interpreter.cpp index 50d1ddbfcf07b..13e6be3b54abc 100644 --- a/clang/lib/Interpreter/Interpreter.cpp +++ b/clang/lib/Interpreter/Interpreter.cpp @@ -492,6 +492,9 @@ llvm::Error Interpreter::LoadDynamicLibrary(const char *name) { if (auto DLSG = llvm::orc::EPCDynamicLibrarySearchGenerator::Load( EE->getExecutionSession(), name)) + EE->getMainJITDylib().addGenerator(std::move(*DLSG)); + else + return DLSG.takeError(); return llvm::Error::success(); } diff --git a/clang/test/Interpreter/dynamic-library.cpp b/clang/test/Interpreter/dynamic-library.cpp index 6c4621f729c1c..c2d186f71ebfe 100644 --- a/clang/test/Interpreter/dynamic-library.cpp +++ b/clang/test/Interpreter/dynamic-library.cpp @@ -15,6 +15,7 @@ // } // RUN: cat %s | env LD_LIBRARY_PATH=%S/Inputs:$LD_LIBRARY_PATH clang-repl | FileCheck %s +// RUN: cat %s | env LD_LIBRARY_PATH=%S/Inputs:$LD_LIBRARY_PATH clang-repl -oop-executor | FileCheck %s extern "C" int printf(const char* format, ...); diff --git a/clang/test/Interpreter/out-of-process.cpp b/clang/test/Interpreter/out-of-process.cpp index 39ae1442f1b13..ddbf86ec65881 100644 --- a/clang/test/Interpreter/out-of-process.cpp +++ b/clang/test/Interpreter/out-of-process.cpp @@ -31,15 +31,6 @@ int a = 12; static __typeof(a) b __attribute__((__weakref__("a"))); int c = b; -// Test dynamic libraries. -extern "C" int ultimate_answer; -extern "C" int calculate_answer(); -%lib libdynamic-library-test.so -printf("Return value: %d\n", calculate_answer()); -// CHECK: Return value: 5 -printf("Variable: %d\n", ultimate_answer); -// CHECK-NEXT: Variable: 42 - // Test lambdas. auto l1 = []() { printf("ONE\n"); return 42; }; auto l2 = []() { printf("TWO\n"); return 17; }; diff --git a/llvm/lib/ExecutionEngine/Orc/LLJIT.cpp b/llvm/lib/ExecutionEngine/Orc/LLJIT.cpp index 54030c83b7eb0..9bfbe951727c8 100644 --- a/llvm/lib/ExecutionEngine/Orc/LLJIT.cpp +++ b/llvm/lib/ExecutionEngine/Orc/LLJIT.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "llvm/ExecutionEngine/Orc/LLJIT.h" +#include "llvm/ADT/SmallSet.h" #include "llvm/ExecutionEngine/JITLink/EHFrameSupport.h" #include "llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h" #include "llvm/ExecutionEngine/Orc/COFFPlatform.h" @@ -108,10 +109,10 @@ class ORCPlatformSupport : public LLJIT::PlatformSupport { std::string WrapperToCall = "__orc_rt_jit_dlopen_wrapper"; auto Triple = ES.getTargetTriple(); if (Triple.isOSBinFormatELF()) { - WrapperToCall = FirstInitialization ? "__orc_rt_jit_dlopen_wrapper" : "__orc_rt_jit_dlupdate_wrapper"; - if (FirstInitialization) { - FirstInitialization = false; - } + WrapperToCall = !InitializedJITDylibs.contains(&JD) + ? "__orc_rt_jit_dlopen_wrapper" + : "__orc_rt_jit_dlupdate_wrapper"; + InitializedJITDylibs.insert(&JD); } if (auto WrapperAddr = @@ -152,7 +153,9 @@ class ORCPlatformSupport : public LLJIT::PlatformSupport { private: orc::LLJIT &J; DenseMap<orc::JITDylib *, orc::ExecutorAddr> DSOHandles; - bool FirstInitialization = true; // Used to track if reinitialization is needed for ELF + llvm::SmallPtrSet<orc::JITDylib const *, 8> + InitializedJITDylibs; // Used to track if reinitialization is required for + // ELF. }; class GenericLLVMIRPlatformSupport; >From 40adce49c38437c998c2bb41cd090da7aba76366 Mon Sep 17 00:00:00 2001 From: James Hu <jhudson15...@gmail.com> Date: Wed, 31 Jan 2024 21:19:51 -0500 Subject: [PATCH 5/7] [clang-repl] Disable networking headers on Windows --- clang/include/clang/Interpreter/Interpreter.h | 3 ++- clang/lib/Interpreter/IncrementalExecutor.cpp | 3 ++- clang/lib/Interpreter/IncrementalExecutor.h | 3 ++- clang/lib/Interpreter/Interpreter.cpp | 2 +- clang/tools/clang-repl/ClangRepl.cpp | 7 +++++-- compiler-rt/lib/orc/dlfcn_wrapper.cpp | 2 -- llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp | 2 +- llvm/lib/ExecutionEngine/Orc/LLJIT.cpp | 3 +-- 8 files changed, 14 insertions(+), 11 deletions(-) diff --git a/clang/include/clang/Interpreter/Interpreter.h b/clang/include/clang/Interpreter/Interpreter.h index 314beb7b72dac..c1e63a9cdb631 100644 --- a/clang/include/clang/Interpreter/Interpreter.h +++ b/clang/include/clang/Interpreter/Interpreter.h @@ -107,7 +107,8 @@ class Interpreter { static llvm::Expected<std::unique_ptr<Interpreter>> createWithOutOfProcessExecutor( std::unique_ptr<CompilerInstance> CI, - std::unique_ptr<llvm::orc::ExecutorProcessControl> EI, llvm::StringRef OrcRuntimePath); + std::unique_ptr<llvm::orc::ExecutorProcessControl> EI, + llvm::StringRef OrcRuntimePath); const ASTContext &getASTContext() const; ASTContext &getASTContext(); const CompilerInstance *getCompilerInstance() const; diff --git a/clang/lib/Interpreter/IncrementalExecutor.cpp b/clang/lib/Interpreter/IncrementalExecutor.cpp index 30b24caa4a594..62458e5182492 100644 --- a/clang/lib/Interpreter/IncrementalExecutor.cpp +++ b/clang/lib/Interpreter/IncrementalExecutor.cpp @@ -66,7 +66,8 @@ IncrementalExecutor::IncrementalExecutor(llvm::orc::ThreadSafeContext &TSC, IncrementalExecutor::IncrementalExecutor( llvm::orc::ThreadSafeContext &TSC, llvm::Error &Err, const clang::TargetInfo &TI, - std::unique_ptr<llvm::orc::ExecutorProcessControl> EPC, llvm::StringRef OrcRuntimePath) + std::unique_ptr<llvm::orc::ExecutorProcessControl> EPC, + llvm::StringRef OrcRuntimePath) : TSCtx(TSC) { using namespace llvm::orc; llvm::ErrorAsOutParameter EAO(&Err); diff --git a/clang/lib/Interpreter/IncrementalExecutor.h b/clang/lib/Interpreter/IncrementalExecutor.h index a73ba9035182c..6d75594793e6d 100644 --- a/clang/lib/Interpreter/IncrementalExecutor.h +++ b/clang/lib/Interpreter/IncrementalExecutor.h @@ -48,7 +48,8 @@ class IncrementalExecutor { const clang::TargetInfo &TI); IncrementalExecutor(llvm::orc::ThreadSafeContext &TSC, llvm::Error &Err, const clang::TargetInfo &TI, - std::unique_ptr<llvm::orc::ExecutorProcessControl> EPC, llvm::StringRef OrcRuntimePath); + std::unique_ptr<llvm::orc::ExecutorProcessControl> EPC, + llvm::StringRef OrcRuntimePath); ~IncrementalExecutor(); llvm::Error addModule(PartialTranslationUnit &PTU); diff --git a/clang/lib/Interpreter/Interpreter.cpp b/clang/lib/Interpreter/Interpreter.cpp index 13e6be3b54abc..fbc866723773a 100644 --- a/clang/lib/Interpreter/Interpreter.cpp +++ b/clang/lib/Interpreter/Interpreter.cpp @@ -244,7 +244,7 @@ Interpreter::~Interpreter() { toString(std::move(Err))); } - if (EPC) { + if (EPC) { if (auto Err = EPC->disconnect()) { llvm::report_fatal_error( llvm::Twine("Failed to clean up EPC (IncrementalExecutor has not yet " diff --git a/clang/tools/clang-repl/ClangRepl.cpp b/clang/tools/clang-repl/ClangRepl.cpp index 1c43e7b503646..8b00d550b10e4 100644 --- a/clang/tools/clang-repl/ClangRepl.cpp +++ b/clang/tools/clang-repl/ClangRepl.cpp @@ -26,11 +26,14 @@ #include "llvm/Support/Signals.h" #include "llvm/Support/TargetSelect.h" #include "llvm/TargetParser/Host.h" -#include <netdb.h> #include <optional> -#include <sys/socket.h> #include <sys/types.h> + +#ifdef LLVM_ON_UNIX +#include <netdb.h> +#include <sys/socket.h> #include <unistd.h> +#endif // LLVM_ON_UNIX // Disable LSan for this test. // FIXME: Re-enable once we can assume GCC 13.2 or higher. diff --git a/compiler-rt/lib/orc/dlfcn_wrapper.cpp b/compiler-rt/lib/orc/dlfcn_wrapper.cpp index a8b207d27157e..b2c4857e31392 100644 --- a/compiler-rt/lib/orc/dlfcn_wrapper.cpp +++ b/compiler-rt/lib/orc/dlfcn_wrapper.cpp @@ -53,8 +53,6 @@ __orc_rt_jit_dlupdate_wrapper(const char *ArgData, size_t ArgSize) { .release(); } - - ORC_RT_INTERFACE orc_rt_CWrapperFunctionResult __orc_rt_jit_dlclose_wrapper(const char *ArgData, size_t ArgSize) { return WrapperFunction<int32_t(SPSExecutorAddr)>::handle( diff --git a/llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp b/llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp index b32d9d4c1046d..a3c5b589603ac 100644 --- a/llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp +++ b/llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp @@ -551,7 +551,7 @@ Error ELFNixPlatform::registerInitInfo( } Lock.lock(); - // We can allow reinitialization by reinserting the handles to each + // We can allow reinitialization by reinserting the handles to each // JITDylib into InitSeqs. InitSeqs.insert(std::make_pair( &JD, diff --git a/llvm/lib/ExecutionEngine/Orc/LLJIT.cpp b/llvm/lib/ExecutionEngine/Orc/LLJIT.cpp index 9bfbe951727c8..229fd97ecab2d 100644 --- a/llvm/lib/ExecutionEngine/Orc/LLJIT.cpp +++ b/llvm/lib/ExecutionEngine/Orc/LLJIT.cpp @@ -116,8 +116,7 @@ class ORCPlatformSupport : public LLJIT::PlatformSupport { } if (auto WrapperAddr = - ES.lookup(MainSearchOrder, - J.mangleAndIntern(WrapperToCall))) { + ES.lookup(MainSearchOrder, J.mangleAndIntern(WrapperToCall))) { return ES.callSPSWrapper<SPSDLOpenSig>(WrapperAddr->getAddress(), DSOHandles[&JD], JD.getName(), int32_t(ORC_RT_RTLD_LAZY)); >From 54dca498962884e4a9dab5bc7c0cca5fcf7cf63f Mon Sep 17 00:00:00 2001 From: James Hu <jhudson15...@gmail.com> Date: Thu, 1 Feb 2024 18:59:57 -0500 Subject: [PATCH 6/7] [clang-repl] Disable executor launch in Windows --- clang/lib/Interpreter/IncrementalExecutor.cpp | 3 +- clang/lib/Interpreter/Interpreter.cpp | 8 ++--- clang/tools/clang-repl/ClangRepl.cpp | 30 ++++++++++++++----- 3 files changed, 29 insertions(+), 12 deletions(-) diff --git a/clang/lib/Interpreter/IncrementalExecutor.cpp b/clang/lib/Interpreter/IncrementalExecutor.cpp index 62458e5182492..3da8d24606c37 100644 --- a/clang/lib/Interpreter/IncrementalExecutor.cpp +++ b/clang/lib/Interpreter/IncrementalExecutor.cpp @@ -83,7 +83,8 @@ IncrementalExecutor::IncrementalExecutor( return llvm::Error::success(); }); Builder.setExecutorProcessControl(std::move(EPC)); - Builder.setPlatformSetUp(llvm::orc::ExecutorNativePlatform(OrcRuntimePath.str())); + Builder.setPlatformSetUp( + llvm::orc::ExecutorNativePlatform(OrcRuntimePath.str())); if (auto JitOrErr = Builder.create()) { Jit = std::move(*JitOrErr); diff --git a/clang/lib/Interpreter/Interpreter.cpp b/clang/lib/Interpreter/Interpreter.cpp index fbc866723773a..5953afbb17f8e 100644 --- a/clang/lib/Interpreter/Interpreter.cpp +++ b/clang/lib/Interpreter/Interpreter.cpp @@ -325,11 +325,11 @@ Interpreter::createWithCUDA(std::unique_ptr<CompilerInstance> CI, return Interp; } - llvm::Expected<std::unique_ptr<Interpreter>> Interpreter::createWithOutOfProcessExecutor( std::unique_ptr<CompilerInstance> CI, - std::unique_ptr<llvm::orc::ExecutorProcessControl> EI, llvm::StringRef OrcRuntimePath) { + std::unique_ptr<llvm::orc::ExecutorProcessControl> EI, + llvm::StringRef OrcRuntimePath) { auto Interp = create(std::move(CI)); if (auto E = Interp.takeError()) { return std::move(E); @@ -389,8 +389,8 @@ llvm::Error Interpreter::CreateExecutor() { llvm::Error Err = llvm::Error::success(); std::unique_ptr<IncrementalExecutor> Executor; if (EPC) { - Executor = - std::make_unique<IncrementalExecutor>(*TSCtx, Err, TI, std::move(EPC), OrcRuntimePath); + Executor = std::make_unique<IncrementalExecutor>( + *TSCtx, Err, TI, std::move(EPC), OrcRuntimePath); } else { Executor = std::make_unique<IncrementalExecutor>(*TSCtx, Err, TI); } diff --git a/clang/tools/clang-repl/ClangRepl.cpp b/clang/tools/clang-repl/ClangRepl.cpp index 8b00d550b10e4..2aa2ad6416704 100644 --- a/clang/tools/clang-repl/ClangRepl.cpp +++ b/clang/tools/clang-repl/ClangRepl.cpp @@ -66,10 +66,9 @@ static llvm::cl::opt<std::string> OutOfProcessExecutorConnect( "oop-executor-connect", llvm::cl::desc("Connect to an out-of-process executor via TCP"), llvm::cl::cat(OOPCategory)); -static llvm::cl::opt<std::string> OrcRuntimePath( - "orc-runtime", - llvm::cl::desc("Path to the ORC runtime"), - llvm::cl::cat(OOPCategory)); +static llvm::cl::opt<std::string> + OrcRuntimePath("orc-runtime", llvm::cl::desc("Path to the ORC runtime"), + llvm::cl::cat(OOPCategory)); static void LLVMErrorHandler(void *UserData, const char *Message, bool GenCrashDiag) { @@ -197,13 +196,17 @@ static llvm::Error sanitizeOopArguments(const char *ArgV0) { OutOfProcessExecutor = OOPExecutorPath.str().str(); } - // Out-of-process executors must run with the ORC runtime for destructor support. - if (OrcRuntimePath.empty() && (OutOfProcessExecutor.getNumOccurrences() || OutOfProcessExecutorConnect.getNumOccurrences())) { + // Out-of-process executors must run with the ORC runtime for destructor + // support. + if (OrcRuntimePath.empty() && + (OutOfProcessExecutor.getNumOccurrences() || + OutOfProcessExecutorConnect.getNumOccurrences())) { llvm::SmallString<256> OrcPath(llvm::sys::fs::getMainExecutable( ArgV0, reinterpret_cast<void *>(&sanitizeOopArguments))); llvm::sys::path::remove_filename(OrcPath); // Remove clang-repl filename. llvm::sys::path::remove_filename(OrcPath); // Remove ./bin directory. - llvm::sys::path::append(OrcPath, "lib/clang/18/lib/x86_64-unknown-linux-gnu/liborc_rt.a"); + llvm::sys::path::append( + OrcPath, "lib/clang/18/lib/x86_64-unknown-linux-gnu/liborc_rt.a"); OrcRuntimePath = OrcPath.str().str(); } @@ -212,6 +215,18 @@ static llvm::Error sanitizeOopArguments(const char *ArgV0) { static llvm::Expected<std::unique_ptr<llvm::orc::ExecutorProcessControl>> launchExecutor() { +#ifndef LLVM_ON_UNIX + // FIXME: Add support for Windows. + return make_error<StringError>("-" + OutOfProcessExecutor.ArgStr + + " not supported on non-unix platforms", + inconvertibleErrorCode()); +#elif !LLVM_ENABLE_THREADS + return make_error<StringError>( + "-" + OutOfProcessExecutor.ArgStr + + " requires threads, but LLVM was built with " + "LLVM_ENABLE_THREADS=Off", + inconvertibleErrorCode()); +#else constexpr int ReadEnd = 0; constexpr int WriteEnd = 1; @@ -269,6 +284,7 @@ launchExecutor() { llvm::orc::FDSimpleRemoteEPCTransport>( std::make_unique<llvm::orc::DynamicThreadPoolTaskDispatcher>(), std::move(S), FromExecutor[ReadEnd], ToExecutor[WriteEnd]); +#endif } #if LLVM_ON_UNIX && LLVM_ENABLE_THREADS >From a5e33d9948ec2260aefae25890bca627935f5d4c Mon Sep 17 00:00:00 2001 From: James Hu <jhudson15...@gmail.com> Date: Thu, 1 Feb 2024 19:35:14 -0500 Subject: [PATCH 7/7] [clang-repl] Fix missing namespace --- clang/tools/clang-repl/ClangRepl.cpp | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/clang/tools/clang-repl/ClangRepl.cpp b/clang/tools/clang-repl/ClangRepl.cpp index 2aa2ad6416704..f52a9d8956339 100644 --- a/clang/tools/clang-repl/ClangRepl.cpp +++ b/clang/tools/clang-repl/ClangRepl.cpp @@ -217,15 +217,16 @@ static llvm::Expected<std::unique_ptr<llvm::orc::ExecutorProcessControl>> launchExecutor() { #ifndef LLVM_ON_UNIX // FIXME: Add support for Windows. - return make_error<StringError>("-" + OutOfProcessExecutor.ArgStr + - " not supported on non-unix platforms", - inconvertibleErrorCode()); + return llvm::make_error<llvm::StringError>( + "-" + OutOfProcessExecutor.ArgStr + + " not supported on non-unix platforms", + llvm::inconvertibleErrorCode()); #elif !LLVM_ENABLE_THREADS - return make_error<StringError>( + return llvm::make_error<llvm::StringError>( "-" + OutOfProcessExecutor.ArgStr + " requires threads, but LLVM was built with " "LLVM_ENABLE_THREADS=Off", - inconvertibleErrorCode()); + llvm::inconvertibleErrorCode()); #else constexpr int ReadEnd = 0; constexpr int WriteEnd = 1; @@ -338,17 +339,17 @@ static llvm::Expected<std::unique_ptr<llvm::orc::ExecutorProcessControl>> connectToExecutor() { #ifndef LLVM_ON_UNIX // FIXME: Add TCP support for Windows. - return llvm::make_error<StringError>( + return llvm::make_error<llvm::StringError>( "-" + OutOfProcessExecutorConnect.ArgStr + " not supported on non-unix platforms", - inconvertibleErrorCode()); + llvm::inconvertibleErrorCode()); #elif !LLVM_ENABLE_THREADS // Out of process mode using SimpleRemoteEPC depends on threads. - return llvm::make_error<StringError>( + return llvm::make_error<llvm::StringError>( "-" + OutOfProcessExecutorConnect.ArgStr + " requires threads, but LLVM was built with " "LLVM_ENABLE_THREADS=Off", - inconvertibleErrorCode()); + llvm::inconvertibleErrorCode()); #else llvm::StringRef Host, PortStr; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits