Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions clang/include/clang/Interpreter/Interpreter.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
#define LLVM_CLANG_INTERPRETER_INTERPRETER_H

#include "clang/AST/GlobalDecl.h"
#include "clang/Driver/ToolChain.h"
#include "clang/Interpreter/OutOfProcessJITConfig.h"
#include "clang/Interpreter/PartialTranslationUnit.h"
#include "clang/Interpreter/Value.h"

Expand Down Expand Up @@ -136,15 +138,19 @@ class Interpreter {

public:
virtual ~Interpreter();
static llvm::Expected<std::unique_ptr<Interpreter>>
create(std::unique_ptr<CompilerInstance> CI,
std::unique_ptr<llvm::orc::LLJITBuilder> JITBuilder = nullptr);
static llvm::Expected<std::unique_ptr<Interpreter>> create(
std::unique_ptr<CompilerInstance> CI,
std::optional<OutOfProcessJITConfig> OutOfProcessConfig = std::nullopt);
static llvm::Expected<std::unique_ptr<Interpreter>>
createWithCUDA(std::unique_ptr<CompilerInstance> CI,
std::unique_ptr<CompilerInstance> DCI);
static llvm::Expected<std::unique_ptr<llvm::orc::LLJITBuilder>>
createLLJITBuilder(std::unique_ptr<llvm::orc::ExecutorProcessControl> EPC,
llvm::StringRef OrcRuntimePath);
static std::unique_ptr<llvm::orc::LLJITBuilder>
outOfProcessJITBuilder(OutOfProcessJITConfig OutOfProcessConfig);
static llvm::Expected<std::string>
getOrcRuntimePath(const driver::ToolChain &TC);
const ASTContext &getASTContext() const;
ASTContext &getASTContext();
const CompilerInstance *getCompilerInstance() const;
Expand Down
45 changes: 45 additions & 0 deletions clang/include/clang/Interpreter/OutOfProcessJITConfig.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
//===-- OutOfProcessJITConfig.h - Struct for Out-Of-Process JIT--*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file defines a struct that holds configuration options for
// out-of-process JIT execution.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_INTERPRETER_OUTOFPROCESSJITCONFIG_H
#define LLVM_CLANG_INTERPRETER_OUTOFPROCESSJITCONFIG_H

#include <functional>
#include <string>
#include <utility>

namespace clang {

/// \brief Configuration options for out-of-process JIT execution.
struct OutOfProcessJITConfig {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That struct can go as a nested Interpreter class.

/// Indicates whether out-of-process JIT execution is enabled.
bool IsOutOfProcess = false;

/// Path to the out-of-process JIT executor.
std::string OOPExecutor;

std::string OOPExecutorConnect;

/// Indicates whether to use shared memory for communication.
bool UseSharedMemory;

/// String representing the slab allocation size for memory management.
std::string SlabAllocateSizeString;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be an unsigned int I think. All of these should have good default values.


/// Path to the ORC runtime library.
std::string OrcRuntimePath;
};

} // namespace clang

#endif // LLVM_CLANG_INTERPRETER_OUTOFPROCESSJITCONFIG_H
12 changes: 11 additions & 1 deletion clang/include/clang/Interpreter/RemoteJITUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@

llvm::Expected<std::unique_ptr<llvm::orc::SimpleRemoteEPC>>
launchExecutor(llvm::StringRef ExecutablePath, bool UseSharedMemory,
llvm::StringRef SlabAllocateSizeString);
llvm::StringRef SlabAllocateSizeString,
std::function<void()> CustomizeFork = nullptr);

/// Create a JITLinkExecutor that connects to the given network address
/// through a TCP socket. A valid NetworkAddress provides hostname and port,
Expand All @@ -35,4 +36,13 @@ llvm::Expected<std::unique_ptr<llvm::orc::SimpleRemoteEPC>>
connectTCPSocket(llvm::StringRef NetworkAddress, bool UseSharedMemory,
llvm::StringRef SlabAllocateSizeString);

#ifdef LLVM_ON_UNIX
/// Returns PID of last launched executor.
pid_t getLastLaunchedExecutorPID();

/// Returns PID of nth launched executor.
/// 1-based indexing.
pid_t getNthLaunchedExecutorPID(int n);
#endif

