[clang] 95c8f74 - [Clang] Introduce Clang Linker Wrapper Tool
Joseph Huber via cfe-commits
cfe-commits at lists.llvm.org
Mon Jan 31 12:56:20 PST 2022
Author: Joseph Huber
Date: 2022-01-31T15:56:04-05:00
New Revision: 95c8f7464092e2ccd45c3ae6dc42da6bd9a037b5
URL: https://github.com/llvm/llvm-project/commit/95c8f7464092e2ccd45c3ae6dc42da6bd9a037b5
DIFF: https://github.com/llvm/llvm-project/commit/95c8f7464092e2ccd45c3ae6dc42da6bd9a037b5.diff
LOG: [Clang] Introduce Clang Linker Wrapper Tool
This patch introduces a linker wrapper tool that allows us to preprocess
files before they are sent to the linker. This adds a dummy action and
job to the driver stage that builds the linker command as usual and then
replaces the command line with the wrapper tool.
Depends on D116543
Reviewed By: JonChesterfield
Differential Revision: https://reviews.llvm.org/D116544
Added:
clang/docs/ClangLinkerWrapper.rst
clang/tools/clang-linker-wrapper/CMakeLists.txt
clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
Modified:
clang/docs/ReleaseNotes.rst
clang/include/clang/Driver/Action.h
clang/include/clang/Driver/Job.h
clang/include/clang/Driver/ToolChain.h
clang/lib/Driver/Action.cpp
clang/lib/Driver/Driver.cpp
clang/lib/Driver/ToolChain.cpp
clang/lib/Driver/ToolChains/Clang.cpp
clang/lib/Driver/ToolChains/Clang.h
clang/tools/CMakeLists.txt
Removed:
################################################################################
diff --git a/clang/docs/ClangLinkerWrapper.rst b/clang/docs/ClangLinkerWrapper.rst
new file mode 100644
index 0000000000000..3bb5a67789a23
--- /dev/null
+++ b/clang/docs/ClangLinkerWrapper.rst
@@ -0,0 +1,61 @@
+====================
+Clang Linker Wrapper
+====================
+
+.. contents::
+ :local:
+
+.. _clang-linker-wrapper:
+
+Introduction
+============
+
+This tool works as a wrapper over a linking job. The tool is used to create
+linked device images for offloading. It scans the linker's input for embedded
+device offloading data stored in sections ``.llvm.offloading.<triple>.<arch>``
+and extracts it as a temporary file. The extracted device files will then be
+passed to a device linking job to create a final device image.
+
+Usage
+=====
+
+This tool can be used with the following options. Arguments to the host linker
+being wrapper around are passed as positional arguments using the ``--`` flag to
+override parsing.
+
+.. code-block:: console
+
+ USAGE: clang-linker-wrapper [options] <options to be passed to linker>...
+
+ OPTIONS:
+
+ Generic Options:
+
+ --help - Display available options (--help-hidden for more)
+ --help-list - Display list of available options (--help-list-hidden for more)
+ --version - Display the version of this program
+
+ clang-linker-wrapper options:
+
+ --host-triple=<string> - Triple to use for the host compilation
+ --linker-path=<string> - Path of linker binary
+ --opt-level=<string> - Optimization level for LTO
+ --ptxas-option=<string> - Argument to pass to the ptxas invocation
+ --save-temps - Save intermediary results.
+ --strip-sections - Strip offloading sections from the host object file.
+ --target-embed-bc - Embed linked bitcode instead of an executable device image
+ --target-feature=<string> - Target features for triple
+ --target-library=<string> - Path for the target bitcode library
+ -v - Verbose output from tools
+
+Example
+=======
+
+This tool links object files with offloading images embedded within it using the
+``-fembed-offload-object`` flag in Clang. Given an input file containing the
+magic section we can pass it to this tool to extract the data contained at that
+section and run a device linking job on it.
+
+.. code-block:: console
+
+ clang-linker-wrapper -host-triple x86_64-unknown-linux-gnu -linker-path /usr/bin/ld -- <Args>
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 3a42b4252ed73..0c9968597b737 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -257,7 +257,7 @@ OpenMP Support in Clang
-----------------------
- ``clang-nvlink-wrapper`` tool introduced to support linking of cubin files archived in an archive. See :doc:`ClangNvlinkWrapper`.
-
+- ``clang-linker-wrapper`` tool introduced to support linking using a new OpenMP target offloading method. See :doc:`ClangLinkerWrapper`.
CUDA Support in Clang
---------------------
diff --git a/clang/include/clang/Driver/Action.h b/clang/include/clang/Driver/Action.h
index ba84d886a6cf0..3b6c9e31faa3e 100644
--- a/clang/include/clang/Driver/Action.h
+++ b/clang/include/clang/Driver/Action.h
@@ -73,6 +73,7 @@ class Action {
OffloadBundlingJobClass,
OffloadUnbundlingJobClass,
OffloadWrapperJobClass,
+ LinkerWrapperJobClass,
StaticLibJobClass,
JobClassFirst = PreprocessJobClass,
@@ -642,6 +643,17 @@ class OffloadWrapperJobAction : public JobAction {
}
};
+class LinkerWrapperJobAction : public JobAction {
+ void anchor() override;
+
+public:
+ LinkerWrapperJobAction(ActionList &Inputs, types::ID Type);
+
+ static bool classof(const Action *A) {
+ return A->getKind() == LinkerWrapperJobClass;
+ }
+};
+
class StaticLibJobAction : public JobAction {
void anchor() override;
diff --git a/clang/include/clang/Driver/Job.h b/clang/include/clang/Driver/Job.h
index 6e3b51f2a7995..ae9337f3c2d0a 100644
--- a/clang/include/clang/Driver/Job.h
+++ b/clang/include/clang/Driver/Job.h
@@ -208,6 +208,8 @@ class Command {
Arguments = std::move(List);
}
+ void replaceExecutable(const char *Exe) { Executable = Exe; }
+
const char *getExecutable() const { return Executable; }
const llvm::opt::ArgStringList &getArguments() const { return Arguments; }
diff --git a/clang/include/clang/Driver/ToolChain.h b/clang/include/clang/Driver/ToolChain.h
index 7cd6a5fd37773..bfc46af002657 100644
--- a/clang/include/clang/Driver/ToolChain.h
+++ b/clang/include/clang/Driver/ToolChain.h
@@ -151,6 +151,7 @@ class ToolChain {
mutable std::unique_ptr<Tool> IfsMerge;
mutable std::unique_ptr<Tool> OffloadBundler;
mutable std::unique_ptr<Tool> OffloadWrapper;
+ mutable std::unique_ptr<Tool> LinkerWrapper;
Tool *getClang() const;
Tool *getFlang() const;
@@ -161,6 +162,7 @@ class ToolChain {
Tool *getClangAs() const;
Tool *getOffloadBundler() const;
Tool *getOffloadWrapper() const;
+ Tool *getLinkerWrapper() const;
mutable bool SanitizerArgsChecked = false;
mutable std::unique_ptr<XRayArgs> XRayArguments;
diff --git a/clang/lib/Driver/Action.cpp b/clang/lib/Driver/Action.cpp
index e2d2f6c22de06..eb08bfe9cde56 100644
--- a/clang/lib/Driver/Action.cpp
+++ b/clang/lib/Driver/Action.cpp
@@ -43,6 +43,8 @@ const char *Action::getClassName(ActionClass AC) {
return "clang-offload-unbundler";
case OffloadWrapperJobClass:
return "clang-offload-wrapper";
+ case LinkerWrapperJobClass:
+ return "clang-linker-wrapper";
case StaticLibJobClass:
return "static-lib-linker";
}
@@ -418,6 +420,12 @@ OffloadWrapperJobAction::OffloadWrapperJobAction(ActionList &Inputs,
types::ID Type)
: JobAction(OffloadWrapperJobClass, Inputs, Type) {}
+void LinkerWrapperJobAction::anchor() {}
+
+LinkerWrapperJobAction::LinkerWrapperJobAction(ActionList &Inputs,
+ types::ID Type)
+ : JobAction(LinkerWrapperJobClass, Inputs, Type) {}
+
void StaticLibJobAction::anchor() {}
StaticLibJobAction::StaticLibJobAction(ActionList &Inputs, types::ID Type)
diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp
index 0dba3e33eb6eb..b8ef960f30459 100644
--- a/clang/lib/Driver/Driver.cpp
+++ b/clang/lib/Driver/Driver.cpp
@@ -3955,14 +3955,16 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
// Check if this Linker Job should emit a static library.
if (ShouldEmitStaticLibrary(Args)) {
LA = C.MakeAction<StaticLibJobAction>(LinkerInputs, types::TY_Image);
+ } else if (Args.hasArg(options::OPT_fopenmp_new_driver) &&
+ OffloadKinds != Action::OFK_None) {
+ LA = C.MakeAction<LinkerWrapperJobAction>(LinkerInputs, types::TY_Image);
+ LA->propagateHostOffloadInfo(OffloadKinds,
+ /*BoundArch=*/nullptr);
} else {
LA = C.MakeAction<LinkJobAction>(LinkerInputs, types::TY_Image);
}
if (!Args.hasArg(options::OPT_fopenmp_new_driver))
LA = OffloadBuilder.processHostLinkAction(LA);
- if (Args.hasArg(options::OPT_fopenmp_new_driver))
- LA->propagateHostOffloadInfo(OffloadKinds,
- /*BoundArch=*/nullptr);
Actions.push_back(LA);
}
diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp
index 3c13f1b1cacba..d657d21bfcdb0 100644
--- a/clang/lib/Driver/ToolChain.cpp
+++ b/clang/lib/Driver/ToolChain.cpp
@@ -327,6 +327,12 @@ Tool *ToolChain::getOffloadWrapper() const {
return OffloadWrapper.get();
}
+Tool *ToolChain::getLinkerWrapper() const {
+ if (!LinkerWrapper)
+ LinkerWrapper.reset(new tools::LinkerWrapper(*this, getLink()));
+ return LinkerWrapper.get();
+}
+
Tool *ToolChain::getTool(Action::ActionClass AC) const {
switch (AC) {
case Action::AssembleJobClass:
@@ -365,6 +371,8 @@ Tool *ToolChain::getTool(Action::ActionClass AC) const {
case Action::OffloadWrapperJobClass:
return getOffloadWrapper();
+ case Action::LinkerWrapperJobClass:
+ return getLinkerWrapper();
}
llvm_unreachable("Invalid tool kind.");
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 66943302388de..59139eca54ee9 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -8142,3 +8142,28 @@ void OffloadWrapper::ConstructJob(Compilation &C, const JobAction &JA,
Args.MakeArgString(getToolChain().GetProgramPath(getShortName())),
CmdArgs, Inputs, Output));
}
+
+void LinkerWrapper::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ ArgStringList CmdArgs;
+
+ // Construct the link job so we can wrap around it.
+ Linker->ConstructJob(C, JA, Output, Inputs, Args, LinkingOutput);
+ const auto &LinkCommand = C.getJobs().getJobs().back();
+
+ CmdArgs.push_back("-linker-path");
+ CmdArgs.push_back(LinkCommand->getExecutable());
+ for (const char *LinkArg : LinkCommand->getArguments())
+ CmdArgs.push_back(LinkArg);
+
+ const char *Exec =
+ Args.MakeArgString(getToolChain().GetProgramPath("clang-linker-wrapper"));
+
+ // Replace the executable and arguments associated with the link job to the
+ // wrapper.
+ LinkCommand->replaceExecutable(Exec);
+ LinkCommand->replaceArguments(CmdArgs);
+}
diff --git a/clang/lib/Driver/ToolChains/Clang.h b/clang/lib/Driver/ToolChains/Clang.h
index 013cd2341e17c..79407c9884d51 100644
--- a/clang/lib/Driver/ToolChains/Clang.h
+++ b/clang/lib/Driver/ToolChains/Clang.h
@@ -170,6 +170,21 @@ class LLVM_LIBRARY_VISIBILITY OffloadWrapper final : public Tool {
const char *LinkingOutput) const override;
};
+/// Linker wrapper tool.
+class LLVM_LIBRARY_VISIBILITY LinkerWrapper final : public Tool {
+ const Tool *Linker;
+
+public:
+ LinkerWrapper(const ToolChain &TC, const Tool *Linker)
+ : Tool("Offload::Linker", "linker", TC), Linker(Linker) {}
+
+ bool hasIntegratedCPP() const override { return false; }
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
+};
+
} // end namespace tools
} // end namespace driver
diff --git a/clang/tools/CMakeLists.txt b/clang/tools/CMakeLists.txt
index 38b7496b97f72..b071a776b32ae 100644
--- a/clang/tools/CMakeLists.txt
+++ b/clang/tools/CMakeLists.txt
@@ -9,6 +9,7 @@ add_clang_subdirectory(clang-format-vs)
add_clang_subdirectory(clang-fuzzer)
add_clang_subdirectory(clang-import-test)
add_clang_subdirectory(clang-nvlink-wrapper)
+add_clang_subdirectory(clang-linker-wrapper)
add_clang_subdirectory(clang-offload-bundler)
add_clang_subdirectory(clang-offload-wrapper)
add_clang_subdirectory(clang-scan-deps)
diff --git a/clang/tools/clang-linker-wrapper/CMakeLists.txt b/clang/tools/clang-linker-wrapper/CMakeLists.txt
new file mode 100644
index 0000000000000..17c50b6d80cad
--- /dev/null
+++ b/clang/tools/clang-linker-wrapper/CMakeLists.txt
@@ -0,0 +1,25 @@
+set(LLVM_LINK_COMPONENTS BitWriter Core Object Support)
+
+if(NOT CLANG_BUILT_STANDALONE)
+ set(tablegen_deps intrinsics_gen)
+endif()
+
+add_clang_executable(clang-linker-wrapper
+ ClangLinkerWrapper.cpp
+
+ DEPENDS
+ ${tablegen_deps}
+ )
+
+set(CLANG_LINKER_WRAPPER_LIB_DEPS
+ clangBasic
+ )
+
+add_dependencies(clang clang-linker-wrapper)
+
+target_link_libraries(clang-linker-wrapper
+ PRIVATE
+ ${CLANG_LINKER_WRAPPER_LIB_DEPS}
+ )
+
+install(TARGETS clang-linker-wrapper RUNTIME DESTINATION bin)
diff --git a/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp b/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
new file mode 100644
index 0000000000000..5cadb3dbb1e98
--- /dev/null
+++ b/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
@@ -0,0 +1,91 @@
+//===-- clang-linker-wrapper/ClangLinkerWrapper.cpp - wrapper over linker-===//
+//
+// 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
+//
+//===---------------------------------------------------------------------===//
+///
+//===---------------------------------------------------------------------===//
+
+#include "clang/Basic/Version.h"
+#include "llvm/Object/Archive.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Program.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/StringSaver.h"
+#include "llvm/Support/WithColor.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+
+static cl::opt<bool> Help("h", cl::desc("Alias for -help"), cl::Hidden);
+
+// Mark all our options with this category, everything else (except for -help)
+// will be hidden.
+static cl::OptionCategory
+ ClangLinkerWrapperCategory("clang-linker-wrapper options");
+
+static cl::opt<std::string> LinkerUserPath("linker-path",
+ cl::desc("Path of linker binary"),
+ cl::cat(ClangLinkerWrapperCategory));
+
+// Do not parse linker options
+static cl::list<std::string>
+ LinkerArgs(cl::Sink, cl::desc("<options to be passed to linker>..."));
+
+static Error runLinker(std::string LinkerPath,
+ SmallVectorImpl<std::string> &Args) {
+ std::vector<StringRef> LinkerArgs;
+ LinkerArgs.push_back(LinkerPath);
+ for (auto &Arg : Args)
+ LinkerArgs.push_back(Arg);
+
+ if (sys::ExecuteAndWait(LinkerPath, LinkerArgs))
+ return createStringError(inconvertibleErrorCode(), "'linker' failed");
+ return Error::success();
+}
+
+static void PrintVersion(raw_ostream &OS) {
+ OS << clang::getClangToolFullVersion("clang-linker-wrapper") << '\n';
+}
+
+int main(int argc, const char **argv) {
+ sys::PrintStackTraceOnErrorSignal(argv[0]);
+ cl::SetVersionPrinter(PrintVersion);
+ cl::HideUnrelatedOptions(ClangLinkerWrapperCategory);
+ cl::ParseCommandLineOptions(
+ argc, argv,
+ "A wrapper utility over the host linker. It scans the input files for\n"
+ "sections that require additional processing prior to linking. The tool\n"
+ "will then transparently pass all arguments and input to the specified\n"
+ "host linker to create the final binary.\n");
+
+ if (Help) {
+ cl::PrintHelpMessage();
+ return EXIT_SUCCESS;
+ }
+
+ auto reportError = [argv](Error E) {
+ logAllUnhandledErrors(std::move(E), WithColor::error(errs(), argv[0]));
+ exit(EXIT_FAILURE);
+ };
+
+ // TODO: Scan input object files for offloading sections and extract them.
+ // TODO: Perform appropriate device linking action.
+ // TODO: Wrap device image in a host binary and pass it to the linker.
+ WithColor::warning(errs(), argv[0]) << "Offload linking not yet supported.\n";
+
+ SmallVector<std::string, 0> Argv;
+ for (const std::string &Arg : LinkerArgs)
+ Argv.push_back(Arg);
+
+ if (Error Err = runLinker(LinkerUserPath, Argv))
+ reportError(std::move(Err));
+
+ return EXIT_SUCCESS;
+}
More information about the cfe-commits
mailing list