@@ -99,7 +99,17 @@ const char *SYCL::Linker::constructLLVMLinkCommand(
99
99
Compilation &C, const JobAction &JA, const InputInfo &Output,
100
100
const ArgList &Args, StringRef SubArchName, StringRef OutputFilePrefix,
101
101
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;
103
113
// Add the input bc's created by compile step.
104
114
// When offloading, the input file(s) could be from unbundled partially
105
115
// linked archives. The unbundled information is a list of files and not
@@ -119,31 +129,65 @@ const char *SYCL::Linker::constructLLVMLinkCommand(
119
129
// Go through the Inputs to the link. When a listfile is encountered, we
120
130
// know it is an unbundled generated list.
121
131
if (LinkSYCLDeviceLibs)
122
- CmdArgs .push_back (" -only-needed" );
132
+ Opts .push_back (" -only-needed" );
123
133
for (const auto &II : InputFiles) {
124
134
if (II.getType () == types::TY_Tempfilelist) {
125
135
// Pass the unbundled list with '@' to be processed.
126
136
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 ());
128
140
} else
129
- CmdArgs .push_back (II.getFilename ());
141
+ Objs .push_back (II.getFilename ());
130
142
}
131
143
} else
132
144
for (const auto &II : InputFiles)
133
- CmdArgs .push_back (II.getFilename ());
145
+ Objs .push_back (II.getFilename ());
134
146
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.
142
148
SmallString<128 > ExecPath (C.getDriver ().Dir );
143
149
llvm::sys::path::append (ExecPath, " llvm-link" );
144
150
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
+ }
147
191
return OutputFileName;
148
192
}
149
193
0 commit comments