14
14
// target-specific device code.
15
15
// ===---------------------------------------------------------------------===//
16
16
17
+ #include " clang/Basic/OffloadArch.h"
17
18
#include " clang/Basic/Version.h"
18
19
19
20
#include " llvm/ADT/StringExtras.h"
54
55
using namespace llvm ;
55
56
using namespace llvm ::opt;
56
57
using namespace llvm ::object;
58
+ using namespace clang ;
57
59
58
60
// / Save intermediary results.
59
61
static bool SaveTemps = false ;
@@ -128,6 +130,12 @@ const OptTable &getOptTable() {
128
130
exit (EXIT_FAILURE);
129
131
}
130
132
133
+ std::string getMainExecutable (const char *Name) {
134
+ void *Ptr = (void *)(intptr_t )&getMainExecutable;
135
+ auto COWPath = sys::fs::getMainExecutable (Name, Ptr );
136
+ return sys::path::parent_path (COWPath).str ();
137
+ }
138
+
131
139
Expected<StringRef> createTempFile (const ArgList &Args, const Twine &Prefix,
132
140
StringRef Extension) {
133
141
SmallString<128 > OutputFile;
@@ -145,6 +153,40 @@ Expected<StringRef> createTempFile(const ArgList &Args, const Twine &Prefix,
145
153
return TempFiles.back ();
146
154
}
147
155
156
+ Expected<std::string> findProgram (const ArgList &Args, StringRef Name,
157
+ ArrayRef<StringRef> Paths) {
158
+ if (Args.hasArg (OPT_dry_run))
159
+ return Name.str ();
160
+ ErrorOr<std::string> Path = sys::findProgramByName (Name, Paths);
161
+ if (!Path)
162
+ Path = sys::findProgramByName (Name);
163
+ if (!Path)
164
+ return createStringError (Path.getError (),
165
+ " Unable to find '" + Name + " ' in path" );
166
+ return *Path;
167
+ }
168
+
169
+ void printCommands (ArrayRef<StringRef> CmdArgs) {
170
+ if (CmdArgs.empty ())
171
+ return ;
172
+
173
+ llvm::errs () << " \" " << CmdArgs.front () << " \" " ;
174
+ llvm::errs () << llvm::join (std::next (CmdArgs.begin ()), CmdArgs.end (), " " )
175
+ << " \n " ;
176
+ }
177
+
178
+ // / Execute the command \p ExecutablePath with the arguments \p Args.
179
+ Error executeCommands (StringRef ExecutablePath, ArrayRef<StringRef> Args) {
180
+ if (Verbose || DryRun)
181
+ printCommands (Args);
182
+
183
+ if (!DryRun)
184
+ if (sys::ExecuteAndWait (ExecutablePath, Args))
185
+ return createStringError (
186
+ " '%s' failed" , sys::path::filename (ExecutablePath).str ().c_str ());
187
+ return Error::success ();
188
+ }
189
+
148
190
Expected<SmallVector<std::string>> getInput (const ArgList &Args) {
149
191
// Collect all input bitcode files to be passed to the device linking stage.
150
192
SmallVector<std::string> BitcodeFiles;
@@ -338,6 +380,92 @@ static Error runSPIRVCodeGen(StringRef File, const ArgList &Args,
338
380
return Error::success ();
339
381
}
340
382
383
+ // / Run AOT compilation for Intel CPU.
384
+ // / Calls opencl-aot tool to generate device code for the Intel OpenCL CPU
385
+ // / Runtime.
386
+ // / \param InputFile The input SPIR-V file.
387
+ // / \param OutputFile The output file name.
388
+ // / \param Args Encompasses all arguments required for linking and wrapping
389
+ // / device code and will be parsed to generate options required to be passed
390
+ // / into the SYCL AOT compilation step.
391
+ static Error runAOTCompileIntelCPU (StringRef InputFile, StringRef OutputFile,
392
+ const ArgList &Args) {
393
+ SmallVector<StringRef, 8 > CmdArgs;
394
+ Expected<std::string> OpenCLAOTPath =
395
+ findProgram (Args, " opencl-aot" , {getMainExecutable (" opencl-aot" )});
396
+ if (!OpenCLAOTPath)
397
+ return OpenCLAOTPath.takeError ();
398
+
399
+ CmdArgs.push_back (*OpenCLAOTPath);
400
+ CmdArgs.push_back (" --device=cpu" );
401
+ StringRef ExtraArgs = Args.getLastArgValue (OPT_opencl_aot_options_EQ);
402
+ ExtraArgs.split (CmdArgs, " " , /* MaxSplit=*/ -1 , /* KeepEmpty=*/ false );
403
+ CmdArgs.push_back (" -o" );
404
+ CmdArgs.push_back (OutputFile);
405
+ CmdArgs.push_back (InputFile);
406
+ if (Error Err = executeCommands (*OpenCLAOTPath, CmdArgs))
407
+ return Err;
408
+ return Error::success ();
409
+ }
410
+
411
+ // / Run AOT compilation for Intel GPU.
412
+ // / Calls ocloc tool to generate device code for the Intel Graphics Compute
413
+ // / Runtime.
414
+ // / \param InputFile The input SPIR-V file.
415
+ // / \param OutputFile The output file name.
416
+ // / \param Args Encompasses all arguments required for linking and wrapping
417
+ // / device code and will be parsed to generate options required to be passed
418
+ // / into the SYCL AOT compilation step.
419
+ static Error runAOTCompileIntelGPU (StringRef InputFile, StringRef OutputFile,
420
+ const ArgList &Args) {
421
+ SmallVector<StringRef, 8 > CmdArgs;
422
+ Expected<std::string> OclocPath =
423
+ findProgram (Args, " ocloc" , {getMainExecutable (" ocloc" )});
424
+ if (!OclocPath)
425
+ return OclocPath.takeError ();
426
+
427
+ CmdArgs.push_back (*OclocPath);
428
+ // The next line prevents ocloc from modifying the image name
429
+ CmdArgs.push_back (" -output_no_suffix" );
430
+ CmdArgs.push_back (" -spirv_input" );
431
+
432
+ StringRef Arch (Args.getLastArgValue (OPT_arch_EQ));
433
+ if (Arch.empty ())
434
+ return createStringError (inconvertibleErrorCode (),
435
+ " Arch must be specified for AOT compilation" );
436
+ CmdArgs.push_back (" -device" );
437
+ CmdArgs.push_back (Arch);
438
+
439
+ StringRef ExtraArgs = Args.getLastArgValue (OPT_ocloc_options_EQ);
440
+ ExtraArgs.split (CmdArgs, " " , /* MaxSplit=*/ -1 , /* KeepEmpty=*/ false );
441
+
442
+ CmdArgs.push_back (" -output" );
443
+ CmdArgs.push_back (OutputFile);
444
+ CmdArgs.push_back (" -file" );
445
+ CmdArgs.push_back (InputFile);
446
+ if (Error Err = executeCommands (*OclocPath, CmdArgs))
447
+ return Err;
448
+ return Error::success ();
449
+ }
450
+
451
+ // / Run AOT compilation for Intel CPU/GPU.
452
+ // / \param InputFile The input SPIR-V file.
453
+ // / \param OutputFile The output file name.
454
+ // / \param Args Encompasses all arguments required for linking and wrapping
455
+ // / device code and will be parsed to generate options required to be passed
456
+ // / into the SYCL AOT compilation step.
457
+ static Error runAOTCompile (StringRef InputFile, StringRef OutputFile,
458
+ const ArgList &Args) {
459
+ StringRef Arch = Args.getLastArgValue (OPT_arch_EQ);
460
+ OffloadArch OffloadArch = StringToOffloadArch (Arch);
461
+ if (IsIntelGPUOffloadArch (OffloadArch))
462
+ return runAOTCompileIntelGPU (InputFile, OutputFile, Args);
463
+ if (IsIntelCPUOffloadArch (OffloadArch))
464
+ return runAOTCompileIntelCPU (InputFile, OutputFile, Args);
465
+
466
+ return createStringError (inconvertibleErrorCode (), " Unsupported arch" );
467
+ }
468
+
341
469
// / Performs the following steps:
342
470
// / 1. Link input device code (user code and SYCL device library code).
343
471
// / 2. Run SPIR-V code generation.
@@ -349,7 +477,7 @@ Error runSYCLLink(ArrayRef<std::string> Files, const ArgList &Args) {
349
477
// Link all input bitcode files and SYCL device library files, if any.
350
478
auto LinkedFile = linkDeviceCode (Files, Args, C);
351
479
if (!LinkedFile)
352
- reportError ( LinkedFile.takeError () );
480
+ return LinkedFile.takeError ();
353
481
354
482
// TODO: SYCL post link functionality involves device code splitting and will
355
483
// result in multiple bitcode codes.
@@ -358,15 +486,24 @@ Error runSYCLLink(ArrayRef<std::string> Files, const ArgList &Args) {
358
486
SmallVector<std::string> SplitModules;
359
487
SplitModules.emplace_back (*LinkedFile);
360
488
489
+ bool IsAOTCompileNeeded = IsIntelOffloadArch (
490
+ StringToOffloadArch (Args.getLastArgValue (OPT_arch_EQ)));
491
+
361
492
// SPIR-V code generation step.
362
493
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, C);
367
- if (Err)
494
+ StringRef Stem = OutputFile.rsplit (' .' ).first ;
495
+ std::string SPVFile = (Stem + " _" + Twine (I) + " .spv" ).str ();
496
+ if (Error Err = runSPIRVCodeGen (SplitModules[I], Args, SPVFile, C))
368
497
return Err;
369
- SplitModules[I] = SPVFile;
498
+ if (!IsAOTCompileNeeded) {
499
+ SplitModules[I] = SPVFile;
500
+ } else {
501
+ // AOT compilation step.
502
+ std::string AOTFile = (Stem + " _" + Twine (I) + " .out" ).str ();
503
+ if (Error Err = runAOTCompile (SPVFile, AOTFile, Args))
504
+ return Err;
505
+ SplitModules[I] = AOTFile;
506
+ }
370
507
}
371
508
372
509
// Write the final output into file.
@@ -440,9 +577,12 @@ int main(int argc, char **argv) {
440
577
DryRun = Args.hasArg (OPT_dry_run);
441
578
SaveTemps = Args.hasArg (OPT_save_temps);
442
579
443
- OutputFile = " a.out" ;
444
- if (Args.hasArg (OPT_o))
445
- OutputFile = Args.getLastArgValue (OPT_o);
580
+ if (!Args.hasArg (OPT_o))
581
+ reportError (createStringError (" Output file must be specified" ));
582
+ OutputFile = Args.getLastArgValue (OPT_o);
583
+
584
+ if (!Args.hasArg (OPT_triple_EQ))
585
+ reportError (createStringError (" Target triple must be specified" ));
446
586
447
587
if (Args.hasArg (OPT_spirv_dump_device_code_EQ)) {
448
588
Arg *A = Args.getLastArg (OPT_spirv_dump_device_code_EQ);
0 commit comments