From f368e6424fbfb7fdea4b9d9a2e44f2f7e188c133 Mon Sep 17 00:00:00 2001 From: Natalie Chouinard Date: Mon, 4 Dec 2023 12:24:51 -0500 Subject: [SPIR-V] Add SPIRV-Tools for testing (#73044) Add spirv-dis (disassembler) and spirv-val (validator) from SPIRV-Tools as external dependencies for testing the SPIR-V backend. These tools are test dependencies only. SPIR-V backend tests now have a dependency on the spirv-dis and spirv-val targets when the `LLVM_INCLUDE_SPIRV_TOOLS_TESTS` cmake variable is set, which allows additional test files with the `REQUIRES: spirv-tools` constraint to run, along with additional `RUN: %if spirv-tools ...` lines in existing tests. All other SPIR-V backend tests will run normally when `LLVM_INCLUDE_SPIRV_TOOLS_TESTS` is not set. Several tests are included to show these tools' use, however more tests will be migrated and added later. * OpVariable_order.ll shows how spirv-val can catch bugs in the backend. * basic_int_types_spirvdis.ll shows how tests can be much shorter and more readable by FileChecking the spirv-dis output. * basic_int_types.ll shows how an additional RUN line can add validation to existing tests. RFC: https://discourse.llvm.org/t/rfc-add-a-test-dependency-on-spirv-tools/75135 --- llvm/test/CMakeLists.txt | 6 ++ llvm/test/CodeGen/SPIRV/OpVariable_order.ll | 17 ++++++ llvm/test/CodeGen/SPIRV/basic_int_types.ll | 1 + .../test/CodeGen/SPIRV/basic_int_types_spirvdis.ll | 45 +++++++++++++++ llvm/test/CodeGen/SPIRV/lit.local.cfg | 5 ++ llvm/test/lit.site.cfg.py.in | 1 + llvm/tools/spirv-tools/CMakeLists.txt | 65 ++++++++++++++++++++++ 7 files changed, 140 insertions(+) create mode 100644 llvm/test/CodeGen/SPIRV/OpVariable_order.ll create mode 100644 llvm/test/CodeGen/SPIRV/basic_int_types_spirvdis.ll create mode 100644 llvm/tools/spirv-tools/CMakeLists.txt diff --git a/llvm/test/CMakeLists.txt b/llvm/test/CMakeLists.txt index 8aa6522..6127b76 100644 --- a/llvm/test/CMakeLists.txt +++ b/llvm/test/CMakeLists.txt @@ -24,6 +24,7 @@ llvm_canonicalize_cmake_booleans( LLVM_ENABLE_REVERSE_ITERATION LLVM_INCLUDE_DXIL_TESTS LLVM_TOOL_LLVM_DRIVER_BUILD + LLVM_INCLUDE_SPIRV_TOOLS_TESTS ) configure_lit_site_cfg( @@ -222,6 +223,11 @@ if(LLVM_ENABLE_HTTPLIB) list(APPEND LLVM_TEST_DEPENDS llvm-debuginfod) endif() +if (LLVM_INCLUDE_SPIRV_TOOLS_TESTS) + list(APPEND LLVM_TEST_DEPENDS spirv-dis) + list(APPEND LLVM_TEST_DEPENDS spirv-val) +endif() + add_custom_target(llvm-test-depends DEPENDS ${LLVM_TEST_DEPENDS}) set_target_properties(llvm-test-depends PROPERTIES FOLDER "Tests") diff --git a/llvm/test/CodeGen/SPIRV/OpVariable_order.ll b/llvm/test/CodeGen/SPIRV/OpVariable_order.ll new file mode 100644 index 0000000..a4ca3aa --- /dev/null +++ b/llvm/test/CodeGen/SPIRV/OpVariable_order.ll @@ -0,0 +1,17 @@ +; REQUIRES: spirv-tools +; RUN: llc -O0 -mtriple=spirv-unknown-linux %s -o - -filetype=obj | not spirv-val 2>&1 | FileCheck %s + +; TODO(#66261): The SPIR-V backend should reorder OpVariable instructions so this doesn't fail, +; but in the meantime it's a good example of the spirv-val tool working as intended. + +; CHECK: All OpVariable instructions in a function must be the first instructions in the first block. + +define void @main() #1 { +entry: + %0 = alloca <2 x i32>, align 4 + %1 = getelementptr <2 x i32>, ptr %0, i32 0, i32 0 + %2 = alloca float, align 4 + ret void +} + +attributes #1 = { "hlsl.numthreads"="4,8,16" "hlsl.shader"="compute" } diff --git a/llvm/test/CodeGen/SPIRV/basic_int_types.ll b/llvm/test/CodeGen/SPIRV/basic_int_types.ll index b479cee..6bfc990 100644 --- a/llvm/test/CodeGen/SPIRV/basic_int_types.ll +++ b/llvm/test/CodeGen/SPIRV/basic_int_types.ll @@ -1,6 +1,7 @@ ; RUN: llc -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s ; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s ; RUN: llc -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s +; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-unknown %s -o - -filetype=obj | spirv-val %} define void @main() { entry: diff --git a/llvm/test/CodeGen/SPIRV/basic_int_types_spirvdis.ll b/llvm/test/CodeGen/SPIRV/basic_int_types_spirvdis.ll new file mode 100644 index 0000000..3778d89 --- /dev/null +++ b/llvm/test/CodeGen/SPIRV/basic_int_types_spirvdis.ll @@ -0,0 +1,45 @@ +; REQUIRES: spirv-tools +; RUN: llc -O0 -mtriple=spirv-unknown-unknown %s -o - --filetype=obj | spirv-dis | FileCheck %s +; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - --filetype=obj | spirv-dis | FileCheck %s +; RUN: llc -O0 -mtriple=spirv64-unknown-unknown %s -o - --filetype=obj | spirv-dis | FileCheck %s + +define void @main() { +entry: +; CHECK: %int16_t_Val = OpVariable %_ptr_Function_ushort Function + %int16_t_Val = alloca i16, align 2 + +; CHECK: %int_Val = OpVariable %_ptr_Function_uint Function + %int_Val = alloca i32, align 4 + +; CHECK: %int64_t_Val = OpVariable %_ptr_Function_ulong Function + %int64_t_Val = alloca i64, align 8 + +; CHECK: %int16_t2_Val = OpVariable %_ptr_Function_v2ushort Function + %int16_t2_Val = alloca <2 x i16>, align 4 + +; CHECK: %int16_t3_Val = OpVariable %_ptr_Function_v3ushort Function + %int16_t3_Val = alloca <3 x i16>, align 8 + +; CHECK: %int16_t4_Val = OpVariable %_ptr_Function_v4ushort Function + %int16_t4_Val = alloca <4 x i16>, align 8 + +; CHECK: %int2_Val = OpVariable %_ptr_Function_v2uint Function + %int2_Val = alloca <2 x i32>, align 8 + +; CHECK: %int3_Val = OpVariable %_ptr_Function_v3uint Function + %int3_Val = alloca <3 x i32>, align 16 + +; CHECK: %int4_Val = OpVariable %_ptr_Function_v4uint Function + %int4_Val = alloca <4 x i32>, align 16 + +; CHECK: %int64_t2_Val = OpVariable %_ptr_Function_v2ulong Function + %int64_t2_Val = alloca <2 x i64>, align 16 + +; CHECK: %int64_t3_Val = OpVariable %_ptr_Function_v3ulong Function + %int64_t3_Val = alloca <3 x i64>, align 32 + +; CHECK: %int64_t4_Val = OpVariable %_ptr_Function_v4ulong Function + %int64_t4_Val = alloca <4 x i64>, align 32 + + ret void +} diff --git a/llvm/test/CodeGen/SPIRV/lit.local.cfg b/llvm/test/CodeGen/SPIRV/lit.local.cfg index 78dd74c..00f50fb 100644 --- a/llvm/test/CodeGen/SPIRV/lit.local.cfg +++ b/llvm/test/CodeGen/SPIRV/lit.local.cfg @@ -1,2 +1,7 @@ if not "SPIRV" in config.root.targets: config.unsupported = True + +if config.spirv_tools_tests: + config.available_features.add("spirv-tools") + config.substitutions.append(("spirv-dis", os.path.join(config.llvm_tools_dir, "spirv-dis"))) + config.substitutions.append(("spirv-val", os.path.join(config.llvm_tools_dir, "spirv-val"))) diff --git a/llvm/test/lit.site.cfg.py.in b/llvm/test/lit.site.cfg.py.in index 6f3ab65..1138b2c 100644 --- a/llvm/test/lit.site.cfg.py.in +++ b/llvm/test/lit.site.cfg.py.in @@ -60,6 +60,7 @@ config.expensive_checks = @LLVM_ENABLE_EXPENSIVE_CHECKS@ config.reverse_iteration = @LLVM_ENABLE_REVERSE_ITERATION@ config.dxil_tests = @LLVM_INCLUDE_DXIL_TESTS@ config.have_llvm_driver = @LLVM_TOOL_LLVM_DRIVER_BUILD@ +config.spirv_tools_tests = @LLVM_INCLUDE_SPIRV_TOOLS_TESTS@ import lit.llvm lit.llvm.initialize(lit_config, config) diff --git a/llvm/tools/spirv-tools/CMakeLists.txt b/llvm/tools/spirv-tools/CMakeLists.txt new file mode 100644 index 0000000..f73dcad --- /dev/null +++ b/llvm/tools/spirv-tools/CMakeLists.txt @@ -0,0 +1,65 @@ +option(LLVM_INCLUDE_SPIRV_TOOLS_TESTS "Include tests that use SPIRV-Tools" Off) +mark_as_advanced(LLVM_INCLUDE_SPIRV_TOOLS_TESTS) + +if (NOT LLVM_INCLUDE_SPIRV_TOOLS_TESTS) + return() +endif () + +if (NOT "SPIRV" IN_LIST LLVM_TARGETS_TO_BUILD) + message(FATAL_ERROR "Building SPIRV-Tools tests is unsupported without the SPIR-V target") +endif () + +# SPIRV_DIS and SPIRV_VAL variables can be used to provide paths to existing +# spirv-dis and spirv-val binaries, respectively. Otherwise, build them from +# SPIRV-Tools source. +if (NOT SPIRV_DIS OR NOT SPIRV_VAL) + include(ExternalProject) + + set(BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/SPIRVTools-bin) + + ExternalProject_Add(SPIRVTools + GIT_REPOSITORY https://github.com/KhronosGroup/SPIRV-Tools.git + GIT_TAG main + BINARY_DIR ${BINARY_DIR} + BUILD_COMMAND ${CMAKE_COMMAND} --build ${BINARY_DIR} --target spirv-dis spirv-val + BUILD_BYPRODUCTS ${BINARY_DIR}/tools/spirv-dis ${BINARY_DIR}/tools/spirv-val + DOWNLOAD_COMMAND git clone https://github.com/KhronosGroup/SPIRV-Tools.git SPIRVTools && + cd SPIRVTools && + ${Python3_EXECUTABLE} utils/git-sync-deps + UPDATE_COMMAND git pull origin main && + ${Python3_EXECUTABLE} utils/git-sync-deps + # Don't auto-update on every build. + UPDATE_DISCONNECTED 1 + # Allow manual updating with an explicit SPIRVTools-update target. + STEP_TARGETS update + # Install handled below. + INSTALL_COMMAND "" + ) +endif () + +if (CMAKE_HOST_UNIX) + set(LLVM_LINK_OR_COPY create_symlink) +else () + set(LLVM_LINK_OR_COPY copy) +endif () + +# Link the provided or just built spirv-dis and spirv-val binaries. +if (SPIRV_DIS) + add_custom_target(spirv-dis + COMMAND ${CMAKE_COMMAND} -E ${LLVM_LINK_OR_COPY} "${SPIRV_DIS}" "${LLVM_RUNTIME_OUTPUT_INTDIR}/spirv-dis") +else () + add_custom_target(spirv-dis + COMMAND ${CMAKE_COMMAND} -E ${LLVM_LINK_OR_COPY} "${BINARY_DIR}/tools/spirv-dis" "${LLVM_RUNTIME_OUTPUT_INTDIR}/spirv-dis" + DEPENDS SPIRVTools + ) +endif () + +if (SPIRV_VAL) + add_custom_target(spirv-val + COMMAND ${CMAKE_COMMAND} -E ${LLVM_LINK_OR_COPY} "${SPIRV_VAL}" "${LLVM_RUNTIME_OUTPUT_INTDIR}/spirv-val") +else () + add_custom_target(spirv-val + COMMAND ${CMAKE_COMMAND} -E ${LLVM_LINK_OR_COPY} "${BINARY_DIR}/tools/spirv-val" "${LLVM_RUNTIME_OUTPUT_INTDIR}/spirv-val" + DEPENDS SPIRVTools + ) +endif () -- cgit v1.1