Skip to content

Commit 5c3e538

Browse files
authored
[SYCL] Link only needed symbols from fat static libraries on device side (#2970)
This patch changes SYCL linking to link only needed symbols from unbundled fat static libraries instead of linking whole device archive. This is the last change in the series of patches for improving offload linking process. Signed-off-by: Sergey Dmitriev <serguei.n.dmitriev@intel.com>
1 parent f58c568 commit 5c3e538

File tree

3 files changed

+62
-16
lines changed

3 files changed

+62
-16
lines changed

clang/lib/Driver/ToolChains/SYCL.cpp

Lines changed: 58 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,17 @@ const char *SYCL::Linker::constructLLVMLinkCommand(
9999
Compilation &C, const JobAction &JA, const InputInfo &Output,
100100
const ArgList &Args, StringRef SubArchName, StringRef OutputFilePrefix,
101101
const InputInfoList &InputFiles) const {
102-
ArgStringList CmdArgs;
102+
// Split inputs into libraries which have 'archive' type and other inputs
103+
// which can be either objects or list files. Objects/list files are linked
104+
// together in a usual way, but the libraries need to be linked differently.
105+
// We need to fetch only required symbols from the libraries. With the current
106+
// llvm-link command line interface that can be achieved with two step
107+
// linking: at the first step we will link objects into an intermediate
108+
// partially linked image which on the second step will be linked with the
109+
// libraries with --only-needed option.
110+
ArgStringList Opts;
111+
ArgStringList Objs;
112+
ArgStringList Libs;
103113
// Add the input bc's created by compile step.
104114
// When offloading, the input file(s) could be from unbundled partially
105115
// linked archives. The unbundled information is a list of files and not
@@ -119,31 +129,65 @@ const char *SYCL::Linker::constructLLVMLinkCommand(
119129
// Go through the Inputs to the link. When a listfile is encountered, we
120130
// know it is an unbundled generated list.
121131
if (LinkSYCLDeviceLibs)
122-
CmdArgs.push_back("-only-needed");
132+
Opts.push_back("-only-needed");
123133
for (const auto &II : InputFiles) {
124134
if (II.getType() == types::TY_Tempfilelist) {
125135
// Pass the unbundled list with '@' to be processed.
126136
std::string FileName(II.getFilename());
127-
CmdArgs.push_back(C.getArgs().MakeArgString("@" + FileName));
137+
Objs.push_back(C.getArgs().MakeArgString("@" + FileName));
138+
} else if (II.getType() == types::TY_Archive && !LinkSYCLDeviceLibs) {
139+
Libs.push_back(II.getFilename());
128140
} else
129-
CmdArgs.push_back(II.getFilename());
141+
Objs.push_back(II.getFilename());
130142
}
131143
} else
132144
for (const auto &II : InputFiles)
133-
CmdArgs.push_back(II.getFilename());
145+
Objs.push_back(II.getFilename());
134146

135-
// Add an intermediate output file.
136-
CmdArgs.push_back("-o");
137-
const char *OutputFileName = Output.getFilename();
138-
CmdArgs.push_back(OutputFileName);
139-
// TODO: temporary workaround for a problem with warnings reported by
140-
// llvm-link when driver links LLVM modules with empty modules
141-
CmdArgs.push_back("--suppress-warnings");
147+
// Get llvm-link path.
142148
SmallString<128> ExecPath(C.getDriver().Dir);
143149
llvm::sys::path::append(ExecPath, "llvm-link");
144150
const char *Exec = C.getArgs().MakeArgString(ExecPath);
145-
C.addCommand(std::make_unique<Command>(
146-
JA, *this, ResponseFileSupport::AtFileUTF8(), Exec, CmdArgs, None));
151+
152+
auto AddLinkCommand = [this, &C, &JA, Exec](const char *Output,
153+
const ArgStringList &Inputs,
154+
const ArgStringList &Options) {
155+
ArgStringList CmdArgs;
156+
llvm::copy(Options, std::back_inserter(CmdArgs));
157+
llvm::copy(Inputs, std::back_inserter(CmdArgs));
158+
CmdArgs.push_back("-o");
159+
CmdArgs.push_back(Output);
160+
// TODO: temporary workaround for a problem with warnings reported by
161+
// llvm-link when driver links LLVM modules with empty modules
162+
CmdArgs.push_back("--suppress-warnings");
163+
C.addCommand(std::make_unique<Command>(
164+
JA, *this, ResponseFileSupport::AtFileUTF8(), Exec, CmdArgs, None));
165+
};
166+
167+
// Add an intermediate output file.
168+
const char *OutputFileName = Output.getFilename();
169+
170+
if (Libs.empty())
171+
AddLinkCommand(OutputFileName, Objs, Opts);
172+
else {
173+
assert(Opts.empty() && "unexpected options");
174+
175+
// Linker will be invoked twice if inputs contain libraries. First time we
176+
// will link input objects into an intermediate temporary file, and on the
177+
// second invocation intermediate temporary object will be linked with the
178+
// libraries, but now only required symbols will be added to the final
179+
// output.
180+
std::string TempFile =
181+
C.getDriver().GetTemporaryPath(OutputFilePrefix.str() + "-link", "bc");
182+
const char *LinkOutput = C.addTempFile(C.getArgs().MakeArgString(TempFile));
183+
AddLinkCommand(LinkOutput, Objs, {});
184+
185+
// Now invoke linker for the second time to link required symbols from the
186+
// input libraries.
187+
ArgStringList LinkInputs{LinkOutput};
188+
llvm::copy(Libs, std::back_inserter(LinkInputs));
189+
AddLinkCommand(OutputFileName, LinkInputs, {"--only-needed"});
190+
}
147191
return OutputFileName;
148192
}
149193

clang/test/Driver/sycl-offload-static-lib-2.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,8 @@
8080
// STATIC_LIB_SRC2: ld{{(.exe)?}}" {{.*}} "-o" "[[HOSTEXE:.+\.out]]"
8181
// STATIC_LIB_SRC2: clang-offload-deps{{.*}} "-outputs=[[OUTDEPS:.+\.bc]]" "[[HOSTEXE]]"
8282
// STATIC_LIB_SRC2: clang-offload-bundler{{.*}} "-type=a" {{.*}} "-outputs=[[OUTLIB:.+\.a]]"
83-
// STATIC_LIB_SRC2: llvm-link{{.*}} "[[OUTDEPS]]" "[[OUTLIB]]"
83+
// STATIC_LIB_SRC2: llvm-link{{.*}} "[[OUTDEPS]]" "-o" "[[OUTTEMP:.+\.bc]]"
84+
// STATIC_LIB_SRC2: llvm-link{{.*}} "--only-needed" "[[OUTTEMP]]" "[[OUTLIB]]"
8485
// STATIC_LIB_SRC2: ld{{(.exe)?}}" {{.*}} "[[HOSTOBJ]]"
8586

8687
/// ###########################################################################

clang/test/Driver/sycl-offload-static-lib.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,8 @@
8484
// FOFFLOAD_STATIC_LIB_SRC2: ld{{(.exe)?}}" {{.*}} "-o" "[[HOSTEXE:.+\.out]]"
8585
// FOFFLOAD_STATIC_LIB_SRC2: clang-offload-deps{{.*}} "-outputs=[[OUTDEPS:.+\.bc]]" "[[HOSTEXE]]"
8686
// FOFFLOAD_STATIC_LIB_SRC2: clang-offload-bundler{{.*}} "-type=a" {{.*}} "-outputs=[[OUTLIB:.+\.a]]"
87-
// FOFFLOAD_STATIC_LIB_SRC2: llvm-link{{.*}} "[[OUTDEPS]]" "[[OUTLIB]]"
87+
// FOFFLOAD_STATIC_LIB_SRC2: llvm-link{{.*}} "[[OUTDEPS]]" "-o" "[[OUTTEMP:.+\.bc]]"
88+
// FOFFLOAD_STATIC_LIB_SRC2: llvm-link{{.*}} "--only-needed" "[[OUTTEMP]]" "[[OUTLIB]]"
8889
// FOFFLOAD_STATIC_LIB_SRC2: ld{{(.exe)?}}" {{.*}} "[[HOSTOBJ]]"
8990

9091
/// ###########################################################################

0 commit comments

Comments
 (0)