#endif // LLVM_CLANG_INTERPRETER_REMOTEJITUTILS_H
95 changes: 94 additions & 1 deletion clang/lib/Interpreter/Interpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@
#include "clang/Frontend/TextDiagnosticBuffer.h"
#include "clang/FrontendTool/Utils.h"
#include "clang/Interpreter/Interpreter.h"
#include "clang/Interpreter/OutOfProcessJITConfig.h"
#include "clang/Interpreter/RemoteJITUtils.h"
#include "clang/Interpreter/Value.h"
#include "clang/Lex/PreprocessorOptions.h"
#include "clang/Sema/Lookup.h"
Expand All @@ -55,6 +57,8 @@
#include "llvm/TargetParser/Host.h"
#include "llvm/Transforms/Utils/Cloning.h" // for CloneModule

#include <iostream>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We probably do not need this include.


#define DEBUG_TYPE "clang-repl"

using namespace clang;
Expand Down Expand Up @@ -460,10 +464,99 @@ const char *const Runtimes = R"(
EXTERN_C void __clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal, void *OpaqueType, ...);
)";

llvm::ExitOnError ExitOnErr;

std::unique_ptr<llvm::orc::LLJITBuilder>
Interpreter::outOfProcessJITBuilder(OutOfProcessJITConfig OutOfProcessConfig) {
std::unique_ptr<llvm::orc::ExecutorProcessControl> EPC;
if (OutOfProcessConfig.OOPExecutor != "") {
// Launch an out-of-process executor locally in a child process.
EPC = ExitOnErr(launchExecutor(OutOfProcessConfig.OOPExecutor,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remember this is the library, it must not abort the process. Instead the interface should return llvm::Expected<std::unique_ptr<llvm::orc::LLJITBuilder>> and propagate the error up.

OutOfProcessConfig.UseSharedMemory,
OutOfProcessConfig.SlabAllocateSizeString));
} else if (OutOfProcessConfig.OOPExecutorConnect != "") {
EPC =
ExitOnErr(connectTCPSocket(OutOfProcessConfig.OOPExecutorConnect,
OutOfProcessConfig.UseSharedMemory,
OutOfProcessConfig.SlabAllocateSizeString));
}

std::unique_ptr<llvm::orc::LLJITBuilder> JB;
if (EPC) {
JB = ExitOnErr(clang::Interpreter::createLLJITBuilder(
std::move(EPC), OutOfProcessConfig.OrcRuntimePath));
}

return JB;
}

llvm::Expected<std::string>
Interpreter::getOrcRuntimePath(const driver::ToolChain &TC) {
std::optional<std::string> CompilerRTPath = TC.getCompilerRTPath();
if (!CompilerRTPath) {
return llvm::make_error<llvm::StringError>("CompilerRT path not found",
std::error_code());
}
llvm::SmallString<256> BasePath(llvm::sys::fs::getMainExecutable(
"clang-repl", reinterpret_cast<void *>(&getOrcRuntimePath)));
Comment on lines +500 to +501
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That does not work when we are in a library. Why do we need the BasePath at all? I'd think we can ask the TC and that is mostly it. Do you try to get somehow to the source directory?

// Remove paths until you find /build at last
while (!(llvm::sys::path::filename(BasePath) == "build") &&
!BasePath.empty()) {
llvm::sys::path::remove_filename(BasePath);
}

llvm::sys::path::append(BasePath, *CompilerRTPath);

if (llvm::sys::fs::exists(BasePath.str().str() + "/liborc_rt.a")) {
llvm::sys::path::append(BasePath, "liborc_rt.a");
} else if (llvm::sys::fs::exists(BasePath.str().str() + "/liborc_rt_osx.a")) {
llvm::sys::path::append(BasePath, "liborc_rt_osx.a");
} else if (llvm::sys::fs::exists(BasePath.str().str() +
"/liborc_rt-x86_64.a")) {
llvm::sys::path::append(BasePath, "liborc_rt-x86_64.a");
} else {
return llvm::make_error<llvm::StringError>("OrcRuntime library not found",
std::error_code());
}

return BasePath.str().str();
}

