-
Couldn't load subscription status.
- Fork 0
[SYCL][SPIR-V Backend] Add SPIR-V backend support inside clang-sycl-linker #3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 6 commits
9f33792
e97d1d5
b81a6dd
f446dcf
a3eb786
9e19659
be91b6b
aca480f
0cc4423
72e9f95
1d0dfe3
3e9c850
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,8 +1,10 @@ | ||
| set(LLVM_LINK_COMPONENTS | ||
| ${LLVM_TARGETS_TO_BUILD} | ||
| BinaryFormat | ||
| MC | ||
| Option | ||
| Object | ||
| Target | ||
| TargetParser | ||
| Support | ||
| ) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -23,6 +23,7 @@ | |
| #include "llvm/IR/DiagnosticPrinter.h" | ||
| #include "llvm/IRReader/IRReader.h" | ||
| #include "llvm/LTO/LTO.h" | ||
| #include "llvm/MC/TargetRegistry.h" | ||
| #include "llvm/Object/Archive.h" | ||
| #include "llvm/Object/ArchiveWriter.h" | ||
| #include "llvm/Object/Binary.h" | ||
|
|
@@ -46,6 +47,7 @@ | |
| #include "llvm/Support/TargetSelect.h" | ||
| #include "llvm/Support/TimeProfiler.h" | ||
| #include "llvm/Support/WithColor.h" | ||
| #include "llvm/Target/TargetMachine.h" | ||
|
|
||
| using namespace llvm; | ||
| using namespace llvm::opt; | ||
|
|
@@ -77,6 +79,17 @@ static const char *Executable; | |
| static SmallVector<SmallString<128>> TempFiles; | ||
|
|
||
| namespace { | ||
|
|
||
| std::once_flag InitOnceFlag; | ||
| void InitializeSPIRVTarget() { | ||
| std::call_once(InitOnceFlag, []() { | ||
| LLVMInitializeSPIRVTargetInfo(); | ||
| LLVMInitializeSPIRVTarget(); | ||
| LLVMInitializeSPIRVTargetMC(); | ||
| LLVMInitializeSPIRVAsmPrinter(); | ||
| }); | ||
| } | ||
|
|
||
| // Must not overlap with llvm::opt::DriverFlag. | ||
| enum LinkerFlags { LinkerOnlyOption = (1 << 4) }; | ||
|
|
||
|
|
@@ -206,7 +219,7 @@ Expected<SmallVector<std::string>> getInput(const ArgList &Args) { | |
| /// be parsed to generate options required to be passed into llvm-link. | ||
| Expected<StringRef> linkDeviceInputFiles(ArrayRef<std::string> InputFiles, | ||
| const ArgList &Args) { | ||
| llvm::TimeTraceScope TimeScope("SYCL LinkDeviceInputFiles"); | ||
| llvm::TimeTraceScope TimeScope("Link device input files"); | ||
|
|
||
| assert(InputFiles.size() && "No inputs to llvm-link"); | ||
| // Early check to see if there is only one input. | ||
|
|
@@ -271,7 +284,7 @@ Expected<SmallVector<std::string>> getSYCLDeviceLibs(const ArgList &Args) { | |
| /// be parsed to generate options required to be passed into llvm-link tool. | ||
| static Expected<StringRef> linkDeviceLibFiles(StringRef InputFile, | ||
| const ArgList &Args) { | ||
| llvm::TimeTraceScope TimeScope("LinkDeviceLibraryFiles"); | ||
| llvm::TimeTraceScope TimeScope("Link device library files"); | ||
|
|
||
| auto SYCLDeviceLibFiles = getSYCLDeviceLibs(Args); | ||
| if (!SYCLDeviceLibFiles) | ||
|
|
@@ -304,126 +317,70 @@ static Expected<StringRef> linkDeviceLibFiles(StringRef InputFile, | |
| return *OutFileOrErr; | ||
| } | ||
|
|
||
| /// Add any llvm-spirv option that relies on a specific Triple in addition | ||
| /// to user supplied options. | ||
| static void getSPIRVTransOpts(const ArgList &Args, | ||
| SmallVector<StringRef, 8> &TranslatorArgs, | ||
| const llvm::Triple Triple) { | ||
| // Enable NonSemanticShaderDebugInfo.200 for non-Windows | ||
| const bool IsWindowsMSVC = | ||
| Triple.isWindowsMSVCEnvironment() || Args.hasArg(OPT_is_windows_msvc_env); | ||
| const bool EnableNonSemanticDebug = !IsWindowsMSVC; | ||
| if (EnableNonSemanticDebug) { | ||
| TranslatorArgs.push_back( | ||
| "-spirv-debug-info-version=nonsemantic-shader-200"); | ||
| } else { | ||
| TranslatorArgs.push_back("-spirv-debug-info-version=ocl-100"); | ||
| // Prevent crash in the translator if input IR contains DIExpression | ||
| // operations which don't have mapping to OpenCL.DebugInfo.100 spec. | ||
| TranslatorArgs.push_back("-spirv-allow-extra-diexpressions"); | ||
| } | ||
| std::string UnknownIntrinsics("-spirv-allow-unknown-intrinsics=llvm.genx."); | ||
|
|
||
| TranslatorArgs.push_back(Args.MakeArgString(UnknownIntrinsics)); | ||
|
|
||
| // Disable all the extensions by default | ||
| std::string ExtArg("-spirv-ext=-all"); | ||
| std::string DefaultExtArg = | ||
| ",+SPV_EXT_shader_atomic_float_add,+SPV_EXT_shader_atomic_float_min_max" | ||
| ",+SPV_KHR_no_integer_wrap_decoration,+SPV_KHR_float_controls" | ||
| ",+SPV_KHR_expect_assume,+SPV_KHR_linkonce_odr"; | ||
| std::string INTELExtArg = | ||
| ",+SPV_INTEL_subgroups,+SPV_INTEL_media_block_io" | ||
| ",+SPV_INTEL_device_side_avc_motion_estimation" | ||
| ",+SPV_INTEL_fpga_loop_controls,+SPV_INTEL_unstructured_loop_controls" | ||
| ",+SPV_INTEL_fpga_reg,+SPV_INTEL_blocking_pipes" | ||
| ",+SPV_INTEL_function_pointers,+SPV_INTEL_kernel_attributes" | ||
| ",+SPV_INTEL_io_pipes,+SPV_INTEL_inline_assembly" | ||
| ",+SPV_INTEL_arbitrary_precision_integers" | ||
| ",+SPV_INTEL_float_controls2,+SPV_INTEL_vector_compute" | ||
| ",+SPV_INTEL_fast_composite" | ||
| ",+SPV_INTEL_arbitrary_precision_fixed_point" | ||
| ",+SPV_INTEL_arbitrary_precision_floating_point" | ||
| ",+SPV_INTEL_variable_length_array,+SPV_INTEL_fp_fast_math_mode" | ||
| ",+SPV_INTEL_long_constant_composite" | ||
| ",+SPV_INTEL_arithmetic_fence" | ||
| ",+SPV_INTEL_global_variable_decorations" | ||
| ",+SPV_INTEL_cache_controls" | ||
| ",+SPV_INTEL_fpga_buffer_location" | ||
| ",+SPV_INTEL_fpga_argument_interfaces" | ||
| ",+SPV_INTEL_fpga_invocation_pipelining_attributes" | ||
| ",+SPV_INTEL_fpga_latency_control" | ||
| ",+SPV_INTEL_task_sequence" | ||
| ",+SPV_KHR_shader_clock" | ||
| ",+SPV_INTEL_bindless_images"; | ||
| ExtArg = ExtArg + DefaultExtArg + INTELExtArg; | ||
| ExtArg += ",+SPV_INTEL_token_type" | ||
| ",+SPV_INTEL_bfloat16_conversion" | ||
| ",+SPV_INTEL_joint_matrix" | ||
| ",+SPV_INTEL_hw_thread_queries" | ||
| ",+SPV_KHR_uniform_group_instructions" | ||
| ",+SPV_INTEL_masked_gather_scatter" | ||
| ",+SPV_INTEL_tensor_float32_conversion" | ||
| ",+SPV_INTEL_optnone" | ||
| ",+SPV_KHR_non_semantic_info" | ||
| ",+SPV_KHR_cooperative_matrix"; | ||
| TranslatorArgs.push_back(Args.MakeArgString(ExtArg)); | ||
| } | ||
|
|
||
| /// Run LLVM to SPIR-V translation. | ||
| /// Converts 'File' from LLVM bitcode to SPIR-V format using llvm-spirv tool. | ||
| /// Converts 'File' from LLVM bitcode to SPIR-V format using SPIR-V backend. | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we need to stack this on top of the #4.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm. A good point. We might want to hold off this change (to use LLVM Module) as we will be introducing a PR soon to incorporate sycl-post-link based calls The test won't fail as both the tests do not have any symbols in them. Thanks There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I will wait for the llvm-linker changes to be merged upstream before proceeding with this one. Thanks |
||
| /// 'Args' encompasses all arguments required for linking device code and will | ||
| /// be parsed to generate options required to be passed into llvm-spirv tool. | ||
| static Expected<StringRef> runLLVMToSPIRVTranslation(StringRef File, | ||
| const ArgList &Args) { | ||
| llvm::TimeTraceScope TimeScope("LLVMToSPIRVTranslation"); | ||
| StringRef LLVMSPIRVPath = Args.getLastArgValue(OPT_llvm_spirv_path_EQ); | ||
| Expected<std::string> LLVMToSPIRVProg = | ||
| findProgram(Args, "llvm-spirv", {LLVMSPIRVPath}); | ||
| if (!LLVMToSPIRVProg) | ||
| return LLVMToSPIRVProg.takeError(); | ||
|
|
||
| SmallVector<StringRef, 8> CmdArgs; | ||
| CmdArgs.push_back(*LLVMToSPIRVProg); | ||
| const llvm::Triple Triple(Args.getLastArgValue(OPT_triple)); | ||
| getSPIRVTransOpts(Args, CmdArgs, Triple); | ||
| StringRef LLVMToSPIRVOptions; | ||
| if (Arg *A = Args.getLastArg(OPT_llvm_spirv_options_EQ)) | ||
| LLVMToSPIRVOptions = A->getValue(); | ||
| LLVMToSPIRVOptions.split(CmdArgs, " ", /* MaxSplit = */ -1, | ||
| /* KeepEmpty = */ false); | ||
| CmdArgs.append({"-o", OutputFile}); | ||
| CmdArgs.push_back(File); | ||
| if (Error Err = executeCommands(*LLVMToSPIRVProg, CmdArgs)) | ||
| return std::move(Err); | ||
|
|
||
| if (!SPIRVDumpDir.empty()) { | ||
| std::error_code EC = | ||
| llvm::sys::fs::create_directory(SPIRVDumpDir, /*IgnoreExisting*/ true); | ||
| if (EC) | ||
| return createStringError( | ||
| EC, | ||
| formatv("failed to create dump directory. path: {0}, error_code: {1}", | ||
| SPIRVDumpDir, EC.value())); | ||
|
|
||
| StringRef Path = OutputFile; | ||
| StringRef Filename = llvm::sys::path::filename(Path); | ||
| SmallString<128> CopyPath = SPIRVDumpDir; | ||
| CopyPath.append(Filename); | ||
| EC = llvm::sys::fs::copy_file(Path, CopyPath); | ||
| if (EC) | ||
| return createStringError( | ||
| EC, | ||
| formatv( | ||
| "failed to copy file. original: {0}, copy: {1}, error_code: {2}", | ||
| Path, CopyPath, EC.value())); | ||
| /// be parsed to generate options required to be passed into the backend. | ||
| static Expected<StringRef> runSPIRVCodeGen(StringRef File, | ||
| const ArgList &Args) { | ||
| llvm::TimeTraceScope TimeScope("SPIR-V code generation"); | ||
| if (Verbose || DryRun) { | ||
| errs() << formatv("LLVM-SPIRV-Backend: input: {0}, output: {1}\n", File, | ||
| OutputFile); | ||
| if (DryRun) | ||
| return OutputFile; | ||
| } | ||
|
|
||
| // SPIR-V-specific target initialization. | ||
| InitializeSPIRVTarget(); | ||
|
|
||
| SMDiagnostic Err; | ||
| LLVMContext C; | ||
| std::unique_ptr<Module> M = parseIRFile(File, Err, C); | ||
| if (!M) | ||
| return createStringError(inconvertibleErrorCode(), Err.getMessage()); | ||
|
|
||
| static const std::string DefaultTriple = "spirv64v1.6-unknown-unknown"; | ||
| Triple TargetTriple(M->getTargetTriple()); | ||
| if (TargetTriple.getTriple().empty()) | ||
asudarsa marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| TargetTriple.setTriple(DefaultTriple); | ||
| TargetTriple.setArch(TargetTriple.getArch(), Triple::SPIRVSubArch_v16); | ||
asudarsa marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| M->setTargetTriple(TargetTriple); | ||
| assert(TargetTriple.isSPIROrSPIRV() && "Target triple is not SPIR or SPIR-V"); | ||
|
|
||
| std::string Msg; | ||
| const Target *T = TargetRegistry::lookupTarget(M->getTargetTriple(), Msg); | ||
| if (!T) | ||
| return createStringError(Msg + ": " + M->getTargetTriple().str()); | ||
|
|
||
| TargetOptions Options; | ||
| std::optional<Reloc::Model> RM; | ||
| std::optional<CodeModel::Model> CM; | ||
| std::unique_ptr<TargetMachine> TM(T->createTargetMachine( | ||
| M->getTargetTriple().str(), "", "", Options, RM, CM)); | ||
asudarsa marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| if (!TM) | ||
| return createStringError("Could not allocate target machine!"); | ||
|
|
||
| if (M->getDataLayout().isDefault()) | ||
| M->setDataLayout(TM->createDataLayout()); | ||
|
|
||
| int FD = -1; | ||
| if (std::error_code EC = sys::fs::openFileForWrite(OutputFile, FD)) | ||
| return errorCodeToError(EC); | ||
| auto OS = std::make_unique<llvm::raw_fd_ostream>(FD, true); | ||
|
|
||
| legacy::PassManager CodeGenPasses; | ||
| TargetLibraryInfoImpl TLII(M->getTargetTriple()); | ||
| CodeGenPasses.add(new TargetLibraryInfoWrapperPass(TLII)); | ||
| if (TM->addPassesToEmitFile(CodeGenPasses, *OS, nullptr, | ||
| CodeGenFileType::ObjectFile)) | ||
| return createStringError("Failed to execute SPIR-V backend"); | ||
| CodeGenPasses.run(*M); | ||
| return OutputFile; | ||
| } | ||
|
|
||
| Error runSYCLLink(ArrayRef<std::string> Files, const ArgList &Args) { | ||
| llvm::TimeTraceScope TimeScope("SYCLDeviceLink"); | ||
| llvm::TimeTraceScope TimeScope("SYCL device linking"); | ||
| // First llvm-link step | ||
| auto LinkedFile = linkDeviceInputFiles(Files, Args); | ||
| if (!LinkedFile) | ||
|
|
@@ -434,8 +391,8 @@ Error runSYCLLink(ArrayRef<std::string> Files, const ArgList &Args) { | |
| if (!DeviceLinkedFile) | ||
| reportError(DeviceLinkedFile.takeError()); | ||
|
|
||
| // LLVM to SPIR-V translation step | ||
| auto SPVFile = runLLVMToSPIRVTranslation(*DeviceLinkedFile, Args); | ||
| // SPIR-V code generation step | ||
| auto SPVFile = runSPIRVCodeGen(*DeviceLinkedFile, Args); | ||
| if (!SPVFile) | ||
| return SPVFile.takeError(); | ||
| return Error::success(); | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.