@@ -70,6 +70,8 @@ static StringRef OutputFile;
70
70
// / Directory to dump SPIR-V IR if requested by user.
71
71
static SmallString<128 > SPIRVDumpDir;
72
72
73
+ using OffloadingImage = OffloadBinary::OffloadingImage;
74
+
73
75
static void printVersion (raw_ostream &OS) {
74
76
OS << clang::getClangToolFullVersion (" clang-sycl-linker" ) << ' \n ' ;
75
77
}
@@ -168,10 +170,10 @@ Expected<SmallVector<std::string>> getInput(const ArgList &Args) {
168
170
// / are LLVM IR bitcode files.
169
171
// TODO: Support SPIR-V IR files.
170
172
Expected<std::unique_ptr<Module>> getBitcodeModule (StringRef File,
171
- LLVMContext &C ) {
173
+ LLVMContext &Ctx ) {
172
174
SMDiagnostic Err;
173
175
174
- auto M = getLazyIRFileModule (File, Err, C );
176
+ auto M = getLazyIRFileModule (File, Err, Ctx );
175
177
if (M)
176
178
return std::move (M);
177
179
return createStringError (Err.getMessage ());
@@ -211,16 +213,16 @@ Expected<SmallVector<std::string>> getSYCLDeviceLibs(const ArgList &Args) {
211
213
// / 3. Link all the images gathered in Step 2 with the output of Step 1 using
212
214
// / linkInModule API. LinkOnlyNeeded flag is used.
213
215
Expected<StringRef> linkDeviceCode (ArrayRef<std::string> InputFiles,
214
- const ArgList &Args, LLVMContext &C ) {
216
+ const ArgList &Args, LLVMContext &Ctx ) {
215
217
llvm::TimeTraceScope TimeScope (" SYCL link device code" );
216
218
217
219
assert (InputFiles.size () && " No inputs to link" );
218
220
219
- auto LinkerOutput = std::make_unique<Module>(" sycl-device-link" , C );
221
+ auto LinkerOutput = std::make_unique<Module>(" sycl-device-link" , Ctx );
220
222
Linker L (*LinkerOutput);
221
223
// Link SYCL device input files.
222
224
for (auto &File : InputFiles) {
223
- auto ModOrErr = getBitcodeModule (File, C );
225
+ auto ModOrErr = getBitcodeModule (File, Ctx );
224
226
if (!ModOrErr)
225
227
return ModOrErr.takeError ();
226
228
if (L.linkInModule (std::move (*ModOrErr)))
@@ -235,7 +237,7 @@ Expected<StringRef> linkDeviceCode(ArrayRef<std::string> InputFiles,
235
237
// Link in SYCL device library files.
236
238
const llvm::Triple Triple (Args.getLastArgValue (OPT_triple_EQ));
237
239
for (auto &File : *SYCLDeviceLibFiles) {
238
- auto LibMod = getBitcodeModule (File, C );
240
+ auto LibMod = getBitcodeModule (File, Ctx );
239
241
if (!LibMod)
240
242
return LibMod.takeError ();
241
243
if ((*LibMod)->getTargetTriple () == Triple) {
@@ -278,18 +280,18 @@ Expected<StringRef> linkDeviceCode(ArrayRef<std::string> InputFiles,
278
280
// / Converts 'File' from LLVM bitcode to SPIR-V format using SPIR-V backend.
279
281
// / 'Args' encompasses all arguments required for linking device code and will
280
282
// / be parsed to generate options required to be passed into the backend.
281
- static Expected<StringRef> runSPIRVCodeGen (StringRef File, const ArgList &Args,
282
- LLVMContext &C ) {
283
+ static Error runSPIRVCodeGen (StringRef File, const ArgList &Args,
284
+ StringRef OutputFile, LLVMContext &Ctx ) {
283
285
llvm::TimeTraceScope TimeScope (" SPIR-V code generation" );
284
286
285
287
// Parse input module.
286
- SMDiagnostic Err ;
287
- std::unique_ptr<Module> M = parseIRFile (File, Err, C );
288
+ SMDiagnostic E ;
289
+ std::unique_ptr<Module> M = parseIRFile (File, E, Ctx );
288
290
if (!M)
289
- return createStringError (Err .getMessage ());
291
+ return createStringError (E .getMessage ());
290
292
291
293
if (Error Err = M->materializeAll ())
292
- return std::move ( Err) ;
294
+ return Err;
293
295
294
296
Triple TargetTriple (Args.getLastArgValue (OPT_triple_EQ));
295
297
M->setTargetTriple (TargetTriple);
@@ -333,7 +335,7 @@ static Expected<StringRef> runSPIRVCodeGen(StringRef File, const ArgList &Args,
333
335
errs () << formatv (" SPIR-V Backend: input: {0}, output: {1}\n " , File,
334
336
OutputFile);
335
337
336
- return OutputFile ;
338
+ return Error::success () ;
337
339
}
338
340
339
341
// / Performs the following steps:
@@ -342,17 +344,61 @@ static Expected<StringRef> runSPIRVCodeGen(StringRef File, const ArgList &Args,
342
344
Error runSYCLLink (ArrayRef<std::string> Files, const ArgList &Args) {
343
345
llvm::TimeTraceScope TimeScope (" SYCL device linking" );
344
346
345
- LLVMContext C ;
347
+ LLVMContext Ctx ;
346
348
347
349
// Link all input bitcode files and SYCL device library files, if any.
348
- auto LinkedFile = linkDeviceCode (Files, Args, C );
350
+ auto LinkedFile = linkDeviceCode (Files, Args, Ctx );
349
351
if (!LinkedFile)
350
352
reportError (LinkedFile.takeError ());
351
353
354
+ // TODO: SYCL post link functionality involves device code splitting and will
355
+ // result in multiple bitcode codes.
356
+ // The following lines are placeholders to represent multiple files and will
357
+ // be refactored once SYCL post link support is available.
358
+ SmallVector<std::string> SplitModules;
359
+ SplitModules.emplace_back (*LinkedFile);
360
+
352
361
// SPIR-V code generation step.
353
- auto SPVFile = runSPIRVCodeGen (*LinkedFile, Args, C);
354
- if (!SPVFile)
355
- return SPVFile.takeError ();
362
+ for (size_t I = 0 , E = SplitModules.size (); I != E; ++I) {
363
+ auto Stem = OutputFile.rsplit (' .' ).first ;
364
+ std::string SPVFile (Stem);
365
+ SPVFile.append (" _" + utostr (I) + " .spv" );
366
+ auto Err = runSPIRVCodeGen (SplitModules[I], Args, SPVFile, Ctx);
367
+ if (Err)
368
+ return std::move (Err);
369
+ SplitModules[I] = SPVFile;
370
+ }
371
+
372
+ // Write the final output into file.
373
+ int FD = -1 ;
374
+ if (std::error_code EC = sys::fs::openFileForWrite (OutputFile, FD))
375
+ return errorCodeToError (EC);
376
+ llvm::raw_fd_ostream FS (FD, /* shouldClose=*/ true );
377
+
378
+ for (size_t I = 0 , E = SplitModules.size (); I != E; ++I) {
379
+ auto File = SplitModules[I];
380
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> FileOrErr =
381
+ llvm::MemoryBuffer::getFileOrSTDIN (File);
382
+ if (std::error_code EC = FileOrErr.getError ()) {
383
+ if (DryRun)
384
+ FileOrErr = MemoryBuffer::getMemBuffer (" " );
385
+ else
386
+ return createFileError (File, EC);
387
+ }
388
+ OffloadingImage TheImage{};
389
+ TheImage.TheImageKind = IMG_Object;
390
+ TheImage.TheOffloadKind = OFK_SYCL;
391
+ TheImage.StringData [" triple" ] =
392
+ Args.MakeArgString (Args.getLastArgValue (OPT_triple_EQ));
393
+ TheImage.StringData [" arch" ] =
394
+ Args.MakeArgString (Args.getLastArgValue (OPT_arch_EQ));
395
+ TheImage.Image = std::move (*FileOrErr);
396
+
397
+ llvm::SmallString<0 > Buffer = OffloadBinary::write (TheImage);
398
+ if (Buffer.size () % OffloadBinary::getAlignment () != 0 )
399
+ return createStringError (" Offload binary has invalid size alignment" );
400
+ FS << Buffer;
401
+ }
356
402
return Error::success ();
357
403
}
358
404
@@ -394,7 +440,7 @@ int main(int argc, char **argv) {
394
440
DryRun = Args.hasArg (OPT_dry_run);
395
441
SaveTemps = Args.hasArg (OPT_save_temps);
396
442
397
- OutputFile = " a.spv " ;
443
+ OutputFile = " a.out " ;
398
444
if (Args.hasArg (OPT_o))
399
445
OutputFile = Args.getLastArgValue (OPT_o);
400
446
0 commit comments