Skip to content

Commit 0ab4031

Browse files
committed
[SYCL][SPIR-V Backend][clang-sycl-linker] Add SPIR-V backend support inside clang-sycl-linker
This PR does the following: 1. Use SPIR-V backend to do LLVM to SPIR-V translation inside clang-sycl-linker 2. Remove llvm-spirv translator from clang-sycl-linker Currently, no SPIR-V extensions are enabled for SYCL compilation flow. This will be updated in subsequent commits. Thanks Signed-off-by: Arvind Sudarsanam <[email protected]>
1 parent f14ff59 commit 0ab4031

File tree

5 files changed

+76
-138
lines changed

5 files changed

+76
-138
lines changed

clang/test/Driver/clang-sycl-linker-test.cpp

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,15 @@
66
// RUN: clang-sycl-linker --dry-run -v -triple=spirv64 %t_1.bc %t_2.bc -o a.spv 2>&1 \
77
// RUN: | FileCheck %s --check-prefix=SIMPLE-FO
88
// SIMPLE-FO: sycl-device-link: inputs: {{.*}}.bc, {{.*}}.bc libfiles: output: [[LLVMLINKOUT:.*]].bc
9-
// SIMPLE-FO-NEXT: "{{.*}}llvm-spirv{{.*}}" {{.*}}-o a.spv [[LLVMLINKOUT]].bc
9+
// SIMPLE-FO-NEXT: SPIR-V Backend: input: [[LLVMLINKOUT]].bc, output: a.spv
1010
//
1111
// Test the dry run of a simple case with device library files specified.
1212
// RUN: touch %T/lib1.bc
1313
// RUN: touch %T/lib2.bc
1414
// RUN: clang-sycl-linker --dry-run -v -triple=spirv64 %t_1.bc %t_2.bc --library-path=%T --device-libs=lib1.bc,lib2.bc -o a.spv 2>&1 \
1515
// RUN: | FileCheck %s --check-prefix=DEVLIBS
1616
// DEVLIBS: sycl-device-link: inputs: {{.*}}.bc libfiles: {{.*}}lib1.bc, {{.*}}lib2.bc output: [[LLVMLINKOUT:.*]].bc
17-
// DEVLIBS-NEXT: "{{.*}}llvm-spirv{{.*}}" {{.*}}-o a.spv [[LLVMLINKOUT]].bc
17+
// DEVLIBS-NEXT: SPIR-V Backend: input: [[LLVMLINKOUT]].bc, output: a.spv
1818
//
1919
// Test a simple case with a random file (not bitcode) as input.
2020
// RUN: touch %t.o
@@ -29,13 +29,3 @@
2929
// RUN: not clang-sycl-linker --dry-run -triple=spirv64 %t_1.bc %t_2.bc --library-path=%T --device-libs=lib1.bc,lib2.bc,lib3.bc -o a.spv 2>&1 \
3030
// RUN: | FileCheck %s --check-prefix=DEVLIBSERR2
3131
// DEVLIBSERR2: '{{.*}}lib3.bc' SYCL device library file is not found
32-
//
33-
// Test if correct set of llvm-spirv options are emitted for windows environment.
34-
// RUN: clang-sycl-linker --dry-run -v -triple=spirv64 --is-windows-msvc-env %t_1.bc %t_2.bc -o a.spv 2>&1 \
35-
// RUN: | FileCheck %s --check-prefix=LLVMOPTSWIN
36-
// LLVMOPTSWIN: -spirv-debug-info-version=ocl-100 -spirv-allow-extra-diexpressions -spirv-allow-unknown-intrinsics=llvm.genx. -spirv-ext=
37-
//
38-
// Test if correct set of llvm-spirv options are emitted for linux environment.
39-
// RUN: clang-sycl-linker --dry-run -v -triple=spirv64 %t_1.bc %t_2.bc -o a.spv 2>&1 \
40-
// RUN: | FileCheck %s --check-prefix=LLVMOPTSLIN
41-
// LLVMOPTSLIN: -spirv-debug-info-version=nonsemantic-shader-200 -spirv-allow-unknown-intrinsics=llvm.genx. -spirv-ext=

