[clang] f28c315 - [OpenMP] Add support for embedding bitcode images in wrapper tool
Joseph Huber via cfe-commits
cfe-commits at lists.llvm.org
Mon Jan 31 20:12:02 PST 2022
Author: Joseph Huber
Date: 2022-01-31T23:11:41-05:00
New Revision: f28c3153ee6d93aa07610682519bdf0ea93755b4
URL: https://github.com/llvm/llvm-project/commit/f28c3153ee6d93aa07610682519bdf0ea93755b4
DIFF: https://github.com/llvm/llvm-project/commit/f28c3153ee6d93aa07610682519bdf0ea93755b4.diff
LOG: [OpenMP] Add support for embedding bitcode images in wrapper tool
Summary;
This patch adds support for embedding device images in the linker
wrapper tool. This will be used for performing JIT functionality in the
future.
Depends on D117048
Differential Revision: https://reviews.llvm.org/D117049
Added:
Modified:
clang/lib/Driver/ToolChains/Clang.cpp
clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
Removed:
################################################################################
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 7cc47b74ca916..dd631339635a3 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -8217,6 +8217,7 @@ void LinkerWrapper::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-linker-path");
CmdArgs.push_back(LinkCommand->getExecutable());
+ CmdArgs.push_back("--");
for (const char *LinkArg : LinkCommand->getArguments())
CmdArgs.push_back(LinkArg);
diff --git a/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp b/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
index 27f4bdf153c53..63afbd834cb7a 100644
--- a/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
+++ b/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
@@ -76,12 +76,18 @@ static cl::opt<std::string>
cl::desc("Path for the target bitcode library"),
cl::cat(ClangLinkerWrapperCategory));
+static cl::opt<bool> EmbedBC(
+ "target-embed-bc", cl::ZeroOrMore,
+ cl::desc("Embed linked bitcode instead of an executable device image."),
+ cl::init(false), cl::cat(ClangLinkerWrapperCategory));
+
// Do not parse linker options.
static cl::list<std::string>
- HostLinkerArgs(cl::Sink, cl::desc("<options to be passed to linker>..."));
+ HostLinkerArgs(cl::Positional,
+ cl::desc("<options to be passed to linker>..."));
/// Path of the current binary.
-static std::string LinkerExecutable;
+static const char *LinkerExecutable;
/// Temporary files created by the linker wrapper.
static SmallVector<std::string, 16> TempFiles;
@@ -411,8 +417,8 @@ extractFromArchive(const Archive &Library,
std::unique_ptr<MemoryBuffer> Buffer =
MemoryBuffer::getMemBuffer(Library.getMemoryBufferRef(), false);
- if (Error Err = writeArchive(TempFile, Members, true, Library.kind(),
- true, Library.isThin(), std::move(Buffer)))
+ if (Error Err = writeArchive(TempFile, Members, true, Library.kind(), true,
+ Library.isThin(), std::move(Buffer)))
return std::move(Err);
return static_cast<std::string>(TempFile);
@@ -489,7 +495,7 @@ Expected<std::string> assemble(StringRef InputFile, Triple TheTriple,
return static_cast<std::string>(TempFile);
}
-Expected<std::string> link(ArrayRef<StringRef> InputFiles,
+Expected<std::string> link(ArrayRef<std::string> InputFiles,
ArrayRef<std::string> LinkerArgs, Triple TheTriple,
StringRef Arch) {
// NVPTX uses the nvlink binary to link device object files.
@@ -520,7 +526,7 @@ Expected<std::string> link(ArrayRef<StringRef> InputFiles,
CmdArgs.push_back(Arg);
// Add extracted input files.
- for (auto Input : InputFiles)
+ for (StringRef Input : InputFiles)
CmdArgs.push_back(Input);
if (sys::ExecuteAndWait(*NvlinkPath, CmdArgs))
@@ -530,7 +536,7 @@ Expected<std::string> link(ArrayRef<StringRef> InputFiles,
}
} // namespace nvptx
-Expected<std::string> linkDevice(ArrayRef<StringRef> InputFiles,
+Expected<std::string> linkDevice(ArrayRef<std::string> InputFiles,
ArrayRef<std::string> LinkerArgs,
Triple TheTriple, StringRef Arch) {
switch (TheTriple.getArch()) {
@@ -597,8 +603,10 @@ CodeGenOpt::Level getCGOptLevel(unsigned OptLevel) {
llvm_unreachable("Invalid optimization level");
}
-std::unique_ptr<lto::LTO> createLTO(const Triple &TheTriple, StringRef Arch,
- bool WholeProgram) {
+template <typename ModuleHook = function_ref<bool(size_t, const Module &)>>
+std::unique_ptr<lto::LTO> createLTO(
+ const Triple &TheTriple, StringRef Arch, bool WholeProgram,
+ ModuleHook Hook = [](size_t, const Module &) { return true; }) {
lto::Config Conf;
lto::ThinBackend Backend;
// TODO: Handle index-only thin-LTO
@@ -617,7 +625,7 @@ std::unique_ptr<lto::LTO> createLTO(const Triple &TheTriple, StringRef Arch,
Conf.PTO.LoopVectorization = Conf.OptLevel > 1;
Conf.PTO.SLPVectorization = Conf.OptLevel > 1;
- // TODO: Handle outputting bitcode using a module hook.
+ Conf.PostInternalizeModuleHook = Hook;
if (TheTriple.isNVPTX())
Conf.CGFileType = CGFT_AssemblyFile;
else
@@ -637,11 +645,11 @@ bool isValidCIdentifier(StringRef S) {
[](char C) { return C == '_' || isAlnum(C); });
}
-Expected<Optional<std::string>> linkBitcodeFiles(ArrayRef<StringRef> InputFiles,
- const Triple &TheTriple,
- StringRef Arch) {
+Error linkBitcodeFiles(SmallVectorImpl<std::string> &InputFiles,
+ const Triple &TheTriple, StringRef Arch) {
SmallVector<std::unique_ptr<MemoryBuffer>, 4> SavedBuffers;
SmallVector<std::unique_ptr<lto::InputFile>, 4> BitcodeFiles;
+ SmallVector<std::string, 4> NewInputFiles;
StringMap<bool> UsedInRegularObj;
// Search for bitcode files in the input and create an LTO input file. If it
@@ -660,6 +668,7 @@ Expected<Optional<std::string>> linkBitcodeFiles(ArrayRef<StringRef> InputFiles,
if (!ObjFile)
return ObjFile.takeError();
+ NewInputFiles.push_back(File.str());
for (auto &Sym : (*ObjFile)->symbols()) {
Expected<StringRef> Name = Sym.getName();
if (!Name)
@@ -679,12 +688,36 @@ Expected<Optional<std::string>> linkBitcodeFiles(ArrayRef<StringRef> InputFiles,
}
if (BitcodeFiles.empty())
- return None;
+ return Error::success();
+
+ auto HandleError = [&](std::error_code EC) {
+ logAllUnhandledErrors(errorCodeToError(EC),
+ WithColor::error(errs(), LinkerExecutable));
+ exit(1);
+ };
+
+ // LTO Module hook to output bitcode without running the backend.
+ auto LinkOnly = [&](size_t Task, const Module &M) {
+ SmallString<128> TempFile;
+ if (std::error_code EC = sys::fs::createTemporaryFile(
+ "jit-" + TheTriple.getTriple(), "bc", TempFile))
+ HandleError(EC);
+ std::error_code EC;
+ raw_fd_ostream LinkedBitcode(TempFile, EC, sys::fs::OF_None);
+ if (EC)
+ HandleError(EC);
+ WriteBitcodeToFile(M, LinkedBitcode);
+ TempFiles.push_back(static_cast<std::string>(TempFile));
+ NewInputFiles.push_back(static_cast<std::string>(TempFile));
+ return false;
+ };
// We have visibility of the whole program if every input is bitcode, all
// inputs are statically linked so there should be no external references.
bool WholeProgram = BitcodeFiles.size() == InputFiles.size();
- StringMap<bool> PrevailingSymbols;
+ auto LTOBackend = (EmbedBC)
+ ? createLTO(TheTriple, Arch, WholeProgram, LinkOnly)
+ : createLTO(TheTriple, Arch, WholeProgram);
// TODO: Run more tests to verify that this is correct.
// Create the LTO instance with the necessary config and add the bitcode files
@@ -694,7 +727,7 @@ Expected<Optional<std::string>> linkBitcodeFiles(ArrayRef<StringRef> InputFiles,
// 2. We do not support relocatable object files.
// 3. All inputs are relocatable object files extracted from host binaries, so
// there is no resolution to a dynamic library.
- auto LTOBackend = createLTO(TheTriple, Arch, WholeProgram);
+ StringMap<bool> PrevailingSymbols;
for (auto &BitcodeFile : BitcodeFiles) {
const auto Symbols = BitcodeFile->symbols();
SmallVector<lto::SymbolResolution, 16> Resolutions(Symbols.size());
@@ -743,16 +776,18 @@ Expected<Optional<std::string>> linkBitcodeFiles(ArrayRef<StringRef> InputFiles,
StringRef Extension = (TheTriple.isNVPTX()) ? "s" : "o";
if (std::error_code EC = sys::fs::createTemporaryFile(
"lto-" + TheTriple.getTriple(), Extension, FD, TempFile))
- return nullptr;
+ HandleError(EC);
TempFiles.push_back(static_cast<std::string>(TempFile));
return std::make_unique<CachedFileStream>(
std::make_unique<llvm::raw_fd_ostream>(FD, true));
};
+
if (Error Err = LTOBackend->run(AddStream))
return std::move(Err);
+ // Is we are compiling for NVPTX we need to run the assembler first.
for (auto &File : Files) {
- if (!TheTriple.isNVPTX())
+ if (!TheTriple.isNVPTX() || EmbedBC)
continue;
auto FileOrErr = nvptx::assemble(File, TheTriple, Arch);
@@ -761,7 +796,12 @@ Expected<Optional<std::string>> linkBitcodeFiles(ArrayRef<StringRef> InputFiles,
File = *FileOrErr;
}
- return static_cast<std::string>(Files.front());
+ // Append the new inputs to the device linker input.
+ for (auto &File : Files)
+ NewInputFiles.push_back(static_cast<std::string>(File));
+ InputFiles = NewInputFiles;
+
+ return Error::success();
}
/// Runs the appropriate linking action on all the device files specified in \p
@@ -770,7 +810,7 @@ Error linkDeviceFiles(ArrayRef<DeviceFile> DeviceFiles,
ArrayRef<std::string> LinkerArgs,
SmallVectorImpl<std::string> &LinkedImages) {
// Get the list of inputs for a specific device.
- StringMap<SmallVector<StringRef, 4>> LinkerInputMap;
+ StringMap<SmallVector<std::string, 4>> LinkerInputMap;
for (auto &File : DeviceFiles)
LinkerInputMap[StringRef(File)].push_back(File.Filename);
@@ -780,13 +820,16 @@ Error linkDeviceFiles(ArrayRef<DeviceFile> DeviceFiles,
Triple TheTriple(TargetFeatures.first);
StringRef Arch(TargetFeatures.second);
- // TODO: Run LTO or bitcode linking before the final link job.
- auto ObjectOrErr =
- linkBitcodeFiles(LinkerInput.getValue(), TheTriple, Arch);
- if (!ObjectOrErr)
- return ObjectOrErr.takeError();
- if ((*ObjectOrErr).hasValue())
- LinkerInput.getValue() = {**ObjectOrErr};
+ // Run LTO on any bitcode files and replace the input with the result.
+ if (Error Err = linkBitcodeFiles(LinkerInput.getValue(), TheTriple, Arch))
+ return std::move(Err);
+
+ // If we are embedding bitcode for JIT, skip the final device linking.
+ if (EmbedBC) {
+ assert(!LinkerInput.getValue().empty() && "No bitcode image to embed");
+ LinkedImages.push_back(LinkerInput.getValue().front());
+ continue;
+ }
auto ImageOrErr =
linkDevice(LinkerInput.getValue(), LinkerArgs, TheTriple, Arch);
More information about the cfe-commits
mailing list