2525#include " llvm/IRReader/IRReader.h"
2626#include " llvm/LTO/LTO.h"
2727#include " llvm/Linker/Linker.h"
28+ #include " llvm/MC/TargetRegistry.h"
2829#include " llvm/Object/Archive.h"
2930#include " llvm/Object/ArchiveWriter.h"
3031#include " llvm/Object/Binary.h"
4849#include " llvm/Support/TargetSelect.h"
4950#include " llvm/Support/TimeProfiler.h"
5051#include " llvm/Support/WithColor.h"
52+ #include " llvm/Target/TargetMachine.h"
5153
5254using namespace llvm ;
5355using namespace llvm ::opt;
@@ -141,40 +143,6 @@ Expected<StringRef> createTempFile(const ArgList &Args, const Twine &Prefix,
141143 return TempFiles.back ();
142144}
143145
144- Expected<std::string> findProgram (const ArgList &Args, StringRef Name,
145- ArrayRef<StringRef> Paths) {
146- if (Args.hasArg (OPT_dry_run))
147- return Name.str ();
148- ErrorOr<std::string> Path = sys::findProgramByName (Name, Paths);
149- if (!Path)
150- Path = sys::findProgramByName (Name);
151- if (!Path)
152- return createStringError (Path.getError (),
153- " Unable to find '" + Name + " ' in path" );
154- return *Path;
155- }
156-
157- void printCommands (ArrayRef<StringRef> CmdArgs) {
158- if (CmdArgs.empty ())
159- return ;
160-
161- llvm::errs () << " \" " << CmdArgs.front () << " \" " ;
162- llvm::errs () << llvm::join (std::next (CmdArgs.begin ()), CmdArgs.end (), " " )
163- << " \n " ;
164- }
165-
166- // / Execute the command \p ExecutablePath with the arguments \p Args.
167- Error executeCommands (StringRef ExecutablePath, ArrayRef<StringRef> Args) {
168- if (Verbose || DryRun)
169- printCommands (Args);
170-
171- if (!DryRun)
172- if (sys::ExecuteAndWait (ExecutablePath, Args))
173- return createStringError (
174- " '%s' failed" , sys::path::filename (ExecutablePath).str ().c_str ());
175- return Error::success ();
176- }
177-
178146Expected<SmallVector<std::string>> getInput (const ArgList &Args) {
179147 // Collect all input bitcode files to be passed to the device linking stage.
180148 SmallVector<std::string> BitcodeFiles;
@@ -243,12 +211,11 @@ Expected<SmallVector<std::string>> getSYCLDeviceLibs(const ArgList &Args) {
243211// / 3. Link all the images gathered in Step 2 with the output of Step 1 using
244212// / linkInModule API. LinkOnlyNeeded flag is used.
245213Expected<StringRef> linkDeviceCode (ArrayRef<std::string> InputFiles,
246- const ArgList &Args) {
214+ const ArgList &Args, LLVMContext &C ) {
247215 llvm::TimeTraceScope TimeScope (" SYCL link device code" );
248216
249217 assert (InputFiles.size () && " No inputs to link" );
250218
251- LLVMContext C;
252219 auto LinkerOutput = std::make_unique<Module>(" sycl-device-link" , C);
253220 Linker L (*LinkerOutput);
254221 // Link SYCL device input files.
@@ -307,120 +274,61 @@ Expected<StringRef> linkDeviceCode(ArrayRef<std::string> InputFiles,
307274 return *BitcodeOutput;
308275}
309276
310- // / Add any llvm-spirv option that relies on a specific Triple in addition
311- // / to user supplied options.
312- static void getSPIRVTransOpts (const ArgList &Args,
313- SmallVector<StringRef, 8 > &TranslatorArgs,
314- const llvm::Triple Triple) {
315- // Enable NonSemanticShaderDebugInfo.200 for non-Windows
316- const bool IsWindowsMSVC =
317- Triple.isWindowsMSVCEnvironment () || Args.hasArg (OPT_is_windows_msvc_env);
318- const bool EnableNonSemanticDebug = !IsWindowsMSVC;
319- if (EnableNonSemanticDebug) {
320- TranslatorArgs.push_back (
321- " -spirv-debug-info-version=nonsemantic-shader-200" );
322- } else {
323- TranslatorArgs.push_back (" -spirv-debug-info-version=ocl-100" );
324- // Prevent crash in the translator if input IR contains DIExpression
325- // operations which don't have mapping to OpenCL.DebugInfo.100 spec.
326- TranslatorArgs.push_back (" -spirv-allow-extra-diexpressions" );
327- }
328- std::string UnknownIntrinsics (" -spirv-allow-unknown-intrinsics=llvm.genx." );
329-
330- TranslatorArgs.push_back (Args.MakeArgString (UnknownIntrinsics));
331-
332- // Disable all the extensions by default
333- std::string ExtArg (" -spirv-ext=-all" );
334- std::string DefaultExtArg =
335- " ,+SPV_EXT_shader_atomic_float_add,+SPV_EXT_shader_atomic_float_min_max"
336- " ,+SPV_KHR_no_integer_wrap_decoration,+SPV_KHR_float_controls"
337- " ,+SPV_KHR_expect_assume,+SPV_KHR_linkonce_odr" ;
338- std::string INTELExtArg =
339- " ,+SPV_INTEL_subgroups,+SPV_INTEL_media_block_io"
340- " ,+SPV_INTEL_device_side_avc_motion_estimation"
341- " ,+SPV_INTEL_fpga_loop_controls,+SPV_INTEL_unstructured_loop_controls"
342- " ,+SPV_INTEL_fpga_reg,+SPV_INTEL_blocking_pipes"
343- " ,+SPV_INTEL_function_pointers,+SPV_INTEL_kernel_attributes"
344- " ,+SPV_INTEL_io_pipes,+SPV_INTEL_inline_assembly"
345- " ,+SPV_INTEL_arbitrary_precision_integers"
346- " ,+SPV_INTEL_float_controls2,+SPV_INTEL_vector_compute"
347- " ,+SPV_INTEL_fast_composite"
348- " ,+SPV_INTEL_arbitrary_precision_fixed_point"
349- " ,+SPV_INTEL_arbitrary_precision_floating_point"
350- " ,+SPV_INTEL_variable_length_array,+SPV_INTEL_fp_fast_math_mode"
351- " ,+SPV_INTEL_long_composites"
352- " ,+SPV_INTEL_arithmetic_fence"
353- " ,+SPV_INTEL_global_variable_decorations"
354- " ,+SPV_INTEL_cache_controls"
355- " ,+SPV_INTEL_fpga_buffer_location"
356- " ,+SPV_INTEL_fpga_argument_interfaces"
357- " ,+SPV_INTEL_fpga_invocation_pipelining_attributes"
358- " ,+SPV_INTEL_fpga_latency_control"
359- " ,+SPV_INTEL_task_sequence"
360- " ,+SPV_KHR_shader_clock"
361- " ,+SPV_INTEL_bindless_images" ;
362- ExtArg = ExtArg + DefaultExtArg + INTELExtArg;
363- ExtArg += " ,+SPV_INTEL_token_type"
364- " ,+SPV_INTEL_bfloat16_conversion"
365- " ,+SPV_INTEL_joint_matrix"
366- " ,+SPV_INTEL_hw_thread_queries"
367- " ,+SPV_KHR_uniform_group_instructions"
368- " ,+SPV_INTEL_masked_gather_scatter"
369- " ,+SPV_INTEL_tensor_float32_conversion"
370- " ,+SPV_INTEL_optnone"
371- " ,+SPV_KHR_non_semantic_info"
372- " ,+SPV_KHR_cooperative_matrix" ;
373- TranslatorArgs.push_back (Args.MakeArgString (ExtArg));
374- }
375-
376277// / Run LLVM to SPIR-V translation.
377- // / Converts 'File' from LLVM bitcode to SPIR-V format using llvm-spirv tool .
278+ // / Converts 'File' from LLVM bitcode to SPIR-V format using SPIR-V backend .
378279// / 'Args' encompasses all arguments required for linking device code and will
379- // / be parsed to generate options required to be passed into llvm-spirv tool.
380- static Expected<StringRef> runLLVMToSPIRVTranslation (StringRef File,
381- const ArgList &Args) {
382- llvm::TimeTraceScope TimeScope (" LLVMToSPIRVTranslation" );
383- StringRef LLVMSPIRVPath = Args.getLastArgValue (OPT_llvm_spirv_path_EQ);
384- Expected<std::string> LLVMToSPIRVProg =
385- findProgram (Args, " llvm-spirv" , {LLVMSPIRVPath});
386- if (!LLVMToSPIRVProg)
387- return LLVMToSPIRVProg.takeError ();
388-
389- SmallVector<StringRef, 8 > CmdArgs;
390- CmdArgs.push_back (*LLVMToSPIRVProg);
391- const llvm::Triple Triple (Args.getLastArgValue (OPT_triple_EQ));
392- getSPIRVTransOpts (Args, CmdArgs, Triple);
393- StringRef LLVMToSPIRVOptions;
394- if (Arg *A = Args.getLastArg (OPT_llvm_spirv_options_EQ))
395- LLVMToSPIRVOptions = A->getValue ();
396- LLVMToSPIRVOptions.split (CmdArgs, " " , /* MaxSplit = */ -1 ,
397- /* KeepEmpty = */ false );
398- CmdArgs.append ({" -o" , OutputFile});
399- CmdArgs.push_back (File);
400- if (Error Err = executeCommands (*LLVMToSPIRVProg, CmdArgs))
401- return std::move (Err);
402-
403- if (!SPIRVDumpDir.empty ()) {
404- std::error_code EC =
405- llvm::sys::fs::create_directory (SPIRVDumpDir, /* IgnoreExisting*/ true );
406- if (EC)
407- return createStringError (
408- EC,
409- formatv (" failed to create dump directory. path: {0}, error_code: {1}" ,
410- SPIRVDumpDir, EC.value ()));
411-
412- StringRef Path = OutputFile;
413- StringRef Filename = llvm::sys::path::filename (Path);
414- SmallString<128 > CopyPath = SPIRVDumpDir;
415- CopyPath.append (Filename);
416- EC = llvm::sys::fs::copy_file (Path, CopyPath);
417- if (EC)
418- return createStringError (
419- EC,
420- formatv (
421- " failed to copy file. original: {0}, copy: {1}, error_code: {2}" ,
422- Path, CopyPath, EC.value ()));
423- }
280+ // / 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+ llvm::TimeTraceScope TimeScope (" SPIR-V code generation" );
284+
285+ // Parse input module.
286+ SMDiagnostic Err;
287+ std::unique_ptr<Module> M = parseIRFile (File, Err, C);
288+ if (!M)
289+ return createStringError (Err.getMessage ());
290+
291+ Triple TargetTriple (Args.getLastArgValue (OPT_triple_EQ));
292+ M->setTargetTriple (TargetTriple);
293+
294+ // Get a handle to SPIR-V target backend.
295+ std::string Msg;
296+ const Target *T = TargetRegistry::lookupTarget (M->getTargetTriple (), Msg);
297+ if (!T)
298+ return createStringError (Msg + " : " + M->getTargetTriple ().str ());
299+
300+ // Allocate SPIR-V target machine.
301+ TargetOptions Options;
302+ std::optional<Reloc::Model> RM;
303+ std::optional<CodeModel::Model> CM;
304+ std::unique_ptr<TargetMachine> TM (
305+ T->createTargetMachine (M->getTargetTriple (), /* CPU */ " " ,
306+ /* Features */ " " , Options, RM, CM));
307+ if (!TM)
308+ return createStringError (" Could not allocate target machine!" );
309+
310+ // Set data layout if needed.
311+ if (M->getDataLayout ().isDefault ())
312+ M->setDataLayout (TM->createDataLayout ());
313+
314+ // Open output file for writing.
315+ int FD = -1 ;
316+ if (std::error_code EC = sys::fs::openFileForWrite (OutputFile, FD))
317+ return errorCodeToError (EC);
318+ auto OS = std::make_unique<llvm::raw_fd_ostream>(FD, true );
319+
320+ // Run SPIR-V codegen passes to generate SPIR-V file.
321+ legacy::PassManager CodeGenPasses;
322+ TargetLibraryInfoImpl TLII (M->getTargetTriple ());
323+ CodeGenPasses.add (new TargetLibraryInfoWrapperPass (TLII));
324+ if (TM->addPassesToEmitFile (CodeGenPasses, *OS, nullptr ,
325+ CodeGenFileType::ObjectFile))
326+ return createStringError (" Failed to execute SPIR-V Backend" );
327+ CodeGenPasses.run (*M);
328+
329+ if (Verbose)
330+ errs () << formatv (" SPIR-V Backend: input: {0}, output: {1}\n " , File,
331+ OutputFile);
424332
425333 return OutputFile;
426334}
@@ -429,15 +337,17 @@ static Expected<StringRef> runLLVMToSPIRVTranslation(StringRef File,
429337// / 1. Link input device code (user code and SYCL device library code).
430338// / 2. Run SPIR-V code generation.
431339Error runSYCLLink (ArrayRef<std::string> Files, const ArgList &Args) {
432- llvm::TimeTraceScope TimeScope (" SYCLDeviceLink" );
340+ llvm::TimeTraceScope TimeScope (" SYCL device linking" );
341+
342+ LLVMContext C;
433343
434344 // Link all input bitcode files and SYCL device library files, if any.
435- auto LinkedFile = linkDeviceCode (Files, Args);
345+ auto LinkedFile = linkDeviceCode (Files, Args, C );
436346 if (!LinkedFile)
437347 reportError (LinkedFile.takeError ());
438348
439- // LLVM to SPIR-V translation step
440- auto SPVFile = runLLVMToSPIRVTranslation (*LinkedFile, Args);
349+ // SPIR-V code generation step.
350+ auto SPVFile = runSPIRVCodeGen (*LinkedFile, Args, C );
441351 if (!SPVFile)
442352 return SPVFile.takeError ();
443353 return Error::success ();
@@ -447,6 +357,11 @@ Error runSYCLLink(ArrayRef<std::string> Files, const ArgList &Args) {
447357
448358int main (int argc, char **argv) {
449359 InitLLVM X (argc, argv);
360+ InitializeAllTargetInfos ();
361+ InitializeAllTargets ();
362+ InitializeAllTargetMCs ();
363+ InitializeAllAsmParsers ();
364+ InitializeAllAsmPrinters ();
450365
451366 Executable = argv[0 ];
452367 sys::PrintStackTraceOnErrorSignal (argv[0 ]);
0 commit comments