clang/test/Driver/sycl-link-spirv-target.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
//
44
// Test that -Xlinker options are being passed to clang-sycl-linker.
55
// RUN: touch %t.bc
6-
// RUN: %clangxx -### --target=spirv64 --sycl-link -Xlinker --llvm-spirv-path=/tmp \
7-
// RUN: -Xlinker -triple=spirv64 -Xlinker --library-path=/tmp -Xlinker --device-libs=lib1.bc,lib2.bc %t.bc 2>&1 \
6+
// RUN: %clangxx -### --target=spirv64 --sycl-link -Xlinker -triple=spirv64 -Xlinker --library-path=/tmp \
7+
// RUN: -Xlinker --device-libs=lib1.bc,lib2.bc %t.bc 2>&1 \
88
// RUN: | FileCheck %s -check-prefix=XLINKEROPTS
9-
// XLINKEROPTS: "{{.*}}clang-sycl-linker{{.*}}" "--llvm-spirv-path=/tmp" "-triple=spirv64" "--library-path=/tmp" "--device-libs=lib1.bc,lib2.bc" "{{.*}}.bc" "-o" "a.out"
9+
// XLINKEROPTS: "{{.*}}clang-sycl-linker{{.*}}" "-triple=spirv64" "--library-path=/tmp" "--device-libs=lib1.bc,lib2.bc" "{{.*}}.bc" "-o" "a.out"

clang/tools/clang-sycl-linker/CMakeLists.txt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
set(LLVM_LINK_COMPONENTS
22
${LLVM_TARGETS_TO_BUILD}
3+
Analysis
34
BinaryFormat
45
BitWriter
56
Core
67
IRReader
78
Linker
9+
MC
810
Option
911
Object
10-
TargetParser
1112
Support
13+
Target
14+
TargetParser
1215
)
1316

1417
set(LLVM_TARGET_DEFINITIONS SYCLLinkOpts.td)

clang/tools/clang-sycl-linker/ClangSYCLLinker.cpp

Lines changed: 66 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
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"
@@ -48,6 +49,7 @@
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

5254
using namespace llvm;
5355
using namespace llvm::opt;
@@ -79,6 +81,7 @@ static const char *Executable;
7981
static SmallVector<SmallString<128>> TempFiles;
8082

