Skip to content

Added partial support for compiling C++20 modules and header-units without scanning. #147682

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
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
10 changes: 10 additions & 0 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -9416,3 +9416,13 @@ def wasm_opt : Flag<["--"], "wasm-opt">,
Group<m_Group>,
HelpText<"Enable the wasm-opt optimizer (default)">,
MarshallingInfoNegativeFlag<LangOpts<"NoWasmOpt">>;

def no_scan_ipc : Flag<["-"], "noScanIPC">,
Visibility<[ClangOption, CC1Option]>,
HelpText<"Enable No scan IPC approach">;
def translate_include : Flag<["-"], "translateInclude">,
Visibility<[ClangOption, CC1Option]>,
HelpText<"Consider header includes as header-units">;
def find_include : Flag<["-"], "findIncludes">,
Visibility<[ClangOption, CC1Option]>,
HelpText<"In No Scan IPC approach, compiler will relay the finding includes responsibility to the build-system">;
5 changes: 5 additions & 0 deletions clang/include/clang/Frontend/CompilerInstance.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Frontend/PCHContainerOperations.h"
#include "clang/Frontend/Utils.h"
#include "clang/IPC2978/IPCManagerCompiler.hpp"
#include "clang/Lex/DependencyDirectivesScanner.h"
#include "clang/Lex/HeaderSearchOptions.h"
#include "clang/Lex/ModuleLoader.h"
Expand Down Expand Up @@ -180,6 +181,10 @@ class CompilerInstance : public ModuleLoader {
/// The stream for verbose output.
raw_ostream *VerboseOutputStream = &llvm::errs();

/// Pointer for managing communication with build-system if noScan flag is
/// set.
N2978::IPCManagerCompiler *ipcManager = nullptr;

/// Holds information about the output file.
///
/// If TempFilename is not empty we must rename it to Filename at the end.
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/IPC2978/.clang-format-ignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*
39 changes: 39 additions & 0 deletions clang/include/clang/IPC2978/IPCManagerBS.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@

#ifndef IPC_MANAGER_BS_HPP
#define IPC_MANAGER_BS_HPP

#include "clang/IPC2978/Manager.hpp"
#include "clang/IPC2978/Messages.hpp"

namespace N2978
{

// IPC Manager BuildSystem
class IPCManagerBS : Manager
{
friend tl::expected<IPCManagerBS, string> makeIPCManagerBS(string BMIIfHeaderUnitObjOtherwisePath);
bool connectedToCompiler = false;

#ifdef _WIN32
explicit IPCManagerBS(void *hPipe_);
#else
explicit IPCManagerBS(int fdSocket_);
#endif

public:
IPCManagerBS(const IPCManagerBS &) = default;
IPCManagerBS &operator=(const IPCManagerBS &) = default;
IPCManagerBS(IPCManagerBS &&) = default;
IPCManagerBS &operator=(IPCManagerBS &&) = default;
tl::expected<void, string> receiveMessage(char (&ctbBuffer)[320], CTB &messageType) const;
[[nodiscard]] tl::expected<void, string> sendMessage(const BTCModule &moduleFile) const;
[[nodiscard]] tl::expected<void, string> sendMessage(const BTCNonModule &nonModule) const;
[[nodiscard]] tl::expected<void, string> sendMessage(const BTCLastMessage &lastMessage) const;
static tl::expected<ProcessMappingOfBMIFile, string> createSharedMemoryBMIFile(const BMIFile &bmiFile);
static tl::expected<void, string> closeBMIFileMapping(const ProcessMappingOfBMIFile &processMappingOfBMIFile);
void closeConnection() const;
};

tl::expected<IPCManagerBS, string> makeIPCManagerBS(string BMIIfHeaderUnitObjOtherwisePath);
} // namespace N2978
#endif // IPC_MANAGER_BS_HPP
129 changes: 129 additions & 0 deletions clang/include/clang/IPC2978/IPCManagerCompiler.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@

#ifndef IPC_MANAGER_COMPILER_HPP
#define IPC_MANAGER_COMPILER_HPP

#include "clang/IPC2978/Manager.hpp"
#include "clang/IPC2978/expected.hpp"

using std::string_view;
namespace N2978
{

// IPC Manager Compiler
class IPCManagerCompiler : Manager
{
template <typename T> tl::expected<T, string> receiveMessage() const;
// This is not exposed. sendCTBLastMessage calls this.
[[nodiscard]] tl::expected<void, string> receiveBTCLastMessage() const;

public:
#ifdef _WIN32
explicit IPCManagerCompiler(void *hPipe_);
#else
explicit IPCManagerCompiler(int fdSocket_);
#endif
[[nodiscard]] tl::expected<BTCModule, string> receiveBTCModule(const CTBModule &moduleName) const;
[[nodiscard]] tl::expected<BTCNonModule, string> receiveBTCNonModule(const CTBNonModule &nonModule) const;
[[nodiscard]] tl::expected<void, string> sendCTBLastMessage(const CTBLastMessage &lastMessage) const;
[[nodiscard]] tl::expected<void, string> sendCTBLastMessage(const CTBLastMessage &lastMessage,
const string &bmiFile, const string &filePath) const;
static tl::expected<ProcessMappingOfBMIFile, string> readSharedMemoryBMIFile(const BMIFile &file);
static tl::expected<void, string> closeBMIFileMapping(const ProcessMappingOfBMIFile &processMappingOfBMIFile);
void closeConnection() const;
};

template <typename T> tl::expected<T, string> IPCManagerCompiler::receiveMessage() const
{
// Read from the pipe.
char buffer[BUFFERSIZE];
uint32_t bytesRead;
if (const auto &r = readInternal(buffer); !r)
{
return tl::unexpected(r.error());
}
else
{
bytesRead = *r;
}

uint32_t bytesProcessed = 0;

if constexpr (std::is_same_v<T, BTCModule>)
{
const auto &r = readProcessMappingOfBMIFileFromPipe(buffer, bytesRead, bytesProcessed);
if (!r)
{
return tl::unexpected(r.error());
}

const auto &r2 = readVectorOfModuleDepFromPipe(buffer, bytesRead, bytesProcessed);
if (!r2)
{
return tl::unexpected(r2.error());
}

BTCModule moduleFile;
moduleFile.requested = *r;
moduleFile.deps = *r2;
if (bytesRead == bytesProcessed)
{
return moduleFile;
}
}
else if constexpr (std::is_same_v<T, BTCNonModule>)
{
const auto &r = readBoolFromPipe(buffer, bytesRead, bytesProcessed);
if (!r)
{
return tl::unexpected(r.error());
}

const auto &r2 = readStringFromPipe(buffer, bytesRead, bytesProcessed);
if (!r2)
{
return tl::unexpected(r2.error());
}

const auto &r3 = readBoolFromPipe(buffer, bytesRead, bytesProcessed);
if (!r3)
{
return tl::unexpected(r3.error());
}

const auto &r4 = readUInt32FromPipe(buffer, bytesRead, bytesProcessed);
if (!r4)
{
return tl::unexpected(r4.error());
}

const auto &r5 = readVectorOfHuDepFromPipe(buffer, bytesRead, bytesProcessed);
if (!r5)
{
return tl::unexpected(r5.error());
}

BTCNonModule nonModule;
nonModule.isHeaderUnit = *r;
nonModule.filePath = *r2;
nonModule.angled = *r3;
nonModule.fileSize = *r4;
nonModule.deps = *r5;

if (bytesRead == bytesProcessed)
{
return nonModule;
}
}
else
{
static_assert(false && "Unknown type\n");
}

if (bytesRead != bytesProcessed)
{
return tl::unexpected(getErrorString(bytesRead, bytesProcessed));
}
}
[[nodiscard]] tl::expected<IPCManagerCompiler, string> makeIPCManagerCompiler(string BMIIfHeaderUnitObjOtherwisePath);
} // namespace N2978
#endif // IPC_MANAGER_COMPILER_HPP
135 changes: 135 additions & 0 deletions clang/include/clang/IPC2978/Manager.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@

#ifndef MANAGER_HPP
#define MANAGER_HPP

#include "clang/IPC2978/Messages.hpp"
#include "clang/IPC2978/expected.hpp"

#include <string>
#include <vector>

using std::string, std::vector, std::string_view;

#define BUFFERSIZE 4096

#ifdef _WIN32
// The following variable is used in CreateNamedFunction.
#define PIPE_TIMEOUT 5000
#endif

namespace tl
{
template <typename T, typename U> class expected;
}

namespace N2978
{

enum class ErrorCategory : uint8_t
{
NONE,

// error-category for API errors
READ_FILE_ZERO_BYTES_READ,
INCORRECT_BTC_LAST_MESSAGE,
UNKNOWN_CTB_TYPE,
};

string getErrorString();
string getErrorString(uint32_t bytesRead_, uint32_t bytesProcessed_);
string getErrorString(ErrorCategory errorCategory_);
// to facilitate error propagation.
inline string getErrorString(string err)
{
return err;
}

struct ProcessMappingOfBMIFile
{
string_view file;
#ifdef _WIN32
void *mapping;
void *view;
#else
void *mapping;
uint32_t mappingSize;
#endif
};

class Manager
{
public:
#ifdef _WIN32
void *hPipe = nullptr;
#else
int fdSocket = 0;
#endif

tl::expected<uint32_t, string> readInternal(char (&buffer)[BUFFERSIZE]) const;
tl::expected<void, string> writeInternal(const vector<char> &buffer) const;

static vector<char> getBufferWithType(CTB type);
static void writeUInt32(vector<char> &buffer, uint32_t value);
static void writeString(vector<char> &buffer, const string &str);
static void writeProcessMappingOfBMIFile(vector<char> &buffer, const BMIFile &file);
static void writeModuleDep(vector<char> &buffer, const ModuleDep &dep);
static void writeHuDep(vector<char> &buffer, const HuDep &dep);
static void writeVectorOfStrings(vector<char> &buffer, const vector<string> &strs);
static void writeVectorOfProcessMappingOfBMIFiles(vector<char> &buffer, const vector<BMIFile> &files);
static void writeVectorOfModuleDep(vector<char> &buffer, const vector<ModuleDep> &deps);
static void writeVectorOfHuDep(vector<char> &buffer, const vector<HuDep> &deps);

tl::expected<bool, string> readBoolFromPipe(char (&buffer)[BUFFERSIZE], uint32_t &bytesRead,
uint32_t &bytesProcessed) const;
tl::expected<uint32_t, string> readUInt32FromPipe(char (&buffer)[BUFFERSIZE], uint32_t &bytesRead,
uint32_t &bytesProcessed) const;
tl::expected<string, string> readStringFromPipe(char (&buffer)[BUFFERSIZE], uint32_t &bytesRead,
uint32_t &bytesProcessed) const;
tl::expected<BMIFile, string> readProcessMappingOfBMIFileFromPipe(char (&buffer)[BUFFERSIZE], uint32_t &bytesRead,
uint32_t &bytesProcessed) const;
tl::expected<vector<string>, string> readVectorOfStringFromPipe(char (&buffer)[BUFFERSIZE], uint32_t &bytesRead,
uint32_t &bytesProcessed) const;
tl::expected<ModuleDep, string> readModuleDepFromPipe(char (&buffer)[BUFFERSIZE], uint32_t &bytesRead,
uint32_t &bytesProcessed) const;
tl::expected<vector<ModuleDep>, string> readVectorOfModuleDepFromPipe(char (&buffer)[BUFFERSIZE],
uint32_t &bytesRead,
uint32_t &bytesProcessed) const;
tl::expected<HuDep, string> readHuDepFromPipe(char (&buffer)[BUFFERSIZE], uint32_t &bytesRead,
uint32_t &bytesProcessed) const;
tl::expected<vector<HuDep>, string> readVectorOfHuDepFromPipe(char (&buffer)[BUFFERSIZE], uint32_t &bytesRead,
uint32_t &bytesProcessed) const;
tl::expected<void, string> readNumberOfBytes(char *output, uint32_t size, char (&buffer)[BUFFERSIZE],
uint32_t &bytesRead, uint32_t &bytesProcessed) const;
};

template <typename T, typename... Args> constexpr T *construct_at(T *p, Args &&...args)
{
return ::new (static_cast<void *>(p)) T(std::forward<Args>(args)...);
}

template <typename T> T &getInitializedObjectFromBuffer(char (&buffer)[320])
{
T &t = reinterpret_cast<T &>(buffer);
construct_at(&t);
return t;
}

inline std::string to16charHexString(const uint64_t v)
{
static auto lut = "0123456789abcdef";
std::string out;
out.resize(16);
for (int i = 0; i < 8; ++i)
{
// extract byte in big-endian order:
const auto byte = static_cast<uint8_t>(v >> ((7 - i) * 8));
// high nibble:
out[2 * i] = lut[byte >> 4];
// low nibble:
out[2 * i + 1] = lut[byte & 0xF];
}
return out;
}

} // namespace N2978
#endif // MANAGER_HPP
Loading