17#include "clang/Config/config.h"
23#include "llvm/ADT/SmallString.h"
24#include "llvm/ADT/SmallVector.h"
25#include "llvm/ADT/StringRef.h"
26#include "llvm/ADT/Twine.h"
28#include "llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h"
29#include "llvm/ExecutionEngine/Orc/AbsoluteSymbols.h"
30#include "llvm/ExecutionEngine/Orc/Debugging/DebuggerSupport.h"
31#include "llvm/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.h"
32#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"
33#include "llvm/ExecutionEngine/Orc/ExecutorProcessControl.h"
34#include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h"
35#include "llvm/ExecutionEngine/Orc/LLJIT.h"
36#include "llvm/ExecutionEngine/Orc/MapperJITLinkMemoryManager.h"
37#include "llvm/ExecutionEngine/Orc/Shared/SimpleRemoteEPCUtils.h"
38#include "llvm/ExecutionEngine/Orc/SharedMemoryMapSPS.h"
39#include "llvm/ExecutionEngine/Orc/SimpleRemoteEPC.h"
41#include "llvm/Support/Error.h"
42#include "llvm/Support/FileSystem.h"
43#include "llvm/Support/FormatVariadic.h"
44#include "llvm/Support/Path.h"
45#include "llvm/Support/raw_ostream.h"
47#include "llvm/TargetParser/Host.h"
58#include <netinet/in.h>
59#include <sys/socket.h>
75#if CLANG_HAVE_EMUTLS_GET_ADDRESS
76extern "C" void *__emutls_get_address(
void *);
78 return reinterpret_cast<void *
>(&__emutls_get_address);
88std::unique_ptr<IncrementalExecutorBuilder>
90 return std::make_unique<OrcIncrementalExecutorBuilder>();
103 return llvm::Error::success();
109 llvm::consumeError(Triple.takeError());
117 auto J = llvm::orc::LLJITBuilder().create();
119 return J.takeError();
120 return (*J)->getTargetTriple();
125 if (TT.getTriple() == llvm::sys::getProcessTriple())
127 return llvm::orc::JITTargetMachineBuilder::detectHost();
130 return llvm::orc::JITTargetMachineBuilder(TT);
135 auto JITBuilder = std::make_unique<llvm::orc::LLJITBuilder>();
136 JITBuilder->setJITTargetMachineBuilder(std::move(JTMB));
137 JITBuilder->setPrePlatformSetup([](llvm::orc::LLJIT &J) {
140 consumeError(llvm::orc::enableDebuggerSupport(J));
141 return llvm::Error::success();
143 return std::move(JITBuilder);
148 unsigned SlabAllocateSize) {
149 auto &ES = EPC.getExecutionSession();
150 auto B = llvm::orc::sps::createSharedMemoryMapBindings(ES);
152 return B.takeError();
155 if (llvm::Triple(llvm::sys::getProcessTriple()).isOSWindows())
156 SlabSize = 1024 * 1024;
158 SlabSize = 1024 * 1024 * 1024;
160 if (SlabAllocateSize > 0)
161 SlabSize = SlabAllocateSize;
163 return llvm::orc::MapperJITLinkMemoryManager::CreateWithMapper<
164 llvm::orc::SharedMemoryMapper>(SlabSize, ES, std::move(*B));
168 std::pair<std::unique_ptr<llvm::orc::SimpleRemoteEPC>,
uint32_t>>
173 return llvm::make_error<llvm::StringError>(
174 "-" + ExecutablePath +
" not supported on non-unix platforms",
175 llvm::inconvertibleErrorCode());
176#elif !LLVM_ENABLE_THREADS
178 return llvm::make_error<llvm::StringError>(
179 "-" + ExecutablePath +
180 " requires threads, but LLVM was built with "
181 "LLVM_ENABLE_THREADS=Off",
182 llvm::inconvertibleErrorCode());
185 if (!llvm::sys::fs::can_execute(ExecutablePath))
186 return llvm::make_error<llvm::StringError>(
187 llvm::formatv(
"Specified executor invalid: {0}", ExecutablePath),
188 llvm::inconvertibleErrorCode());
190 constexpr int ReadEnd = 0;
191 constexpr int WriteEnd = 1;
200 if (pipe(ToExecutor) != 0 || pipe(FromExecutor) != 0)
201 return llvm::make_error<llvm::StringError>(
202 "Unable to create pipe for executor", llvm::inconvertibleErrorCode());
210 close(ToExecutor[WriteEnd]);
211 close(FromExecutor[ReadEnd]);
217 std::unique_ptr<char[]> ExecutorPath, FDSpecifier;
219 ExecutorPath = std::make_unique<char[]>(ExecutablePath.size() + 1);
220 strcpy(ExecutorPath.get(), ExecutablePath.data());
222 std::string FDSpecifierStr(
"filedescs=");
223 FDSpecifierStr += llvm::utostr(ToExecutor[ReadEnd]);
224 FDSpecifierStr +=
',';
225 FDSpecifierStr += llvm::utostr(FromExecutor[WriteEnd]);
226 FDSpecifier = std::make_unique<char[]>(FDSpecifierStr.size() + 1);
227 strcpy(FDSpecifier.get(), FDSpecifierStr.c_str());
230 char *
const Args[] = {ExecutorPath.get(), FDSpecifier.get(),
nullptr};
231 int RC = execvp(ExecutorPath.get(), Args);
233 llvm::errs() <<
"unable to launch out-of-process executor \""
234 << ExecutorPath.get() <<
"\"\n";
241 close(ToExecutor[ReadEnd]);
242 close(FromExecutor[WriteEnd]);
245 llvm::orc::SimpleRemoteEPC::Create<llvm::orc::FDSimpleRemoteEPCTransport>(
246 std::make_unique<llvm::orc::DynamicThreadPoolTaskDispatcher>(
248 FromExecutor[ReadEnd], ToExecutor[WriteEnd]);
250 return EPCOrErr.takeError();
251 return std::make_pair(std::move(*EPCOrErr), ChildPID);
255#if LLVM_ON_UNIX && LLVM_ENABLE_THREADS
258 std::string PortStr) {
261 Hints.ai_family = AF_INET;
262 Hints.ai_socktype = SOCK_STREAM;
263 Hints.ai_flags = AI_NUMERICSERV;
265 if (
int EC = getaddrinfo(
Host.c_str(), PortStr.c_str(), &Hints, &AI))
266 return llvm::make_error<llvm::StringError>(
267 llvm::formatv(
"address resolution failed ({0})", strerror(EC)),
268 llvm::inconvertibleErrorCode());
273 for (Server = AI; Server !=
nullptr; Server = Server->ai_next) {
276 if ((SockFD = socket(AI->ai_family, AI->ai_socktype, AI->ai_protocol)) < 0)
280 if (connect(SockFD, Server->ai_addr, Server->ai_addrlen) == 0)
289 if (Server ==
nullptr)
290 return llvm::make_error<llvm::StringError>(
"invalid hostname",
291 llvm::inconvertibleErrorCode());
297connectTCPSocket(llvm::StringRef NetworkAddress) {
300 return llvm::make_error<llvm::StringError>(
301 "-" + NetworkAddress +
" not supported on non-unix platforms",
302 llvm::inconvertibleErrorCode());
303#elif !LLVM_ENABLE_THREADS
305 return llvm::make_error<llvm::StringError>(
306 "-" + NetworkAddress +
307 " requires threads, but LLVM was built with "
308 "LLVM_ENABLE_THREADS=Off",
309 llvm::inconvertibleErrorCode());
312 auto CreateErr = [NetworkAddress](Twine Details) {
313 return llvm::make_error<llvm::StringError>(
314 formatv(
"Failed to connect TCP socket '{0}': {1}", NetworkAddress,
316 llvm::inconvertibleErrorCode());
319 StringRef
Host, PortStr;
320 std::tie(
Host, PortStr) = NetworkAddress.split(
':');
322 return CreateErr(
"Host name for -" + NetworkAddress +
" can not be empty");
324 return CreateErr(
"Port number in -" + NetworkAddress +
" can not be empty");
326 if (PortStr.getAsInteger(10, Port))
327 return CreateErr(
"Port number '" + PortStr +
"' is not a valid integer");
331 return SockFD.takeError();
333 return llvm::orc::SimpleRemoteEPC::Create<
334 llvm::orc::FDSimpleRemoteEPCTransport>(
335 std::make_unique<llvm::orc::DynamicThreadPoolTaskDispatcher>(
344 llvm::StringRef OrcRuntimePath) {
347 return JTMB.takeError();
350 return JB.takeError();
352 (*JB)->setExecutorProcessControl(std::move(EPC));
353 (*JB)->setPlatformSetUp(
354 llvm::orc::ExecutorNativePlatform(OrcRuntimePath.str()));
356 return std::move(*JB);
360 std::pair<std::unique_ptr<llvm::orc::LLJITBuilder>,
uint32_t>>
363 std::unique_ptr<llvm::orc::ExecutorProcessControl> EPC;
370 return ResultOrErr.takeError();
371 childPid = ResultOrErr->second;
372 auto EPCOrErr = std::move(ResultOrErr->first);
373 EPC = std::move(EPCOrErr);
375#if LLVM_ON_UNIX && LLVM_ENABLE_THREADS
378 return EPCOrErr.takeError();
379 EPC = std::move(*EPCOrErr);
381 return llvm::make_error<llvm::StringError>(
382 "Out-of-process JIT over TCP is not supported on this platform",
387 std::unique_ptr<llvm::orc::LLJITBuilder> JB;
392 return JBOrErr.takeError();
393 JB = std::move(*JBOrErr);
396 JB->setMemoryManagerCreator(
398 llvm::orc::ExecutionSession &ES) {
399 return createSharedMemoryManager(ES.getExecutorProcessControl(),
404 return std::make_pair(std::move(JB), childPid);
408OrcIncrementalExecutorBuilder::createExecutor(llvm::orc::ThreadSafeContext &TSC,
415 return ResOrErr.takeError();
420 return llvm::make_error<llvm::StringError>(
421 "Operation failed. No LLJITBuilder for out-of-process JIT",
428 return JTMB.takeError();
430 JTMB->setCodeModel(
CM);
433 return JB.takeError();
451 [EmuTLSGetAddress](llvm::orc::LLJIT &J) {
452 auto &JD = J.getProcessSymbolsJITDylib()
453 ? *J.getProcessSymbolsJITDylib()
454 : J.getMainJITDylib();
455 return JD.define(llvm::orc::absoluteSymbols(
456 {{J.mangleAndIntern(
"__emutls_get_address"),
457 {llvm::orc::ExecutorAddr::fromPtr(EmuTLSGetAddress),
458 llvm::JITSymbolFlags::Exported}}}));
462 llvm::Error Err = llvm::Error::success();
463 std::unique_ptr<IncrementalExecutor> Executor =
464 std::make_unique<OrcIncrementalExecutor>(TSC, *
JITBuilder, Err);
467 return std::move(Err);
469 return std::move(Executor);
472llvm::Error OrcIncrementalExecutorBuilder::UpdateOrcRuntimePath(
473 const clang::driver::Compilation &
C) {
475 return llvm::Error::success();
477 const clang::driver::Driver &D =
C.getDriver();
478 const clang::driver::ToolChain &TC =
C.getDefaultToolChain();
480 llvm::SmallVector<std::string, 2> OrcRTLibNames;
483 std::string CompilerRTPath = TC.
getCompilerRT(
C.getArgs(),
"orc_rt");
484 llvm::StringRef CanonicalFilename = llvm::sys::path::filename(CompilerRTPath);
486 if (CanonicalFilename.empty()) {
487 return llvm::make_error<llvm::StringError>(
488 "Could not determine OrcRuntime filename from ToolChain",
489 llvm::inconvertibleErrorCode());
492 OrcRTLibNames.push_back(CanonicalFilename.str());
495 llvm::StringRef LegacySuffix = CanonicalFilename;
496 if (LegacySuffix.consume_front(
"libclang_rt.")) {
497 OrcRTLibNames.push_back((
"lib" + LegacySuffix).str());
501 llvm::SmallString<256> OrcRTDir(CompilerRTPath);
502 llvm::sys::path::remove_filename(OrcRTDir);
504 llvm::SmallVector<std::string, 8> triedPaths;
506 auto findInDir = [&](llvm::StringRef Dir) -> std::optional<std::string> {
507 for (
const auto &LibName : OrcRTLibNames) {
508 llvm::SmallString<256> FullPath = Dir;
509 llvm::sys::path::append(FullPath, LibName);
510 if (llvm::sys::fs::exists(FullPath))
511 return std::string(FullPath.str());
512 triedPaths.push_back(std::string(FullPath.str()));
518 if (
auto Found = findInDir(OrcRTDir)) {
520 return llvm::Error::success();
525 llvm::StringRef Rel = OrcRTDir.str();
526 if (!Rel.consume_front(llvm::sys::path::parent_path(D.
Dir))) {
527 return llvm::make_error<llvm::StringError>(
528 llvm::formatv(
"OrcRuntime library path ({0}) is not located within the "
529 "Clang resource directory ({1}). Check your installation "
530 "or provide an explicit path via -resource-dir.",
533 llvm::inconvertibleErrorCode());
539 while (llvm::sys::path::has_parent_path(Cursor)) {
540 Cursor = llvm::sys::path::parent_path(Cursor).str();
541 llvm::SmallString<256> Candidate =
Cursor;
542 llvm::sys::path::append(Candidate, Rel);
544 if (
auto Found = findInDir(Candidate)) {
546 return llvm::Error::success();
550 if (triedPaths.size() > 32)
556 for (
size_t i = 0; i < triedPaths.size(); ++i) {
559 Joined += triedPaths[i];
562 return llvm::make_error<llvm::StringError>(
563 llvm::formatv(
"OrcRuntime library not found. Checked: {0}",
564 Joined.empty() ?
"<none>" : Joined)
566 std::make_error_code(std::errc::no_such_file_or_directory));
static void * getEmuTLSGetAddressPtr()
Create a pre-configured CompilerInstance for incremental processing.
void SetDriverCompilationCallback(std::function< DriverCompilationFn > C)
static std::unique_ptr< IncrementalExecutorBuilder > createDefault()
Create the default builder for the platform clangInterpreter is built for.
Configuration for in-process and out-of-process ORC execution.
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.
llvm::Error configure(IncrementalCompilerBuilder &CB, const Options &Opts) override
Apply execution options and configure the compiler for this backend.
bool UseSharedMemory
Indicates whether to use shared memory for communication.
std::function< llvm::Error(const driver::Compilation &)> UpdateOrcRuntimePathCB
A default callback that can be used in the IncrementalCompilerBuilder to retrieve the path to the orc...
bool supportsJIT() const override
Probe whether this backend can JIT code for the host.
std::string OOPExecutorConnect
std::unique_ptr< llvm::orc::LLJITBuilder > JITBuilder
An optional external ORC JIT builder.
std::function< void()> CustomizeFork
Custom lambda to be executed inside child process/executor.
std::string OrcRuntimePath
Path to the ORC runtime library.
OrcIncrementalExecutorBuilder()
llvm::Expected< llvm::Triple > getHostJITTriple() const override
Return the host triple used by this backend.
~OrcIncrementalExecutorBuilder() override
std::string OOPExecutor
Path to the out-of-process JIT executor.
uint32_t ExecutorPID
PID of the out-of-process JIT executor.
bool IsOutOfProcess
Indicates whether out-of-process JIT execution is enabled.
Exposes information about the current target.
const llvm::Triple & getTriple() const
Returns the target triple of the primary target.
std::string Dir
The path the driver executable was in, as invoked from the command line.
Defines the clang::TargetInfo interface.
Top level wrappers for InstallAPI frontend operations.
static llvm::Expected< std::unique_ptr< llvm::orc::LLJITBuilder > > createLLJITBuilder(std::unique_ptr< llvm::orc::ExecutorProcessControl > EPC, llvm::StringRef OrcRuntimePath)
static llvm::Expected< std::pair< std::unique_ptr< llvm::orc::LLJITBuilder >, uint32_t > > outOfProcessJITBuilder(const OrcIncrementalExecutorBuilder &IncrExecutorBuilder)
static llvm::Expected< std::unique_ptr< llvm::orc::LLJITBuilder > > createDefaultJITBuilder(llvm::orc::JITTargetMachineBuilder JTMB)
static llvm::Expected< std::pair< std::unique_ptr< llvm::orc::SimpleRemoteEPC >, uint32_t > > launchExecutor(llvm::StringRef ExecutablePath, std::function< void()> CustomizeFork)
static llvm::Expected< llvm::orc::JITTargetMachineBuilder > createJITTargetMachineBuilder(const llvm::Triple &TT)
Expected< std::unique_ptr< llvm::jitlink::JITLinkMemoryManager > > createSharedMemoryManager(llvm::orc::ExecutorProcessControl &EPC, unsigned SlabAllocateSize)
int const char * function
Options passed to the backend when configuring execution.
unsigned SlabAllocateSize