8183
namespace {
84+
8285
// Must not overlap with llvm::opt::DriverFlag.
8386
enum LinkerFlags { LinkerOnlyOption = (1 << 4) };
8487

@@ -124,12 +127,6 @@ const OptTable &getOptTable() {
124127
exit(EXIT_FAILURE);
125128
}
126129

127-
std::string getMainExecutable(const char *Name) {
128-
void *Ptr = (void *)(intptr_t)&getMainExecutable;
129-
auto COWPath = sys::fs::getMainExecutable(Name, Ptr);
130-
return sys::path::parent_path(COWPath).str();
131-
}
132-
133130
Expected<StringRef> createTempFile(const ArgList &Args, const Twine &Prefix,
134131
StringRef Extension) {
135132
SmallString<128> OutputFile;
@@ -211,7 +208,7 @@ Expected<std::unique_ptr<Module>> getBitcodeModule(StringRef File,
211208

212209
auto M = getLazyIRFileModule(File, Err, C);
213210
if (M)
214-
return M;
211+
return std::move(M);
215212
return createStringError(Err.getMessage());
216213
}
217214

@@ -313,119 +310,62 @@ Expected<StringRef> linkDeviceCode(ArrayRef<std::string> InputFiles,
313310
return *BitcodeOutput;
314311
}
315312

316-
/// Add any llvm-spirv option that relies on a specific Triple in addition
317-
/// to user supplied options.
318-
static void getSPIRVTransOpts(const ArgList &Args,
319-
SmallVector<StringRef, 8> &TranslatorArgs,
320-
const llvm::Triple Triple) {
321-
// Enable NonSemanticShaderDebugInfo.200 for non-Windows
322-
const bool IsWindowsMSVC =
323-
Triple.isWindowsMSVCEnvironment() || Args.hasArg(OPT_is_windows_msvc_env);
324-
const bool EnableNonSemanticDebug = !IsWindowsMSVC;
325-
if (EnableNonSemanticDebug) {
326-
TranslatorArgs.push_back(
327-
"-spirv-debug-info-version=nonsemantic-shader-200");
328-
} else {
329-
TranslatorArgs.push_back("-spirv-debug-info-version=ocl-100");
330-
// Prevent crash in the translator if input IR contains DIExpression
331-
// operations which don't have mapping to OpenCL.DebugInfo.100 spec.
332-
TranslatorArgs.push_back("-spirv-allow-extra-diexpressions");
333-
}
334-
std::string UnknownIntrinsics("-spirv-allow-unknown-intrinsics=llvm.genx.");
335-
336-
TranslatorArgs.push_back(Args.MakeArgString(UnknownIntrinsics));
337-
338-
// Disable all the extensions by default
339-
std::string ExtArg("-spirv-ext=-all");
340-
std::string DefaultExtArg =
341-
",+SPV_EXT_shader_atomic_float_add,+SPV_EXT_shader_atomic_float_min_max"
342-
",+SPV_KHR_no_integer_wrap_decoration,+SPV_KHR_float_controls"
343-
",+SPV_KHR_expect_assume,+SPV_KHR_linkonce_odr";
344-
std::string INTELExtArg =
345-
",+SPV_INTEL_subgroups,+SPV_INTEL_media_block_io"
346-
",+SPV_INTEL_device_side_avc_motion_estimation"
347-
",+SPV_INTEL_fpga_loop_controls,+SPV_INTEL_unstructured_loop_controls"
348-
",+SPV_INTEL_fpga_reg,+SPV_INTEL_blocking_pipes"
349-
",+SPV_INTEL_function_pointers,+SPV_INTEL_kernel_attributes"
350-
",+SPV_INTEL_io_pipes,+SPV_INTEL_inline_assembly"
351-
",+SPV_INTEL_arbitrary_precision_integers"
352-
",+SPV_INTEL_float_controls2,+SPV_INTEL_vector_compute"
353-
",+SPV_INTEL_fast_composite"
354-
",+SPV_INTEL_arbitrary_precision_fixed_point"
355-
",+SPV_INTEL_arbitrary_precision_floating_point"
356-
",+SPV_INTEL_variable_length_array,+SPV_INTEL_fp_fast_math_mode"
357-
",+SPV_INTEL_long_composites"
358-
",+SPV_INTEL_arithmetic_fence"
359-
",+SPV_INTEL_global_variable_decorations"
360-
",+SPV_INTEL_cache_controls"
361-
",+SPV_INTEL_fpga_buffer_location"
362-
",+SPV_INTEL_fpga_argument_interfaces"
363-
",+SPV_INTEL_fpga_invocation_pipelining_attributes"
364-
",+SPV_INTEL_fpga_latency_control"
365-
",+SPV_INTEL_task_sequence"
366-
",+SPV_KHR_shader_clock"
367-
",+SPV_INTEL_bindless_images";
368-
ExtArg = ExtArg + DefaultExtArg + INTELExtArg;
369-
ExtArg += ",+SPV_INTEL_token_type"
370-
",+SPV_INTEL_bfloat16_conversion"
371-
",+SPV_INTEL_joint_matrix"
372-
",+SPV_INTEL_hw_thread_queries"
373-
",+SPV_KHR_uniform_group_instructions"
374-
",+SPV_INTEL_masked_gather_scatter"
375-
",+SPV_INTEL_tensor_float32_conversion"
376-
",+SPV_INTEL_optnone"
377-
",+SPV_KHR_non_semantic_info"
378-
",+SPV_KHR_cooperative_matrix";
379-
TranslatorArgs.push_back(Args.MakeArgString(ExtArg));
380-
}
381-
382313
/// Run LLVM to SPIR-V translation.
383-
/// Converts 'File' from LLVM bitcode to SPIR-V format using llvm-spirv tool.
314+
/// Converts 'File' from LLVM bitcode to SPIR-V format using SPIR-V backend.
384315
/// 'Args' encompasses all arguments required for linking device code and will
385-
/// be parsed to generate options required to be passed into llvm-spirv tool.
386-
static Expected<StringRef> runLLVMToSPIRVTranslation(StringRef File,
387-
const ArgList &Args) {
388-
llvm::TimeTraceScope TimeScope("LLVMToSPIRVTranslation");
389-
StringRef LLVMSPIRVPath = Args.getLastArgValue(OPT_llvm_spirv_path_EQ);
390-
Expected<std::string> LLVMToSPIRVProg =
391-
findProgram(Args, "llvm-spirv", {LLVMSPIRVPath});
392-
if (!LLVMToSPIRVProg)
393-
return LLVMToSPIRVProg.takeError();
394-
395-
SmallVector<StringRef, 8> CmdArgs;
396-
CmdArgs.push_back(*LLVMToSPIRVProg);
397-
const llvm::Triple Triple(Args.getLastArgValue(OPT_triple_EQ));
398-
getSPIRVTransOpts(Args, CmdArgs, Triple);
399-
StringRef LLVMToSPIRVOptions;
400-
if (Arg *A = Args.getLastArg(OPT_llvm_spirv_options_EQ))
401-
LLVMToSPIRVOptions = A->getValue();
402-
LLVMToSPIRVOptions.split(CmdArgs, " ", /* MaxSplit = */ -1,
403-
/* KeepEmpty = */ false);
404-
CmdArgs.append({"-o", OutputFile});
405-
CmdArgs.push_back(File);
406-
if (Error Err = executeCommands(*LLVMToSPIRVProg, CmdArgs))
407-
return std::move(Err);
408-
409-
if (!SPIRVDumpDir.empty()) {
410-
std::error_code EC =
411-
llvm::sys::fs::create_directory(SPIRVDumpDir, /*IgnoreExisting*/ true);
412-
if (EC)
413-
return createStringError(
414-
EC,
415-
formatv("failed to create dump directory. path: {0}, error_code: {1}",
416-
SPIRVDumpDir, EC.value()));
417-
418-
StringRef Path = OutputFile;
419-
StringRef Filename = llvm::sys::path::filename(Path);
420-
SmallString<128> CopyPath = SPIRVDumpDir;
421-
CopyPath.append(Filename);
422-
EC = llvm::sys::fs::copy_file(Path, CopyPath);
423-
if (EC)
424-
return createStringError(
425-
EC,
426-
formatv(
427-
"failed to copy file. original: {0}, copy: {1}, error_code: {2}",
428-
Path, CopyPath, EC.value()));
316+
/// be parsed to generate options required to be passed into the backend.
317+
static Expected<StringRef> runSPIRVCodeGen(StringRef File,
318+
const ArgList &Args) {
319+
llvm::TimeTraceScope TimeScope("SPIR-V code generation");
320+
321+
// Parse input module.
322+
SMDiagnostic Err;
323+
LLVMContext C;
324+
std::unique_ptr<Module> M = parseIRFile(File, Err, C);
325+
if (!M)
326+
return createStringError(inconvertibleErrorCode(), Err.getMessage());
327+
328+
Triple TargetTriple(Args.getLastArgValue(OPT_triple_EQ));
329+
M->setTargetTriple(TargetTriple);
330+
331+
// Get a handle to SPIR-V target backend.
332+
std::string Msg;
333+
const Target *T = TargetRegistry::lookupTarget(M->getTargetTriple(), Msg);
334+
if (!T)
335+
return createStringError(Msg + ": " + M->getTargetTriple().str());
336+
337+
// Allocate SPIR-V target machine.
338+
TargetOptions Options;
339+
std::optional<Reloc::Model> RM;
340+
std::optional<CodeModel::Model> CM;
341+
std::unique_ptr<TargetMachine> TM(
342+
T->createTargetMachine(M->getTargetTriple(), /* CPU */ "",
343+
/* Features */ "", Options, RM, CM));
344+
if (!TM)
345+
return createStringError("Could not allocate target machine!");
346+
347+
// Set data layout if needed.
348+
if (M->getDataLayout().isDefault())
349+
M->setDataLayout(TM->createDataLayout());
350+
351+
// Open output file for writing.
352+
int FD = -1;
353+
if (std::error_code EC = sys::fs::openFileForWrite(OutputFile, FD))
354+
return errorCodeToError(EC);
355+
auto OS = std::make_unique<llvm::raw_fd_ostream>(FD, true);
356+
357+
// Run SPIR-V codegen passes to generate SPIR-V file.
358+
legacy::PassManager CodeGenPasses;
359+
TargetLibraryInfoImpl TLII(M->getTargetTriple());
360+
CodeGenPasses.add(new TargetLibraryInfoWrapperPass(TLII));
361+
if (TM->addPassesToEmitFile(CodeGenPasses, *OS, nullptr,
362+
CodeGenFileType::ObjectFile))
363+
return createStringError("Failed to execute SPIR-V Backend");
364+
CodeGenPasses.run(*M);
365+
366+
if (Verbose) {
367+
errs() << formatv("SPIR-V Backend: input: {0}, output: {1}\n", File,
368+
OutputFile);
429369
}
430370

431371
return OutputFile;
@@ -435,15 +375,15 @@ static Expected<StringRef> runLLVMToSPIRVTranslation(StringRef File,
435375
/// 1. Link input device code (user code and SYCL device library code).
436376
/// 2. Run SPIR-V code generation.
437377
Error runSYCLLink(ArrayRef<std::string> Files, const ArgList &Args) {
438-
llvm::TimeTraceScope TimeScope("SYCLDeviceLink");
378+
llvm::TimeTraceScope TimeScope("SYCL device linking");
439379

440380
// Link all input bitcode files and SYCL device library files, if any.
441381
auto LinkedFile = linkDeviceCode(Files, Args);
442382
if (!LinkedFile)
443383
reportError(LinkedFile.takeError());
444384

445-
// LLVM to SPIR-V translation step
446-
auto SPVFile = runLLVMToSPIRVTranslation(*LinkedFile, Args);
385+
// SPIR-V code generation step.
386+
auto SPVFile = runSPIRVCodeGen(*LinkedFile, Args);
447387
if (!SPVFile)
448388
return SPVFile.takeError();
449389
return Error::success();
@@ -453,6 +393,11 @@ Error runSYCLLink(ArrayRef<std::string> Files, const ArgList &Args) {
453393

454394
int main(int argc, char **argv) {
455395
InitLLVM X(argc, argv);
396+
InitializeAllTargetInfos();
397+
InitializeAllTargets();
398+
InitializeAllTargetMCs();
399+
InitializeAllAsmParsers();
400+
InitializeAllAsmPrinters();
456401

457402
Executable = argv[0];
458403
sys::PrintStackTraceOnErrorSignal(argv[0]);

clang/tools/clang-sycl-linker/SYCLLinkOpts.td

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ def device_libs_EQ : CommaJoined<["--", "-"], "device-libs=">,
2727
def arch_EQ : Joined<["--", "-"], "arch=">,
2828
Flags<[LinkerOnlyOption]>,
2929
MetaVarName<"<arch>">,
30-
HelpText<"The device subarchitecture">;
30+
HelpText<"The device architecture">;
3131
def triple_EQ : Joined<["--", "-"], "triple=">,
3232
Flags<[LinkerOnlyOption]>,
3333
MetaVarName<"<triple>">,

0 commit comments

Comments
 (0)