llvm::Expected<std::unique_ptr<Interpreter>>
Interpreter::create(std::unique_ptr<CompilerInstance> CI,
std::unique_ptr<llvm::orc::LLJITBuilder> JB) {
std::optional<OutOfProcessJITConfig> OutOfProcessConfig) {
llvm::Error Err = llvm::Error::success();

std::unique_ptr<llvm::orc::LLJITBuilder> JB;

if (OutOfProcessConfig != std::nullopt &&
OutOfProcessConfig->IsOutOfProcess) {
const TargetInfo &TI = CI->getTarget();
const llvm::Triple &Triple = TI.getTriple();

DiagnosticsEngine &Diags = CI->getDiagnostics();
driver::Driver Driver("clang", Triple.str(), Diags);

std::vector<const char *> Args = {"clang", "--version"};
std::unique_ptr<clang::driver::Compilation> C(
Driver.BuildCompilation(Args));
if (!C) {
return llvm::make_error<llvm::StringError>(
"Failed to create driver compilation for out-of-process JIT",
std::error_code());
}

const clang::driver::ToolChain &TC = C->getDefaultToolChain();

auto OrcRuntimePathOrErr = getOrcRuntimePath(TC);
if (!OrcRuntimePathOrErr) {
return OrcRuntimePathOrErr.takeError();
}

OutOfProcessConfig->OrcRuntimePath = *OrcRuntimePathOrErr;
JB = outOfProcessJITBuilder(*OutOfProcessConfig);
}

auto Interp = std::unique_ptr<Interpreter>(
new Interpreter(std::move(CI), Err, JB ? std::move(JB) : nullptr));
if (Err)
Expand Down
31 changes: 30 additions & 1 deletion clang/lib/Interpreter/RemoteJITUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@
using namespace llvm;
using namespace llvm::orc;

#if LLVM_ON_UNIX
static std::vector<pid_t> LaunchedExecutorPID;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That should be a member of the Interpreter class I think.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This vector is updated in launchExecutor. And launchExecutor is called before creation of interpreter. I can define it as static but I don't think it is related enough to be in interpreter class.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need a home for this. The process is not the right home. Either the Interpreter class or the IncrementalExecutor should be good options.

#endif

Expected<uint64_t> getSlabAllocSize(StringRef SizeString) {
SizeString = SizeString.trim();

Expand Down Expand Up @@ -89,9 +93,14 @@ createSharedMemoryManager(SimpleRemoteEPC &SREPC,
SlabSize, SREPC, SAs);
}

// Launches an out-of-process executor for remote JIT. The calling program can
// provide a CustomizeFork callback, which allows it to run custom code in the
// child process before exec. This enables sending custom setup or code to be
// executed in the child (out-of-process) executor.
Expected<std::unique_ptr<SimpleRemoteEPC>>
launchExecutor(StringRef ExecutablePath, bool UseSharedMemory,
llvm::StringRef SlabAllocateSizeString) {
llvm::StringRef SlabAllocateSizeString,
std::function<void()> CustomizeFork) {
#ifndef LLVM_ON_UNIX
// FIXME: Add support for Windows.
return make_error<StringError>("-" + ExecutablePath +
Expand Down Expand Up @@ -134,6 +143,9 @@ launchExecutor(StringRef ExecutablePath, bool UseSharedMemory,
close(ToExecutor[WriteEnd]);
close(FromExecutor[ReadEnd]);

if (CustomizeFork)
CustomizeFork();

// Execute the child process.
std::unique_ptr<char[]> ExecutorPath, FDSpecifier;
{
Expand All @@ -158,6 +170,8 @@ launchExecutor(StringRef ExecutablePath, bool UseSharedMemory,
}
// else we're the parent...

LaunchedExecutorPID.push_back(ChildPID);

// Close the child ends of the pipes
close(ToExecutor[ReadEnd]);
close(FromExecutor[WriteEnd]);
Expand Down Expand Up @@ -265,3 +279,18 @@ connectTCPSocket(StringRef NetworkAddress, bool UseSharedMemory,
std::move(S), *SockFD, *SockFD);
#endif
}

#if LLVM_ON_UNIX

pid_t getLastLaunchedExecutorPID() {
if (!LaunchedExecutorPID.size())
return -1;
return LaunchedExecutorPID.back();
}

pid_t getNthLaunchedExecutorPID(int n) {
if (n - 1 < 0 || n - 1 >= static_cast<int>(LaunchedExecutorPID.size()))
return -1;
return LaunchedExecutorPID.at(n - 1);
}
#endif
Loading
Loading