Skip to content

Commit 8f8001a

Browse files
svenvhvmaksimo
authored andcommitted
Add --spirv-tools-dis option to disassemble using SPIRV-Tools
llvm-spirv's text rendering of a SPIR-V module uses an internal non-standard format that is not compatible with any other tools. Add support for emitting SPIR-V assembly using the more widely used SPIR-V Tools format. This is achieved by linking to SPIRV-Tools and invoking its disassembler. For now, this functionality is only available if the SPIRV-Tools package is found at build configuration time. The main motivation for this change is the proposed integration of llvm-spirv in Clang. Particularly, we would like Clang invocations such as `clang -S -target spirv` to produce the standard SPIR-V assembly format instead of llvm-spirv's internal format. Original commit: KhronosGroup/SPIRV-LLVM-Translator@beb88bf
1 parent e28680e commit 8f8001a

File tree

7 files changed

+129
-4
lines changed

7 files changed

+129
-4
lines changed

llvm-spirv/CMakeLists.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ endif(NOT DEFINED BASE_LLVM_VERSION)
66
set(LLVM_SPIRV_VERSION ${BASE_LLVM_VERSION}.0)
77

88
include(FetchContent)
9+
include(FindPkgConfig)
910

1011
option(LLVM_SPIRV_INCLUDE_TESTS
1112
"Generate build targets for the llvm-spirv lit tests."
@@ -103,6 +104,12 @@ endif()
103104

104105
set(LLVM_SPIRV_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/include)
105106

107+
pkg_search_module(SPIRV_TOOLS SPIRV-Tools)
108+
if(NOT SPIRV_TOOLS_FOUND)
109+
message(STATUS "SPIRV-Tools not found; project will be built without "
110+
"--spirv-tools-dis support.")
111+
endif(NOT SPIRV_TOOLS_FOUND)
112+
106113
add_subdirectory(lib/SPIRV)
107114
add_subdirectory(tools/llvm-spirv)
108115
if(LLVM_SPIRV_INCLUDE_TESTS)

llvm-spirv/test/CMakeLists.txt

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,10 @@
1-
include(FindPkgConfig)
2-
31
llvm_canonicalize_cmake_booleans(SPIRV_SKIP_CLANG_BUILD)
42
llvm_canonicalize_cmake_booleans(SPIRV_SKIP_DEBUG_INFO_TESTS)
53

64
# required by lit.site.cfg.py.in
75
get_target_property(LLVM_SPIRV_DIR llvm-spirv BINARY_DIR)
86
set(LLVM_SPIRV_TEST_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
97

10-
# find spirv-val
11-
pkg_search_module(SPIRV_TOOLS SPIRV-Tools)
128
if(SPIRV_TOOLS_FOUND)
139
find_program(SPIRV_TOOLS_SPIRV_AS NAMES spirv-as PATHS ${SPIRV_TOOLS_PREFIX}/bin)
1410
if(SPIRV_TOOLS_SPIRV_AS)

llvm-spirv/test/lit.cfg.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@
2121
# excludes: A list of directories and fles to exclude from the testsuite.
2222
config.excludes = ['CMakeLists.txt']
2323

24+
if config.spirv_tools_found:
25+
config.available_features.add('libspirv_dis')
26+
2427
if not config.spirv_skip_debug_info_tests:
2528
# Direct object generation.
2629
config.available_features.add('object-emission')

llvm-spirv/test/lit.site.cfg.py.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ config.target_triple = "@TARGET_TRIPLE@"
1515
config.host_arch = "@HOST_ARCH@"
1616
config.python_executable = "@PYTHON_EXECUTABLE@"
1717
config.test_run_dir = "@CMAKE_CURRENT_BINARY_DIR@"
18+
config.spirv_tools_found = @SPIRV_TOOLS_FOUND@
1819
config.spirv_tools_have_spirv_as = @SPIRV_TOOLS_SPIRV_AS_FOUND@
1920
config.spirv_tools_have_spirv_link = @SPIRV_TOOLS_SPIRV_LINK_FOUND@
2021
config.spirv_tools_have_spirv_val = @SPIRV_TOOLS_SPIRV_VAL_FOUND@

llvm-spirv/test/spirv-tools-dis.ll

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
; RUN: llvm-as %s -o %t.bc
2+
; RUN: llvm-spirv %t.bc --spirv-tools-dis -o - | FileCheck %s
3+
; RUN: llvm-spirv %t.bc --spirv-tools-dis -o - | spirv-as
4+
5+
; Verify that the --spirv-tools-dis options results in SPIRV-Tools compatible assembly.
6+
7+
; REQUIRES: libspirv_dis, spirv-as
8+
9+
; CHECK: %1 = OpExtInstImport "OpenCL.std"
10+
; CHECK: %uint = OpTypeInt 32 0
11+
12+
target datalayout = "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024"
13+
target triple = "spir-unknown-unknown"
14+
15+
; Function Attrs: nounwind
16+
define spir_kernel void @foo(i32 addrspace(1)* %a) !kernel_arg_addr_space !1 !kernel_arg_access_qual !2 !kernel_arg_type !3 !kernel_arg_base_type !4 !kernel_arg_type_qual !5 {
17+
entry:
18+
%a.addr = alloca i32 addrspace(1)*, align 4
19+
store i32 addrspace(1)* %a, i32 addrspace(1)** %a.addr, align 4
20+
%0 = load i32 addrspace(1)*, i32 addrspace(1)** %a.addr, align 4
21+
store i32 0, i32 addrspace(1)* %0, align 4
22+
ret void
23+
}
24+
25+
!opencl.enable.FP_CONTRACT = !{}
26+
!opencl.spir.version = !{!6}
27+
!opencl.ocl.version = !{!6}
28+
!opencl.used.extensions = !{!7}
29+
!opencl.used.optional.core.features = !{!7}
30+
!opencl.compiler.options = !{!7}
31+
32+
!1 = !{i32 1}
33+
!2 = !{!"none"}
34+
!3 = !{!"int*"}
35+
!4 = !{!"int*"}
36+
!5 = !{!""}
37+
!6 = !{i32 1, i32 2}
38+
!7 = !{}

llvm-spirv/tools/llvm-spirv/CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,9 @@ target_include_directories(llvm-spirv
2323
${LLVM_INCLUDE_DIRS}
2424
${LLVM_SPIRV_INCLUDE_DIRS}
2525
)
26+
27+
if(SPIRV_TOOLS_FOUND)
28+
target_compile_definitions(llvm-spirv PRIVATE LLVM_SPIRV_HAVE_SPIRV_TOOLS=1)
29+
target_include_directories(llvm-spirv PRIVATE ${SPIRV_TOOLS_INCLUDE_DIRS})
30+
target_link_libraries(llvm-spirv PRIVATE ${SPIRV_TOOLS_LDFLAGS})
31+
endif(SPIRV_TOOLS_FOUND)

llvm-spirv/tools/llvm-spirv/llvm-spirv.cpp

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,10 @@
5959
#include "llvm/Support/Signals.h"
6060
#include "llvm/Support/ToolOutputFile.h"
6161

62+
#ifdef LLVM_SPIRV_HAVE_SPIRV_TOOLS
63+
#include "spirv-tools/libspirv.hpp"
64+
#endif
65+
6266
#ifndef _SPIRV_SUPPORT_TEXT_FMT
6367
#define _SPIRV_SUPPORT_TEXT_FMT
6468
#endif
@@ -144,6 +148,10 @@ static cl::opt<bool>
144148
cl::desc("Preserve OpenCL kernel_arg_type and kernel_arg_type_qual "
145149
"metadata through OpString"));
146150

151+
static cl::opt<bool>
152+
SPIRVToolsDis("spirv-tools-dis", cl::init(false),
153+
cl::desc("Emit textual assembly using SPIRV-Tools"));
154+
147155
using SPIRV::ExtensionID;
148156

149157
#ifdef _SPIRV_SUPPORT_TEXT_FMT
@@ -227,6 +235,30 @@ static std::string removeExt(const std::string &FileName) {
227235

228236
static ExitOnError ExitOnErr;
229237

238+
#ifdef LLVM_SPIRV_HAVE_SPIRV_TOOLS
239+
/// Stream buffer that captures written data into a vector and allows reading
240+
/// the data back as an array of uint32_t's.
241+
class StreambufToArray : public std::streambuf {
242+
public:
243+
const uint32_t *data() const {
244+
return reinterpret_cast<const uint32_t *>(Buffer.data());
245+
}
246+
247+
size_t size() const { return Buffer.size() / sizeof(uint32_t); }
248+
249+
protected:
250+
std::streamsize xsputn(const char *s, std::streamsize count) override {
251+
for (std::streamsize I = 0; I < count; I++) {
252+
Buffer.push_back(s[I]);
253+
}
254+
return count;
255+
}
256+
257+
private:
258+
std::vector<char> Buffer;
259+
};
260+
#endif // LLVM_SPIRV_HAVE_SPIRV_TOOLS
261+
230262
static int convertLLVMToSPIRV(const SPIRV::TranslatorOpts &Opts) {
231263
LLVMContext Context;
232264

@@ -246,6 +278,48 @@ static int convertLLVMToSPIRV(const SPIRV::TranslatorOpts &Opts) {
246278
(SPIRV::SPIRVUseTextFormat ? kExt::SpirvText : kExt::SpirvBinary);
247279
}
248280

281+
if (SPIRVToolsDis) {
282+
#ifdef LLVM_SPIRV_HAVE_SPIRV_TOOLS
283+
auto DisMessagePrinter = [](spv_message_level_t Level, const char *source,
284+
const spv_position_t &position,
285+
const char *message) -> void {
286+
errs() << source << ": " << message << "\n";
287+
};
288+
spvtools::SpirvTools SpvTool(SPV_ENV_OPENCL_2_0);
289+
SpvTool.SetMessageConsumer(DisMessagePrinter);
290+
std::string DisOutput;
291+
292+
// Serialize the SPIR-V module to a uint32_t array and then invoke the
293+
// SPIR-V tools disassembler to obtain textual assembly.
294+
std::string Err;
295+
StreambufToArray OutStreamBuf;
296+
std::ostream OutStream(&OutStreamBuf);
297+
bool Success = writeSpirv(M.get(), Opts, OutStream, Err);
298+
if (!Success) {
299+
errs() << "Failed to translate SPIR-V: " << Err << '\n';
300+
return -1;
301+
}
302+
303+
if (!SpvTool.Disassemble(OutStreamBuf.data(), OutStreamBuf.size(),
304+
&DisOutput)) {
305+
errs() << "Failed to generate textual assembly\n";
306+
return -1;
307+
}
308+
309+
if (OutputFile != "-") {
310+
std::ofstream OutFile(OutputFile, std::ios::binary);
311+
OutFile << DisOutput;
312+
} else {
313+
std::cout << DisOutput;
314+
}
315+
316+
return 0;
317+
#else
318+
errs() << "llvm-spirv was built without --spirv-tools-dis support\n";
319+
return -1;
320+
#endif // LLVM_SPIRV_HAVE_SPIRV_TOOLS
321+
}
322+
249323
std::string Err;
250324
bool Success = false;
251325
if (OutputFile != "-") {

0 commit comments

Comments
 (0)