25
25
#include " llvm/IRReader/IRReader.h"
26
26
#include " llvm/LTO/LTO.h"
27
27
#include " llvm/Linker/Linker.h"
28
+ #include " llvm/MC/TargetRegistry.h"
28
29
#include " llvm/Object/Archive.h"
29
30
#include " llvm/Object/ArchiveWriter.h"
30
31
#include " llvm/Object/Binary.h"
48
49
#include " llvm/Support/TargetSelect.h"
49
50
#include " llvm/Support/TimeProfiler.h"
50
51
#include " llvm/Support/WithColor.h"
52
+ #include " llvm/Target/TargetMachine.h"
51
53
52
54
using namespace llvm ;
53
55
using namespace llvm ::opt;
@@ -141,40 +143,6 @@ Expected<StringRef> createTempFile(const ArgList &Args, const Twine &Prefix,
141
143
return TempFiles.back ();
142
144
}
143
145
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
-
178
146
Expected<SmallVector<std::string>> getInput (const ArgList &Args) {
179
147
// Collect all input bitcode files to be passed to the device linking stage.
180
148
SmallVector<std::string> BitcodeFiles;
@@ -243,12 +211,11 @@ Expected<SmallVector<std::string>> getSYCLDeviceLibs(const ArgList &Args) {
243
211
// / 3. Link all the images gathered in Step 2 with the output of Step 1 using
244
212
// / linkInModule API. LinkOnlyNeeded flag is used.
245
213
Expected<StringRef> linkDeviceCode (ArrayRef<std::string> InputFiles,
246
- const ArgList &Args) {
214
+ const ArgList &Args, LLVMContext &C ) {
247
215
llvm::TimeTraceScope TimeScope (" SYCL link device code" );
248
216
249
217
assert (InputFiles.size () && " No inputs to link" );
250
218
251
- LLVMContext C;
252
219
auto LinkerOutput = std::make_unique<Module>(" sycl-device-link" , C);
253
220
Linker L (*LinkerOutput);
254
221
// Link SYCL device input files.
@@ -307,120 +274,61 @@ Expected<StringRef> linkDeviceCode(ArrayRef<std::string> InputFiles,
307
274
return *BitcodeOutput;
308
275
}
309
276
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
-
376
277
// / 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 .
378
279
// / '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);
424
332
425
333
return OutputFile;
426
334
}
@@ -429,15 +337,17 @@ static Expected<StringRef> runLLVMToSPIRVTranslation(StringRef File,
429
337
// / 1. Link input device code (user code and SYCL device library code).
430
338
// / 2. Run SPIR-V code generation.
431
339
Error runSYCLLink (ArrayRef<std::string> Files, const ArgList &Args) {
432
- llvm::TimeTraceScope TimeScope (" SYCLDeviceLink" );
340
+ llvm::TimeTraceScope TimeScope (" SYCL device linking" );
341
+
342
+ LLVMContext C;
433
343
434
344
// 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 );
436
346
if (!LinkedFile)
437
347
reportError (LinkedFile.takeError ());
438
348
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 );
441
351
if (!SPVFile)
442
352
return SPVFile.takeError ();
443
353
return Error::success ();
@@ -447,6 +357,11 @@ Error runSYCLLink(ArrayRef<std::string> Files, const ArgList &Args) {
447
357
448
358
int main (int argc, char **argv) {
449
359
InitLLVM X (argc, argv);
360
+ InitializeAllTargetInfos ();
361
+ InitializeAllTargets ();
362
+ InitializeAllTargetMCs ();
363
+ InitializeAllAsmParsers ();
364
+ InitializeAllAsmPrinters ();
450
365
451
366
Executable = argv[0 ];
452
367
sys::PrintStackTraceOnErrorSignal (argv[0 ]);
0 commit comments