1414// target-specific device code.
1515// ===---------------------------------------------------------------------===//
1616
17+ #include " clang/Basic/OffloadArch.h"
1718#include " clang/Basic/Version.h"
1819
1920#include " llvm/ADT/StringExtras.h"
5455using namespace llvm ;
5556using namespace llvm ::opt;
5657using namespace llvm ::object;
58+ using namespace clang ;
5759
5860// / Save intermediary results.
5961static bool SaveTemps = false ;
@@ -128,6 +130,12 @@ const OptTable &getOptTable() {
128130 exit (EXIT_FAILURE);
129131}
130132
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+
131139Expected<StringRef> createTempFile (const ArgList &Args, const Twine &Prefix,
132140 StringRef Extension) {
133141 SmallString<128 > OutputFile;
@@ -145,6 +153,40 @@ Expected<StringRef> createTempFile(const ArgList &Args, const Twine &Prefix,
145153 return TempFiles.back ();
146154}
147155
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+
148190Expected<SmallVector<std::string>> getInput (const ArgList &Args) {
149191 // Collect all input bitcode files to be passed to the device linking stage.
150192 SmallVector<std::string> BitcodeFiles;
@@ -338,6 +380,92 @@ static Error runSPIRVCodeGen(StringRef File, const ArgList &Args,
338380 return Error::success ();
339381}
340382
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+
341469// / Performs the following steps:
342470// / 1. Link input device code (user code and SYCL device library code).
343471// / 2. Run SPIR-V code generation.
@@ -349,7 +477,7 @@ Error runSYCLLink(ArrayRef<std::string> Files, const ArgList &Args) {
349477 // Link all input bitcode files and SYCL device library files, if any.
350478 auto LinkedFile = linkDeviceCode (Files, Args, C);
351479 if (!LinkedFile)
352- reportError ( LinkedFile.takeError () );
480+ return LinkedFile.takeError ();
353481
354482 // TODO: SYCL post link functionality involves device code splitting and will
355483 // result in multiple bitcode codes.
@@ -358,15 +486,24 @@ Error runSYCLLink(ArrayRef<std::string> Files, const ArgList &Args) {
358486 SmallVector<std::string> SplitModules;
359487 SplitModules.emplace_back (*LinkedFile);
360488
489+ bool IsAOTCompileNeeded = IsIntelOffloadArch (
490+ StringToOffloadArch (Args.getLastArgValue (OPT_arch_EQ)));
491+
361492 // SPIR-V code generation step.
362493 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))
368497 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+ }
370507 }
371508
372509 // Write the final output into file.
@@ -440,9 +577,12 @@ int main(int argc, char **argv) {
440577 DryRun = Args.hasArg (OPT_dry_run);
441578 SaveTemps = Args.hasArg (OPT_save_temps);
442579
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" ));
446586
447587 if (Args.hasArg (OPT_spirv_dump_device_code_EQ)) {
448588 Arg *A = Args.getLastArg (OPT_spirv_dump_device_code_EQ);
0 commit comments