mirror of
https://github.com/bkaradzic/bgfx.git
synced 2026-02-19 13:32:59 +01:00
Removed spirv-tools tests.
This commit is contained in:
192
3rdparty/spirv-tools/test/CMakeLists.txt
vendored
192
3rdparty/spirv-tools/test/CMakeLists.txt
vendored
@@ -1,192 +0,0 @@
|
||||
# Copyright (c) 2015-2016 The Khronos Group Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# Add a SPIR-V Tools unit test. Signature:
|
||||
# add_spvtools_unittest(
|
||||
# TARGET target_name
|
||||
# SRCS src_file.h src_file.cpp
|
||||
# LIBS lib1 lib2
|
||||
# )
|
||||
|
||||
if (NOT "${SPIRV_SKIP_TESTS}")
|
||||
if (TARGET gmock_main)
|
||||
message(STATUS "Found Google Mock, building tests.")
|
||||
else()
|
||||
message(STATUS "Did not find googletest, tests will not be built. "
|
||||
"To enable tests place googletest in '<spirv-dir>/external/googletest'.")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
function(add_spvtools_unittest)
|
||||
if (NOT "${SPIRV_SKIP_TESTS}" AND TARGET gmock_main)
|
||||
set(one_value_args TARGET PCH_FILE)
|
||||
set(multi_value_args SRCS LIBS ENVIRONMENT)
|
||||
cmake_parse_arguments(
|
||||
ARG "" "${one_value_args}" "${multi_value_args}" ${ARGN})
|
||||
set(target test_${ARG_TARGET})
|
||||
set(SRC_COPY ${ARG_SRCS})
|
||||
if (DEFINED ARG_PCH_FILE)
|
||||
spvtools_pch(SRC_COPY ${ARG_PCH_FILE})
|
||||
endif()
|
||||
add_executable(${target} ${SRC_COPY})
|
||||
spvtools_default_compile_options(${target})
|
||||
if(${COMPILER_IS_LIKE_GNU})
|
||||
target_compile_options(${target} PRIVATE -Wno-undef)
|
||||
# Effcee and RE2 headers exhibit shadowing.
|
||||
target_compile_options(${target} PRIVATE -Wno-shadow)
|
||||
endif()
|
||||
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
||||
# Disable C4503 "decorated name length exceeded" warning,
|
||||
# triggered by some heavily templated types.
|
||||
# We don't care much about that in test code.
|
||||
# Important to do since we have warnings-as-errors.
|
||||
target_compile_options(${target} PRIVATE /wd4503)
|
||||
# Googletest accidentally turns off support for ::testing::Combine
|
||||
# in VS 2017. See https://github.com/google/googletest/issues/1352
|
||||
# Forcibly turn it on again.
|
||||
target_compile_options(${target} PRIVATE /DGTEST_HAS_COMBINE=1)
|
||||
endif()
|
||||
target_include_directories(${target} PRIVATE
|
||||
${SPIRV_HEADER_INCLUDE_DIR}
|
||||
${spirv-tools_SOURCE_DIR}
|
||||
${spirv-tools_SOURCE_DIR}/include
|
||||
${spirv-tools_SOURCE_DIR}/test
|
||||
${spirv-tools_BINARY_DIR}
|
||||
${gtest_SOURCE_DIR}/include
|
||||
${gmock_SOURCE_DIR}/include
|
||||
)
|
||||
if (TARGET effcee)
|
||||
# If using Effcee for testing, then add its include directory.
|
||||
target_include_directories(${target} PRIVATE ${effcee_SOURCE_DIR})
|
||||
endif()
|
||||
target_link_libraries(${target} PRIVATE ${ARG_LIBS})
|
||||
if (TARGET effcee)
|
||||
target_link_libraries(${target} PRIVATE effcee)
|
||||
endif()
|
||||
target_link_libraries(${target} PRIVATE gmock_main)
|
||||
add_test(NAME spirv-tools-${target} COMMAND ${target})
|
||||
if (DEFINED ARG_ENVIRONMENT)
|
||||
set_tests_properties(spirv-tools-${target} PROPERTIES ENVIRONMENT ${ARG_ENVIRONMENT})
|
||||
endif()
|
||||
set_property(TARGET ${target} PROPERTY FOLDER "SPIRV-Tools tests")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
set(TEST_SOURCES
|
||||
test_fixture.h
|
||||
unit_spirv.h
|
||||
|
||||
assembly_context_test.cpp
|
||||
assembly_format_test.cpp
|
||||
binary_destroy_test.cpp
|
||||
binary_endianness_test.cpp
|
||||
binary_header_get_test.cpp
|
||||
binary_parse_test.cpp
|
||||
binary_strnlen_s_test.cpp
|
||||
binary_to_text_test.cpp
|
||||
binary_to_text.literal_test.cpp
|
||||
comment_test.cpp
|
||||
diagnostic_test.cpp
|
||||
enum_string_mapping_test.cpp
|
||||
enum_set_test.cpp
|
||||
ext_inst.debuginfo_test.cpp
|
||||
ext_inst.glsl_test.cpp
|
||||
ext_inst.opencl_test.cpp
|
||||
fix_word_test.cpp
|
||||
generator_magic_number_test.cpp
|
||||
hex_float_test.cpp
|
||||
immediate_int_test.cpp
|
||||
libspirv_macros_test.cpp
|
||||
log_test.cpp
|
||||
named_id_test.cpp
|
||||
name_mapper_test.cpp
|
||||
opcode_make_test.cpp
|
||||
opcode_require_capabilities_test.cpp
|
||||
opcode_split_test.cpp
|
||||
opcode_table_get_test.cpp
|
||||
operand_capabilities_test.cpp
|
||||
operand_test.cpp
|
||||
operand_pattern_test.cpp
|
||||
parse_number_test.cpp
|
||||
preserve_numeric_ids_test.cpp
|
||||
software_version_test.cpp
|
||||
string_utils_test.cpp
|
||||
target_env_test.cpp
|
||||
text_advance_test.cpp
|
||||
text_destroy_test.cpp
|
||||
text_literal_test.cpp
|
||||
text_start_new_inst_test.cpp
|
||||
text_to_binary.annotation_test.cpp
|
||||
text_to_binary.barrier_test.cpp
|
||||
text_to_binary.composite_test.cpp
|
||||
text_to_binary.constant_test.cpp
|
||||
text_to_binary.control_flow_test.cpp
|
||||
text_to_binary_test.cpp
|
||||
text_to_binary.debug_test.cpp
|
||||
text_to_binary.device_side_enqueue_test.cpp
|
||||
text_to_binary.extension_test.cpp
|
||||
text_to_binary.function_test.cpp
|
||||
text_to_binary.group_test.cpp
|
||||
text_to_binary.image_test.cpp
|
||||
text_to_binary.literal_test.cpp
|
||||
text_to_binary.memory_test.cpp
|
||||
text_to_binary.misc_test.cpp
|
||||
text_to_binary.mode_setting_test.cpp
|
||||
text_to_binary.pipe_storage_test.cpp
|
||||
text_to_binary.type_declaration_test.cpp
|
||||
text_to_binary.subgroup_dispatch_test.cpp
|
||||
text_to_binary.reserved_sampling_test.cpp
|
||||
text_word_get_test.cpp
|
||||
|
||||
unit_spirv.cpp
|
||||
)
|
||||
|
||||
spvtools_pch(TEST_SOURCES pch_test)
|
||||
|
||||
add_spvtools_unittest(
|
||||
TARGET spirv_unit_tests
|
||||
SRCS ${TEST_SOURCES}
|
||||
LIBS ${SPIRV_TOOLS})
|
||||
|
||||
add_spvtools_unittest(
|
||||
TARGET c_interface
|
||||
SRCS c_interface_test.cpp
|
||||
LIBS ${SPIRV_TOOLS})
|
||||
|
||||
add_spvtools_unittest(
|
||||
TARGET c_interface_shared
|
||||
SRCS c_interface_test.cpp
|
||||
LIBS ${SPIRV_TOOLS}-shared
|
||||
ENVIRONMENT PATH=$<TARGET_FILE_DIR:${SPIRV_TOOLS}-shared>)
|
||||
|
||||
add_spvtools_unittest(
|
||||
TARGET cpp_interface
|
||||
SRCS cpp_interface_test.cpp
|
||||
LIBS SPIRV-Tools-opt)
|
||||
|
||||
if (${SPIRV_TIMER_ENABLED})
|
||||
add_spvtools_unittest(
|
||||
TARGET timer
|
||||
SRCS timer_test.cpp
|
||||
LIBS ${SPIRV_TOOLS})
|
||||
endif()
|
||||
|
||||
|
||||
add_subdirectory(link)
|
||||
add_subdirectory(opt)
|
||||
add_subdirectory(reduce)
|
||||
add_subdirectory(fuzz)
|
||||
add_subdirectory(tools)
|
||||
add_subdirectory(util)
|
||||
add_subdirectory(val)
|
||||
@@ -1,77 +0,0 @@
|
||||
// Copyright (c) 2015-2016 The Khronos Group Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "source/instruction.h"
|
||||
#include "source/util/string_utils.h"
|
||||
#include "test/unit_spirv.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace {
|
||||
|
||||
using spvtest::AutoText;
|
||||
using spvtest::Concatenate;
|
||||
using ::testing::Eq;
|
||||
|
||||
struct EncodeStringCase {
|
||||
std::string str;
|
||||
std::vector<uint32_t> initial_contents;
|
||||
};
|
||||
|
||||
using EncodeStringTest = ::testing::TestWithParam<EncodeStringCase>;
|
||||
|
||||
TEST_P(EncodeStringTest, Sample) {
|
||||
AssemblyContext context(AutoText(""), nullptr);
|
||||
spv_instruction_t inst;
|
||||
inst.words = GetParam().initial_contents;
|
||||
ASSERT_EQ(SPV_SUCCESS,
|
||||
context.binaryEncodeString(GetParam().str.c_str(), &inst));
|
||||
// We already trust MakeVector
|
||||
EXPECT_THAT(inst.words, Eq(Concatenate({GetParam().initial_contents,
|
||||
utils::MakeVector(GetParam().str)})));
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
BinaryEncodeString, EncodeStringTest,
|
||||
::testing::ValuesIn(std::vector<EncodeStringCase>{
|
||||
// Use cases that exercise at least one to two words,
|
||||
// and both empty and non-empty initial contents.
|
||||
{"", {}},
|
||||
{"", {1,2,3}},
|
||||
{"a", {}},
|
||||
{"a", {4}},
|
||||
{"ab", {4}},
|
||||
{"abc", {}},
|
||||
{"abc", {18}},
|
||||
{"abcd", {}},
|
||||
{"abcd", {22}},
|
||||
{"abcde", {4}},
|
||||
{"abcdef", {}},
|
||||
{"abcdef", {99,42}},
|
||||
{"abcdefg", {}},
|
||||
{"abcdefg", {101}},
|
||||
{"abcdefgh", {}},
|
||||
{"abcdefgh", {102, 103, 104}},
|
||||
// A very long string, encoded after an initial word.
|
||||
// SPIR-V limits strings to 65535 characters.
|
||||
{std::string(65535, 'a'), {1}},
|
||||
}));
|
||||
// clang-format on
|
||||
|
||||
} // namespace
|
||||
} // namespace spvtools
|
||||
@@ -1,50 +0,0 @@
|
||||
// Copyright (c) 2015-2016 The Khronos Group Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "test/test_fixture.h"
|
||||
|
||||
namespace svptools {
|
||||
namespace {
|
||||
|
||||
using spvtest::ScopedContext;
|
||||
using spvtest::TextToBinaryTest;
|
||||
|
||||
TEST_F(TextToBinaryTest, InstOpcodeProducesResultIDButNoIDDefinedFails) {
|
||||
SetText("OpTypeMatrix %1 %2 1000");
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_TEXT,
|
||||
spvTextToBinary(ScopedContext().context, text.str, text.length,
|
||||
&binary, &diagnostic));
|
||||
ASSERT_NE(nullptr, diagnostic);
|
||||
EXPECT_STREQ(
|
||||
"Expected <result-id> at the beginning of an instruction, found "
|
||||
"'OpTypeMatrix'.",
|
||||
diagnostic->error);
|
||||
EXPECT_EQ(0u, diagnostic->position.line);
|
||||
}
|
||||
|
||||
TEST_F(TextToBinaryTest,
|
||||
InstDefinesResultIDButOpcodeDoesNotProduceAResultFails) {
|
||||
SetText("\n\n%foo = OpName %1 \"bar\"");
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_TEXT,
|
||||
spvTextToBinary(ScopedContext().context, text.str, text.length,
|
||||
&binary, &diagnostic));
|
||||
ASSERT_NE(nullptr, diagnostic);
|
||||
EXPECT_STREQ(
|
||||
"Cannot set ID %foo because OpName does not produce a result ID.",
|
||||
diagnostic->error);
|
||||
EXPECT_EQ(2u, diagnostic->position.line);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace svptools
|
||||
@@ -1,44 +0,0 @@
|
||||
// Copyright (c) 2015-2016 The Khronos Group Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "test/unit_spirv.h"
|
||||
|
||||
#include "test/test_fixture.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace {
|
||||
|
||||
using spvtest::ScopedContext;
|
||||
|
||||
TEST(BinaryDestroy, Null) {
|
||||
// There is no state or return value to check. Just check
|
||||
// for the ability to call the API without abnormal termination.
|
||||
spvBinaryDestroy(nullptr);
|
||||
}
|
||||
|
||||
using BinaryDestroySomething = spvtest::TextToBinaryTest;
|
||||
|
||||
// Checks safety of destroying a validly constructed binary.
|
||||
TEST_F(BinaryDestroySomething, Default) {
|
||||
// Use a binary object constructed by the API instead of rolling our own.
|
||||
SetText("OpSource OpenCL_C 120");
|
||||
spv_binary my_binary = nullptr;
|
||||
ASSERT_EQ(SPV_SUCCESS, spvTextToBinary(ScopedContext().context, text.str,
|
||||
text.length, &my_binary, &diagnostic));
|
||||
ASSERT_NE(nullptr, my_binary);
|
||||
spvBinaryDestroy(my_binary);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace spvtools
|
||||
@@ -1,54 +0,0 @@
|
||||
// Copyright (c) 2015-2016 The Khronos Group Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "test/unit_spirv.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace {
|
||||
|
||||
TEST(BinaryEndianness, InvalidCode) {
|
||||
uint32_t invalidMagicNumber[] = {0};
|
||||
spv_const_binary_t binary = {invalidMagicNumber, 1};
|
||||
spv_endianness_t endian;
|
||||
ASSERT_EQ(SPV_ERROR_INVALID_BINARY, spvBinaryEndianness(&binary, &endian));
|
||||
}
|
||||
|
||||
TEST(BinaryEndianness, Little) {
|
||||
uint32_t magicNumber;
|
||||
if (I32_ENDIAN_HOST == I32_ENDIAN_LITTLE) {
|
||||
magicNumber = 0x07230203;
|
||||
} else {
|
||||
magicNumber = 0x03022307;
|
||||
}
|
||||
spv_const_binary_t binary = {&magicNumber, 1};
|
||||
spv_endianness_t endian;
|
||||
ASSERT_EQ(SPV_SUCCESS, spvBinaryEndianness(&binary, &endian));
|
||||
ASSERT_EQ(SPV_ENDIANNESS_LITTLE, endian);
|
||||
}
|
||||
|
||||
TEST(BinaryEndianness, Big) {
|
||||
uint32_t magicNumber;
|
||||
if (I32_ENDIAN_HOST == I32_ENDIAN_BIG) {
|
||||
magicNumber = 0x07230203;
|
||||
} else {
|
||||
magicNumber = 0x03022307;
|
||||
}
|
||||
spv_const_binary_t binary = {&magicNumber, 1};
|
||||
spv_endianness_t endian;
|
||||
ASSERT_EQ(SPV_SUCCESS, spvBinaryEndianness(&binary, &endian));
|
||||
ASSERT_EQ(SPV_ENDIANNESS_BIG, endian);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace spvtools
|
||||
@@ -1,85 +0,0 @@
|
||||
// Copyright (c) 2015-2016 The Khronos Group Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "source/spirv_constant.h"
|
||||
#include "test/unit_spirv.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace {
|
||||
|
||||
class BinaryHeaderGet : public ::testing::Test {
|
||||
public:
|
||||
BinaryHeaderGet() { memset(code, 0, sizeof(code)); }
|
||||
|
||||
virtual void SetUp() {
|
||||
code[0] = SpvMagicNumber;
|
||||
code[1] = SpvVersion;
|
||||
code[2] = SPV_GENERATOR_CODEPLAY;
|
||||
code[3] = 1; // NOTE: Bound
|
||||
code[4] = 0; // NOTE: Schema; reserved
|
||||
code[5] = 0; // NOTE: Instructions
|
||||
|
||||
binary.code = code;
|
||||
binary.wordCount = 6;
|
||||
}
|
||||
spv_const_binary_t get_const_binary() {
|
||||
return spv_const_binary_t{binary.code, binary.wordCount};
|
||||
}
|
||||
virtual void TearDown() {}
|
||||
|
||||
uint32_t code[6];
|
||||
spv_binary_t binary;
|
||||
};
|
||||
|
||||
TEST_F(BinaryHeaderGet, Default) {
|
||||
spv_endianness_t endian;
|
||||
spv_const_binary_t const_bin = get_const_binary();
|
||||
ASSERT_EQ(SPV_SUCCESS, spvBinaryEndianness(&const_bin, &endian));
|
||||
|
||||
spv_header_t header;
|
||||
ASSERT_EQ(SPV_SUCCESS, spvBinaryHeaderGet(&const_bin, endian, &header));
|
||||
|
||||
ASSERT_EQ(static_cast<uint32_t>(SpvMagicNumber), header.magic);
|
||||
// Expect SPIRV-Headers updated to SPIR-V 1.5.
|
||||
ASSERT_EQ(0x00010500u, header.version);
|
||||
ASSERT_EQ(static_cast<uint32_t>(SPV_GENERATOR_CODEPLAY), header.generator);
|
||||
ASSERT_EQ(1u, header.bound);
|
||||
ASSERT_EQ(0u, header.schema);
|
||||
ASSERT_EQ(&code[5], header.instructions);
|
||||
}
|
||||
|
||||
TEST_F(BinaryHeaderGet, InvalidCode) {
|
||||
spv_const_binary_t my_binary = {nullptr, 0};
|
||||
spv_header_t header;
|
||||
ASSERT_EQ(SPV_ERROR_INVALID_BINARY,
|
||||
spvBinaryHeaderGet(&my_binary, SPV_ENDIANNESS_LITTLE, &header));
|
||||
}
|
||||
|
||||
TEST_F(BinaryHeaderGet, InvalidPointerHeader) {
|
||||
spv_const_binary_t const_bin = get_const_binary();
|
||||
ASSERT_EQ(SPV_ERROR_INVALID_POINTER,
|
||||
spvBinaryHeaderGet(&const_bin, SPV_ENDIANNESS_LITTLE, nullptr));
|
||||
}
|
||||
|
||||
TEST_F(BinaryHeaderGet, TruncatedHeader) {
|
||||
for (uint8_t i = 1; i < SPV_INDEX_INSTRUCTION; i++) {
|
||||
binary.wordCount = i;
|
||||
spv_const_binary_t const_bin = get_const_binary();
|
||||
ASSERT_EQ(SPV_ERROR_INVALID_BINARY,
|
||||
spvBinaryHeaderGet(&const_bin, SPV_ENDIANNESS_LITTLE, nullptr));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace spvtools
|
||||
893
3rdparty/spirv-tools/test/binary_parse_test.cpp
vendored
893
3rdparty/spirv-tools/test/binary_parse_test.cpp
vendored
@@ -1,893 +0,0 @@
|
||||
// Copyright (c) 2015-2016 The Khronos Group Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "source/latest_version_opencl_std_header.h"
|
||||
#include "source/table.h"
|
||||
#include "source/util/string_utils.h"
|
||||
#include "test/test_fixture.h"
|
||||
#include "test/unit_spirv.h"
|
||||
|
||||
// Returns true if two spv_parsed_operand_t values are equal.
|
||||
// To use this operator, this definition must appear in the same namespace
|
||||
// as spv_parsed_operand_t.
|
||||
static bool operator==(const spv_parsed_operand_t& a,
|
||||
const spv_parsed_operand_t& b) {
|
||||
return a.offset == b.offset && a.num_words == b.num_words &&
|
||||
a.type == b.type && a.number_kind == b.number_kind &&
|
||||
a.number_bit_width == b.number_bit_width;
|
||||
}
|
||||
|
||||
namespace spvtools {
|
||||
namespace {
|
||||
|
||||
using ::spvtest::Concatenate;
|
||||
using ::spvtest::MakeInstruction;
|
||||
using utils::MakeVector;
|
||||
using ::spvtest::ScopedContext;
|
||||
using ::testing::_;
|
||||
using ::testing::AnyOf;
|
||||
using ::testing::Eq;
|
||||
using ::testing::InSequence;
|
||||
using ::testing::Return;
|
||||
|
||||
// An easily-constructible and comparable object for the contents of an
|
||||
// spv_parsed_instruction_t. Unlike spv_parsed_instruction_t, owns the memory
|
||||
// of its components.
|
||||
struct ParsedInstruction {
|
||||
explicit ParsedInstruction(const spv_parsed_instruction_t& inst)
|
||||
: words(inst.words, inst.words + inst.num_words),
|
||||
opcode(static_cast<SpvOp>(inst.opcode)),
|
||||
ext_inst_type(inst.ext_inst_type),
|
||||
type_id(inst.type_id),
|
||||
result_id(inst.result_id),
|
||||
operands(inst.operands, inst.operands + inst.num_operands) {}
|
||||
|
||||
std::vector<uint32_t> words;
|
||||
SpvOp opcode;
|
||||
spv_ext_inst_type_t ext_inst_type;
|
||||
uint32_t type_id;
|
||||
uint32_t result_id;
|
||||
std::vector<spv_parsed_operand_t> operands;
|
||||
|
||||
bool operator==(const ParsedInstruction& b) const {
|
||||
return words == b.words && opcode == b.opcode &&
|
||||
ext_inst_type == b.ext_inst_type && type_id == b.type_id &&
|
||||
result_id == b.result_id && operands == b.operands;
|
||||
}
|
||||
};
|
||||
|
||||
// Prints a ParsedInstruction object to the given output stream, and returns
|
||||
// the stream.
|
||||
std::ostream& operator<<(std::ostream& os, const ParsedInstruction& inst) {
|
||||
os << "\nParsedInstruction( {";
|
||||
spvtest::PrintTo(spvtest::WordVector(inst.words), &os);
|
||||
os << "}, opcode: " << int(inst.opcode)
|
||||
<< " ext_inst_type: " << int(inst.ext_inst_type)
|
||||
<< " type_id: " << inst.type_id << " result_id: " << inst.result_id;
|
||||
for (const auto& operand : inst.operands) {
|
||||
os << " { offset: " << operand.offset << " num_words: " << operand.num_words
|
||||
<< " type: " << int(operand.type)
|
||||
<< " number_kind: " << int(operand.number_kind)
|
||||
<< " number_bit_width: " << int(operand.number_bit_width) << "}";
|
||||
}
|
||||
os << ")";
|
||||
return os;
|
||||
}
|
||||
|
||||
// Sanity check for the equality operator on ParsedInstruction.
|
||||
TEST(ParsedInstruction, ZeroInitializedAreEqual) {
|
||||
spv_parsed_instruction_t pi = {};
|
||||
ParsedInstruction a(pi);
|
||||
ParsedInstruction b(pi);
|
||||
EXPECT_THAT(a, ::testing::TypedEq<ParsedInstruction>(b));
|
||||
}
|
||||
|
||||
// Googlemock class receiving Header/Instruction calls from spvBinaryParse().
|
||||
class MockParseClient {
|
||||
public:
|
||||
MOCK_METHOD6(Header, spv_result_t(spv_endianness_t endian, uint32_t magic,
|
||||
uint32_t version, uint32_t generator,
|
||||
uint32_t id_bound, uint32_t reserved));
|
||||
MOCK_METHOD1(Instruction, spv_result_t(const ParsedInstruction&));
|
||||
};
|
||||
|
||||
// Casts user_data as MockParseClient and invokes its Header().
|
||||
spv_result_t invoke_header(void* user_data, spv_endianness_t endian,
|
||||
uint32_t magic, uint32_t version, uint32_t generator,
|
||||
uint32_t id_bound, uint32_t reserved) {
|
||||
return static_cast<MockParseClient*>(user_data)->Header(
|
||||
endian, magic, version, generator, id_bound, reserved);
|
||||
}
|
||||
|
||||
// Casts user_data as MockParseClient and invokes its Instruction().
|
||||
spv_result_t invoke_instruction(
|
||||
void* user_data, const spv_parsed_instruction_t* parsed_instruction) {
|
||||
return static_cast<MockParseClient*>(user_data)->Instruction(
|
||||
ParsedInstruction(*parsed_instruction));
|
||||
}
|
||||
|
||||
// The SPIR-V module header words for the Khronos Assembler generator,
|
||||
// for a module with an ID bound of 1.
|
||||
const uint32_t kHeaderForBound1[] = {
|
||||
SpvMagicNumber, SpvVersion,
|
||||
SPV_GENERATOR_WORD(SPV_GENERATOR_KHRONOS_ASSEMBLER, 0), 1 /*bound*/,
|
||||
0 /*schema*/};
|
||||
|
||||
// Returns the expected SPIR-V module header words for the Khronos
|
||||
// Assembler generator, and with a given Id bound.
|
||||
std::vector<uint32_t> ExpectedHeaderForBound(uint32_t bound) {
|
||||
return {SpvMagicNumber, 0x10000,
|
||||
SPV_GENERATOR_WORD(SPV_GENERATOR_KHRONOS_ASSEMBLER, 0), bound, 0};
|
||||
}
|
||||
|
||||
// Returns a parsed operand for a non-number value at the given word offset
|
||||
// within an instruction.
|
||||
spv_parsed_operand_t MakeSimpleOperand(uint16_t offset,
|
||||
spv_operand_type_t type) {
|
||||
return {offset, 1, type, SPV_NUMBER_NONE, 0};
|
||||
}
|
||||
|
||||
// Returns a parsed operand for a literal unsigned integer value at the given
|
||||
// word offset within an instruction.
|
||||
spv_parsed_operand_t MakeLiteralNumberOperand(uint16_t offset) {
|
||||
return {offset, 1, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_NUMBER_UNSIGNED_INT,
|
||||
32};
|
||||
}
|
||||
|
||||
// Returns a parsed operand for a literal string value at the given
|
||||
// word offset within an instruction.
|
||||
spv_parsed_operand_t MakeLiteralStringOperand(uint16_t offset,
|
||||
uint16_t length) {
|
||||
return {offset, length, SPV_OPERAND_TYPE_LITERAL_STRING, SPV_NUMBER_NONE, 0};
|
||||
}
|
||||
|
||||
// Returns a ParsedInstruction for an OpTypeVoid instruction that would
|
||||
// generate the given result Id.
|
||||
ParsedInstruction MakeParsedVoidTypeInstruction(uint32_t result_id) {
|
||||
const auto void_inst = MakeInstruction(SpvOpTypeVoid, {result_id});
|
||||
const auto void_operands = std::vector<spv_parsed_operand_t>{
|
||||
MakeSimpleOperand(1, SPV_OPERAND_TYPE_RESULT_ID)};
|
||||
const spv_parsed_instruction_t parsed_void_inst = {
|
||||
void_inst.data(),
|
||||
static_cast<uint16_t>(void_inst.size()),
|
||||
SpvOpTypeVoid,
|
||||
SPV_EXT_INST_TYPE_NONE,
|
||||
0, // type id
|
||||
result_id,
|
||||
void_operands.data(),
|
||||
static_cast<uint16_t>(void_operands.size())};
|
||||
return ParsedInstruction(parsed_void_inst);
|
||||
}
|
||||
|
||||
// Returns a ParsedInstruction for an OpTypeInt instruction that generates
|
||||
// the given result Id for a 32-bit signed integer scalar type.
|
||||
ParsedInstruction MakeParsedInt32TypeInstruction(uint32_t result_id) {
|
||||
const auto i32_inst = MakeInstruction(SpvOpTypeInt, {result_id, 32, 1});
|
||||
const auto i32_operands = std::vector<spv_parsed_operand_t>{
|
||||
MakeSimpleOperand(1, SPV_OPERAND_TYPE_RESULT_ID),
|
||||
MakeLiteralNumberOperand(2), MakeLiteralNumberOperand(3)};
|
||||
spv_parsed_instruction_t parsed_i32_inst = {
|
||||
i32_inst.data(),
|
||||
static_cast<uint16_t>(i32_inst.size()),
|
||||
SpvOpTypeInt,
|
||||
SPV_EXT_INST_TYPE_NONE,
|
||||
0, // type id
|
||||
result_id,
|
||||
i32_operands.data(),
|
||||
static_cast<uint16_t>(i32_operands.size())};
|
||||
return ParsedInstruction(parsed_i32_inst);
|
||||
}
|
||||
|
||||
class BinaryParseTest : public spvtest::TextToBinaryTestBase<::testing::Test> {
|
||||
protected:
|
||||
~BinaryParseTest() { spvDiagnosticDestroy(diagnostic_); }
|
||||
|
||||
void Parse(const SpirvVector& words, spv_result_t expected_result,
|
||||
bool flip_words = false) {
|
||||
SpirvVector flipped_words(words);
|
||||
SCOPED_TRACE(flip_words ? "Flipped Endianness" : "Normal Endianness");
|
||||
if (flip_words) {
|
||||
std::transform(flipped_words.begin(), flipped_words.end(),
|
||||
flipped_words.begin(), [](const uint32_t raw_word) {
|
||||
return spvFixWord(raw_word,
|
||||
I32_ENDIAN_HOST == I32_ENDIAN_BIG
|
||||
? SPV_ENDIANNESS_LITTLE
|
||||
: SPV_ENDIANNESS_BIG);
|
||||
});
|
||||
}
|
||||
EXPECT_EQ(expected_result,
|
||||
spvBinaryParse(ScopedContext().context, &client_,
|
||||
flipped_words.data(), flipped_words.size(),
|
||||
invoke_header, invoke_instruction, &diagnostic_));
|
||||
}
|
||||
|
||||
spv_diagnostic diagnostic_ = nullptr;
|
||||
MockParseClient client_;
|
||||
};
|
||||
|
||||
// Adds an EXPECT_CALL to client_->Header() with appropriate parameters,
|
||||
// including bound. Returns the EXPECT_CALL result.
|
||||
#define EXPECT_HEADER(bound) \
|
||||
EXPECT_CALL( \
|
||||
client_, \
|
||||
Header(AnyOf(SPV_ENDIANNESS_LITTLE, SPV_ENDIANNESS_BIG), SpvMagicNumber, \
|
||||
0x10000, SPV_GENERATOR_WORD(SPV_GENERATOR_KHRONOS_ASSEMBLER, 0), \
|
||||
bound, 0 /*reserved*/))
|
||||
|
||||
static const bool kSwapEndians[] = {false, true};
|
||||
|
||||
TEST_F(BinaryParseTest, EmptyModuleHasValidHeaderAndNoInstructionCallbacks) {
|
||||
for (bool endian_swap : kSwapEndians) {
|
||||
const auto words = CompileSuccessfully("");
|
||||
EXPECT_HEADER(1).WillOnce(Return(SPV_SUCCESS));
|
||||
EXPECT_CALL(client_, Instruction(_)).Times(0); // No instruction callback.
|
||||
Parse(words, SPV_SUCCESS, endian_swap);
|
||||
EXPECT_EQ(nullptr, diagnostic_);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(BinaryParseTest, NullDiagnosticsIsOkForGoodParse) {
|
||||
const auto words = CompileSuccessfully("");
|
||||
EXPECT_HEADER(1).WillOnce(Return(SPV_SUCCESS));
|
||||
EXPECT_CALL(client_, Instruction(_)).Times(0); // No instruction callback.
|
||||
EXPECT_EQ(
|
||||
SPV_SUCCESS,
|
||||
spvBinaryParse(ScopedContext().context, &client_, words.data(),
|
||||
words.size(), invoke_header, invoke_instruction, nullptr));
|
||||
}
|
||||
|
||||
TEST_F(BinaryParseTest, NullDiagnosticsIsOkForBadParse) {
|
||||
auto words = CompileSuccessfully("");
|
||||
words.push_back(0xffffffff); // Certainly invalid instruction header.
|
||||
EXPECT_HEADER(1).WillOnce(Return(SPV_SUCCESS));
|
||||
EXPECT_CALL(client_, Instruction(_)).Times(0); // No instruction callback.
|
||||
EXPECT_EQ(
|
||||
SPV_ERROR_INVALID_BINARY,
|
||||
spvBinaryParse(ScopedContext().context, &client_, words.data(),
|
||||
words.size(), invoke_header, invoke_instruction, nullptr));
|
||||
}
|
||||
|
||||
// Make sure that we don't blow up when both the consumer and the diagnostic are
|
||||
// null.
|
||||
TEST_F(BinaryParseTest, NullConsumerNullDiagnosticsForBadParse) {
|
||||
auto words = CompileSuccessfully("");
|
||||
|
||||
auto ctx = spvtools::Context(SPV_ENV_UNIVERSAL_1_1);
|
||||
ctx.SetMessageConsumer(nullptr);
|
||||
|
||||
words.push_back(0xffffffff); // Certainly invalid instruction header.
|
||||
EXPECT_HEADER(1).WillOnce(Return(SPV_SUCCESS));
|
||||
EXPECT_CALL(client_, Instruction(_)).Times(0); // No instruction callback.
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_BINARY,
|
||||
spvBinaryParse(ctx.CContext(), &client_, words.data(), words.size(),
|
||||
invoke_header, invoke_instruction, nullptr));
|
||||
}
|
||||
|
||||
TEST_F(BinaryParseTest, SpecifyConsumerNullDiagnosticsForGoodParse) {
|
||||
const auto words = CompileSuccessfully("");
|
||||
|
||||
auto ctx = spvtools::Context(SPV_ENV_UNIVERSAL_1_1);
|
||||
int invocation = 0;
|
||||
ctx.SetMessageConsumer([&invocation](spv_message_level_t, const char*,
|
||||
const spv_position_t&,
|
||||
const char*) { ++invocation; });
|
||||
|
||||
EXPECT_HEADER(1).WillOnce(Return(SPV_SUCCESS));
|
||||
EXPECT_CALL(client_, Instruction(_)).Times(0); // No instruction callback.
|
||||
EXPECT_EQ(SPV_SUCCESS,
|
||||
spvBinaryParse(ctx.CContext(), &client_, words.data(), words.size(),
|
||||
invoke_header, invoke_instruction, nullptr));
|
||||
EXPECT_EQ(0, invocation);
|
||||
}
|
||||
|
||||
TEST_F(BinaryParseTest, SpecifyConsumerNullDiagnosticsForBadParse) {
|
||||
auto words = CompileSuccessfully("");
|
||||
|
||||
auto ctx = spvtools::Context(SPV_ENV_UNIVERSAL_1_1);
|
||||
int invocation = 0;
|
||||
ctx.SetMessageConsumer(
|
||||
[&invocation](spv_message_level_t level, const char* source,
|
||||
const spv_position_t& position, const char* message) {
|
||||
++invocation;
|
||||
EXPECT_EQ(SPV_MSG_ERROR, level);
|
||||
EXPECT_STREQ("input", source);
|
||||
EXPECT_EQ(0u, position.line);
|
||||
EXPECT_EQ(0u, position.column);
|
||||
EXPECT_EQ(1u, position.index);
|
||||
EXPECT_STREQ("Invalid opcode: 65535", message);
|
||||
});
|
||||
|
||||
words.push_back(0xffffffff); // Certainly invalid instruction header.
|
||||
EXPECT_HEADER(1).WillOnce(Return(SPV_SUCCESS));
|
||||
EXPECT_CALL(client_, Instruction(_)).Times(0); // No instruction callback.
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_BINARY,
|
||||
spvBinaryParse(ctx.CContext(), &client_, words.data(), words.size(),
|
||||
invoke_header, invoke_instruction, nullptr));
|
||||
EXPECT_EQ(1, invocation);
|
||||
}
|
||||
|
||||
TEST_F(BinaryParseTest, SpecifyConsumerSpecifyDiagnosticsForGoodParse) {
|
||||
const auto words = CompileSuccessfully("");
|
||||
|
||||
auto ctx = spvtools::Context(SPV_ENV_UNIVERSAL_1_1);
|
||||
int invocation = 0;
|
||||
ctx.SetMessageConsumer([&invocation](spv_message_level_t, const char*,
|
||||
const spv_position_t&,
|
||||
const char*) { ++invocation; });
|
||||
|
||||
EXPECT_HEADER(1).WillOnce(Return(SPV_SUCCESS));
|
||||
EXPECT_CALL(client_, Instruction(_)).Times(0); // No instruction callback.
|
||||
EXPECT_EQ(SPV_SUCCESS,
|
||||
spvBinaryParse(ctx.CContext(), &client_, words.data(), words.size(),
|
||||
invoke_header, invoke_instruction, &diagnostic_));
|
||||
EXPECT_EQ(0, invocation);
|
||||
EXPECT_EQ(nullptr, diagnostic_);
|
||||
}
|
||||
|
||||
TEST_F(BinaryParseTest, SpecifyConsumerSpecifyDiagnosticsForBadParse) {
|
||||
auto words = CompileSuccessfully("");
|
||||
|
||||
auto ctx = spvtools::Context(SPV_ENV_UNIVERSAL_1_1);
|
||||
int invocation = 0;
|
||||
ctx.SetMessageConsumer([&invocation](spv_message_level_t, const char*,
|
||||
const spv_position_t&,
|
||||
const char*) { ++invocation; });
|
||||
|
||||
words.push_back(0xffffffff); // Certainly invalid instruction header.
|
||||
EXPECT_HEADER(1).WillOnce(Return(SPV_SUCCESS));
|
||||
EXPECT_CALL(client_, Instruction(_)).Times(0); // No instruction callback.
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_BINARY,
|
||||
spvBinaryParse(ctx.CContext(), &client_, words.data(), words.size(),
|
||||
invoke_header, invoke_instruction, &diagnostic_));
|
||||
EXPECT_EQ(0, invocation);
|
||||
EXPECT_STREQ("Invalid opcode: 65535", diagnostic_->error);
|
||||
}
|
||||
|
||||
TEST_F(BinaryParseTest,
|
||||
ModuleWithSingleInstructionHasValidHeaderAndInstructionCallback) {
|
||||
for (bool endian_swap : kSwapEndians) {
|
||||
const auto words = CompileSuccessfully("%1 = OpTypeVoid");
|
||||
InSequence calls_expected_in_specific_order;
|
||||
EXPECT_HEADER(2).WillOnce(Return(SPV_SUCCESS));
|
||||
EXPECT_CALL(client_, Instruction(MakeParsedVoidTypeInstruction(1)))
|
||||
.WillOnce(Return(SPV_SUCCESS));
|
||||
Parse(words, SPV_SUCCESS, endian_swap);
|
||||
EXPECT_EQ(nullptr, diagnostic_);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(BinaryParseTest, NullHeaderCallbackIsIgnored) {
|
||||
const auto words = CompileSuccessfully("%1 = OpTypeVoid");
|
||||
EXPECT_CALL(client_, Header(_, _, _, _, _, _))
|
||||
.Times(0); // No header callback.
|
||||
EXPECT_CALL(client_, Instruction(MakeParsedVoidTypeInstruction(1)))
|
||||
.WillOnce(Return(SPV_SUCCESS));
|
||||
EXPECT_EQ(SPV_SUCCESS, spvBinaryParse(ScopedContext().context, &client_,
|
||||
words.data(), words.size(), nullptr,
|
||||
invoke_instruction, &diagnostic_));
|
||||
EXPECT_EQ(nullptr, diagnostic_);
|
||||
}
|
||||
|
||||
TEST_F(BinaryParseTest, NullInstructionCallbackIsIgnored) {
|
||||
const auto words = CompileSuccessfully("%1 = OpTypeVoid");
|
||||
EXPECT_HEADER((2)).WillOnce(Return(SPV_SUCCESS));
|
||||
EXPECT_CALL(client_, Instruction(_)).Times(0); // No instruction callback.
|
||||
EXPECT_EQ(SPV_SUCCESS,
|
||||
spvBinaryParse(ScopedContext().context, &client_, words.data(),
|
||||
words.size(), invoke_header, nullptr, &diagnostic_));
|
||||
EXPECT_EQ(nullptr, diagnostic_);
|
||||
}
|
||||
|
||||
// Check the result of multiple instruction callbacks.
|
||||
//
|
||||
// This test exercises non-default values for the following members of the
|
||||
// spv_parsed_instruction_t struct: words, num_words, opcode, result_id,
|
||||
// operands, num_operands.
|
||||
TEST_F(BinaryParseTest, TwoScalarTypesGenerateTwoInstructionCallbacks) {
|
||||
for (bool endian_swap : kSwapEndians) {
|
||||
const auto words = CompileSuccessfully(
|
||||
"%1 = OpTypeVoid "
|
||||
"%2 = OpTypeInt 32 1");
|
||||
InSequence calls_expected_in_specific_order;
|
||||
EXPECT_HEADER(3).WillOnce(Return(SPV_SUCCESS));
|
||||
EXPECT_CALL(client_, Instruction(MakeParsedVoidTypeInstruction(1)))
|
||||
.WillOnce(Return(SPV_SUCCESS));
|
||||
EXPECT_CALL(client_, Instruction(MakeParsedInt32TypeInstruction(2)))
|
||||
.WillOnce(Return(SPV_SUCCESS));
|
||||
Parse(words, SPV_SUCCESS, endian_swap);
|
||||
EXPECT_EQ(nullptr, diagnostic_);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(BinaryParseTest, EarlyReturnWithZeroPassingCallbacks) {
|
||||
for (bool endian_swap : kSwapEndians) {
|
||||
const auto words = CompileSuccessfully(
|
||||
"%1 = OpTypeVoid "
|
||||
"%2 = OpTypeInt 32 1");
|
||||
InSequence calls_expected_in_specific_order;
|
||||
EXPECT_HEADER(3).WillOnce(Return(SPV_ERROR_INVALID_BINARY));
|
||||
// Early exit means no calls to Instruction().
|
||||
EXPECT_CALL(client_, Instruction(_)).Times(0);
|
||||
Parse(words, SPV_ERROR_INVALID_BINARY, endian_swap);
|
||||
// On error, the binary parser doesn't generate its own diagnostics.
|
||||
EXPECT_EQ(nullptr, diagnostic_);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(BinaryParseTest,
|
||||
EarlyReturnWithZeroPassingCallbacksAndSpecifiedResultCode) {
|
||||
for (bool endian_swap : kSwapEndians) {
|
||||
const auto words = CompileSuccessfully(
|
||||
"%1 = OpTypeVoid "
|
||||
"%2 = OpTypeInt 32 1");
|
||||
InSequence calls_expected_in_specific_order;
|
||||
EXPECT_HEADER(3).WillOnce(Return(SPV_REQUESTED_TERMINATION));
|
||||
// Early exit means no calls to Instruction().
|
||||
EXPECT_CALL(client_, Instruction(_)).Times(0);
|
||||
Parse(words, SPV_REQUESTED_TERMINATION, endian_swap);
|
||||
// On early termination, the binary parser doesn't generate its own
|
||||
// diagnostics.
|
||||
EXPECT_EQ(nullptr, diagnostic_);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(BinaryParseTest, EarlyReturnWithOnePassingCallback) {
|
||||
for (bool endian_swap : kSwapEndians) {
|
||||
const auto words = CompileSuccessfully(
|
||||
"%1 = OpTypeVoid "
|
||||
"%2 = OpTypeInt 32 1 "
|
||||
"%3 = OpTypeFloat 32");
|
||||
InSequence calls_expected_in_specific_order;
|
||||
EXPECT_HEADER(4).WillOnce(Return(SPV_SUCCESS));
|
||||
EXPECT_CALL(client_, Instruction(MakeParsedVoidTypeInstruction(1)))
|
||||
.WillOnce(Return(SPV_REQUESTED_TERMINATION));
|
||||
Parse(words, SPV_REQUESTED_TERMINATION, endian_swap);
|
||||
// On early termination, the binary parser doesn't generate its own
|
||||
// diagnostics.
|
||||
EXPECT_EQ(nullptr, diagnostic_);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(BinaryParseTest, EarlyReturnWithTwoPassingCallbacks) {
|
||||
for (bool endian_swap : kSwapEndians) {
|
||||
const auto words = CompileSuccessfully(
|
||||
"%1 = OpTypeVoid "
|
||||
"%2 = OpTypeInt 32 1 "
|
||||
"%3 = OpTypeFloat 32");
|
||||
InSequence calls_expected_in_specific_order;
|
||||
EXPECT_HEADER(4).WillOnce(Return(SPV_SUCCESS));
|
||||
EXPECT_CALL(client_, Instruction(MakeParsedVoidTypeInstruction(1)))
|
||||
.WillOnce(Return(SPV_SUCCESS));
|
||||
EXPECT_CALL(client_, Instruction(MakeParsedInt32TypeInstruction(2)))
|
||||
.WillOnce(Return(SPV_REQUESTED_TERMINATION));
|
||||
Parse(words, SPV_REQUESTED_TERMINATION, endian_swap);
|
||||
// On early termination, the binary parser doesn't generate its own
|
||||
// diagnostics.
|
||||
EXPECT_EQ(nullptr, diagnostic_);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(BinaryParseTest, InstructionWithStringOperand) {
|
||||
const std::string str =
|
||||
"the future is already here, it's just not evenly distributed";
|
||||
const auto str_words = MakeVector(str);
|
||||
const auto instruction = MakeInstruction(SpvOpName, {99}, str_words);
|
||||
const auto words = Concatenate({ExpectedHeaderForBound(100), instruction});
|
||||
InSequence calls_expected_in_specific_order;
|
||||
EXPECT_HEADER(100).WillOnce(Return(SPV_SUCCESS));
|
||||
const auto operands = std::vector<spv_parsed_operand_t>{
|
||||
MakeSimpleOperand(1, SPV_OPERAND_TYPE_ID),
|
||||
MakeLiteralStringOperand(2, static_cast<uint16_t>(str_words.size()))};
|
||||
EXPECT_CALL(client_,
|
||||
Instruction(ParsedInstruction(spv_parsed_instruction_t{
|
||||
instruction.data(), static_cast<uint16_t>(instruction.size()),
|
||||
SpvOpName, SPV_EXT_INST_TYPE_NONE, 0 /*type id*/,
|
||||
0 /* No result id for OpName*/, operands.data(),
|
||||
static_cast<uint16_t>(operands.size())})))
|
||||
.WillOnce(Return(SPV_SUCCESS));
|
||||
// Since we are actually checking the output, don't test the
|
||||
// endian-swapped version.
|
||||
Parse(words, SPV_SUCCESS, false);
|
||||
EXPECT_EQ(nullptr, diagnostic_);
|
||||
}
|
||||
|
||||
// Checks for non-zero values for the result_id and ext_inst_type members
|
||||
// spv_parsed_instruction_t.
|
||||
TEST_F(BinaryParseTest, ExtendedInstruction) {
|
||||
const auto words = CompileSuccessfully(
|
||||
"%extcl = OpExtInstImport \"OpenCL.std\" "
|
||||
"%result = OpExtInst %float %extcl sqrt %x");
|
||||
EXPECT_HEADER(5).WillOnce(Return(SPV_SUCCESS));
|
||||
EXPECT_CALL(client_, Instruction(_)).WillOnce(Return(SPV_SUCCESS));
|
||||
// We're only interested in the second call to Instruction():
|
||||
const auto operands = std::vector<spv_parsed_operand_t>{
|
||||
MakeSimpleOperand(1, SPV_OPERAND_TYPE_TYPE_ID),
|
||||
MakeSimpleOperand(2, SPV_OPERAND_TYPE_RESULT_ID),
|
||||
MakeSimpleOperand(3,
|
||||
SPV_OPERAND_TYPE_ID), // Extended instruction set Id
|
||||
MakeSimpleOperand(4, SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER),
|
||||
MakeSimpleOperand(5, SPV_OPERAND_TYPE_ID), // Id of the argument
|
||||
};
|
||||
const auto instruction = MakeInstruction(
|
||||
SpvOpExtInst,
|
||||
{2, 3, 1, static_cast<uint32_t>(OpenCLLIB::Entrypoints::Sqrt), 4});
|
||||
EXPECT_CALL(client_,
|
||||
Instruction(ParsedInstruction(spv_parsed_instruction_t{
|
||||
instruction.data(), static_cast<uint16_t>(instruction.size()),
|
||||
SpvOpExtInst, SPV_EXT_INST_TYPE_OPENCL_STD, 2 /*type id*/,
|
||||
3 /*result id*/, operands.data(),
|
||||
static_cast<uint16_t>(operands.size())})))
|
||||
.WillOnce(Return(SPV_SUCCESS));
|
||||
// Since we are actually checking the output, don't test the
|
||||
// endian-swapped version.
|
||||
Parse(words, SPV_SUCCESS, false);
|
||||
EXPECT_EQ(nullptr, diagnostic_);
|
||||
}
|
||||
|
||||
// A binary parser diagnostic test case where we provide the words array
|
||||
// pointer and word count explicitly.
|
||||
struct WordsAndCountDiagnosticCase {
|
||||
const uint32_t* words;
|
||||
size_t num_words;
|
||||
std::string expected_diagnostic;
|
||||
};
|
||||
|
||||
using BinaryParseWordsAndCountDiagnosticTest = spvtest::TextToBinaryTestBase<
|
||||
::testing::TestWithParam<WordsAndCountDiagnosticCase>>;
|
||||
|
||||
TEST_P(BinaryParseWordsAndCountDiagnosticTest, WordAndCountCases) {
|
||||
EXPECT_EQ(
|
||||
SPV_ERROR_INVALID_BINARY,
|
||||
spvBinaryParse(ScopedContext().context, nullptr, GetParam().words,
|
||||
GetParam().num_words, nullptr, nullptr, &diagnostic));
|
||||
ASSERT_NE(nullptr, diagnostic);
|
||||
EXPECT_THAT(diagnostic->error, Eq(GetParam().expected_diagnostic));
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
BinaryParseDiagnostic, BinaryParseWordsAndCountDiagnosticTest,
|
||||
::testing::ValuesIn(std::vector<WordsAndCountDiagnosticCase>{
|
||||
{nullptr, 0, "Missing module."},
|
||||
{kHeaderForBound1, 0,
|
||||
"Module has incomplete header: only 0 words instead of 5"},
|
||||
{kHeaderForBound1, 1,
|
||||
"Module has incomplete header: only 1 words instead of 5"},
|
||||
{kHeaderForBound1, 2,
|
||||
"Module has incomplete header: only 2 words instead of 5"},
|
||||
{kHeaderForBound1, 3,
|
||||
"Module has incomplete header: only 3 words instead of 5"},
|
||||
{kHeaderForBound1, 4,
|
||||
"Module has incomplete header: only 4 words instead of 5"},
|
||||
}));
|
||||
|
||||
// A binary parser diagnostic test case where a vector of words is
|
||||
// provided. We'll use this to express cases that can't be created
|
||||
// via the assembler. Either we want to make a malformed instruction,
|
||||
// or an invalid case the assembler would reject.
|
||||
struct WordVectorDiagnosticCase {
|
||||
std::vector<uint32_t> words;
|
||||
std::string expected_diagnostic;
|
||||
};
|
||||
|
||||
using BinaryParseWordVectorDiagnosticTest = spvtest::TextToBinaryTestBase<
|
||||
::testing::TestWithParam<WordVectorDiagnosticCase>>;
|
||||
|
||||
TEST_P(BinaryParseWordVectorDiagnosticTest, WordVectorCases) {
|
||||
const auto& words = GetParam().words;
|
||||
EXPECT_THAT(spvBinaryParse(ScopedContext().context, nullptr, words.data(),
|
||||
words.size(), nullptr, nullptr, &diagnostic),
|
||||
AnyOf(SPV_ERROR_INVALID_BINARY, SPV_ERROR_INVALID_ID));
|
||||
ASSERT_NE(nullptr, diagnostic);
|
||||
EXPECT_THAT(diagnostic->error, Eq(GetParam().expected_diagnostic));
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
BinaryParseDiagnostic, BinaryParseWordVectorDiagnosticTest,
|
||||
::testing::ValuesIn(std::vector<WordVectorDiagnosticCase>{
|
||||
{Concatenate({ExpectedHeaderForBound(1), {spvOpcodeMake(0, SpvOpNop)}}),
|
||||
"Invalid instruction word count: 0"},
|
||||
{Concatenate(
|
||||
{ExpectedHeaderForBound(1),
|
||||
{spvOpcodeMake(1, static_cast<SpvOp>(
|
||||
std::numeric_limits<uint16_t>::max()))}}),
|
||||
"Invalid opcode: 65535"},
|
||||
{Concatenate({ExpectedHeaderForBound(1),
|
||||
MakeInstruction(SpvOpNop, {42})}),
|
||||
"Invalid instruction OpNop starting at word 5: expected "
|
||||
"no more operands after 1 words, but stated word count is 2."},
|
||||
// Supply several more unexpectd words.
|
||||
{Concatenate({ExpectedHeaderForBound(1),
|
||||
MakeInstruction(SpvOpNop, {42, 43, 44, 45, 46, 47})}),
|
||||
"Invalid instruction OpNop starting at word 5: expected "
|
||||
"no more operands after 1 words, but stated word count is 7."},
|
||||
{Concatenate({ExpectedHeaderForBound(1),
|
||||
MakeInstruction(SpvOpTypeVoid, {1, 2})}),
|
||||
"Invalid instruction OpTypeVoid starting at word 5: expected "
|
||||
"no more operands after 2 words, but stated word count is 3."},
|
||||
{Concatenate({ExpectedHeaderForBound(1),
|
||||
MakeInstruction(SpvOpTypeVoid, {1, 2, 5, 9, 10})}),
|
||||
"Invalid instruction OpTypeVoid starting at word 5: expected "
|
||||
"no more operands after 2 words, but stated word count is 6."},
|
||||
{Concatenate({ExpectedHeaderForBound(1),
|
||||
MakeInstruction(SpvOpTypeInt, {1, 32, 1, 9})}),
|
||||
"Invalid instruction OpTypeInt starting at word 5: expected "
|
||||
"no more operands after 4 words, but stated word count is 5."},
|
||||
{Concatenate({ExpectedHeaderForBound(1),
|
||||
MakeInstruction(SpvOpTypeInt, {1})}),
|
||||
"End of input reached while decoding OpTypeInt starting at word 5:"
|
||||
" expected more operands after 2 words."},
|
||||
|
||||
// Check several cases for running off the end of input.
|
||||
|
||||
// Detect a missing single word operand.
|
||||
{Concatenate({ExpectedHeaderForBound(1),
|
||||
{spvOpcodeMake(2, SpvOpTypeStruct)}}),
|
||||
"End of input reached while decoding OpTypeStruct starting at word"
|
||||
" 5: missing result ID operand at word offset 1."},
|
||||
// Detect this a missing a multi-word operand to OpConstant.
|
||||
// We also lie and say the OpConstant instruction has 5 words when
|
||||
// it only has 3. Corresponds to something like this:
|
||||
// %1 = OpTypeInt 64 0
|
||||
// %2 = OpConstant %1 <missing>
|
||||
{Concatenate({ExpectedHeaderForBound(3),
|
||||
{MakeInstruction(SpvOpTypeInt, {1, 64, 0})},
|
||||
{spvOpcodeMake(5, SpvOpConstant), 1, 2}}),
|
||||
"End of input reached while decoding OpConstant starting at word"
|
||||
" 9: missing possibly multi-word literal number operand at word "
|
||||
"offset 3."},
|
||||
// Detect when we provide only one word from the 64-bit literal,
|
||||
// and again lie about the number of words in the instruction.
|
||||
{Concatenate({ExpectedHeaderForBound(3),
|
||||
{MakeInstruction(SpvOpTypeInt, {1, 64, 0})},
|
||||
{spvOpcodeMake(5, SpvOpConstant), 1, 2, 42}}),
|
||||
"End of input reached while decoding OpConstant starting at word"
|
||||
" 9: truncated possibly multi-word literal number operand at word "
|
||||
"offset 3."},
|
||||
// Detect when a required string operand is missing.
|
||||
// Also, lie about the length of the instruction.
|
||||
{Concatenate({ExpectedHeaderForBound(3),
|
||||
{spvOpcodeMake(3, SpvOpString), 1}}),
|
||||
"End of input reached while decoding OpString starting at word"
|
||||
" 5: missing literal string operand at word offset 2."},
|
||||
// Detect when a required string operand is truncated: it's missing
|
||||
// a null terminator. Catching the error avoids a buffer overrun.
|
||||
{Concatenate({ExpectedHeaderForBound(3),
|
||||
{spvOpcodeMake(4, SpvOpString), 1, 0x41414141,
|
||||
0x41414141}}),
|
||||
"End of input reached while decoding OpString starting at word"
|
||||
" 5: truncated literal string operand at word offset 2."},
|
||||
// Detect when an optional string operand is truncated: it's missing
|
||||
// a null terminator. Catching the error avoids a buffer overrun.
|
||||
// (It is valid for an optional string operand to be absent.)
|
||||
{Concatenate({ExpectedHeaderForBound(3),
|
||||
{spvOpcodeMake(6, SpvOpSource),
|
||||
static_cast<uint32_t>(SpvSourceLanguageOpenCL_C), 210,
|
||||
1 /* file id */,
|
||||
/*start of string*/ 0x41414141, 0x41414141}}),
|
||||
"End of input reached while decoding OpSource starting at word"
|
||||
" 5: truncated literal string operand at word offset 4."},
|
||||
|
||||
// (End of input exhaustion test cases.)
|
||||
|
||||
// In this case the instruction word count is too small, where
|
||||
// it would truncate a multi-word operand to OpConstant.
|
||||
{Concatenate({ExpectedHeaderForBound(3),
|
||||
{MakeInstruction(SpvOpTypeInt, {1, 64, 0})},
|
||||
{spvOpcodeMake(4, SpvOpConstant), 1, 2, 44, 44}}),
|
||||
"Invalid word count: OpConstant starting at word 9 says it has 4"
|
||||
" words, but found 5 words instead."},
|
||||
// Word count is to small, where it would truncate a literal string.
|
||||
{Concatenate({ExpectedHeaderForBound(2),
|
||||
{spvOpcodeMake(3, SpvOpString), 1, 0x41414141, 0}}),
|
||||
"Invalid word count: OpString starting at word 5 says it has 3"
|
||||
" words, but found 4 words instead."},
|
||||
// Word count is too large. The string terminates before the last
|
||||
// word.
|
||||
{Concatenate({ExpectedHeaderForBound(2),
|
||||
{spvOpcodeMake(4, SpvOpString), 1 /* result id */},
|
||||
MakeVector("abc"),
|
||||
{0 /* this word does not belong*/}}),
|
||||
"Invalid instruction OpString starting at word 5: expected no more"
|
||||
" operands after 3 words, but stated word count is 4."},
|
||||
// Word count is too large. There are too many words after the string
|
||||
// literal. A linkage attribute decoration is the only case in SPIR-V
|
||||
// where a string operand is followed by another operand.
|
||||
{Concatenate({ExpectedHeaderForBound(2),
|
||||
{spvOpcodeMake(6, SpvOpDecorate), 1 /* target id */,
|
||||
static_cast<uint32_t>(SpvDecorationLinkageAttributes)},
|
||||
MakeVector("abc"),
|
||||
{static_cast<uint32_t>(SpvLinkageTypeImport),
|
||||
0 /* does not belong */}}),
|
||||
"Invalid instruction OpDecorate starting at word 5: expected no more"
|
||||
" operands after 5 words, but stated word count is 6."},
|
||||
// Like the previous case, but with 5 extra words.
|
||||
{Concatenate({ExpectedHeaderForBound(2),
|
||||
{spvOpcodeMake(10, SpvOpDecorate), 1 /* target id */,
|
||||
static_cast<uint32_t>(SpvDecorationLinkageAttributes)},
|
||||
MakeVector("abc"),
|
||||
{static_cast<uint32_t>(SpvLinkageTypeImport),
|
||||
/* don't belong */ 0, 1, 2, 3, 4}}),
|
||||
"Invalid instruction OpDecorate starting at word 5: expected no more"
|
||||
" operands after 5 words, but stated word count is 10."},
|
||||
// Like the previous two cases, but with OpMemberDecorate.
|
||||
{Concatenate({ExpectedHeaderForBound(2),
|
||||
{spvOpcodeMake(7, SpvOpMemberDecorate), 1 /* target id */,
|
||||
42 /* member index */,
|
||||
static_cast<uint32_t>(SpvDecorationLinkageAttributes)},
|
||||
MakeVector("abc"),
|
||||
{static_cast<uint32_t>(SpvLinkageTypeImport),
|
||||
0 /* does not belong */}}),
|
||||
"Invalid instruction OpMemberDecorate starting at word 5: expected no"
|
||||
" more operands after 6 words, but stated word count is 7."},
|
||||
{Concatenate({ExpectedHeaderForBound(2),
|
||||
{spvOpcodeMake(11, SpvOpMemberDecorate),
|
||||
1 /* target id */, 42 /* member index */,
|
||||
static_cast<uint32_t>(SpvDecorationLinkageAttributes)},
|
||||
MakeVector("abc"),
|
||||
{static_cast<uint32_t>(SpvLinkageTypeImport),
|
||||
/* don't belong */ 0, 1, 2, 3, 4}}),
|
||||
"Invalid instruction OpMemberDecorate starting at word 5: expected no"
|
||||
" more operands after 6 words, but stated word count is 11."},
|
||||
// Word count is too large. There should be no more words
|
||||
// after the RelaxedPrecision decoration.
|
||||
{Concatenate({ExpectedHeaderForBound(2),
|
||||
{spvOpcodeMake(4, SpvOpDecorate), 1 /* target id */,
|
||||
static_cast<uint32_t>(SpvDecorationRelaxedPrecision),
|
||||
0 /* does not belong */}}),
|
||||
"Invalid instruction OpDecorate starting at word 5: expected no"
|
||||
" more operands after 3 words, but stated word count is 4."},
|
||||
// Word count is too large. There should be only one word after
|
||||
// the SpecId decoration enum word.
|
||||
{Concatenate({ExpectedHeaderForBound(2),
|
||||
{spvOpcodeMake(5, SpvOpDecorate), 1 /* target id */,
|
||||
static_cast<uint32_t>(SpvDecorationSpecId),
|
||||
42 /* the spec id */, 0 /* does not belong */}}),
|
||||
"Invalid instruction OpDecorate starting at word 5: expected no"
|
||||
" more operands after 4 words, but stated word count is 5."},
|
||||
{Concatenate({ExpectedHeaderForBound(2),
|
||||
{spvOpcodeMake(2, SpvOpTypeVoid), 0}}),
|
||||
"Error: Result Id is 0"},
|
||||
{Concatenate({
|
||||
ExpectedHeaderForBound(2),
|
||||
{spvOpcodeMake(2, SpvOpTypeVoid), 1},
|
||||
{spvOpcodeMake(2, SpvOpTypeBool), 1},
|
||||
}),
|
||||
"Id 1 is defined more than once"},
|
||||
{Concatenate({ExpectedHeaderForBound(3),
|
||||
MakeInstruction(SpvOpExtInst, {2, 3, 100, 4, 5})}),
|
||||
"OpExtInst set Id 100 does not reference an OpExtInstImport result "
|
||||
"Id"},
|
||||
{Concatenate({ExpectedHeaderForBound(101),
|
||||
MakeInstruction(SpvOpExtInstImport, {100},
|
||||
MakeVector("OpenCL.std")),
|
||||
// OpenCL cos is #14
|
||||
MakeInstruction(SpvOpExtInst, {2, 3, 100, 14, 5, 999})}),
|
||||
"Invalid instruction OpExtInst starting at word 10: expected no "
|
||||
"more operands after 6 words, but stated word count is 7."},
|
||||
// In this case, the OpSwitch selector refers to an invalid ID.
|
||||
{Concatenate({ExpectedHeaderForBound(3),
|
||||
MakeInstruction(SpvOpSwitch, {1, 2, 42, 3})}),
|
||||
"Invalid OpSwitch: selector id 1 has no type"},
|
||||
// In this case, the OpSwitch selector refers to an ID that has
|
||||
// no type.
|
||||
{Concatenate({ExpectedHeaderForBound(3),
|
||||
MakeInstruction(SpvOpLabel, {1}),
|
||||
MakeInstruction(SpvOpSwitch, {1, 2, 42, 3})}),
|
||||
"Invalid OpSwitch: selector id 1 has no type"},
|
||||
{Concatenate({ExpectedHeaderForBound(3),
|
||||
MakeInstruction(SpvOpTypeInt, {1, 32, 0}),
|
||||
MakeInstruction(SpvOpSwitch, {1, 3, 42, 3})}),
|
||||
"Invalid OpSwitch: selector id 1 is a type, not a value"},
|
||||
{Concatenate({ExpectedHeaderForBound(3),
|
||||
MakeInstruction(SpvOpTypeFloat, {1, 32}),
|
||||
MakeInstruction(SpvOpConstant, {1, 2, 0x78f00000}),
|
||||
MakeInstruction(SpvOpSwitch, {2, 3, 42, 3})}),
|
||||
"Invalid OpSwitch: selector id 2 is not a scalar integer"},
|
||||
{Concatenate({ExpectedHeaderForBound(3),
|
||||
MakeInstruction(SpvOpExtInstImport, {1},
|
||||
MakeVector("invalid-import"))}),
|
||||
"Invalid extended instruction import 'invalid-import'"},
|
||||
{Concatenate({
|
||||
ExpectedHeaderForBound(3),
|
||||
MakeInstruction(SpvOpTypeInt, {1, 32, 0}),
|
||||
MakeInstruction(SpvOpConstant, {2, 2, 42}),
|
||||
}),
|
||||
"Type Id 2 is not a type"},
|
||||
{Concatenate({
|
||||
ExpectedHeaderForBound(3),
|
||||
MakeInstruction(SpvOpTypeBool, {1}),
|
||||
MakeInstruction(SpvOpConstant, {1, 2, 42}),
|
||||
}),
|
||||
"Type Id 1 is not a scalar numeric type"},
|
||||
}));
|
||||
|
||||
// A binary parser diagnostic case generated from an assembly text input.
|
||||
struct AssemblyDiagnosticCase {
|
||||
std::string assembly;
|
||||
std::string expected_diagnostic;
|
||||
};
|
||||
|
||||
using BinaryParseAssemblyDiagnosticTest = spvtest::TextToBinaryTestBase<
|
||||
::testing::TestWithParam<AssemblyDiagnosticCase>>;
|
||||
|
||||
TEST_P(BinaryParseAssemblyDiagnosticTest, AssemblyCases) {
|
||||
auto words = CompileSuccessfully(GetParam().assembly);
|
||||
EXPECT_THAT(spvBinaryParse(ScopedContext().context, nullptr, words.data(),
|
||||
words.size(), nullptr, nullptr, &diagnostic),
|
||||
AnyOf(SPV_ERROR_INVALID_BINARY, SPV_ERROR_INVALID_ID));
|
||||
ASSERT_NE(nullptr, diagnostic);
|
||||
EXPECT_THAT(diagnostic->error, Eq(GetParam().expected_diagnostic));
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
BinaryParseDiagnostic, BinaryParseAssemblyDiagnosticTest,
|
||||
::testing::ValuesIn(std::vector<AssemblyDiagnosticCase>{
|
||||
{"%1 = OpConstant !0 42", "Error: Type Id is 0"},
|
||||
// A required id is 0.
|
||||
{"OpName !0 \"foo\"", "Id is 0"},
|
||||
// An optional id is 0, in this case the optional
|
||||
// initializer.
|
||||
{"%2 = OpVariable %1 CrossWorkgroup !0", "Id is 0"},
|
||||
{"OpControlBarrier !0 %1 %2", "scope ID is 0"},
|
||||
{"OpControlBarrier %1 !0 %2", "scope ID is 0"},
|
||||
{"OpControlBarrier %1 %2 !0", "memory semantics ID is 0"},
|
||||
{"%import = OpExtInstImport \"GLSL.std.450\" "
|
||||
"%result = OpExtInst %type %import !999999 %x",
|
||||
"Invalid extended instruction number: 999999"},
|
||||
{"%2 = OpSpecConstantOp %1 !1000 %2",
|
||||
"Invalid OpSpecConstantOp opcode: 1000"},
|
||||
{"OpCapability !9999", "Invalid capability operand: 9999"},
|
||||
{"OpSource !9999 100", "Invalid source language operand: 9999"},
|
||||
{"OpEntryPoint !9999", "Invalid execution model operand: 9999"},
|
||||
{"OpMemoryModel !9999", "Invalid addressing model operand: 9999"},
|
||||
{"OpMemoryModel Logical !9999", "Invalid memory model operand: 9999"},
|
||||
{"OpExecutionMode %1 !9999", "Invalid execution mode operand: 9999"},
|
||||
{"OpTypeForwardPointer %1 !9999",
|
||||
"Invalid storage class operand: 9999"},
|
||||
{"%2 = OpTypeImage %1 !9999", "Invalid dimensionality operand: 9999"},
|
||||
{"%2 = OpTypeImage %1 1D 0 0 0 0 !9999",
|
||||
"Invalid image format operand: 9999"},
|
||||
{"OpDecorate %1 FPRoundingMode !9999",
|
||||
"Invalid floating-point rounding mode operand: 9999"},
|
||||
{"OpDecorate %1 LinkageAttributes \"C\" !9999",
|
||||
"Invalid linkage type operand: 9999"},
|
||||
{"%1 = OpTypePipe !9999", "Invalid access qualifier operand: 9999"},
|
||||
{"OpDecorate %1 FuncParamAttr !9999",
|
||||
"Invalid function parameter attribute operand: 9999"},
|
||||
{"OpDecorate %1 !9999", "Invalid decoration operand: 9999"},
|
||||
{"OpDecorate %1 BuiltIn !9999", "Invalid built-in operand: 9999"},
|
||||
{"%2 = OpGroupIAdd %1 %3 !9999",
|
||||
"Invalid group operation operand: 9999"},
|
||||
{"OpDecorate %1 FPFastMathMode !63",
|
||||
"Invalid floating-point fast math mode operand: 63 has invalid mask "
|
||||
"component 32"},
|
||||
{"%2 = OpFunction %2 !31",
|
||||
"Invalid function control operand: 31 has invalid mask component 16"},
|
||||
{"OpLoopMerge %1 %2 !1027",
|
||||
"Invalid loop control operand: 1027 has invalid mask component 1024"},
|
||||
{"%2 = OpImageFetch %1 %image %coord !32770",
|
||||
"Invalid image operand: 32770 has invalid mask component 32768"},
|
||||
{"OpSelectionMerge %1 !7",
|
||||
"Invalid selection control operand: 7 has invalid mask component 4"},
|
||||
}));
|
||||
|
||||
} // namespace
|
||||
} // namespace spvtools
|
||||
@@ -1,32 +0,0 @@
|
||||
// Copyright (c) 2016 Google Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "test/unit_spirv.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace {
|
||||
|
||||
TEST(Strnlen, Samples) {
|
||||
EXPECT_EQ(0u, spv_strnlen_s(nullptr, 0));
|
||||
EXPECT_EQ(0u, spv_strnlen_s(nullptr, 5));
|
||||
EXPECT_EQ(0u, spv_strnlen_s("abc", 0));
|
||||
EXPECT_EQ(1u, spv_strnlen_s("abc", 1));
|
||||
EXPECT_EQ(3u, spv_strnlen_s("abc", 3));
|
||||
EXPECT_EQ(3u, spv_strnlen_s("abc\0", 5));
|
||||
EXPECT_EQ(0u, spv_strnlen_s("\0", 5));
|
||||
EXPECT_EQ(1u, spv_strnlen_s("a\0c", 5));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace spvtools
|
||||
@@ -1,76 +0,0 @@
|
||||
// Copyright (c) 2015-2016 The Khronos Group Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "test/test_fixture.h"
|
||||
#include "test/unit_spirv.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace {
|
||||
|
||||
using ::testing::Eq;
|
||||
using RoundTripLiteralsTest =
|
||||
spvtest::TextToBinaryTestBase<::testing::TestWithParam<std::string>>;
|
||||
|
||||
TEST_P(RoundTripLiteralsTest, Sample) {
|
||||
EXPECT_THAT(EncodeAndDecodeSuccessfully(GetParam()), Eq(GetParam()));
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
StringLiterals, RoundTripLiteralsTest,
|
||||
::testing::ValuesIn(std::vector<std::string>{
|
||||
"OpName %1 \"\"\n", // empty
|
||||
"OpName %1 \"foo\"\n", // normal
|
||||
"OpName %1 \"foo bar\"\n", // string with spaces
|
||||
"OpName %1 \"foo\tbar\"\n", // string with tab
|
||||
"OpName %1 \"\tfoo\"\n", // starts with tab
|
||||
"OpName %1 \" foo\"\n", // starts with space
|
||||
"OpName %1 \"foo \"\n", // ends with space
|
||||
"OpName %1 \"foo\t\"\n", // ends with tab
|
||||
"OpName %1 \"foo\nbar\"\n", // contains newline
|
||||
"OpName %1 \"\nfoo\nbar\"\n", // starts with newline
|
||||
"OpName %1 \"\n\n\nfoo\nbar\"\n", // multiple newlines
|
||||
"OpName %1 \"\\\"foo\nbar\\\"\"\n", // escaped quote
|
||||
"OpName %1 \"\\\\foo\nbar\\\\\"\n", // escaped backslash
|
||||
"OpName %1 \"\xE4\xBA\xB2\"\n", // UTF-8
|
||||
}));
|
||||
// clang-format on
|
||||
|
||||
using RoundTripSpecialCaseLiteralsTest = spvtest::TextToBinaryTestBase<
|
||||
::testing::TestWithParam<std::pair<std::string, std::string>>>;
|
||||
|
||||
// Test case where the generated disassembly is not the same as the
|
||||
// assembly passed in.
|
||||
TEST_P(RoundTripSpecialCaseLiteralsTest, Sample) {
|
||||
EXPECT_THAT(EncodeAndDecodeSuccessfully(std::get<0>(GetParam())),
|
||||
Eq(std::get<1>(GetParam())));
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
StringLiterals, RoundTripSpecialCaseLiteralsTest,
|
||||
::testing::ValuesIn(std::vector<std::pair<std::string, std::string>>{
|
||||
{"OpName %1 \"\\foo\"\n", "OpName %1 \"foo\"\n"}, // Escape f
|
||||
{"OpName %1 \"\\\nfoo\"\n", "OpName %1 \"\nfoo\"\n"}, // Escape newline
|
||||
{"OpName %1 \"\\\xE4\xBA\xB2\"\n", "OpName %1 \"\xE4\xBA\xB2\"\n"}, // Escape utf-8
|
||||
}));
|
||||
// clang-format on
|
||||
|
||||
} // namespace
|
||||
} // namespace spvtools
|
||||
561
3rdparty/spirv-tools/test/binary_to_text_test.cpp
vendored
561
3rdparty/spirv-tools/test/binary_to_text_test.cpp
vendored
@@ -1,561 +0,0 @@
|
||||
// Copyright (c) 2015-2016 The Khronos Group Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "source/spirv_constant.h"
|
||||
#include "test/test_fixture.h"
|
||||
#include "test/unit_spirv.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace {
|
||||
|
||||
using spvtest::AutoText;
|
||||
using spvtest::ScopedContext;
|
||||
using spvtest::TextToBinaryTest;
|
||||
using ::testing::Combine;
|
||||
using ::testing::Eq;
|
||||
using ::testing::HasSubstr;
|
||||
|
||||
class BinaryToText : public ::testing::Test {
|
||||
public:
|
||||
BinaryToText()
|
||||
: context(spvContextCreate(SPV_ENV_UNIVERSAL_1_0)), binary(nullptr) {}
|
||||
~BinaryToText() {
|
||||
spvBinaryDestroy(binary);
|
||||
spvContextDestroy(context);
|
||||
}
|
||||
|
||||
virtual void SetUp() {
|
||||
const char* textStr = R"(
|
||||
OpSource OpenCL_C 12
|
||||
OpMemoryModel Physical64 OpenCL
|
||||
OpSourceExtension "PlaceholderExtensionName"
|
||||
OpEntryPoint Kernel %1 "foo"
|
||||
OpExecutionMode %1 LocalSizeHint 1 1 1
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeBool
|
||||
%4 = OpTypeInt 8 0
|
||||
%5 = OpTypeInt 8 1
|
||||
%6 = OpTypeInt 16 0
|
||||
%7 = OpTypeInt 16 1
|
||||
%8 = OpTypeInt 32 0
|
||||
%9 = OpTypeInt 32 1
|
||||
%10 = OpTypeInt 64 0
|
||||
%11 = OpTypeInt 64 1
|
||||
%12 = OpTypeFloat 16
|
||||
%13 = OpTypeFloat 32
|
||||
%14 = OpTypeFloat 64
|
||||
%15 = OpTypeVector %4 2
|
||||
)";
|
||||
spv_text_t text = {textStr, strlen(textStr)};
|
||||
spv_diagnostic diagnostic = nullptr;
|
||||
spv_result_t error =
|
||||
spvTextToBinary(context, text.str, text.length, &binary, &diagnostic);
|
||||
spvDiagnosticPrint(diagnostic);
|
||||
spvDiagnosticDestroy(diagnostic);
|
||||
ASSERT_EQ(SPV_SUCCESS, error);
|
||||
}
|
||||
|
||||
virtual void TearDown() {
|
||||
spvBinaryDestroy(binary);
|
||||
binary = nullptr;
|
||||
}
|
||||
|
||||
// Compiles the given assembly text, and saves it into 'binary'.
|
||||
void CompileSuccessfully(std::string text) {
|
||||
spvBinaryDestroy(binary);
|
||||
binary = nullptr;
|
||||
spv_diagnostic diagnostic = nullptr;
|
||||
EXPECT_EQ(SPV_SUCCESS, spvTextToBinary(context, text.c_str(), text.size(),
|
||||
&binary, &diagnostic));
|
||||
}
|
||||
|
||||
spv_context context;
|
||||
spv_binary binary;
|
||||
};
|
||||
|
||||
TEST_F(BinaryToText, Default) {
|
||||
spv_text text = nullptr;
|
||||
spv_diagnostic diagnostic = nullptr;
|
||||
ASSERT_EQ(
|
||||
SPV_SUCCESS,
|
||||
spvBinaryToText(context, binary->code, binary->wordCount,
|
||||
SPV_BINARY_TO_TEXT_OPTION_NONE, &text, &diagnostic));
|
||||
printf("%s", text->str);
|
||||
spvTextDestroy(text);
|
||||
}
|
||||
|
||||
TEST_F(BinaryToText, MissingModule) {
|
||||
spv_text text;
|
||||
spv_diagnostic diagnostic = nullptr;
|
||||
EXPECT_EQ(
|
||||
SPV_ERROR_INVALID_BINARY,
|
||||
spvBinaryToText(context, nullptr, 42, SPV_BINARY_TO_TEXT_OPTION_NONE,
|
||||
&text, &diagnostic));
|
||||
EXPECT_THAT(diagnostic->error, Eq(std::string("Missing module.")));
|
||||
if (diagnostic) {
|
||||
spvDiagnosticPrint(diagnostic);
|
||||
spvDiagnosticDestroy(diagnostic);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(BinaryToText, TruncatedModule) {
|
||||
// Make a valid module with zero instructions.
|
||||
CompileSuccessfully("");
|
||||
EXPECT_EQ(SPV_INDEX_INSTRUCTION, binary->wordCount);
|
||||
|
||||
for (size_t length = 0; length < SPV_INDEX_INSTRUCTION; length++) {
|
||||
spv_text text = nullptr;
|
||||
spv_diagnostic diagnostic = nullptr;
|
||||
EXPECT_EQ(
|
||||
SPV_ERROR_INVALID_BINARY,
|
||||
spvBinaryToText(context, binary->code, length,
|
||||
SPV_BINARY_TO_TEXT_OPTION_NONE, &text, &diagnostic));
|
||||
ASSERT_NE(nullptr, diagnostic);
|
||||
std::stringstream expected;
|
||||
expected << "Module has incomplete header: only " << length
|
||||
<< " words instead of " << SPV_INDEX_INSTRUCTION;
|
||||
EXPECT_THAT(diagnostic->error, Eq(expected.str()));
|
||||
spvDiagnosticDestroy(diagnostic);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(BinaryToText, InvalidMagicNumber) {
|
||||
CompileSuccessfully("");
|
||||
std::vector<uint32_t> damaged_binary(binary->code,
|
||||
binary->code + binary->wordCount);
|
||||
damaged_binary[SPV_INDEX_MAGIC_NUMBER] ^= 123;
|
||||
|
||||
spv_diagnostic diagnostic = nullptr;
|
||||
spv_text text;
|
||||
EXPECT_EQ(
|
||||
SPV_ERROR_INVALID_BINARY,
|
||||
spvBinaryToText(context, damaged_binary.data(), damaged_binary.size(),
|
||||
SPV_BINARY_TO_TEXT_OPTION_NONE, &text, &diagnostic));
|
||||
ASSERT_NE(nullptr, diagnostic);
|
||||
std::stringstream expected;
|
||||
expected << "Invalid SPIR-V magic number '" << std::hex
|
||||
<< damaged_binary[SPV_INDEX_MAGIC_NUMBER] << "'.";
|
||||
EXPECT_THAT(diagnostic->error, Eq(expected.str()));
|
||||
spvDiagnosticDestroy(diagnostic);
|
||||
}
|
||||
|
||||
struct FailedDecodeCase {
|
||||
std::string source_text;
|
||||
std::vector<uint32_t> appended_instruction;
|
||||
std::string expected_error_message;
|
||||
};
|
||||
|
||||
using BinaryToTextFail =
|
||||
spvtest::TextToBinaryTestBase<::testing::TestWithParam<FailedDecodeCase>>;
|
||||
|
||||
TEST_P(BinaryToTextFail, EncodeSuccessfullyDecodeFailed) {
|
||||
EXPECT_THAT(EncodeSuccessfullyDecodeFailed(GetParam().source_text,
|
||||
GetParam().appended_instruction),
|
||||
Eq(GetParam().expected_error_message));
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
InvalidIds, BinaryToTextFail,
|
||||
::testing::ValuesIn(std::vector<FailedDecodeCase>{
|
||||
{"", spvtest::MakeInstruction(SpvOpTypeVoid, {0}),
|
||||
"Error: Result Id is 0"},
|
||||
{"", spvtest::MakeInstruction(SpvOpConstant, {0, 1, 42}),
|
||||
"Error: Type Id is 0"},
|
||||
{"%1 = OpTypeVoid", spvtest::MakeInstruction(SpvOpTypeVoid, {1}),
|
||||
"Id 1 is defined more than once"},
|
||||
{"%1 = OpTypeVoid\n"
|
||||
"%2 = OpNot %1 %foo",
|
||||
spvtest::MakeInstruction(SpvOpNot, {1, 2, 3}),
|
||||
"Id 2 is defined more than once"},
|
||||
{"%1 = OpTypeVoid\n"
|
||||
"%2 = OpNot %1 %foo",
|
||||
spvtest::MakeInstruction(SpvOpNot, {1, 1, 3}),
|
||||
"Id 1 is defined more than once"},
|
||||
// The following are the two failure cases for
|
||||
// Parser::setNumericTypeInfoForType.
|
||||
{"", spvtest::MakeInstruction(SpvOpConstant, {500, 1, 42}),
|
||||
"Type Id 500 is not a type"},
|
||||
{"%1 = OpTypeInt 32 0\n"
|
||||
"%2 = OpTypeVector %1 4",
|
||||
spvtest::MakeInstruction(SpvOpConstant, {2, 3, 999}),
|
||||
"Type Id 2 is not a scalar numeric type"},
|
||||
}));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
InvalidIdsCheckedDuringLiteralCaseParsing, BinaryToTextFail,
|
||||
::testing::ValuesIn(std::vector<FailedDecodeCase>{
|
||||
{"", spvtest::MakeInstruction(SpvOpSwitch, {1, 2, 3, 4}),
|
||||
"Invalid OpSwitch: selector id 1 has no type"},
|
||||
{"%1 = OpTypeVoid\n",
|
||||
spvtest::MakeInstruction(SpvOpSwitch, {1, 2, 3, 4}),
|
||||
"Invalid OpSwitch: selector id 1 is a type, not a value"},
|
||||
{"%1 = OpConstantTrue !500",
|
||||
spvtest::MakeInstruction(SpvOpSwitch, {1, 2, 3, 4}),
|
||||
"Type Id 500 is not a type"},
|
||||
{"%1 = OpTypeFloat 32\n%2 = OpConstant %1 1.5",
|
||||
spvtest::MakeInstruction(SpvOpSwitch, {2, 3, 4, 5}),
|
||||
"Invalid OpSwitch: selector id 2 is not a scalar integer"},
|
||||
}));
|
||||
|
||||
TEST_F(TextToBinaryTest, OneInstruction) {
|
||||
const std::string input = "OpSource OpenCL_C 12\n";
|
||||
EXPECT_EQ(input, EncodeAndDecodeSuccessfully(input));
|
||||
}
|
||||
|
||||
// Exercise the case where an operand itself has operands.
|
||||
// This could detect problems in updating the expected-set-of-operands
|
||||
// list.
|
||||
TEST_F(TextToBinaryTest, OperandWithOperands) {
|
||||
const std::string input = R"(OpEntryPoint Kernel %1 "foo"
|
||||
OpExecutionMode %1 LocalSizeHint 100 200 300
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%1 = OpFunction %1 None %3
|
||||
)";
|
||||
EXPECT_EQ(input, EncodeAndDecodeSuccessfully(input));
|
||||
}
|
||||
|
||||
using RoundTripInstructionsTest = spvtest::TextToBinaryTestBase<
|
||||
::testing::TestWithParam<std::tuple<spv_target_env, std::string>>>;
|
||||
|
||||
TEST_P(RoundTripInstructionsTest, Sample) {
|
||||
EXPECT_THAT(EncodeAndDecodeSuccessfully(std::get<1>(GetParam()),
|
||||
SPV_BINARY_TO_TEXT_OPTION_NONE,
|
||||
std::get<0>(GetParam())),
|
||||
Eq(std::get<1>(GetParam())));
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
NumericLiterals, RoundTripInstructionsTest,
|
||||
// This test is independent of environment, so just test the one.
|
||||
Combine(::testing::Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
|
||||
SPV_ENV_UNIVERSAL_1_2, SPV_ENV_UNIVERSAL_1_3),
|
||||
::testing::ValuesIn(std::vector<std::string>{
|
||||
"%1 = OpTypeInt 12 0\n%2 = OpConstant %1 1867\n",
|
||||
"%1 = OpTypeInt 12 1\n%2 = OpConstant %1 1867\n",
|
||||
"%1 = OpTypeInt 12 1\n%2 = OpConstant %1 -1867\n",
|
||||
"%1 = OpTypeInt 32 0\n%2 = OpConstant %1 1867\n",
|
||||
"%1 = OpTypeInt 32 1\n%2 = OpConstant %1 1867\n",
|
||||
"%1 = OpTypeInt 32 1\n%2 = OpConstant %1 -1867\n",
|
||||
"%1 = OpTypeInt 64 0\n%2 = OpConstant %1 18446744073709551615\n",
|
||||
"%1 = OpTypeInt 64 1\n%2 = OpConstant %1 9223372036854775807\n",
|
||||
"%1 = OpTypeInt 64 1\n%2 = OpConstant %1 -9223372036854775808\n",
|
||||
// 16-bit floats print as hex floats.
|
||||
"%1 = OpTypeFloat 16\n%2 = OpConstant %1 0x1.ff4p+16\n",
|
||||
"%1 = OpTypeFloat 16\n%2 = OpConstant %1 -0x1.d2cp-10\n",
|
||||
// 32-bit floats
|
||||
"%1 = OpTypeFloat 32\n%2 = OpConstant %1 -3.125\n",
|
||||
"%1 = OpTypeFloat 32\n%2 = OpConstant %1 0x1.8p+128\n", // NaN
|
||||
"%1 = OpTypeFloat 32\n%2 = OpConstant %1 -0x1.0002p+128\n", // NaN
|
||||
"%1 = OpTypeFloat 32\n%2 = OpConstant %1 0x1p+128\n", // Inf
|
||||
"%1 = OpTypeFloat 32\n%2 = OpConstant %1 -0x1p+128\n", // -Inf
|
||||
// 64-bit floats
|
||||
"%1 = OpTypeFloat 64\n%2 = OpConstant %1 -3.125\n",
|
||||
"%1 = OpTypeFloat 64\n%2 = OpConstant %1 0x1.ffffffffffffap-1023\n", // small normal
|
||||
"%1 = OpTypeFloat 64\n%2 = OpConstant %1 -0x1.ffffffffffffap-1023\n",
|
||||
"%1 = OpTypeFloat 64\n%2 = OpConstant %1 0x1.8p+1024\n", // NaN
|
||||
"%1 = OpTypeFloat 64\n%2 = OpConstant %1 -0x1.0002p+1024\n", // NaN
|
||||
"%1 = OpTypeFloat 64\n%2 = OpConstant %1 0x1p+1024\n", // Inf
|
||||
"%1 = OpTypeFloat 64\n%2 = OpConstant %1 -0x1p+1024\n", // -Inf
|
||||
})));
|
||||
// clang-format on
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
MemoryAccessMasks, RoundTripInstructionsTest,
|
||||
Combine(::testing::Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
|
||||
SPV_ENV_UNIVERSAL_1_2, SPV_ENV_UNIVERSAL_1_3),
|
||||
::testing::ValuesIn(std::vector<std::string>{
|
||||
"OpStore %1 %2\n", // 3 words long.
|
||||
"OpStore %1 %2 None\n", // 4 words long, explicit final 0.
|
||||
"OpStore %1 %2 Volatile\n",
|
||||
"OpStore %1 %2 Aligned 8\n",
|
||||
"OpStore %1 %2 Nontemporal\n",
|
||||
// Combinations show the names from LSB to MSB
|
||||
"OpStore %1 %2 Volatile|Aligned 16\n",
|
||||
"OpStore %1 %2 Volatile|Nontemporal\n",
|
||||
"OpStore %1 %2 Volatile|Aligned|Nontemporal 32\n",
|
||||
})));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
FPFastMathModeMasks, RoundTripInstructionsTest,
|
||||
Combine(
|
||||
::testing::Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
|
||||
SPV_ENV_UNIVERSAL_1_2, SPV_ENV_UNIVERSAL_1_3),
|
||||
::testing::ValuesIn(std::vector<std::string>{
|
||||
"OpDecorate %1 FPFastMathMode None\n",
|
||||
"OpDecorate %1 FPFastMathMode NotNaN\n",
|
||||
"OpDecorate %1 FPFastMathMode NotInf\n",
|
||||
"OpDecorate %1 FPFastMathMode NSZ\n",
|
||||
"OpDecorate %1 FPFastMathMode AllowRecip\n",
|
||||
"OpDecorate %1 FPFastMathMode Fast\n",
|
||||
// Combinations show the names from LSB to MSB
|
||||
"OpDecorate %1 FPFastMathMode NotNaN|NotInf\n",
|
||||
"OpDecorate %1 FPFastMathMode NSZ|AllowRecip\n",
|
||||
"OpDecorate %1 FPFastMathMode NotNaN|NotInf|NSZ|AllowRecip|Fast\n",
|
||||
})));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
LoopControlMasks, RoundTripInstructionsTest,
|
||||
Combine(::testing::Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
|
||||
SPV_ENV_UNIVERSAL_1_3, SPV_ENV_UNIVERSAL_1_2),
|
||||
::testing::ValuesIn(std::vector<std::string>{
|
||||
"OpLoopMerge %1 %2 None\n",
|
||||
"OpLoopMerge %1 %2 Unroll\n",
|
||||
"OpLoopMerge %1 %2 DontUnroll\n",
|
||||
"OpLoopMerge %1 %2 Unroll|DontUnroll\n",
|
||||
})));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(LoopControlMasksV11, RoundTripInstructionsTest,
|
||||
Combine(::testing::Values(SPV_ENV_UNIVERSAL_1_1,
|
||||
SPV_ENV_UNIVERSAL_1_2,
|
||||
SPV_ENV_UNIVERSAL_1_3),
|
||||
::testing::ValuesIn(std::vector<std::string>{
|
||||
"OpLoopMerge %1 %2 DependencyInfinite\n",
|
||||
"OpLoopMerge %1 %2 DependencyLength 8\n",
|
||||
})));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
SelectionControlMasks, RoundTripInstructionsTest,
|
||||
Combine(::testing::Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
|
||||
SPV_ENV_UNIVERSAL_1_3, SPV_ENV_UNIVERSAL_1_2),
|
||||
::testing::ValuesIn(std::vector<std::string>{
|
||||
"OpSelectionMerge %1 None\n",
|
||||
"OpSelectionMerge %1 Flatten\n",
|
||||
"OpSelectionMerge %1 DontFlatten\n",
|
||||
"OpSelectionMerge %1 Flatten|DontFlatten\n",
|
||||
})));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
FunctionControlMasks, RoundTripInstructionsTest,
|
||||
Combine(::testing::Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
|
||||
SPV_ENV_UNIVERSAL_1_2, SPV_ENV_UNIVERSAL_1_3),
|
||||
::testing::ValuesIn(std::vector<std::string>{
|
||||
"%2 = OpFunction %1 None %3\n",
|
||||
"%2 = OpFunction %1 Inline %3\n",
|
||||
"%2 = OpFunction %1 DontInline %3\n",
|
||||
"%2 = OpFunction %1 Pure %3\n",
|
||||
"%2 = OpFunction %1 Const %3\n",
|
||||
"%2 = OpFunction %1 Inline|Pure|Const %3\n",
|
||||
"%2 = OpFunction %1 DontInline|Const %3\n",
|
||||
})));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
ImageMasks, RoundTripInstructionsTest,
|
||||
Combine(::testing::Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
|
||||
SPV_ENV_UNIVERSAL_1_2, SPV_ENV_UNIVERSAL_1_3),
|
||||
::testing::ValuesIn(std::vector<std::string>{
|
||||
"%2 = OpImageFetch %1 %3 %4\n",
|
||||
"%2 = OpImageFetch %1 %3 %4 None\n",
|
||||
"%2 = OpImageFetch %1 %3 %4 Bias %5\n",
|
||||
"%2 = OpImageFetch %1 %3 %4 Lod %5\n",
|
||||
"%2 = OpImageFetch %1 %3 %4 Grad %5 %6\n",
|
||||
"%2 = OpImageFetch %1 %3 %4 ConstOffset %5\n",
|
||||
"%2 = OpImageFetch %1 %3 %4 Offset %5\n",
|
||||
"%2 = OpImageFetch %1 %3 %4 ConstOffsets %5\n",
|
||||
"%2 = OpImageFetch %1 %3 %4 Sample %5\n",
|
||||
"%2 = OpImageFetch %1 %3 %4 MinLod %5\n",
|
||||
"%2 = OpImageFetch %1 %3 %4 Bias|Lod|Grad %5 %6 %7 %8\n",
|
||||
"%2 = OpImageFetch %1 %3 %4 ConstOffset|Offset|ConstOffsets"
|
||||
" %5 %6 %7\n",
|
||||
"%2 = OpImageFetch %1 %3 %4 Sample|MinLod %5 %6\n",
|
||||
"%2 = OpImageFetch %1 %3 %4"
|
||||
" Bias|Lod|Grad|ConstOffset|Offset|ConstOffsets|Sample|MinLod"
|
||||
" %5 %6 %7 %8 %9 %10 %11 %12 %13\n"})));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
NewInstructionsInSPIRV1_2, RoundTripInstructionsTest,
|
||||
Combine(::testing::Values(SPV_ENV_UNIVERSAL_1_2, SPV_ENV_UNIVERSAL_1_3),
|
||||
::testing::ValuesIn(std::vector<std::string>{
|
||||
"OpExecutionModeId %1 SubgroupsPerWorkgroupId %2\n",
|
||||
"OpExecutionModeId %1 LocalSizeId %2 %3 %4\n",
|
||||
"OpExecutionModeId %1 LocalSizeHintId %2\n",
|
||||
"OpDecorateId %1 AlignmentId %2\n",
|
||||
"OpDecorateId %1 MaxByteOffsetId %2\n",
|
||||
})));
|
||||
|
||||
using MaskSorting = TextToBinaryTest;
|
||||
|
||||
TEST_F(MaskSorting, MasksAreSortedFromLSBToMSB) {
|
||||
EXPECT_THAT(EncodeAndDecodeSuccessfully(
|
||||
"OpStore %1 %2 Nontemporal|Aligned|Volatile 32"),
|
||||
Eq("OpStore %1 %2 Volatile|Aligned|Nontemporal 32\n"));
|
||||
EXPECT_THAT(
|
||||
EncodeAndDecodeSuccessfully(
|
||||
"OpDecorate %1 FPFastMathMode NotInf|Fast|AllowRecip|NotNaN|NSZ"),
|
||||
Eq("OpDecorate %1 FPFastMathMode NotNaN|NotInf|NSZ|AllowRecip|Fast\n"));
|
||||
EXPECT_THAT(
|
||||
EncodeAndDecodeSuccessfully("OpLoopMerge %1 %2 DontUnroll|Unroll"),
|
||||
Eq("OpLoopMerge %1 %2 Unroll|DontUnroll\n"));
|
||||
EXPECT_THAT(
|
||||
EncodeAndDecodeSuccessfully("OpSelectionMerge %1 DontFlatten|Flatten"),
|
||||
Eq("OpSelectionMerge %1 Flatten|DontFlatten\n"));
|
||||
EXPECT_THAT(EncodeAndDecodeSuccessfully(
|
||||
"%2 = OpFunction %1 DontInline|Const|Pure|Inline %3"),
|
||||
Eq("%2 = OpFunction %1 Inline|DontInline|Pure|Const %3\n"));
|
||||
EXPECT_THAT(EncodeAndDecodeSuccessfully(
|
||||
"%2 = OpImageFetch %1 %3 %4"
|
||||
" MinLod|Sample|Offset|Lod|Grad|ConstOffsets|ConstOffset|Bias"
|
||||
" %5 %6 %7 %8 %9 %10 %11 %12 %13\n"),
|
||||
Eq("%2 = OpImageFetch %1 %3 %4"
|
||||
" Bias|Lod|Grad|ConstOffset|Offset|ConstOffsets|Sample|MinLod"
|
||||
" %5 %6 %7 %8 %9 %10 %11 %12 %13\n"));
|
||||
}
|
||||
|
||||
using OperandTypeTest = TextToBinaryTest;
|
||||
|
||||
TEST_F(OperandTypeTest, OptionalTypedLiteralNumber) {
|
||||
const std::string input =
|
||||
"%1 = OpTypeInt 32 0\n"
|
||||
"%2 = OpConstant %1 42\n"
|
||||
"OpSwitch %2 %3 100 %4\n";
|
||||
EXPECT_EQ(input, EncodeAndDecodeSuccessfully(input));
|
||||
}
|
||||
|
||||
using IndentTest = spvtest::TextToBinaryTest;
|
||||
|
||||
TEST_F(IndentTest, Sample) {
|
||||
const std::string input = R"(
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
%1 = OpTypeInt 32 0
|
||||
%2 = OpTypeStruct %1 %3 %4 %5 %6 %7 %8 %9 %10 ; force IDs into double digits
|
||||
%11 = OpConstant %1 42
|
||||
OpStore %2 %3 Aligned|Volatile 4 ; bogus, but not indented
|
||||
)";
|
||||
const std::string expected =
|
||||
R"( OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
%1 = OpTypeInt 32 0
|
||||
%2 = OpTypeStruct %1 %3 %4 %5 %6 %7 %8 %9 %10
|
||||
%11 = OpConstant %1 42
|
||||
OpStore %2 %3 Volatile|Aligned 4
|
||||
)";
|
||||
EXPECT_THAT(
|
||||
EncodeAndDecodeSuccessfully(input, SPV_BINARY_TO_TEXT_OPTION_INDENT),
|
||||
expected);
|
||||
}
|
||||
|
||||
using FriendlyNameDisassemblyTest = spvtest::TextToBinaryTest;
|
||||
|
||||
TEST_F(FriendlyNameDisassemblyTest, Sample) {
|
||||
const std::string input = R"(
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
%1 = OpTypeInt 32 0
|
||||
%2 = OpTypeStruct %1 %3 %4 %5 %6 %7 %8 %9 %10 ; force IDs into double digits
|
||||
%11 = OpConstant %1 42
|
||||
)";
|
||||
const std::string expected =
|
||||
R"(OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
%uint = OpTypeInt 32 0
|
||||
%_struct_2 = OpTypeStruct %uint %3 %4 %5 %6 %7 %8 %9 %10
|
||||
%uint_42 = OpConstant %uint 42
|
||||
)";
|
||||
EXPECT_THAT(EncodeAndDecodeSuccessfully(
|
||||
input, SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES),
|
||||
expected);
|
||||
}
|
||||
|
||||
TEST_F(TextToBinaryTest, ShowByteOffsetsWhenRequested) {
|
||||
const std::string input = R"(
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
%1 = OpTypeInt 32 0
|
||||
%2 = OpTypeVoid
|
||||
)";
|
||||
const std::string expected =
|
||||
R"(OpCapability Shader ; 0x00000014
|
||||
OpMemoryModel Logical GLSL450 ; 0x0000001c
|
||||
%1 = OpTypeInt 32 0 ; 0x00000028
|
||||
%2 = OpTypeVoid ; 0x00000038
|
||||
)";
|
||||
EXPECT_THAT(EncodeAndDecodeSuccessfully(
|
||||
input, SPV_BINARY_TO_TEXT_OPTION_SHOW_BYTE_OFFSET),
|
||||
expected);
|
||||
}
|
||||
|
||||
// Test version string.
|
||||
TEST_F(TextToBinaryTest, VersionString) {
|
||||
auto words = CompileSuccessfully("");
|
||||
spv_text decoded_text = nullptr;
|
||||
EXPECT_THAT(spvBinaryToText(ScopedContext().context, words.data(),
|
||||
words.size(), SPV_BINARY_TO_TEXT_OPTION_NONE,
|
||||
&decoded_text, &diagnostic),
|
||||
Eq(SPV_SUCCESS));
|
||||
EXPECT_EQ(nullptr, diagnostic);
|
||||
|
||||
EXPECT_THAT(decoded_text->str, HasSubstr("Version: 1.0\n"))
|
||||
<< EncodeAndDecodeSuccessfully("");
|
||||
spvTextDestroy(decoded_text);
|
||||
}
|
||||
|
||||
// Test generator string.
|
||||
|
||||
// A test case for the generator string. This allows us to
|
||||
// test both of the 16-bit components of the generator word.
|
||||
struct GeneratorStringCase {
|
||||
uint16_t generator;
|
||||
uint16_t misc;
|
||||
std::string expected;
|
||||
};
|
||||
|
||||
using GeneratorStringTest = spvtest::TextToBinaryTestBase<
|
||||
::testing::TestWithParam<GeneratorStringCase>>;
|
||||
|
||||
TEST_P(GeneratorStringTest, Sample) {
|
||||
auto words = CompileSuccessfully("");
|
||||
EXPECT_EQ(2u, SPV_INDEX_GENERATOR_NUMBER);
|
||||
words[SPV_INDEX_GENERATOR_NUMBER] =
|
||||
SPV_GENERATOR_WORD(GetParam().generator, GetParam().misc);
|
||||
|
||||
spv_text decoded_text = nullptr;
|
||||
EXPECT_THAT(spvBinaryToText(ScopedContext().context, words.data(),
|
||||
words.size(), SPV_BINARY_TO_TEXT_OPTION_NONE,
|
||||
&decoded_text, &diagnostic),
|
||||
Eq(SPV_SUCCESS));
|
||||
EXPECT_THAT(diagnostic, Eq(nullptr));
|
||||
EXPECT_THAT(std::string(decoded_text->str), HasSubstr(GetParam().expected));
|
||||
spvTextDestroy(decoded_text);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(GeneratorStrings, GeneratorStringTest,
|
||||
::testing::ValuesIn(std::vector<GeneratorStringCase>{
|
||||
{SPV_GENERATOR_KHRONOS, 12, "Khronos; 12"},
|
||||
{SPV_GENERATOR_LUNARG, 99, "LunarG; 99"},
|
||||
{SPV_GENERATOR_VALVE, 1, "Valve; 1"},
|
||||
{SPV_GENERATOR_CODEPLAY, 65535, "Codeplay; 65535"},
|
||||
{SPV_GENERATOR_NVIDIA, 19, "NVIDIA; 19"},
|
||||
{SPV_GENERATOR_ARM, 1000, "ARM; 1000"},
|
||||
{SPV_GENERATOR_KHRONOS_LLVM_TRANSLATOR, 38,
|
||||
"Khronos LLVM/SPIR-V Translator; 38"},
|
||||
{SPV_GENERATOR_KHRONOS_ASSEMBLER, 2,
|
||||
"Khronos SPIR-V Tools Assembler; 2"},
|
||||
{SPV_GENERATOR_KHRONOS_GLSLANG, 1,
|
||||
"Khronos Glslang Reference Front End; 1"},
|
||||
{1000, 18, "Unknown(1000); 18"},
|
||||
{65535, 32767, "Unknown(65535); 32767"},
|
||||
}));
|
||||
|
||||
// TODO(dneto): Test new instructions and enums in SPIR-V 1.3
|
||||
|
||||
} // namespace
|
||||
} // namespace spvtools
|
||||
299
3rdparty/spirv-tools/test/c_interface_test.cpp
vendored
299
3rdparty/spirv-tools/test/c_interface_test.cpp
vendored
@@ -1,299 +0,0 @@
|
||||
// Copyright (c) 2016 Google Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "source/table.h"
|
||||
#include "spirv-tools/libspirv.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace {
|
||||
|
||||
// TODO(antiagainst): Use public C API for setting the consumer once exists.
|
||||
#ifndef SPIRV_TOOLS_SHAREDLIB
|
||||
void SetContextMessageConsumer(spv_context context, MessageConsumer consumer) {
|
||||
spvtools::SetContextMessageConsumer(context, consumer);
|
||||
}
|
||||
#else
|
||||
void SetContextMessageConsumer(spv_context, MessageConsumer) {}
|
||||
#endif
|
||||
|
||||
// The default consumer is a null std::function.
|
||||
TEST(CInterface, DefaultConsumerNullDiagnosticForValidInput) {
|
||||
auto context = spvContextCreate(SPV_ENV_UNIVERSAL_1_1);
|
||||
const char input_text[] =
|
||||
"OpCapability Shader\n"
|
||||
"OpCapability Linkage\n"
|
||||
"OpMemoryModel Logical GLSL450";
|
||||
|
||||
spv_binary binary = nullptr;
|
||||
EXPECT_EQ(SPV_SUCCESS, spvTextToBinary(context, input_text,
|
||||
sizeof(input_text), &binary, nullptr));
|
||||
|
||||
{
|
||||
// Sadly the compiler don't allow me to feed binary directly to
|
||||
// spvValidate().
|
||||
spv_const_binary_t b{binary->code, binary->wordCount};
|
||||
EXPECT_EQ(SPV_SUCCESS, spvValidate(context, &b, nullptr));
|
||||
}
|
||||
|
||||
spv_text text = nullptr;
|
||||
EXPECT_EQ(SPV_SUCCESS, spvBinaryToText(context, binary->code,
|
||||
binary->wordCount, 0, &text, nullptr));
|
||||
|
||||
spvTextDestroy(text);
|
||||
spvBinaryDestroy(binary);
|
||||
spvContextDestroy(context);
|
||||
}
|
||||
|
||||
// The default consumer is a null std::function.
|
||||
TEST(CInterface, DefaultConsumerNullDiagnosticForInvalidAssembling) {
|
||||
auto context = spvContextCreate(SPV_ENV_UNIVERSAL_1_1);
|
||||
const char input_text[] = "%1 = OpName";
|
||||
|
||||
spv_binary binary = nullptr;
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_TEXT,
|
||||
spvTextToBinary(context, input_text, sizeof(input_text), &binary,
|
||||
nullptr));
|
||||
spvBinaryDestroy(binary);
|
||||
spvContextDestroy(context);
|
||||
}
|
||||
|
||||
// The default consumer is a null std::function.
|
||||
TEST(CInterface, DefaultConsumerNullDiagnosticForInvalidDiassembling) {
|
||||
auto context = spvContextCreate(SPV_ENV_UNIVERSAL_1_1);
|
||||
const char input_text[] = "OpNop";
|
||||
|
||||
spv_binary binary = nullptr;
|
||||
ASSERT_EQ(SPV_SUCCESS, spvTextToBinary(context, input_text,
|
||||
sizeof(input_text), &binary, nullptr));
|
||||
// Change OpNop to an invalid (wordcount|opcode) word.
|
||||
binary->code[binary->wordCount - 1] = 0xffffffff;
|
||||
|
||||
spv_text text = nullptr;
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_BINARY,
|
||||
spvBinaryToText(context, binary->code, binary->wordCount, 0, &text,
|
||||
nullptr));
|
||||
|
||||
spvTextDestroy(text);
|
||||
spvBinaryDestroy(binary);
|
||||
spvContextDestroy(context);
|
||||
}
|
||||
|
||||
// The default consumer is a null std::function.
|
||||
TEST(CInterface, DefaultConsumerNullDiagnosticForInvalidValidating) {
|
||||
auto context = spvContextCreate(SPV_ENV_UNIVERSAL_1_1);
|
||||
const char input_text[] = "OpNop";
|
||||
|
||||
spv_binary binary = nullptr;
|
||||
ASSERT_EQ(SPV_SUCCESS, spvTextToBinary(context, input_text,
|
||||
sizeof(input_text), &binary, nullptr));
|
||||
|
||||
spv_const_binary_t b{binary->code, binary->wordCount};
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_LAYOUT, spvValidate(context, &b, nullptr));
|
||||
|
||||
spvBinaryDestroy(binary);
|
||||
spvContextDestroy(context);
|
||||
}
|
||||
|
||||
TEST(CInterface, SpecifyConsumerNullDiagnosticForAssembling) {
|
||||
const char input_text[] = " OpName\n";
|
||||
|
||||
auto context = spvContextCreate(SPV_ENV_UNIVERSAL_1_1);
|
||||
int invocation = 0;
|
||||
SetContextMessageConsumer(
|
||||
context,
|
||||
[&invocation](spv_message_level_t level, const char* source,
|
||||
const spv_position_t& position, const char* message) {
|
||||
++invocation;
|
||||
EXPECT_EQ(SPV_MSG_ERROR, level);
|
||||
// The error happens at scanning the begining of second line.
|
||||
EXPECT_STREQ("input", source);
|
||||
EXPECT_EQ(1u, position.line);
|
||||
EXPECT_EQ(0u, position.column);
|
||||
EXPECT_EQ(12u, position.index);
|
||||
EXPECT_STREQ("Expected operand, found end of stream.", message);
|
||||
});
|
||||
|
||||
spv_binary binary = nullptr;
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_TEXT,
|
||||
spvTextToBinary(context, input_text, sizeof(input_text), &binary,
|
||||
nullptr));
|
||||
#ifndef SPIRV_TOOLS_SHAREDLIB
|
||||
EXPECT_EQ(1, invocation);
|
||||
#endif
|
||||
spvBinaryDestroy(binary);
|
||||
spvContextDestroy(context);
|
||||
}
|
||||
|
||||
TEST(CInterface, SpecifyConsumerNullDiagnosticForDisassembling) {
|
||||
const char input_text[] = "OpNop";
|
||||
|
||||
auto context = spvContextCreate(SPV_ENV_UNIVERSAL_1_1);
|
||||
int invocation = 0;
|
||||
SetContextMessageConsumer(
|
||||
context,
|
||||
[&invocation](spv_message_level_t level, const char* source,
|
||||
const spv_position_t& position, const char* message) {
|
||||
++invocation;
|
||||
EXPECT_EQ(SPV_MSG_ERROR, level);
|
||||
EXPECT_STREQ("input", source);
|
||||
EXPECT_EQ(0u, position.line);
|
||||
EXPECT_EQ(0u, position.column);
|
||||
EXPECT_EQ(1u, position.index);
|
||||
EXPECT_STREQ("Invalid opcode: 65535", message);
|
||||
});
|
||||
|
||||
spv_binary binary = nullptr;
|
||||
ASSERT_EQ(SPV_SUCCESS, spvTextToBinary(context, input_text,
|
||||
sizeof(input_text), &binary, nullptr));
|
||||
// Change OpNop to an invalid (wordcount|opcode) word.
|
||||
binary->code[binary->wordCount - 1] = 0xffffffff;
|
||||
|
||||
spv_text text = nullptr;
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_BINARY,
|
||||
spvBinaryToText(context, binary->code, binary->wordCount, 0, &text,
|
||||
nullptr));
|
||||
#ifndef SPIRV_TOOLS_SHAREDLIB
|
||||
EXPECT_EQ(1, invocation);
|
||||
#endif
|
||||
|
||||
spvTextDestroy(text);
|
||||
spvBinaryDestroy(binary);
|
||||
spvContextDestroy(context);
|
||||
}
|
||||
|
||||
TEST(CInterface, SpecifyConsumerNullDiagnosticForValidating) {
|
||||
const char input_text[] = "OpNop";
|
||||
|
||||
auto context = spvContextCreate(SPV_ENV_UNIVERSAL_1_1);
|
||||
int invocation = 0;
|
||||
SetContextMessageConsumer(
|
||||
context,
|
||||
[&invocation](spv_message_level_t level, const char* source,
|
||||
const spv_position_t& position, const char* message) {
|
||||
++invocation;
|
||||
EXPECT_EQ(SPV_MSG_ERROR, level);
|
||||
EXPECT_STREQ("input", source);
|
||||
EXPECT_EQ(0u, position.line);
|
||||
EXPECT_EQ(0u, position.column);
|
||||
// TODO(antiagainst): what validation reports is not a word offset here.
|
||||
// It is inconsistent with diassembler. Should be fixed.
|
||||
EXPECT_EQ(1u, position.index);
|
||||
EXPECT_STREQ(
|
||||
"Nop cannot appear before the memory model instruction\n"
|
||||
" OpNop\n",
|
||||
message);
|
||||
});
|
||||
|
||||
spv_binary binary = nullptr;
|
||||
ASSERT_EQ(SPV_SUCCESS, spvTextToBinary(context, input_text,
|
||||
sizeof(input_text), &binary, nullptr));
|
||||
|
||||
spv_const_binary_t b{binary->code, binary->wordCount};
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_LAYOUT, spvValidate(context, &b, nullptr));
|
||||
#ifndef SPIRV_TOOLS_SHAREDLIB
|
||||
EXPECT_EQ(1, invocation);
|
||||
#endif
|
||||
|
||||
spvBinaryDestroy(binary);
|
||||
spvContextDestroy(context);
|
||||
}
|
||||
|
||||
// When having both a consumer and an diagnostic object, the diagnostic object
|
||||
// should take priority.
|
||||
TEST(CInterface, SpecifyConsumerSpecifyDiagnosticForAssembling) {
|
||||
const char input_text[] = " OpName";
|
||||
|
||||
auto context = spvContextCreate(SPV_ENV_UNIVERSAL_1_1);
|
||||
int invocation = 0;
|
||||
SetContextMessageConsumer(
|
||||
context,
|
||||
[&invocation](spv_message_level_t, const char*, const spv_position_t&,
|
||||
const char*) { ++invocation; });
|
||||
|
||||
spv_binary binary = nullptr;
|
||||
spv_diagnostic diagnostic = nullptr;
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_TEXT,
|
||||
spvTextToBinary(context, input_text, sizeof(input_text), &binary,
|
||||
&diagnostic));
|
||||
EXPECT_EQ(0, invocation); // Consumer should not be invoked at all.
|
||||
EXPECT_STREQ("Expected operand, found end of stream.", diagnostic->error);
|
||||
|
||||
spvDiagnosticDestroy(diagnostic);
|
||||
spvBinaryDestroy(binary);
|
||||
spvContextDestroy(context);
|
||||
}
|
||||
|
||||
TEST(CInterface, SpecifyConsumerSpecifyDiagnosticForDisassembling) {
|
||||
const char input_text[] = "OpNop";
|
||||
|
||||
auto context = spvContextCreate(SPV_ENV_UNIVERSAL_1_1);
|
||||
int invocation = 0;
|
||||
SetContextMessageConsumer(
|
||||
context,
|
||||
[&invocation](spv_message_level_t, const char*, const spv_position_t&,
|
||||
const char*) { ++invocation; });
|
||||
|
||||
spv_binary binary = nullptr;
|
||||
ASSERT_EQ(SPV_SUCCESS, spvTextToBinary(context, input_text,
|
||||
sizeof(input_text), &binary, nullptr));
|
||||
// Change OpNop to an invalid (wordcount|opcode) word.
|
||||
binary->code[binary->wordCount - 1] = 0xffffffff;
|
||||
|
||||
spv_diagnostic diagnostic = nullptr;
|
||||
spv_text text = nullptr;
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_BINARY,
|
||||
spvBinaryToText(context, binary->code, binary->wordCount, 0, &text,
|
||||
&diagnostic));
|
||||
|
||||
EXPECT_EQ(0, invocation); // Consumer should not be invoked at all.
|
||||
EXPECT_STREQ("Invalid opcode: 65535", diagnostic->error);
|
||||
|
||||
spvTextDestroy(text);
|
||||
spvDiagnosticDestroy(diagnostic);
|
||||
spvBinaryDestroy(binary);
|
||||
spvContextDestroy(context);
|
||||
}
|
||||
|
||||
TEST(CInterface, SpecifyConsumerSpecifyDiagnosticForValidating) {
|
||||
const char input_text[] = "OpNop";
|
||||
|
||||
auto context = spvContextCreate(SPV_ENV_UNIVERSAL_1_1);
|
||||
int invocation = 0;
|
||||
SetContextMessageConsumer(
|
||||
context,
|
||||
[&invocation](spv_message_level_t, const char*, const spv_position_t&,
|
||||
const char*) { ++invocation; });
|
||||
|
||||
spv_binary binary = nullptr;
|
||||
ASSERT_EQ(SPV_SUCCESS, spvTextToBinary(context, input_text,
|
||||
sizeof(input_text), &binary, nullptr));
|
||||
|
||||
spv_diagnostic diagnostic = nullptr;
|
||||
spv_const_binary_t b{binary->code, binary->wordCount};
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_LAYOUT, spvValidate(context, &b, &diagnostic));
|
||||
|
||||
EXPECT_EQ(0, invocation); // Consumer should not be invoked at all.
|
||||
EXPECT_STREQ(
|
||||
"Nop cannot appear before the memory model instruction\n"
|
||||
" OpNop\n",
|
||||
diagnostic->error);
|
||||
|
||||
spvDiagnosticDestroy(diagnostic);
|
||||
spvBinaryDestroy(binary);
|
||||
spvContextDestroy(context);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace spvtools
|
||||
51
3rdparty/spirv-tools/test/comment_test.cpp
vendored
51
3rdparty/spirv-tools/test/comment_test.cpp
vendored
@@ -1,51 +0,0 @@
|
||||
// Copyright (c) 2015-2016 The Khronos Group Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "source/util/string_utils.h"
|
||||
#include "test/test_fixture.h"
|
||||
#include "test/unit_spirv.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace {
|
||||
|
||||
using spvtest::Concatenate;
|
||||
using spvtest::MakeInstruction;
|
||||
using utils::MakeVector;
|
||||
using spvtest::TextToBinaryTest;
|
||||
using testing::Eq;
|
||||
|
||||
TEST_F(TextToBinaryTest, Whitespace) {
|
||||
std::string input = R"(
|
||||
; I'm a proud comment at the beginning of the file
|
||||
; I hide: OpCapability Shader
|
||||
OpMemoryModel Logical Simple ; comment after instruction
|
||||
;;;;;;;; many ;'s
|
||||
%glsl450 = OpExtInstImport "GLSL.std.450"
|
||||
; comment indented
|
||||
)";
|
||||
|
||||
EXPECT_THAT(
|
||||
CompiledInstructions(input),
|
||||
Eq(Concatenate({MakeInstruction(SpvOpMemoryModel,
|
||||
{uint32_t(SpvAddressingModelLogical),
|
||||
uint32_t(SpvMemoryModelSimple)}),
|
||||
MakeInstruction(SpvOpExtInstImport, {1},
|
||||
MakeVector("GLSL.std.450"))})));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace spvtools
|
||||
328
3rdparty/spirv-tools/test/cpp_interface_test.cpp
vendored
328
3rdparty/spirv-tools/test/cpp_interface_test.cpp
vendored
@@ -1,328 +0,0 @@
|
||||
// Copyright (c) 2016 Google Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "spirv-tools/optimizer.hpp"
|
||||
#include "spirv/1.1/spirv.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace {
|
||||
|
||||
using ::testing::ContainerEq;
|
||||
using ::testing::HasSubstr;
|
||||
|
||||
// Return a string that contains the minimum instructions needed to form
|
||||
// a valid module. Other instructions can be appended to this string.
|
||||
std::string Header() {
|
||||
return R"(OpCapability Shader
|
||||
OpCapability Linkage
|
||||
OpMemoryModel Logical GLSL450
|
||||
)";
|
||||
}
|
||||
|
||||
// When we assemble with a target environment of SPIR-V 1.1, we expect
|
||||
// the following in the module header version word.
|
||||
const uint32_t kExpectedSpvVersion = 0x10100;
|
||||
|
||||
TEST(CppInterface, SuccessfulRoundTrip) {
|
||||
const std::string input_text = "%2 = OpSizeOf %1 %3\n";
|
||||
SpirvTools t(SPV_ENV_UNIVERSAL_1_1);
|
||||
|
||||
std::vector<uint32_t> binary;
|
||||
EXPECT_TRUE(t.Assemble(input_text, &binary));
|
||||
EXPECT_TRUE(binary.size() > 5u);
|
||||
EXPECT_EQ(SpvMagicNumber, binary[0]);
|
||||
EXPECT_EQ(kExpectedSpvVersion, binary[1]);
|
||||
|
||||
// This cannot pass validation since %1 is not defined.
|
||||
t.SetMessageConsumer([](spv_message_level_t level, const char* source,
|
||||
const spv_position_t& position, const char* message) {
|
||||
EXPECT_EQ(SPV_MSG_ERROR, level);
|
||||
EXPECT_STREQ("input", source);
|
||||
EXPECT_EQ(0u, position.line);
|
||||
EXPECT_EQ(0u, position.column);
|
||||
EXPECT_EQ(1u, position.index);
|
||||
EXPECT_STREQ("ID 1[%1] has not been defined\n %2 = OpSizeOf %1 %3\n",
|
||||
message);
|
||||
});
|
||||
EXPECT_FALSE(t.Validate(binary));
|
||||
|
||||
std::string output_text;
|
||||
EXPECT_TRUE(t.Disassemble(binary, &output_text));
|
||||
EXPECT_EQ(input_text, output_text);
|
||||
}
|
||||
|
||||
TEST(CppInterface, AssembleEmptyModule) {
|
||||
std::vector<uint32_t> binary(10, 42);
|
||||
SpirvTools t(SPV_ENV_UNIVERSAL_1_1);
|
||||
EXPECT_TRUE(t.Assemble("", &binary));
|
||||
// We only have the header.
|
||||
EXPECT_EQ(5u, binary.size());
|
||||
EXPECT_EQ(SpvMagicNumber, binary[0]);
|
||||
EXPECT_EQ(kExpectedSpvVersion, binary[1]);
|
||||
}
|
||||
|
||||
TEST(CppInterface, AssembleOverloads) {
|
||||
const std::string input_text = "%2 = OpSizeOf %1 %3\n";
|
||||
SpirvTools t(SPV_ENV_UNIVERSAL_1_1);
|
||||
{
|
||||
std::vector<uint32_t> binary;
|
||||
EXPECT_TRUE(t.Assemble(input_text, &binary));
|
||||
EXPECT_TRUE(binary.size() > 5u);
|
||||
EXPECT_EQ(SpvMagicNumber, binary[0]);
|
||||
EXPECT_EQ(kExpectedSpvVersion, binary[1]);
|
||||
}
|
||||
{
|
||||
std::vector<uint32_t> binary;
|
||||
EXPECT_TRUE(t.Assemble(input_text.data(), input_text.size(), &binary));
|
||||
EXPECT_TRUE(binary.size() > 5u);
|
||||
EXPECT_EQ(SpvMagicNumber, binary[0]);
|
||||
EXPECT_EQ(kExpectedSpvVersion, binary[1]);
|
||||
}
|
||||
{ // Ignore the last newline.
|
||||
std::vector<uint32_t> binary;
|
||||
EXPECT_TRUE(t.Assemble(input_text.data(), input_text.size() - 1, &binary));
|
||||
EXPECT_TRUE(binary.size() > 5u);
|
||||
EXPECT_EQ(SpvMagicNumber, binary[0]);
|
||||
EXPECT_EQ(kExpectedSpvVersion, binary[1]);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(CppInterface, DisassembleEmptyModule) {
|
||||
std::string text(10, 'x');
|
||||
SpirvTools t(SPV_ENV_UNIVERSAL_1_1);
|
||||
int invocation_count = 0;
|
||||
t.SetMessageConsumer(
|
||||
[&invocation_count](spv_message_level_t level, const char* source,
|
||||
const spv_position_t& position, const char* message) {
|
||||
++invocation_count;
|
||||
EXPECT_EQ(SPV_MSG_ERROR, level);
|
||||
EXPECT_STREQ("input", source);
|
||||
EXPECT_EQ(0u, position.line);
|
||||
EXPECT_EQ(0u, position.column);
|
||||
EXPECT_EQ(0u, position.index);
|
||||
EXPECT_STREQ("Missing module.", message);
|
||||
});
|
||||
EXPECT_FALSE(t.Disassemble({}, &text));
|
||||
EXPECT_EQ("xxxxxxxxxx", text); // The original string is unmodified.
|
||||
EXPECT_EQ(1, invocation_count);
|
||||
}
|
||||
|
||||
TEST(CppInterface, DisassembleOverloads) {
|
||||
const std::string input_text = "%2 = OpSizeOf %1 %3\n";
|
||||
SpirvTools t(SPV_ENV_UNIVERSAL_1_1);
|
||||
|
||||
std::vector<uint32_t> binary;
|
||||
EXPECT_TRUE(t.Assemble(input_text, &binary));
|
||||
|
||||
{
|
||||
std::string output_text;
|
||||
EXPECT_TRUE(t.Disassemble(binary, &output_text));
|
||||
EXPECT_EQ(input_text, output_text);
|
||||
}
|
||||
{
|
||||
std::string output_text;
|
||||
EXPECT_TRUE(t.Disassemble(binary.data(), binary.size(), &output_text));
|
||||
EXPECT_EQ(input_text, output_text);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(CppInterface, SuccessfulValidation) {
|
||||
SpirvTools t(SPV_ENV_UNIVERSAL_1_1);
|
||||
int invocation_count = 0;
|
||||
t.SetMessageConsumer([&invocation_count](spv_message_level_t, const char*,
|
||||
const spv_position_t&, const char*) {
|
||||
++invocation_count;
|
||||
});
|
||||
|
||||
std::vector<uint32_t> binary;
|
||||
EXPECT_TRUE(t.Assemble(Header(), &binary));
|
||||
EXPECT_TRUE(t.Validate(binary));
|
||||
EXPECT_EQ(0, invocation_count);
|
||||
}
|
||||
|
||||
TEST(CppInterface, ValidateOverloads) {
|
||||
SpirvTools t(SPV_ENV_UNIVERSAL_1_1);
|
||||
std::vector<uint32_t> binary;
|
||||
EXPECT_TRUE(t.Assemble(Header(), &binary));
|
||||
|
||||
{ EXPECT_TRUE(t.Validate(binary)); }
|
||||
{ EXPECT_TRUE(t.Validate(binary.data(), binary.size())); }
|
||||
}
|
||||
|
||||
TEST(CppInterface, ValidateEmptyModule) {
|
||||
SpirvTools t(SPV_ENV_UNIVERSAL_1_1);
|
||||
int invocation_count = 0;
|
||||
t.SetMessageConsumer(
|
||||
[&invocation_count](spv_message_level_t level, const char* source,
|
||||
const spv_position_t& position, const char* message) {
|
||||
++invocation_count;
|
||||
EXPECT_EQ(SPV_MSG_ERROR, level);
|
||||
EXPECT_STREQ("input", source);
|
||||
EXPECT_EQ(0u, position.line);
|
||||
EXPECT_EQ(0u, position.column);
|
||||
EXPECT_EQ(0u, position.index);
|
||||
EXPECT_STREQ("Invalid SPIR-V magic number.", message);
|
||||
});
|
||||
EXPECT_FALSE(t.Validate({}));
|
||||
EXPECT_EQ(1, invocation_count);
|
||||
}
|
||||
|
||||
// Returns the assembly for a SPIR-V module with a struct declaration
|
||||
// with the given number of members.
|
||||
std::string MakeModuleHavingStruct(int num_members) {
|
||||
std::stringstream os;
|
||||
os << Header();
|
||||
os << R"(%1 = OpTypeInt 32 0
|
||||
%2 = OpTypeStruct)";
|
||||
for (int i = 0; i < num_members; i++) os << " %1";
|
||||
return os.str();
|
||||
}
|
||||
|
||||
TEST(CppInterface, ValidateWithOptionsPass) {
|
||||
SpirvTools t(SPV_ENV_UNIVERSAL_1_1);
|
||||
std::vector<uint32_t> binary;
|
||||
EXPECT_TRUE(t.Assemble(MakeModuleHavingStruct(10), &binary));
|
||||
const ValidatorOptions opts;
|
||||
|
||||
EXPECT_TRUE(t.Validate(binary.data(), binary.size(), opts));
|
||||
}
|
||||
|
||||
TEST(CppInterface, ValidateWithOptionsFail) {
|
||||
SpirvTools t(SPV_ENV_UNIVERSAL_1_1);
|
||||
std::vector<uint32_t> binary;
|
||||
EXPECT_TRUE(t.Assemble(MakeModuleHavingStruct(10), &binary));
|
||||
ValidatorOptions opts;
|
||||
opts.SetUniversalLimit(spv_validator_limit_max_struct_members, 9);
|
||||
std::stringstream os;
|
||||
t.SetMessageConsumer([&os](spv_message_level_t, const char*,
|
||||
const spv_position_t&,
|
||||
const char* message) { os << message; });
|
||||
|
||||
EXPECT_FALSE(t.Validate(binary.data(), binary.size(), opts));
|
||||
EXPECT_THAT(
|
||||
os.str(),
|
||||
HasSubstr(
|
||||
"Number of OpTypeStruct members (10) has exceeded the limit (9)"));
|
||||
}
|
||||
|
||||
// Checks that after running the given optimizer |opt| on the given |original|
|
||||
// source code, we can get the given |optimized| source code.
|
||||
void CheckOptimization(const std::string& original,
|
||||
const std::string& optimized, const Optimizer& opt) {
|
||||
SpirvTools t(SPV_ENV_UNIVERSAL_1_1);
|
||||
std::vector<uint32_t> original_binary;
|
||||
ASSERT_TRUE(t.Assemble(original, &original_binary));
|
||||
|
||||
std::vector<uint32_t> optimized_binary;
|
||||
EXPECT_TRUE(opt.Run(original_binary.data(), original_binary.size(),
|
||||
&optimized_binary));
|
||||
|
||||
std::string optimized_text;
|
||||
EXPECT_TRUE(t.Disassemble(optimized_binary, &optimized_text));
|
||||
EXPECT_EQ(optimized, optimized_text);
|
||||
}
|
||||
|
||||
TEST(CppInterface, OptimizeEmptyModule) {
|
||||
SpirvTools t(SPV_ENV_UNIVERSAL_1_1);
|
||||
std::vector<uint32_t> binary;
|
||||
EXPECT_TRUE(t.Assemble("", &binary));
|
||||
|
||||
Optimizer o(SPV_ENV_UNIVERSAL_1_1);
|
||||
o.RegisterPass(CreateStripDebugInfoPass());
|
||||
|
||||
// Fails to validate.
|
||||
EXPECT_FALSE(o.Run(binary.data(), binary.size(), &binary));
|
||||
}
|
||||
|
||||
TEST(CppInterface, OptimizeModifiedModule) {
|
||||
Optimizer o(SPV_ENV_UNIVERSAL_1_1);
|
||||
o.RegisterPass(CreateStripDebugInfoPass());
|
||||
CheckOptimization(Header() + "OpSource GLSL 450", Header(), o);
|
||||
}
|
||||
|
||||
TEST(CppInterface, OptimizeMulitplePasses) {
|
||||
std::string original_text = Header() +
|
||||
"OpSource GLSL 450 "
|
||||
"OpDecorate %true SpecId 1 "
|
||||
"%bool = OpTypeBool "
|
||||
"%true = OpSpecConstantTrue %bool";
|
||||
|
||||
Optimizer o(SPV_ENV_UNIVERSAL_1_1);
|
||||
o.RegisterPass(CreateStripDebugInfoPass())
|
||||
.RegisterPass(CreateFreezeSpecConstantValuePass());
|
||||
|
||||
std::string expected_text = Header() +
|
||||
"%bool = OpTypeBool\n"
|
||||
"%true = OpConstantTrue %bool\n";
|
||||
|
||||
CheckOptimization(original_text, expected_text, o);
|
||||
}
|
||||
|
||||
TEST(CppInterface, OptimizeDoNothingWithPassToken) {
|
||||
CreateFreezeSpecConstantValuePass();
|
||||
auto token = CreateUnifyConstantPass();
|
||||
}
|
||||
|
||||
TEST(CppInterface, OptimizeReassignPassToken) {
|
||||
auto token = CreateNullPass();
|
||||
token = CreateStripDebugInfoPass();
|
||||
|
||||
CheckOptimization(
|
||||
Header() + "OpSource GLSL 450", Header(),
|
||||
Optimizer(SPV_ENV_UNIVERSAL_1_1).RegisterPass(std::move(token)));
|
||||
}
|
||||
|
||||
TEST(CppInterface, OptimizeMoveConstructPassToken) {
|
||||
auto token1 = CreateStripDebugInfoPass();
|
||||
Optimizer::PassToken token2(std::move(token1));
|
||||
|
||||
CheckOptimization(
|
||||
Header() + "OpSource GLSL 450", Header(),
|
||||
Optimizer(SPV_ENV_UNIVERSAL_1_1).RegisterPass(std::move(token2)));
|
||||
}
|
||||
|
||||
TEST(CppInterface, OptimizeMoveAssignPassToken) {
|
||||
auto token1 = CreateStripDebugInfoPass();
|
||||
auto token2 = CreateNullPass();
|
||||
token2 = std::move(token1);
|
||||
|
||||
CheckOptimization(
|
||||
Header() + "OpSource GLSL 450", Header(),
|
||||
Optimizer(SPV_ENV_UNIVERSAL_1_1).RegisterPass(std::move(token2)));
|
||||
}
|
||||
|
||||
TEST(CppInterface, OptimizeSameAddressForOriginalOptimizedBinary) {
|
||||
SpirvTools t(SPV_ENV_UNIVERSAL_1_1);
|
||||
std::vector<uint32_t> binary;
|
||||
ASSERT_TRUE(t.Assemble(Header() + "OpSource GLSL 450", &binary));
|
||||
|
||||
EXPECT_TRUE(Optimizer(SPV_ENV_UNIVERSAL_1_1)
|
||||
.RegisterPass(CreateStripDebugInfoPass())
|
||||
.Run(binary.data(), binary.size(), &binary));
|
||||
|
||||
std::string optimized_text;
|
||||
EXPECT_TRUE(t.Disassemble(binary, &optimized_text));
|
||||
EXPECT_EQ(Header(), optimized_text);
|
||||
}
|
||||
|
||||
// TODO(antiagainst): tests for SetMessageConsumer().
|
||||
|
||||
} // namespace
|
||||
} // namespace spvtools
|
||||
150
3rdparty/spirv-tools/test/diagnostic_test.cpp
vendored
150
3rdparty/spirv-tools/test/diagnostic_test.cpp
vendored
@@ -1,150 +0,0 @@
|
||||
// Copyright (c) 2015-2016 The Khronos Group Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
#include <utility>
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "test/unit_spirv.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace {
|
||||
|
||||
using ::testing::Eq;
|
||||
|
||||
// Returns a newly created diagnostic value.
|
||||
spv_diagnostic MakeValidDiagnostic() {
|
||||
spv_position_t position = {};
|
||||
spv_diagnostic diagnostic = spvDiagnosticCreate(&position, "");
|
||||
EXPECT_NE(nullptr, diagnostic);
|
||||
return diagnostic;
|
||||
}
|
||||
|
||||
TEST(Diagnostic, DestroyNull) { spvDiagnosticDestroy(nullptr); }
|
||||
|
||||
TEST(Diagnostic, DestroyValidDiagnostic) {
|
||||
spv_diagnostic diagnostic = MakeValidDiagnostic();
|
||||
spvDiagnosticDestroy(diagnostic);
|
||||
// We aren't allowed to use the diagnostic pointer anymore.
|
||||
// So we can't test its behaviour.
|
||||
}
|
||||
|
||||
TEST(Diagnostic, DestroyValidDiagnosticAfterReassignment) {
|
||||
spv_diagnostic diagnostic = MakeValidDiagnostic();
|
||||
spv_diagnostic second_diagnostic = MakeValidDiagnostic();
|
||||
EXPECT_TRUE(diagnostic != second_diagnostic);
|
||||
spvDiagnosticDestroy(diagnostic);
|
||||
diagnostic = second_diagnostic;
|
||||
spvDiagnosticDestroy(diagnostic);
|
||||
}
|
||||
|
||||
TEST(Diagnostic, PrintDefault) {
|
||||
char message[] = "Test Diagnostic!";
|
||||
spv_diagnostic_t diagnostic = {{2, 3, 5}, message};
|
||||
// TODO: Redirect stderr
|
||||
ASSERT_EQ(SPV_SUCCESS, spvDiagnosticPrint(&diagnostic));
|
||||
// TODO: Validate the output of spvDiagnosticPrint()
|
||||
// TODO: Remove the redirection of stderr
|
||||
}
|
||||
|
||||
TEST(Diagnostic, PrintInvalidDiagnostic) {
|
||||
ASSERT_EQ(SPV_ERROR_INVALID_DIAGNOSTIC, spvDiagnosticPrint(nullptr));
|
||||
}
|
||||
|
||||
// TODO(dneto): We should be able to redirect the diagnostic printing.
|
||||
// Once we do that, we can test diagnostic corner cases.
|
||||
|
||||
TEST(DiagnosticStream, ConversionToResultType) {
|
||||
// Check after the DiagnosticStream object is destroyed.
|
||||
spv_result_t value;
|
||||
{ value = DiagnosticStream({}, nullptr, "", SPV_ERROR_INVALID_TEXT); }
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_TEXT, value);
|
||||
|
||||
// Check implicit conversion via plain assignment.
|
||||
value = DiagnosticStream({}, nullptr, "", SPV_SUCCESS);
|
||||
EXPECT_EQ(SPV_SUCCESS, value);
|
||||
|
||||
// Check conversion via constructor.
|
||||
EXPECT_EQ(SPV_FAILED_MATCH,
|
||||
spv_result_t(DiagnosticStream({}, nullptr, "", SPV_FAILED_MATCH)));
|
||||
}
|
||||
|
||||
TEST(
|
||||
DiagnosticStream,
|
||||
MoveConstructorPreservesPreviousMessagesAndPreventsOutputFromExpiringValue) {
|
||||
std::ostringstream messages;
|
||||
int message_count = 0;
|
||||
auto consumer = [&messages, &message_count](spv_message_level_t, const char*,
|
||||
const spv_position_t&,
|
||||
const char* msg) {
|
||||
message_count++;
|
||||
messages << msg;
|
||||
};
|
||||
|
||||
// Enclose the DiagnosticStream variables in a scope to force destruction.
|
||||
{
|
||||
DiagnosticStream ds0({}, consumer, "", SPV_ERROR_INVALID_BINARY);
|
||||
ds0 << "First";
|
||||
DiagnosticStream ds1(std::move(ds0));
|
||||
ds1 << "Second";
|
||||
}
|
||||
EXPECT_THAT(message_count, Eq(1));
|
||||
EXPECT_THAT(messages.str(), Eq("FirstSecond"));
|
||||
}
|
||||
|
||||
TEST(DiagnosticStream, MoveConstructorCanBeDirectlyShiftedTo) {
|
||||
std::ostringstream messages;
|
||||
int message_count = 0;
|
||||
auto consumer = [&messages, &message_count](spv_message_level_t, const char*,
|
||||
const spv_position_t&,
|
||||
const char* msg) {
|
||||
message_count++;
|
||||
messages << msg;
|
||||
};
|
||||
|
||||
// Enclose the DiagnosticStream variables in a scope to force destruction.
|
||||
{
|
||||
DiagnosticStream ds0({}, consumer, "", SPV_ERROR_INVALID_BINARY);
|
||||
ds0 << "First";
|
||||
std::move(ds0) << "Second";
|
||||
}
|
||||
EXPECT_THAT(message_count, Eq(1));
|
||||
EXPECT_THAT(messages.str(), Eq("FirstSecond"));
|
||||
}
|
||||
|
||||
TEST(DiagnosticStream, DiagnosticFromLambdaReturnCanStillBeUsed) {
|
||||
std::ostringstream messages;
|
||||
int message_count = 0;
|
||||
auto consumer = [&messages, &message_count](spv_message_level_t, const char*,
|
||||
const spv_position_t&,
|
||||
const char* msg) {
|
||||
message_count++;
|
||||
messages << msg;
|
||||
};
|
||||
|
||||
{
|
||||
auto emitter = [&consumer]() -> DiagnosticStream {
|
||||
DiagnosticStream ds0({}, consumer, "", SPV_ERROR_INVALID_BINARY);
|
||||
ds0 << "First";
|
||||
return ds0;
|
||||
};
|
||||
emitter() << "Second";
|
||||
}
|
||||
EXPECT_THAT(message_count, Eq(1));
|
||||
EXPECT_THAT(messages.str(), Eq("FirstSecond"));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace spvtools
|
||||
290
3rdparty/spirv-tools/test/enum_set_test.cpp
vendored
290
3rdparty/spirv-tools/test/enum_set_test.cpp
vendored
@@ -1,290 +0,0 @@
|
||||
// Copyright (c) 2016 Google Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "source/enum_set.h"
|
||||
#include "test/unit_spirv.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace {
|
||||
|
||||
using spvtest::ElementsIn;
|
||||
using ::testing::Eq;
|
||||
using ::testing::ValuesIn;
|
||||
|
||||
TEST(EnumSet, IsEmpty1) {
|
||||
EnumSet<uint32_t> set;
|
||||
EXPECT_TRUE(set.IsEmpty());
|
||||
set.Add(0);
|
||||
EXPECT_FALSE(set.IsEmpty());
|
||||
}
|
||||
|
||||
TEST(EnumSet, IsEmpty2) {
|
||||
EnumSet<uint32_t> set;
|
||||
EXPECT_TRUE(set.IsEmpty());
|
||||
set.Add(150);
|
||||
EXPECT_FALSE(set.IsEmpty());
|
||||
}
|
||||
|
||||
TEST(EnumSet, IsEmpty3) {
|
||||
EnumSet<uint32_t> set(4);
|
||||
EXPECT_FALSE(set.IsEmpty());
|
||||
}
|
||||
|
||||
TEST(EnumSet, IsEmpty4) {
|
||||
EnumSet<uint32_t> set(300);
|
||||
EXPECT_FALSE(set.IsEmpty());
|
||||
}
|
||||
|
||||
TEST(EnumSetHasAnyOf, EmptySetEmptyQuery) {
|
||||
const EnumSet<uint32_t> set;
|
||||
const EnumSet<uint32_t> empty;
|
||||
EXPECT_TRUE(set.HasAnyOf(empty));
|
||||
EXPECT_TRUE(EnumSet<uint32_t>().HasAnyOf(EnumSet<uint32_t>()));
|
||||
}
|
||||
|
||||
TEST(EnumSetHasAnyOf, MaskSetEmptyQuery) {
|
||||
EnumSet<uint32_t> set;
|
||||
const EnumSet<uint32_t> empty;
|
||||
set.Add(5);
|
||||
set.Add(8);
|
||||
EXPECT_TRUE(set.HasAnyOf(empty));
|
||||
}
|
||||
|
||||
TEST(EnumSetHasAnyOf, OverflowSetEmptyQuery) {
|
||||
EnumSet<uint32_t> set;
|
||||
const EnumSet<uint32_t> empty;
|
||||
set.Add(200);
|
||||
set.Add(300);
|
||||
EXPECT_TRUE(set.HasAnyOf(empty));
|
||||
}
|
||||
|
||||
TEST(EnumSetHasAnyOf, EmptyQuery) {
|
||||
EnumSet<uint32_t> set;
|
||||
const EnumSet<uint32_t> empty;
|
||||
set.Add(5);
|
||||
set.Add(8);
|
||||
set.Add(200);
|
||||
set.Add(300);
|
||||
EXPECT_TRUE(set.HasAnyOf(empty));
|
||||
}
|
||||
|
||||
TEST(EnumSetHasAnyOf, EmptyQueryAlwaysTrue) {
|
||||
EnumSet<uint32_t> set;
|
||||
const EnumSet<uint32_t> empty;
|
||||
EXPECT_TRUE(set.HasAnyOf(empty));
|
||||
set.Add(5);
|
||||
EXPECT_TRUE(set.HasAnyOf(empty));
|
||||
|
||||
EXPECT_TRUE(EnumSet<uint32_t>(100).HasAnyOf(EnumSet<uint32_t>()));
|
||||
}
|
||||
|
||||
TEST(EnumSetHasAnyOf, ReflexiveMask) {
|
||||
EnumSet<uint32_t> set(3);
|
||||
set.Add(24);
|
||||
set.Add(30);
|
||||
EXPECT_TRUE(set.HasAnyOf(set));
|
||||
}
|
||||
|
||||
TEST(EnumSetHasAnyOf, ReflexiveOverflow) {
|
||||
EnumSet<uint32_t> set(200);
|
||||
set.Add(300);
|
||||
set.Add(400);
|
||||
EXPECT_TRUE(set.HasAnyOf(set));
|
||||
}
|
||||
|
||||
TEST(EnumSetHasAnyOf, Reflexive) {
|
||||
EnumSet<uint32_t> set(3);
|
||||
set.Add(24);
|
||||
set.Add(300);
|
||||
set.Add(400);
|
||||
EXPECT_TRUE(set.HasAnyOf(set));
|
||||
}
|
||||
|
||||
TEST(EnumSetHasAnyOf, EmptySetHasNone) {
|
||||
EnumSet<uint32_t> set;
|
||||
EnumSet<uint32_t> items;
|
||||
for (uint32_t i = 0; i < 200; ++i) {
|
||||
items.Add(i);
|
||||
EXPECT_FALSE(set.HasAnyOf(items));
|
||||
EXPECT_FALSE(set.HasAnyOf(EnumSet<uint32_t>(i)));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(EnumSetHasAnyOf, MaskSetMaskQuery) {
|
||||
EnumSet<uint32_t> set(0);
|
||||
EnumSet<uint32_t> items(1);
|
||||
EXPECT_FALSE(set.HasAnyOf(items));
|
||||
set.Add(2);
|
||||
items.Add(3);
|
||||
EXPECT_FALSE(set.HasAnyOf(items));
|
||||
set.Add(3);
|
||||
EXPECT_TRUE(set.HasAnyOf(items));
|
||||
set.Add(4);
|
||||
EXPECT_TRUE(set.HasAnyOf(items));
|
||||
}
|
||||
|
||||
TEST(EnumSetHasAnyOf, OverflowSetOverflowQuery) {
|
||||
EnumSet<uint32_t> set(100);
|
||||
EnumSet<uint32_t> items(200);
|
||||
EXPECT_FALSE(set.HasAnyOf(items));
|
||||
set.Add(300);
|
||||
items.Add(400);
|
||||
EXPECT_FALSE(set.HasAnyOf(items));
|
||||
set.Add(200);
|
||||
EXPECT_TRUE(set.HasAnyOf(items));
|
||||
set.Add(500);
|
||||
EXPECT_TRUE(set.HasAnyOf(items));
|
||||
}
|
||||
|
||||
TEST(EnumSetHasAnyOf, GeneralCase) {
|
||||
EnumSet<uint32_t> set(0);
|
||||
EnumSet<uint32_t> items(100);
|
||||
EXPECT_FALSE(set.HasAnyOf(items));
|
||||
set.Add(300);
|
||||
items.Add(4);
|
||||
EXPECT_FALSE(set.HasAnyOf(items));
|
||||
set.Add(5);
|
||||
items.Add(500);
|
||||
EXPECT_FALSE(set.HasAnyOf(items));
|
||||
set.Add(500);
|
||||
EXPECT_TRUE(set.HasAnyOf(items));
|
||||
EXPECT_FALSE(set.HasAnyOf(EnumSet<uint32_t>(20)));
|
||||
EXPECT_FALSE(set.HasAnyOf(EnumSet<uint32_t>(600)));
|
||||
EXPECT_TRUE(set.HasAnyOf(EnumSet<uint32_t>(5)));
|
||||
EXPECT_TRUE(set.HasAnyOf(EnumSet<uint32_t>(300)));
|
||||
EXPECT_TRUE(set.HasAnyOf(EnumSet<uint32_t>(0)));
|
||||
}
|
||||
|
||||
TEST(EnumSet, DefaultIsEmpty) {
|
||||
EnumSet<uint32_t> set;
|
||||
for (uint32_t i = 0; i < 1000; ++i) {
|
||||
EXPECT_FALSE(set.Contains(i));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(CapabilitySet, ConstructSingleMemberMatrix) {
|
||||
CapabilitySet s(SpvCapabilityMatrix);
|
||||
EXPECT_TRUE(s.Contains(SpvCapabilityMatrix));
|
||||
EXPECT_FALSE(s.Contains(SpvCapabilityShader));
|
||||
EXPECT_FALSE(s.Contains(static_cast<SpvCapability>(1000)));
|
||||
}
|
||||
|
||||
TEST(CapabilitySet, ConstructSingleMemberMaxInMask) {
|
||||
CapabilitySet s(static_cast<SpvCapability>(63));
|
||||
EXPECT_FALSE(s.Contains(SpvCapabilityMatrix));
|
||||
EXPECT_FALSE(s.Contains(SpvCapabilityShader));
|
||||
EXPECT_TRUE(s.Contains(static_cast<SpvCapability>(63)));
|
||||
EXPECT_FALSE(s.Contains(static_cast<SpvCapability>(64)));
|
||||
EXPECT_FALSE(s.Contains(static_cast<SpvCapability>(1000)));
|
||||
}
|
||||
|
||||
TEST(CapabilitySet, ConstructSingleMemberMinOverflow) {
|
||||
// Check the first one that forces overflow beyond the mask.
|
||||
CapabilitySet s(static_cast<SpvCapability>(64));
|
||||
EXPECT_FALSE(s.Contains(SpvCapabilityMatrix));
|
||||
EXPECT_FALSE(s.Contains(SpvCapabilityShader));
|
||||
EXPECT_FALSE(s.Contains(static_cast<SpvCapability>(63)));
|
||||
EXPECT_TRUE(s.Contains(static_cast<SpvCapability>(64)));
|
||||
EXPECT_FALSE(s.Contains(static_cast<SpvCapability>(1000)));
|
||||
}
|
||||
|
||||
TEST(CapabilitySet, ConstructSingleMemberMaxOverflow) {
|
||||
// Check the max 32-bit signed int.
|
||||
CapabilitySet s(static_cast<SpvCapability>(0x7fffffffu));
|
||||
EXPECT_FALSE(s.Contains(SpvCapabilityMatrix));
|
||||
EXPECT_FALSE(s.Contains(SpvCapabilityShader));
|
||||
EXPECT_FALSE(s.Contains(static_cast<SpvCapability>(1000)));
|
||||
EXPECT_TRUE(s.Contains(static_cast<SpvCapability>(0x7fffffffu)));
|
||||
}
|
||||
|
||||
TEST(CapabilitySet, AddEnum) {
|
||||
CapabilitySet s(SpvCapabilityShader);
|
||||
s.Add(SpvCapabilityKernel);
|
||||
s.Add(static_cast<SpvCapability>(42));
|
||||
EXPECT_FALSE(s.Contains(SpvCapabilityMatrix));
|
||||
EXPECT_TRUE(s.Contains(SpvCapabilityShader));
|
||||
EXPECT_TRUE(s.Contains(SpvCapabilityKernel));
|
||||
EXPECT_TRUE(s.Contains(static_cast<SpvCapability>(42)));
|
||||
}
|
||||
|
||||
TEST(CapabilitySet, InitializerListEmpty) {
|
||||
CapabilitySet s{};
|
||||
for (uint32_t i = 0; i < 1000; i++) {
|
||||
EXPECT_FALSE(s.Contains(static_cast<SpvCapability>(i)));
|
||||
}
|
||||
}
|
||||
|
||||
struct ForEachCase {
|
||||
CapabilitySet capabilities;
|
||||
std::vector<SpvCapability> expected;
|
||||
};
|
||||
|
||||
using CapabilitySetForEachTest = ::testing::TestWithParam<ForEachCase>;
|
||||
|
||||
TEST_P(CapabilitySetForEachTest, CallsAsExpected) {
|
||||
EXPECT_THAT(ElementsIn(GetParam().capabilities), Eq(GetParam().expected));
|
||||
}
|
||||
|
||||
TEST_P(CapabilitySetForEachTest, CopyConstructor) {
|
||||
CapabilitySet copy(GetParam().capabilities);
|
||||
EXPECT_THAT(ElementsIn(copy), Eq(GetParam().expected));
|
||||
}
|
||||
|
||||
TEST_P(CapabilitySetForEachTest, MoveConstructor) {
|
||||
// We need a writable copy to move from.
|
||||
CapabilitySet copy(GetParam().capabilities);
|
||||
CapabilitySet moved(std::move(copy));
|
||||
EXPECT_THAT(ElementsIn(moved), Eq(GetParam().expected));
|
||||
|
||||
// The moved-from set is empty.
|
||||
EXPECT_THAT(ElementsIn(copy), Eq(std::vector<SpvCapability>{}));
|
||||
}
|
||||
|
||||
TEST_P(CapabilitySetForEachTest, OperatorEquals) {
|
||||
CapabilitySet assigned = GetParam().capabilities;
|
||||
EXPECT_THAT(ElementsIn(assigned), Eq(GetParam().expected));
|
||||
}
|
||||
|
||||
TEST_P(CapabilitySetForEachTest, OperatorEqualsSelfAssign) {
|
||||
CapabilitySet assigned{GetParam().capabilities};
|
||||
assigned = assigned;
|
||||
EXPECT_THAT(ElementsIn(assigned), Eq(GetParam().expected));
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(Samples, CapabilitySetForEachTest,
|
||||
ValuesIn(std::vector<ForEachCase>{
|
||||
{{}, {}},
|
||||
{{SpvCapabilityMatrix}, {SpvCapabilityMatrix}},
|
||||
{{SpvCapabilityKernel, SpvCapabilityShader},
|
||||
{SpvCapabilityShader, SpvCapabilityKernel}},
|
||||
{{static_cast<SpvCapability>(999)},
|
||||
{static_cast<SpvCapability>(999)}},
|
||||
{{static_cast<SpvCapability>(0x7fffffff)},
|
||||
{static_cast<SpvCapability>(0x7fffffff)}},
|
||||
// Mixture and out of order
|
||||
{{static_cast<SpvCapability>(0x7fffffff),
|
||||
static_cast<SpvCapability>(100),
|
||||
SpvCapabilityShader, SpvCapabilityMatrix},
|
||||
{SpvCapabilityMatrix, SpvCapabilityShader,
|
||||
static_cast<SpvCapability>(100),
|
||||
static_cast<SpvCapability>(0x7fffffff)}},
|
||||
}));
|
||||
|
||||
} // namespace
|
||||
} // namespace spvtools
|
||||
@@ -1,195 +0,0 @@
|
||||
// Copyright (c) 2017 Google Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Tests for OpExtension validator rules.
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "source/enum_string_mapping.h"
|
||||
#include "source/extensions.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace {
|
||||
|
||||
using ::testing::Values;
|
||||
using ::testing::ValuesIn;
|
||||
|
||||
using ExtensionTest =
|
||||
::testing::TestWithParam<std::pair<Extension, std::string>>;
|
||||
using UnknownExtensionTest = ::testing::TestWithParam<std::string>;
|
||||
using CapabilityTest =
|
||||
::testing::TestWithParam<std::pair<SpvCapability, std::string>>;
|
||||
|
||||
TEST_P(ExtensionTest, TestExtensionFromString) {
|
||||
const std::pair<Extension, std::string>& param = GetParam();
|
||||
const Extension extension = param.first;
|
||||
const std::string extension_str = param.second;
|
||||
Extension result_extension;
|
||||
ASSERT_TRUE(GetExtensionFromString(extension_str.c_str(), &result_extension));
|
||||
EXPECT_EQ(extension, result_extension);
|
||||
}
|
||||
|
||||
TEST_P(ExtensionTest, TestExtensionToString) {
|
||||
const std::pair<Extension, std::string>& param = GetParam();
|
||||
const Extension extension = param.first;
|
||||
const std::string extension_str = param.second;
|
||||
const std::string result_str = ExtensionToString(extension);
|
||||
EXPECT_EQ(extension_str, result_str);
|
||||
}
|
||||
|
||||
TEST_P(UnknownExtensionTest, TestExtensionFromStringFails) {
|
||||
Extension result_extension;
|
||||
ASSERT_FALSE(GetExtensionFromString(GetParam().c_str(), &result_extension));
|
||||
}
|
||||
|
||||
TEST_P(CapabilityTest, TestCapabilityToString) {
|
||||
const std::pair<SpvCapability, std::string>& param = GetParam();
|
||||
const SpvCapability capability = param.first;
|
||||
const std::string capability_str = param.second;
|
||||
const std::string result_str = CapabilityToString(capability);
|
||||
EXPECT_EQ(capability_str, result_str);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
AllExtensions, ExtensionTest,
|
||||
ValuesIn(std::vector<std::pair<Extension, std::string>>({
|
||||
{Extension::kSPV_KHR_16bit_storage, "SPV_KHR_16bit_storage"},
|
||||
{Extension::kSPV_KHR_device_group, "SPV_KHR_device_group"},
|
||||
{Extension::kSPV_KHR_multiview, "SPV_KHR_multiview"},
|
||||
{Extension::kSPV_KHR_shader_ballot, "SPV_KHR_shader_ballot"},
|
||||
{Extension::kSPV_KHR_shader_draw_parameters,
|
||||
"SPV_KHR_shader_draw_parameters"},
|
||||
{Extension::kSPV_KHR_subgroup_vote, "SPV_KHR_subgroup_vote"},
|
||||
{Extension::kSPV_NVX_multiview_per_view_attributes,
|
||||
"SPV_NVX_multiview_per_view_attributes"},
|
||||
{Extension::kSPV_NV_geometry_shader_passthrough,
|
||||
"SPV_NV_geometry_shader_passthrough"},
|
||||
{Extension::kSPV_NV_sample_mask_override_coverage,
|
||||
"SPV_NV_sample_mask_override_coverage"},
|
||||
{Extension::kSPV_NV_stereo_view_rendering,
|
||||
"SPV_NV_stereo_view_rendering"},
|
||||
{Extension::kSPV_NV_viewport_array2, "SPV_NV_viewport_array2"},
|
||||
{Extension::kSPV_GOOGLE_decorate_string, "SPV_GOOGLE_decorate_string"},
|
||||
{Extension::kSPV_GOOGLE_hlsl_functionality1,
|
||||
"SPV_GOOGLE_hlsl_functionality1"},
|
||||
{Extension::kSPV_KHR_8bit_storage, "SPV_KHR_8bit_storage"},
|
||||
})));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(UnknownExtensions, UnknownExtensionTest,
|
||||
Values("", "SPV_KHR_", "SPV_KHR_device_group_ERROR",
|
||||
/*alphabetically before all extensions*/ "A",
|
||||
/*alphabetically after all extensions*/ "Z",
|
||||
"SPV_ERROR_random_string_hfsdklhlktherh"));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
AllCapabilities, CapabilityTest,
|
||||
ValuesIn(std::vector<std::pair<SpvCapability, std::string>>(
|
||||
{{SpvCapabilityMatrix, "Matrix"},
|
||||
{SpvCapabilityShader, "Shader"},
|
||||
{SpvCapabilityGeometry, "Geometry"},
|
||||
{SpvCapabilityTessellation, "Tessellation"},
|
||||
{SpvCapabilityAddresses, "Addresses"},
|
||||
{SpvCapabilityLinkage, "Linkage"},
|
||||
{SpvCapabilityKernel, "Kernel"},
|
||||
{SpvCapabilityVector16, "Vector16"},
|
||||
{SpvCapabilityFloat16Buffer, "Float16Buffer"},
|
||||
{SpvCapabilityFloat16, "Float16"},
|
||||
{SpvCapabilityFloat64, "Float64"},
|
||||
{SpvCapabilityInt64, "Int64"},
|
||||
{SpvCapabilityInt64Atomics, "Int64Atomics"},
|
||||
{SpvCapabilityImageBasic, "ImageBasic"},
|
||||
{SpvCapabilityImageReadWrite, "ImageReadWrite"},
|
||||
{SpvCapabilityImageMipmap, "ImageMipmap"},
|
||||
{SpvCapabilityPipes, "Pipes"},
|
||||
{SpvCapabilityGroups, "Groups"},
|
||||
{SpvCapabilityDeviceEnqueue, "DeviceEnqueue"},
|
||||
{SpvCapabilityLiteralSampler, "LiteralSampler"},
|
||||
{SpvCapabilityAtomicStorage, "AtomicStorage"},
|
||||
{SpvCapabilityInt16, "Int16"},
|
||||
{SpvCapabilityTessellationPointSize, "TessellationPointSize"},
|
||||
{SpvCapabilityGeometryPointSize, "GeometryPointSize"},
|
||||
{SpvCapabilityImageGatherExtended, "ImageGatherExtended"},
|
||||
{SpvCapabilityStorageImageMultisample, "StorageImageMultisample"},
|
||||
{SpvCapabilityUniformBufferArrayDynamicIndexing,
|
||||
"UniformBufferArrayDynamicIndexing"},
|
||||
{SpvCapabilitySampledImageArrayDynamicIndexing,
|
||||
"SampledImageArrayDynamicIndexing"},
|
||||
{SpvCapabilityStorageBufferArrayDynamicIndexing,
|
||||
"StorageBufferArrayDynamicIndexing"},
|
||||
{SpvCapabilityStorageImageArrayDynamicIndexing,
|
||||
"StorageImageArrayDynamicIndexing"},
|
||||
{SpvCapabilityClipDistance, "ClipDistance"},
|
||||
{SpvCapabilityCullDistance, "CullDistance"},
|
||||
{SpvCapabilityImageCubeArray, "ImageCubeArray"},
|
||||
{SpvCapabilitySampleRateShading, "SampleRateShading"},
|
||||
{SpvCapabilityImageRect, "ImageRect"},
|
||||
{SpvCapabilitySampledRect, "SampledRect"},
|
||||
{SpvCapabilityGenericPointer, "GenericPointer"},
|
||||
{SpvCapabilityInt8, "Int8"},
|
||||
{SpvCapabilityInputAttachment, "InputAttachment"},
|
||||
{SpvCapabilitySparseResidency, "SparseResidency"},
|
||||
{SpvCapabilityMinLod, "MinLod"},
|
||||
{SpvCapabilitySampled1D, "Sampled1D"},
|
||||
{SpvCapabilityImage1D, "Image1D"},
|
||||
{SpvCapabilitySampledCubeArray, "SampledCubeArray"},
|
||||
{SpvCapabilitySampledBuffer, "SampledBuffer"},
|
||||
{SpvCapabilityImageBuffer, "ImageBuffer"},
|
||||
{SpvCapabilityImageMSArray, "ImageMSArray"},
|
||||
{SpvCapabilityStorageImageExtendedFormats,
|
||||
"StorageImageExtendedFormats"},
|
||||
{SpvCapabilityImageQuery, "ImageQuery"},
|
||||
{SpvCapabilityDerivativeControl, "DerivativeControl"},
|
||||
{SpvCapabilityInterpolationFunction, "InterpolationFunction"},
|
||||
{SpvCapabilityTransformFeedback, "TransformFeedback"},
|
||||
{SpvCapabilityGeometryStreams, "GeometryStreams"},
|
||||
{SpvCapabilityStorageImageReadWithoutFormat,
|
||||
"StorageImageReadWithoutFormat"},
|
||||
{SpvCapabilityStorageImageWriteWithoutFormat,
|
||||
"StorageImageWriteWithoutFormat"},
|
||||
{SpvCapabilityMultiViewport, "MultiViewport"},
|
||||
{SpvCapabilitySubgroupDispatch, "SubgroupDispatch"},
|
||||
{SpvCapabilityNamedBarrier, "NamedBarrier"},
|
||||
{SpvCapabilityPipeStorage, "PipeStorage"},
|
||||
{SpvCapabilitySubgroupBallotKHR, "SubgroupBallotKHR"},
|
||||
{SpvCapabilityDrawParameters, "DrawParameters"},
|
||||
{SpvCapabilitySubgroupVoteKHR, "SubgroupVoteKHR"},
|
||||
{SpvCapabilityStorageBuffer16BitAccess, "StorageBuffer16BitAccess"},
|
||||
{SpvCapabilityStorageUniformBufferBlock16,
|
||||
"StorageBuffer16BitAccess"}, // Preferred name
|
||||
{SpvCapabilityUniformAndStorageBuffer16BitAccess,
|
||||
"UniformAndStorageBuffer16BitAccess"},
|
||||
{SpvCapabilityStorageUniform16,
|
||||
"UniformAndStorageBuffer16BitAccess"}, // Preferred name
|
||||
{SpvCapabilityStoragePushConstant16, "StoragePushConstant16"},
|
||||
{SpvCapabilityStorageInputOutput16, "StorageInputOutput16"},
|
||||
{SpvCapabilityDeviceGroup, "DeviceGroup"},
|
||||
{SpvCapabilityMultiView, "MultiView"},
|
||||
{SpvCapabilitySampleMaskOverrideCoverageNV,
|
||||
"SampleMaskOverrideCoverageNV"},
|
||||
{SpvCapabilityGeometryShaderPassthroughNV,
|
||||
"GeometryShaderPassthroughNV"},
|
||||
// The next two are different names for the same token.
|
||||
{SpvCapabilityShaderViewportIndexLayerNV,
|
||||
"ShaderViewportIndexLayerEXT"},
|
||||
{SpvCapabilityShaderViewportIndexLayerEXT,
|
||||
"ShaderViewportIndexLayerEXT"},
|
||||
{SpvCapabilityShaderViewportMaskNV, "ShaderViewportMaskNV"},
|
||||
{SpvCapabilityShaderStereoViewNV, "ShaderStereoViewNV"},
|
||||
{SpvCapabilityPerViewAttributesNV, "PerViewAttributesNV"}})));
|
||||
|
||||
} // namespace
|
||||
} // namespace spvtools
|
||||
@@ -1,815 +0,0 @@
|
||||
// Copyright (c) 2017 Google Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "DebugInfo.h"
|
||||
#include "gmock/gmock.h"
|
||||
#include "source/util/string_utils.h"
|
||||
#include "test/test_fixture.h"
|
||||
#include "test/unit_spirv.h"
|
||||
|
||||
// This file tests the correctness of encoding and decoding of instructions
|
||||
// involving the DebugInfo extended instruction set.
|
||||
// Semantic correctness should be the responsibility of validator.
|
||||
//
|
||||
// See https://www.khronos.org/registry/spir-v/specs/1.0/DebugInfo.html
|
||||
|
||||
namespace spvtools {
|
||||
namespace {
|
||||
|
||||
using spvtest::Concatenate;
|
||||
using spvtest::MakeInstruction;
|
||||
using utils::MakeVector;
|
||||
using testing::Eq;
|
||||
|
||||
struct InstructionCase {
|
||||
uint32_t opcode;
|
||||
std::string name;
|
||||
std::string operands;
|
||||
std::vector<uint32_t> expected_operands;
|
||||
};
|
||||
|
||||
using ExtInstDebugInfoRoundTripTest =
|
||||
spvtest::TextToBinaryTestBase<::testing::TestWithParam<InstructionCase>>;
|
||||
using ExtInstDebugInfoRoundTripTestExplicit = spvtest::TextToBinaryTest;
|
||||
|
||||
TEST_P(ExtInstDebugInfoRoundTripTest, ParameterizedExtInst) {
|
||||
const std::string input =
|
||||
"%1 = OpExtInstImport \"DebugInfo\"\n"
|
||||
"%3 = OpExtInst %2 %1 " +
|
||||
GetParam().name + GetParam().operands + "\n";
|
||||
// First make sure it assembles correctly.
|
||||
EXPECT_THAT(
|
||||
CompiledInstructions(input),
|
||||
Eq(Concatenate(
|
||||
{MakeInstruction(SpvOpExtInstImport, {1}, MakeVector("DebugInfo")),
|
||||
MakeInstruction(SpvOpExtInst, {2, 3, 1, GetParam().opcode},
|
||||
GetParam().expected_operands)})))
|
||||
<< input;
|
||||
// Now check the round trip through the disassembler.
|
||||
EXPECT_THAT(EncodeAndDecodeSuccessfully(input), input) << input;
|
||||
}
|
||||
|
||||
#define CASE_0(Enum) \
|
||||
{ \
|
||||
uint32_t(DebugInfoDebug##Enum), "Debug" #Enum, "", {} \
|
||||
}
|
||||
|
||||
#define CASE_ILL(Enum, L0, L1) \
|
||||
{ \
|
||||
uint32_t(DebugInfoDebug##Enum), "Debug" #Enum, " %4 " #L0 " " #L1, { \
|
||||
4, L0, L1 \
|
||||
} \
|
||||
}
|
||||
|
||||
#define CASE_IL(Enum, L0) \
|
||||
{ \
|
||||
uint32_t(DebugInfoDebug##Enum), "Debug" #Enum, " %4 " #L0, { 4, L0 } \
|
||||
}
|
||||
|
||||
#define CASE_I(Enum) \
|
||||
{ \
|
||||
uint32_t(DebugInfoDebug##Enum), "Debug" #Enum, " %4", { 4 } \
|
||||
}
|
||||
|
||||
#define CASE_II(Enum) \
|
||||
{ \
|
||||
uint32_t(DebugInfoDebug##Enum), "Debug" #Enum, " %4 %5", { 4, 5 } \
|
||||
}
|
||||
|
||||
#define CASE_III(Enum) \
|
||||
{ \
|
||||
uint32_t(DebugInfoDebug##Enum), "Debug" #Enum, " %4 %5 %6", { 4, 5, 6 } \
|
||||
}
|
||||
|
||||
#define CASE_IIII(Enum) \
|
||||
{ \
|
||||
uint32_t(DebugInfoDebug##Enum), "Debug" #Enum, " %4 %5 %6 %7", { \
|
||||
4, 5, 6, 7 \
|
||||
} \
|
||||
}
|
||||
|
||||
#define CASE_IIIII(Enum) \
|
||||
{ \
|
||||
uint32_t(DebugInfoDebug##Enum), "Debug" #Enum, " %4 %5 %6 %7 %8", { \
|
||||
4, 5, 6, 7, 8 \
|
||||
} \
|
||||
}
|
||||
|
||||
#define CASE_IIIIII(Enum) \
|
||||
{ \
|
||||
uint32_t(DebugInfoDebug##Enum), "Debug" #Enum, " %4 %5 %6 %7 %8 %9", { \
|
||||
4, 5, 6, 7, 8, 9 \
|
||||
} \
|
||||
}
|
||||
|
||||
#define CASE_IIIIIII(Enum) \
|
||||
{ \
|
||||
uint32_t(DebugInfoDebug##Enum), "Debug" #Enum, " %4 %5 %6 %7 %8 %9 %10", { \
|
||||
4, 5, 6, 7, 8, 9, 10 \
|
||||
} \
|
||||
}
|
||||
|
||||
#define CASE_IIILLI(Enum, L0, L1) \
|
||||
{ \
|
||||
uint32_t(DebugInfoDebug##Enum), "Debug" #Enum, \
|
||||
" %4 %5 %6 " #L0 " " #L1 " %7", { \
|
||||
4, 5, 6, L0, L1, 7 \
|
||||
} \
|
||||
}
|
||||
|
||||
#define CASE_IIILLIL(Enum, L0, L1, L2) \
|
||||
{ \
|
||||
uint32_t(DebugInfoDebug##Enum), "Debug" #Enum, \
|
||||
" %4 %5 %6 " #L0 " " #L1 " %7 " #L2, { \
|
||||
4, 5, 6, L0, L1, 7, L2 \
|
||||
} \
|
||||
}
|
||||
|
||||
#define CASE_IE(Enum, E0) \
|
||||
{ \
|
||||
uint32_t(DebugInfoDebug##Enum), "Debug" #Enum, " %4 " #E0, { \
|
||||
4, uint32_t(DebugInfo##E0) \
|
||||
} \
|
||||
}
|
||||
|
||||
#define CASE_IIE(Enum, E0) \
|
||||
{ \
|
||||
uint32_t(DebugInfoDebug##Enum), "Debug" #Enum, " %4 %5 " #E0, { \
|
||||
4, 5, uint32_t(DebugInfo##E0) \
|
||||
} \
|
||||
}
|
||||
|
||||
#define CASE_ISF(Enum, S0, Fstr, Fnum) \
|
||||
{ \
|
||||
uint32_t(DebugInfoDebug##Enum), "Debug" #Enum, " %4 " #S0 " " Fstr, { \
|
||||
4, uint32_t(SpvStorageClass##S0), Fnum \
|
||||
} \
|
||||
}
|
||||
|
||||
#define CASE_LII(Enum, L0) \
|
||||
{ \
|
||||
uint32_t(DebugInfoDebug##Enum), "Debug" #Enum, " " #L0 " %4 %5", { \
|
||||
L0, 4, 5 \
|
||||
} \
|
||||
}
|
||||
|
||||
#define CASE_ILI(Enum, L0) \
|
||||
{ \
|
||||
uint32_t(DebugInfoDebug##Enum), "Debug" #Enum, " %4 " #L0 " %5", { \
|
||||
4, L0, 5 \
|
||||
} \
|
||||
}
|
||||
|
||||
#define CASE_ILII(Enum, L0) \
|
||||
{ \
|
||||
uint32_t(DebugInfoDebug##Enum), "Debug" #Enum, " %4 " #L0 " %5 %6", { \
|
||||
4, L0, 5, 6 \
|
||||
} \
|
||||
}
|
||||
|
||||
#define CASE_ILLII(Enum, L0, L1) \
|
||||
{ \
|
||||
uint32_t(DebugInfoDebug##Enum), "Debug" #Enum, \
|
||||
" %4 " #L0 " " #L1 " %5 %6", { \
|
||||
4, L0, L1, 5, 6 \
|
||||
} \
|
||||
}
|
||||
|
||||
#define CASE_IIILLIIF(Enum, L0, L1, Fstr, Fnum) \
|
||||
{ \
|
||||
uint32_t(DebugInfoDebug##Enum), "Debug" #Enum, \
|
||||
" %4 %5 %6 " #L0 " " #L1 " %7 %8 " Fstr, { \
|
||||
4, 5, 6, L0, L1, 7, 8, Fnum \
|
||||
} \
|
||||
}
|
||||
|
||||
#define CASE_IIILLIIFII(Enum, L0, L1, Fstr, Fnum) \
|
||||
{ \
|
||||
uint32_t(DebugInfoDebug##Enum), "Debug" #Enum, \
|
||||
" %4 %5 %6 " #L0 " " #L1 " %7 %8 " Fstr " %9 %10", { \
|
||||
4, 5, 6, L0, L1, 7, 8, Fnum, 9, 10 \
|
||||
} \
|
||||
}
|
||||
|
||||
#define CASE_IIILLIIFIIII(Enum, L0, L1, Fstr, Fnum) \
|
||||
{ \
|
||||
uint32_t(DebugInfoDebug##Enum), "Debug" #Enum, \
|
||||
" %4 %5 %6 " #L0 " " #L1 " %7 %8 " Fstr " %9 %10 %11 %12", { \
|
||||
4, 5, 6, L0, L1, 7, 8, Fnum, 9, 10, 11, 12 \
|
||||
} \
|
||||
}
|
||||
|
||||
#define CASE_IIILLIIFIIIIII(Enum, L0, L1, Fstr, Fnum) \
|
||||
{ \
|
||||
uint32_t(DebugInfoDebug##Enum), "Debug" #Enum, \
|
||||
" %4 %5 %6 " #L0 " " #L1 " %7 %8 " Fstr " %9 %10 %11 %12 %13 %14", { \
|
||||
4, 5, 6, L0, L1, 7, 8, Fnum, 9, 10, 11, 12, 13, 14 \
|
||||
} \
|
||||
}
|
||||
|
||||
#define CASE_IEILLIIF(Enum, E0, L0, L1, Fstr, Fnum) \
|
||||
{ \
|
||||
uint32_t(DebugInfoDebug##Enum), "Debug" #Enum, \
|
||||
" %4 " #E0 " %5 " #L0 " " #L1 " %6 %7 " Fstr, { \
|
||||
4, uint32_t(DebugInfo##E0), 5, L0, L1, 6, 7, Fnum \
|
||||
} \
|
||||
}
|
||||
|
||||
#define CASE_IEILLIIFI(Enum, E0, L0, L1, Fstr, Fnum) \
|
||||
{ \
|
||||
uint32_t(DebugInfoDebug##Enum), "Debug" #Enum, \
|
||||
" %4 " #E0 " %5 " #L0 " " #L1 " %6 %7 " Fstr " %8", { \
|
||||
4, uint32_t(DebugInfo##E0), 5, L0, L1, 6, 7, Fnum, 8 \
|
||||
} \
|
||||
}
|
||||
|
||||
#define CASE_IEILLIIFII(Enum, E0, L0, L1, Fstr, Fnum) \
|
||||
{ \
|
||||
uint32_t(DebugInfoDebug##Enum), "Debug" #Enum, \
|
||||
" %4 " #E0 " %5 " #L0 " " #L1 " %6 %7 " Fstr " %8 %9", { \
|
||||
4, uint32_t(DebugInfo##E0), 5, L0, L1, 6, 7, Fnum, 8, 9 \
|
||||
} \
|
||||
}
|
||||
|
||||
#define CASE_IEILLIIFIII(Enum, E0, L0, L1, Fstr, Fnum) \
|
||||
{ \
|
||||
uint32_t(DebugInfoDebug##Enum), "Debug" #Enum, \
|
||||
" %4 " #E0 " %5 " #L0 " " #L1 " %6 %7 " Fstr " %8 %9 %10", { \
|
||||
4, uint32_t(DebugInfo##E0), 5, L0, L1, 6, 7, Fnum, 8, 9, 10 \
|
||||
} \
|
||||
}
|
||||
|
||||
#define CASE_IEILLIIFIIII(Enum, E0, L0, L1, Fstr, Fnum) \
|
||||
{ \
|
||||
uint32_t(DebugInfoDebug##Enum), "Debug" #Enum, \
|
||||
" %4 " #E0 " %5 " #L0 " " #L1 " %6 %7 " Fstr " %8 %9 %10 %11", { \
|
||||
4, uint32_t(DebugInfo##E0), 5, L0, L1, 6, 7, Fnum, 8, 9, 10, 11 \
|
||||
} \
|
||||
}
|
||||
|
||||
#define CASE_IIILLIIIF(Enum, L0, L1, Fstr, Fnum) \
|
||||
{ \
|
||||
uint32_t(DebugInfoDebug##Enum), "Debug" #Enum, \
|
||||
" %4 %5 %6 " #L0 " " #L1 " %7 %8 %9 " Fstr, { \
|
||||
4, 5, 6, L0, L1, 7, 8, 9, Fnum \
|
||||
} \
|
||||
}
|
||||
|
||||
#define CASE_IIILLIIIFI(Enum, L0, L1, Fstr, Fnum) \
|
||||
{ \
|
||||
uint32_t(DebugInfoDebug##Enum), "Debug" #Enum, \
|
||||
" %4 %5 %6 " #L0 " " #L1 " %7 %8 %9 " Fstr " %10", { \
|
||||
4, 5, 6, L0, L1, 7, 8, 9, Fnum, 10 \
|
||||
} \
|
||||
}
|
||||
|
||||
#define CASE_IIIIF(Enum, Fstr, Fnum) \
|
||||
{ \
|
||||
uint32_t(DebugInfoDebug##Enum), "Debug" #Enum, " %4 %5 %6 %7 " Fstr, { \
|
||||
4, 5, 6, 7, Fnum \
|
||||
} \
|
||||
}
|
||||
|
||||
#define CASE_IIILL(Enum, L0, L1) \
|
||||
{ \
|
||||
uint32_t(DebugInfoDebug##Enum), "Debug" #Enum, " %4 %5 %6 " #L0 " " #L1, { \
|
||||
4, 5, 6, L0, L1 \
|
||||
} \
|
||||
}
|
||||
|
||||
#define CASE_IIIILL(Enum, L0, L1) \
|
||||
{ \
|
||||
uint32_t(DebugInfoDebug##Enum), "Debug" #Enum, \
|
||||
" %4 %5 %6 %7 " #L0 " " #L1, { \
|
||||
4, 5, 6, 7, L0, L1 \
|
||||
} \
|
||||
}
|
||||
|
||||
#define CASE_IILLI(Enum, L0, L1) \
|
||||
{ \
|
||||
uint32_t(DebugInfoDebug##Enum), "Debug" #Enum, \
|
||||
" %4 %5 " #L0 " " #L1 " %6", { \
|
||||
4, 5, L0, L1, 6 \
|
||||
} \
|
||||
}
|
||||
|
||||
#define CASE_IILLII(Enum, L0, L1) \
|
||||
{ \
|
||||
uint32_t(DebugInfoDebug##Enum), "Debug" #Enum, \
|
||||
" %4 %5 " #L0 " " #L1 " %6 %7", { \
|
||||
4, 5, L0, L1, 6, 7 \
|
||||
} \
|
||||
}
|
||||
|
||||
#define CASE_IILLIII(Enum, L0, L1) \
|
||||
{ \
|
||||
uint32_t(DebugInfoDebug##Enum), "Debug" #Enum, \
|
||||
" %4 %5 " #L0 " " #L1 " %6 %7 %8", { \
|
||||
4, 5, L0, L1, 6, 7, 8 \
|
||||
} \
|
||||
}
|
||||
|
||||
#define CASE_IILLIIII(Enum, L0, L1) \
|
||||
{ \
|
||||
uint32_t(DebugInfoDebug##Enum), "Debug" #Enum, \
|
||||
" %4 %5 " #L0 " " #L1 " %6 %7 %8 %9", { \
|
||||
4, 5, L0, L1, 6, 7, 8, 9 \
|
||||
} \
|
||||
}
|
||||
|
||||
#define CASE_IIILLIIFLI(Enum, L0, L1, Fstr, Fnum, L2) \
|
||||
{ \
|
||||
uint32_t(DebugInfoDebug##Enum), "Debug" #Enum, \
|
||||
" %4 %5 %6 " #L0 " " #L1 " %7 %8 " Fstr " " #L2 " %9", { \
|
||||
4, 5, 6, L0, L1, 7, 8, Fnum, L2, 9 \
|
||||
} \
|
||||
}
|
||||
|
||||
#define CASE_IIILLIIFLII(Enum, L0, L1, Fstr, Fnum, L2) \
|
||||
{ \
|
||||
uint32_t(DebugInfoDebug##Enum), "Debug" #Enum, \
|
||||
" %4 %5 %6 " #L0 " " #L1 " %7 %8 " Fstr " " #L2 " %9 %10", { \
|
||||
4, 5, 6, L0, L1, 7, 8, Fnum, L2, 9, 10 \
|
||||
} \
|
||||
}
|
||||
|
||||
#define CASE_E(Enum, E0) \
|
||||
{ \
|
||||
uint32_t(DebugInfoDebug##Enum), "Debug" #Enum, " " #E0, { \
|
||||
uint32_t(DebugInfo##E0) \
|
||||
} \
|
||||
}
|
||||
|
||||
#define CASE_EL(Enum, E0, L0) \
|
||||
{ \
|
||||
uint32_t(DebugInfoDebug##Enum), "Debug" #Enum, " " #E0 " " #L0, { \
|
||||
uint32_t(DebugInfo##E0), L0 \
|
||||
} \
|
||||
}
|
||||
|
||||
#define CASE_ELL(Enum, E0, L0, L1) \
|
||||
{ \
|
||||
uint32_t(DebugInfoDebug##Enum), "Debug" #Enum, " " #E0 " " #L0 " " #L1, { \
|
||||
uint32_t(DebugInfo##E0), L0, L1 \
|
||||
} \
|
||||
}
|
||||
|
||||
// DebugInfo 4.1 Absent Debugging Information
|
||||
INSTANTIATE_TEST_SUITE_P(DebugInfoDebugInfoNone, ExtInstDebugInfoRoundTripTest,
|
||||
::testing::ValuesIn(std::vector<InstructionCase>({
|
||||
CASE_0(InfoNone), // enum value 0
|
||||
})));
|
||||
|
||||
// DebugInfo 4.2 Compilation Unit
|
||||
INSTANTIATE_TEST_SUITE_P(DebugInfoDebugCompilationUnit,
|
||||
ExtInstDebugInfoRoundTripTest,
|
||||
::testing::ValuesIn(std::vector<InstructionCase>({
|
||||
CASE_ILL(CompilationUnit, 100, 42),
|
||||
})));
|
||||
|
||||
// DebugInfo 4.3 Type instructions
|
||||
INSTANTIATE_TEST_SUITE_P(DebugInfoDebugTypeBasic, ExtInstDebugInfoRoundTripTest,
|
||||
::testing::ValuesIn(std::vector<InstructionCase>({
|
||||
CASE_IIE(TypeBasic, Unspecified),
|
||||
CASE_IIE(TypeBasic, Address),
|
||||
CASE_IIE(TypeBasic, Boolean),
|
||||
CASE_IIE(TypeBasic, Float),
|
||||
CASE_IIE(TypeBasic, Signed),
|
||||
CASE_IIE(TypeBasic, SignedChar),
|
||||
CASE_IIE(TypeBasic, Unsigned),
|
||||
CASE_IIE(TypeBasic, UnsignedChar),
|
||||
})));
|
||||
|
||||
// The FlagIsPublic is value is (1 << 0) | (1 << 2) which is the same
|
||||
// as the bitwise-OR of FlagIsProtected and FlagIsPrivate.
|
||||
// The disassembler will emit the compound expression instead.
|
||||
// There is no simple fix for this. This enum is not really a mask
|
||||
// for the bottom two bits.
|
||||
TEST_F(ExtInstDebugInfoRoundTripTestExplicit, FlagIsPublic) {
|
||||
const std::string prefix =
|
||||
"%1 = OpExtInstImport \"DebugInfo\"\n"
|
||||
"%3 = OpExtInst %2 %1 DebugTypePointer %4 Private ";
|
||||
const std::string input = prefix + "FlagIsPublic\n";
|
||||
const std::string expected = prefix + "FlagIsProtected|FlagIsPrivate\n";
|
||||
// First make sure it assembles correctly.
|
||||
EXPECT_THAT(
|
||||
CompiledInstructions(input),
|
||||
Eq(Concatenate(
|
||||
{MakeInstruction(SpvOpExtInstImport, {1}, MakeVector("DebugInfo")),
|
||||
MakeInstruction(SpvOpExtInst, {2, 3, 1, DebugInfoDebugTypePointer, 4,
|
||||
uint32_t(SpvStorageClassPrivate),
|
||||
DebugInfoFlagIsPublic})})))
|
||||
<< input;
|
||||
// Now check the round trip through the disassembler.
|
||||
EXPECT_THAT(EncodeAndDecodeSuccessfully(input), Eq(expected)) << input;
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
DebugInfoDebugTypePointer, ExtInstDebugInfoRoundTripTest,
|
||||
::testing::ValuesIn(std::vector<InstructionCase>({
|
||||
|
||||
//// Use each flag independently.
|
||||
CASE_ISF(TypePointer, Private, "FlagIsProtected",
|
||||
uint32_t(DebugInfoFlagIsProtected)),
|
||||
CASE_ISF(TypePointer, Private, "FlagIsPrivate",
|
||||
uint32_t(DebugInfoFlagIsPrivate)),
|
||||
|
||||
// FlagIsPublic is tested above.
|
||||
|
||||
CASE_ISF(TypePointer, Private, "FlagIsLocal",
|
||||
uint32_t(DebugInfoFlagIsLocal)),
|
||||
CASE_ISF(TypePointer, Private, "FlagIsDefinition",
|
||||
uint32_t(DebugInfoFlagIsDefinition)),
|
||||
CASE_ISF(TypePointer, Private, "FlagFwdDecl",
|
||||
uint32_t(DebugInfoFlagFwdDecl)),
|
||||
CASE_ISF(TypePointer, Private, "FlagArtificial",
|
||||
uint32_t(DebugInfoFlagArtificial)),
|
||||
CASE_ISF(TypePointer, Private, "FlagExplicit",
|
||||
uint32_t(DebugInfoFlagExplicit)),
|
||||
CASE_ISF(TypePointer, Private, "FlagPrototyped",
|
||||
uint32_t(DebugInfoFlagPrototyped)),
|
||||
CASE_ISF(TypePointer, Private, "FlagObjectPointer",
|
||||
uint32_t(DebugInfoFlagObjectPointer)),
|
||||
CASE_ISF(TypePointer, Private, "FlagStaticMember",
|
||||
uint32_t(DebugInfoFlagStaticMember)),
|
||||
CASE_ISF(TypePointer, Private, "FlagIndirectVariable",
|
||||
uint32_t(DebugInfoFlagIndirectVariable)),
|
||||
CASE_ISF(TypePointer, Private, "FlagLValueReference",
|
||||
uint32_t(DebugInfoFlagLValueReference)),
|
||||
CASE_ISF(TypePointer, Private, "FlagIsOptimized",
|
||||
uint32_t(DebugInfoFlagIsOptimized)),
|
||||
|
||||
//// Use flags in combination, and try different storage classes.
|
||||
CASE_ISF(TypePointer, Function, "FlagIsProtected|FlagIsPrivate",
|
||||
uint32_t(DebugInfoFlagIsProtected) |
|
||||
uint32_t(DebugInfoFlagIsPrivate)),
|
||||
CASE_ISF(
|
||||
TypePointer, Workgroup,
|
||||
"FlagIsPrivate|FlagFwdDecl|FlagIndirectVariable|FlagIsOptimized",
|
||||
uint32_t(DebugInfoFlagIsPrivate) | uint32_t(DebugInfoFlagFwdDecl) |
|
||||
uint32_t(DebugInfoFlagIndirectVariable) |
|
||||
uint32_t(DebugInfoFlagIsOptimized)),
|
||||
|
||||
})));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(DebugInfoDebugTypeQualifier,
|
||||
ExtInstDebugInfoRoundTripTest,
|
||||
::testing::ValuesIn(std::vector<InstructionCase>({
|
||||
CASE_IE(TypeQualifier, ConstType),
|
||||
CASE_IE(TypeQualifier, VolatileType),
|
||||
CASE_IE(TypeQualifier, RestrictType),
|
||||
})));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(DebugInfoDebugTypeArray, ExtInstDebugInfoRoundTripTest,
|
||||
::testing::ValuesIn(std::vector<InstructionCase>({
|
||||
CASE_II(TypeArray),
|
||||
CASE_III(TypeArray),
|
||||
CASE_IIII(TypeArray),
|
||||
CASE_IIIII(TypeArray),
|
||||
})));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(DebugInfoDebugTypeVector,
|
||||
ExtInstDebugInfoRoundTripTest,
|
||||
::testing::ValuesIn(std::vector<InstructionCase>({
|
||||
CASE_IL(TypeVector, 2),
|
||||
CASE_IL(TypeVector, 3),
|
||||
CASE_IL(TypeVector, 4),
|
||||
CASE_IL(TypeVector, 16),
|
||||
})));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(DebugInfoDebugTypedef, ExtInstDebugInfoRoundTripTest,
|
||||
::testing::ValuesIn(std::vector<InstructionCase>({
|
||||
CASE_IIILLI(Typedef, 12, 13),
|
||||
CASE_IIILLI(Typedef, 14, 99),
|
||||
})));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(DebugInfoDebugTypeFunction,
|
||||
ExtInstDebugInfoRoundTripTest,
|
||||
::testing::ValuesIn(std::vector<InstructionCase>({
|
||||
CASE_I(TypeFunction),
|
||||
CASE_II(TypeFunction),
|
||||
CASE_III(TypeFunction),
|
||||
CASE_IIII(TypeFunction),
|
||||
CASE_IIIII(TypeFunction),
|
||||
})));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
DebugInfoDebugTypeEnum, ExtInstDebugInfoRoundTripTest,
|
||||
::testing::ValuesIn(std::vector<InstructionCase>({
|
||||
CASE_IIILLIIFII(
|
||||
TypeEnum, 12, 13,
|
||||
"FlagIsPrivate|FlagFwdDecl|FlagIndirectVariable|FlagIsOptimized",
|
||||
uint32_t(DebugInfoFlagIsPrivate) | uint32_t(DebugInfoFlagFwdDecl) |
|
||||
uint32_t(DebugInfoFlagIndirectVariable) |
|
||||
uint32_t(DebugInfoFlagIsOptimized)),
|
||||
CASE_IIILLIIFIIII(TypeEnum, 17, 18, "FlagStaticMember",
|
||||
uint32_t(DebugInfoFlagStaticMember)),
|
||||
CASE_IIILLIIFIIIIII(TypeEnum, 99, 1, "FlagStaticMember",
|
||||
uint32_t(DebugInfoFlagStaticMember)),
|
||||
})));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
DebugInfoDebugTypeComposite, ExtInstDebugInfoRoundTripTest,
|
||||
::testing::ValuesIn(std::vector<InstructionCase>({
|
||||
CASE_IEILLIIF(
|
||||
TypeComposite, Class, 12, 13,
|
||||
"FlagIsPrivate|FlagFwdDecl|FlagIndirectVariable|FlagIsOptimized",
|
||||
uint32_t(DebugInfoFlagIsPrivate) | uint32_t(DebugInfoFlagFwdDecl) |
|
||||
uint32_t(DebugInfoFlagIndirectVariable) |
|
||||
uint32_t(DebugInfoFlagIsOptimized)),
|
||||
// Cover all tag values: Class, Structure, Union
|
||||
CASE_IEILLIIF(TypeComposite, Class, 12, 13, "FlagIsPrivate",
|
||||
uint32_t(DebugInfoFlagIsPrivate)),
|
||||
CASE_IEILLIIF(TypeComposite, Structure, 12, 13, "FlagIsPrivate",
|
||||
uint32_t(DebugInfoFlagIsPrivate)),
|
||||
CASE_IEILLIIF(TypeComposite, Union, 12, 13, "FlagIsPrivate",
|
||||
uint32_t(DebugInfoFlagIsPrivate)),
|
||||
// Now add members
|
||||
CASE_IEILLIIFI(TypeComposite, Class, 9, 10, "FlagIsPrivate",
|
||||
uint32_t(DebugInfoFlagIsPrivate)),
|
||||
CASE_IEILLIIFII(TypeComposite, Class, 9, 10, "FlagIsPrivate",
|
||||
uint32_t(DebugInfoFlagIsPrivate)),
|
||||
CASE_IEILLIIFIII(TypeComposite, Class, 9, 10, "FlagIsPrivate",
|
||||
uint32_t(DebugInfoFlagIsPrivate)),
|
||||
CASE_IEILLIIFIIII(TypeComposite, Class, 9, 10, "FlagIsPrivate",
|
||||
uint32_t(DebugInfoFlagIsPrivate)),
|
||||
})));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
DebugInfoDebugTypeMember, ExtInstDebugInfoRoundTripTest,
|
||||
::testing::ValuesIn(std::vector<InstructionCase>({
|
||||
CASE_IIILLIIIF(TypeMember, 12, 13, "FlagIsPrivate",
|
||||
uint32_t(DebugInfoFlagIsPrivate)),
|
||||
CASE_IIILLIIIF(TypeMember, 99, 100, "FlagIsPrivate|FlagFwdDecl",
|
||||
uint32_t(DebugInfoFlagIsPrivate) |
|
||||
uint32_t(DebugInfoFlagFwdDecl)),
|
||||
// Add the optional Id argument.
|
||||
CASE_IIILLIIIFI(TypeMember, 12, 13, "FlagIsPrivate",
|
||||
uint32_t(DebugInfoFlagIsPrivate)),
|
||||
})));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
DebugInfoDebugTypeInheritance, ExtInstDebugInfoRoundTripTest,
|
||||
::testing::ValuesIn(std::vector<InstructionCase>({
|
||||
CASE_IIIIF(TypeInheritance, "FlagIsPrivate",
|
||||
uint32_t(DebugInfoFlagIsPrivate)),
|
||||
CASE_IIIIF(TypeInheritance, "FlagIsPrivate|FlagFwdDecl",
|
||||
uint32_t(DebugInfoFlagIsPrivate) |
|
||||
uint32_t(DebugInfoFlagFwdDecl)),
|
||||
})));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(DebugInfoDebugTypePtrToMember,
|
||||
ExtInstDebugInfoRoundTripTest,
|
||||
::testing::ValuesIn(std::vector<InstructionCase>({
|
||||
CASE_II(TypePtrToMember),
|
||||
})));
|
||||
|
||||
// DebugInfo 4.4 Templates
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(DebugInfoDebugTypeTemplate,
|
||||
ExtInstDebugInfoRoundTripTest,
|
||||
::testing::ValuesIn(std::vector<InstructionCase>({
|
||||
CASE_II(TypeTemplate),
|
||||
CASE_III(TypeTemplate),
|
||||
CASE_IIII(TypeTemplate),
|
||||
CASE_IIIII(TypeTemplate),
|
||||
})));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(DebugInfoDebugTypeTemplateParameter,
|
||||
ExtInstDebugInfoRoundTripTest,
|
||||
::testing::ValuesIn(std::vector<InstructionCase>({
|
||||
CASE_IIIILL(TypeTemplateParameter, 1, 2),
|
||||
CASE_IIIILL(TypeTemplateParameter, 99, 102),
|
||||
CASE_IIIILL(TypeTemplateParameter, 10, 7),
|
||||
})));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(DebugInfoDebugTypeTemplateTemplateParameter,
|
||||
ExtInstDebugInfoRoundTripTest,
|
||||
::testing::ValuesIn(std::vector<InstructionCase>({
|
||||
CASE_IIILL(TypeTemplateTemplateParameter, 1, 2),
|
||||
CASE_IIILL(TypeTemplateTemplateParameter, 99, 102),
|
||||
CASE_IIILL(TypeTemplateTemplateParameter, 10, 7),
|
||||
})));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(DebugInfoDebugTypeTemplateParameterPack,
|
||||
ExtInstDebugInfoRoundTripTest,
|
||||
::testing::ValuesIn(std::vector<InstructionCase>({
|
||||
CASE_IILLI(TypeTemplateParameterPack, 1, 2),
|
||||
CASE_IILLII(TypeTemplateParameterPack, 99, 102),
|
||||
CASE_IILLIII(TypeTemplateParameterPack, 10, 7),
|
||||
CASE_IILLIIII(TypeTemplateParameterPack, 10, 7),
|
||||
})));
|
||||
|
||||
// DebugInfo 4.5 Global Variables
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
DebugInfoDebugGlobalVariable, ExtInstDebugInfoRoundTripTest,
|
||||
::testing::ValuesIn(std::vector<InstructionCase>({
|
||||
CASE_IIILLIIIF(GlobalVariable, 1, 2, "FlagIsOptimized",
|
||||
uint32_t(DebugInfoFlagIsOptimized)),
|
||||
CASE_IIILLIIIF(GlobalVariable, 42, 43, "FlagIsOptimized",
|
||||
uint32_t(DebugInfoFlagIsOptimized)),
|
||||
CASE_IIILLIIIFI(GlobalVariable, 1, 2, "FlagIsOptimized",
|
||||
uint32_t(DebugInfoFlagIsOptimized)),
|
||||
CASE_IIILLIIIFI(GlobalVariable, 42, 43, "FlagIsOptimized",
|
||||
uint32_t(DebugInfoFlagIsOptimized)),
|
||||
})));
|
||||
|
||||
// DebugInfo 4.6 Functions
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
DebugInfoDebugFunctionDeclaration, ExtInstDebugInfoRoundTripTest,
|
||||
::testing::ValuesIn(std::vector<InstructionCase>({
|
||||
CASE_IIILLIIF(FunctionDeclaration, 1, 2, "FlagIsOptimized",
|
||||
uint32_t(DebugInfoFlagIsOptimized)),
|
||||
CASE_IIILLIIF(FunctionDeclaration, 42, 43, "FlagFwdDecl",
|
||||
uint32_t(DebugInfoFlagFwdDecl)),
|
||||
})));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
DebugInfoDebugFunction, ExtInstDebugInfoRoundTripTest,
|
||||
::testing::ValuesIn(std::vector<InstructionCase>({
|
||||
CASE_IIILLIIFLI(Function, 1, 2, "FlagIsOptimized",
|
||||
uint32_t(DebugInfoFlagIsOptimized), 3),
|
||||
CASE_IIILLIIFLI(Function, 42, 43, "FlagFwdDecl",
|
||||
uint32_t(DebugInfoFlagFwdDecl), 44),
|
||||
// Add the optional declaration Id.
|
||||
CASE_IIILLIIFLII(Function, 1, 2, "FlagIsOptimized",
|
||||
uint32_t(DebugInfoFlagIsOptimized), 3),
|
||||
CASE_IIILLIIFLII(Function, 42, 43, "FlagFwdDecl",
|
||||
uint32_t(DebugInfoFlagFwdDecl), 44),
|
||||
})));
|
||||
|
||||
// DebugInfo 4.7 Local Information
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(DebugInfoDebugLexicalBlock,
|
||||
ExtInstDebugInfoRoundTripTest,
|
||||
::testing::ValuesIn(std::vector<InstructionCase>({
|
||||
CASE_ILLII(LexicalBlock, 1, 2),
|
||||
CASE_ILLII(LexicalBlock, 42, 43),
|
||||
})));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(DebugInfoDebugLexicalBlockDiscriminator,
|
||||
ExtInstDebugInfoRoundTripTest,
|
||||
::testing::ValuesIn(std::vector<InstructionCase>({
|
||||
CASE_ILI(LexicalBlockDiscriminator, 1),
|
||||
CASE_ILI(LexicalBlockDiscriminator, 42),
|
||||
})));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(DebugInfoDebugScope, ExtInstDebugInfoRoundTripTest,
|
||||
::testing::ValuesIn(std::vector<InstructionCase>({
|
||||
CASE_I(Scope),
|
||||
CASE_II(Scope),
|
||||
})));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(DebugInfoDebugNoScope, ExtInstDebugInfoRoundTripTest,
|
||||
::testing::ValuesIn(std::vector<InstructionCase>({
|
||||
CASE_0(NoScope),
|
||||
})));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(DebugInfoDebugInlinedAt, ExtInstDebugInfoRoundTripTest,
|
||||
::testing::ValuesIn(std::vector<InstructionCase>({
|
||||
CASE_LII(InlinedAt, 1),
|
||||
CASE_LII(InlinedAt, 42),
|
||||
})));
|
||||
|
||||
// DebugInfo 4.8 Local Variables
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(DebugInfoDebugLocalVariable,
|
||||
ExtInstDebugInfoRoundTripTest,
|
||||
::testing::ValuesIn(std::vector<InstructionCase>({
|
||||
CASE_IIILLI(LocalVariable, 1, 2),
|
||||
CASE_IIILLI(LocalVariable, 42, 43),
|
||||
CASE_IIILLIL(LocalVariable, 1, 2, 3),
|
||||
CASE_IIILLIL(LocalVariable, 42, 43, 44),
|
||||
})));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(DebugInfoDebugInlinedVariable,
|
||||
ExtInstDebugInfoRoundTripTest,
|
||||
::testing::ValuesIn(std::vector<InstructionCase>({
|
||||
CASE_II(InlinedVariable),
|
||||
})));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(DebugInfoDebugDebugDeclare,
|
||||
ExtInstDebugInfoRoundTripTest,
|
||||
::testing::ValuesIn(std::vector<InstructionCase>({
|
||||
CASE_III(Declare),
|
||||
})));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
DebugInfoDebugDebugValue, ExtInstDebugInfoRoundTripTest,
|
||||
::testing::ValuesIn(std::vector<InstructionCase>({
|
||||
CASE_III(Value),
|
||||
CASE_IIII(Value),
|
||||
CASE_IIIII(Value),
|
||||
CASE_IIIIII(Value),
|
||||
// Test up to 4 id parameters. We can always try more.
|
||||
CASE_IIIIIII(Value),
|
||||
})));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(DebugInfoDebugDebugOperation,
|
||||
ExtInstDebugInfoRoundTripTest,
|
||||
::testing::ValuesIn(std::vector<InstructionCase>({
|
||||
CASE_E(Operation, Deref),
|
||||
CASE_E(Operation, Plus),
|
||||
CASE_E(Operation, Minus),
|
||||
CASE_EL(Operation, PlusUconst, 1),
|
||||
CASE_EL(Operation, PlusUconst, 42),
|
||||
CASE_ELL(Operation, BitPiece, 1, 2),
|
||||
CASE_ELL(Operation, BitPiece, 4, 5),
|
||||
CASE_E(Operation, Swap),
|
||||
CASE_E(Operation, Xderef),
|
||||
CASE_E(Operation, StackValue),
|
||||
CASE_EL(Operation, Constu, 1),
|
||||
CASE_EL(Operation, Constu, 42),
|
||||
})));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(DebugInfoDebugDebugExpression,
|
||||
ExtInstDebugInfoRoundTripTest,
|
||||
::testing::ValuesIn(std::vector<InstructionCase>({
|
||||
CASE_0(Expression),
|
||||
CASE_I(Expression),
|
||||
CASE_II(Expression),
|
||||
CASE_III(Expression),
|
||||
CASE_IIII(Expression),
|
||||
CASE_IIIII(Expression),
|
||||
CASE_IIIIII(Expression),
|
||||
CASE_IIIIIII(Expression),
|
||||
})));
|
||||
|
||||
// DebugInfo 4.9 Macros
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(DebugInfoDebugMacroDef, ExtInstDebugInfoRoundTripTest,
|
||||
::testing::ValuesIn(std::vector<InstructionCase>({
|
||||
CASE_ILI(MacroDef, 1),
|
||||
CASE_ILI(MacroDef, 42),
|
||||
CASE_ILII(MacroDef, 1),
|
||||
CASE_ILII(MacroDef, 42),
|
||||
})));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(DebugInfoDebugMacroUndef,
|
||||
ExtInstDebugInfoRoundTripTest,
|
||||
::testing::ValuesIn(std::vector<InstructionCase>({
|
||||
CASE_ILI(MacroUndef, 1),
|
||||
CASE_ILI(MacroUndef, 42),
|
||||
})));
|
||||
|
||||
#undef CASE_0
|
||||
#undef CASE_ILL
|
||||
#undef CASE_IL
|
||||
#undef CASE_I
|
||||
#undef CASE_II
|
||||
#undef CASE_III
|
||||
#undef CASE_IIII
|
||||
#undef CASE_IIIII
|
||||
#undef CASE_IIIIII
|
||||
#undef CASE_IIIIIII
|
||||
#undef CASE_IIILLI
|
||||
#undef CASE_IIILLIL
|
||||
#undef CASE_IE
|
||||
#undef CASE_IIE
|
||||
#undef CASE_ISF
|
||||
#undef CASE_LII
|
||||
#undef CASE_ILI
|
||||
#undef CASE_ILII
|
||||
#undef CASE_ILLII
|
||||
#undef CASE_IIILLIIF
|
||||
#undef CASE_IIILLIIFII
|
||||
#undef CASE_IIILLIIFIIII
|
||||
#undef CASE_IIILLIIFIIIIII
|
||||
#undef CASE_IEILLIIF
|
||||
#undef CASE_IEILLIIFI
|
||||
#undef CASE_IEILLIIFII
|
||||
#undef CASE_IEILLIIFIII
|
||||
#undef CASE_IEILLIIFIIII
|
||||
#undef CASE_IIILLIIIF
|
||||
#undef CASE_IIILLIIIFI
|
||||
#undef CASE_IIIIF
|
||||
#undef CASE_IIILL
|
||||
#undef CASE_IIIILL
|
||||
#undef CASE_IILLI
|
||||
#undef CASE_IILLII
|
||||
#undef CASE_IILLIII
|
||||
#undef CASE_IILLIIII
|
||||
#undef CASE_IIILLIIFLI
|
||||
#undef CASE_IIILLIIFLII
|
||||
#undef CASE_E
|
||||
#undef CASE_EL
|
||||
#undef CASE_ELL
|
||||
|
||||
} // namespace
|
||||
} // namespace spvtools
|
||||
204
3rdparty/spirv-tools/test/ext_inst.glsl_test.cpp
vendored
204
3rdparty/spirv-tools/test/ext_inst.glsl_test.cpp
vendored
@@ -1,204 +0,0 @@
|
||||
// Copyright (c) 2015-2016 The Khronos Group Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "source/latest_version_glsl_std_450_header.h"
|
||||
#include "test/unit_spirv.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace {
|
||||
|
||||
/// Context for an extended instruction.
|
||||
///
|
||||
/// Information about a GLSL extended instruction (including its opname, return
|
||||
/// type, etc.) and related instructions used to generate the return type and
|
||||
/// constant as the operands. Used in generating extended instruction tests.
|
||||
struct ExtInstContext {
|
||||
const char* extInstOpName;
|
||||
const char* extInstOperandVars;
|
||||
/// The following fields are used to check the SPIR-V binary representation
|
||||
/// of this instruction.
|
||||
uint32_t extInstOpcode; ///< Opcode value for this extended instruction.
|
||||
uint32_t extInstLength; ///< Wordcount of this extended instruction.
|
||||
std::vector<uint32_t> extInstOperandIds; ///< Ids for operands.
|
||||
};
|
||||
|
||||
using ExtInstGLSLstd450RoundTripTest = ::testing::TestWithParam<ExtInstContext>;
|
||||
|
||||
TEST_P(ExtInstGLSLstd450RoundTripTest, ParameterizedExtInst) {
|
||||
spv_context context = spvContextCreate(SPV_ENV_UNIVERSAL_1_0);
|
||||
const std::string spirv = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical Simple
|
||||
OpEntryPoint Vertex %2 "main"
|
||||
%3 = OpTypeVoid
|
||||
%4 = OpTypeFunction %3
|
||||
%2 = OpFunction %3 None %5
|
||||
%6 = OpLabel
|
||||
%8 = OpExtInst %7 %1 )" + std::string(GetParam().extInstOpName) +
|
||||
" " + GetParam().extInstOperandVars + R"(
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
const std::string spirv_header =
|
||||
R"(; SPIR-V
|
||||
; Version: 1.0
|
||||
; Generator: Khronos SPIR-V Tools Assembler; 0
|
||||
; Bound: 9
|
||||
; Schema: 0)";
|
||||
spv_binary binary = nullptr;
|
||||
spv_diagnostic diagnostic;
|
||||
spv_result_t error = spvTextToBinary(context, spirv.c_str(), spirv.size(),
|
||||
&binary, &diagnostic);
|
||||
if (error) {
|
||||
spvDiagnosticPrint(diagnostic);
|
||||
spvDiagnosticDestroy(diagnostic);
|
||||
ASSERT_EQ(SPV_SUCCESS, error)
|
||||
<< "Source was: " << std::endl
|
||||
<< spirv << std::endl
|
||||
<< "Test case for : " << GetParam().extInstOpName << std::endl;
|
||||
}
|
||||
|
||||
// Check we do have the extended instruction's corresponding binary code in
|
||||
// the generated SPIR-V binary.
|
||||
std::vector<uint32_t> expected_contains(
|
||||
{12 /*OpExtInst*/ | GetParam().extInstLength << 16, 7 /*return type*/,
|
||||
8 /*result id*/, 1 /*glsl450 import*/, GetParam().extInstOpcode});
|
||||
for (uint32_t operand : GetParam().extInstOperandIds) {
|
||||
expected_contains.push_back(operand);
|
||||
}
|
||||
EXPECT_NE(binary->code + binary->wordCount,
|
||||
std::search(binary->code, binary->code + binary->wordCount,
|
||||
expected_contains.begin(), expected_contains.end()))
|
||||
<< "Cannot find\n"
|
||||
<< spvtest::WordVector(expected_contains).str() << "in\n"
|
||||
<< spvtest::WordVector(*binary).str();
|
||||
|
||||
// Check round trip gives the same text.
|
||||
spv_text output_text = nullptr;
|
||||
error = spvBinaryToText(context, binary->code, binary->wordCount,
|
||||
SPV_BINARY_TO_TEXT_OPTION_NONE, &output_text,
|
||||
&diagnostic);
|
||||
|
||||
if (error) {
|
||||
spvDiagnosticPrint(diagnostic);
|
||||
spvDiagnosticDestroy(diagnostic);
|
||||
ASSERT_EQ(SPV_SUCCESS, error);
|
||||
}
|
||||
EXPECT_EQ(spirv_header + spirv, output_text->str);
|
||||
spvTextDestroy(output_text);
|
||||
spvBinaryDestroy(binary);
|
||||
spvContextDestroy(context);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
ExtInstParameters, ExtInstGLSLstd450RoundTripTest,
|
||||
::testing::ValuesIn(std::vector<ExtInstContext>({
|
||||
// We are only testing the correctness of encoding and decoding here.
|
||||
// Semantic correctness should be the responsibility of validator. So
|
||||
// some of the instructions below have incorrect operand and/or return
|
||||
// types, e.g, Modf, ModfStruct, etc.
|
||||
{"Round", "%5", 1, 6, {5}},
|
||||
{"RoundEven", "%5", 2, 6, {5}},
|
||||
{"Trunc", "%5", 3, 6, {5}},
|
||||
{"FAbs", "%5", 4, 6, {5}},
|
||||
{"SAbs", "%5", 5, 6, {5}},
|
||||
{"FSign", "%5", 6, 6, {5}},
|
||||
{"SSign", "%5", 7, 6, {5}},
|
||||
{"Floor", "%5", 8, 6, {5}},
|
||||
{"Ceil", "%5", 9, 6, {5}},
|
||||
{"Fract", "%5", 10, 6, {5}},
|
||||
{"Radians", "%5", 11, 6, {5}},
|
||||
{"Degrees", "%5", 12, 6, {5}},
|
||||
{"Sin", "%5", 13, 6, {5}},
|
||||
{"Cos", "%5", 14, 6, {5}},
|
||||
{"Tan", "%5", 15, 6, {5}},
|
||||
{"Asin", "%5", 16, 6, {5}},
|
||||
{"Acos", "%5", 17, 6, {5}},
|
||||
{"Atan", "%5", 18, 6, {5}},
|
||||
{"Sinh", "%5", 19, 6, {5}},
|
||||
{"Cosh", "%5", 20, 6, {5}},
|
||||
{"Tanh", "%5", 21, 6, {5}},
|
||||
{"Asinh", "%5", 22, 6, {5}},
|
||||
{"Acosh", "%5", 23, 6, {5}},
|
||||
{"Atanh", "%5", 24, 6, {5}},
|
||||
{"Atan2", "%5 %5", 25, 7, {5, 5}},
|
||||
{"Pow", "%5 %5", 26, 7, {5, 5}},
|
||||
{"Exp", "%5", 27, 6, {5}},
|
||||
{"Log", "%5", 28, 6, {5}},
|
||||
{"Exp2", "%5", 29, 6, {5}},
|
||||
{"Log2", "%5", 30, 6, {5}},
|
||||
{"Sqrt", "%5", 31, 6, {5}},
|
||||
{"InverseSqrt", "%5", 32, 6, {5}},
|
||||
{"Determinant", "%5", 33, 6, {5}},
|
||||
{"MatrixInverse", "%5", 34, 6, {5}},
|
||||
{"Modf", "%5 %5", 35, 7, {5, 5}},
|
||||
{"ModfStruct", "%5", 36, 6, {5}},
|
||||
{"FMin", "%5 %5", 37, 7, {5, 5}},
|
||||
{"UMin", "%5 %5", 38, 7, {5, 5}},
|
||||
{"SMin", "%5 %5", 39, 7, {5, 5}},
|
||||
{"FMax", "%5 %5", 40, 7, {5, 5}},
|
||||
{"UMax", "%5 %5", 41, 7, {5, 5}},
|
||||
{"SMax", "%5 %5", 42, 7, {5, 5}},
|
||||
{"FClamp", "%5 %5 %5", 43, 8, {5, 5, 5}},
|
||||
{"UClamp", "%5 %5 %5", 44, 8, {5, 5, 5}},
|
||||
{"SClamp", "%5 %5 %5", 45, 8, {5, 5, 5}},
|
||||
{"FMix", "%5 %5 %5", 46, 8, {5, 5, 5}},
|
||||
{"IMix", "%5 %5 %5", 47, 8, {5, 5, 5}}, // Bug 15452. Reserved.
|
||||
{"Step", "%5 %5", 48, 7, {5, 5}},
|
||||
{"SmoothStep", "%5 %5 %5", 49, 8, {5, 5, 5}},
|
||||
{"Fma", "%5 %5 %5", 50, 8, {5, 5, 5}},
|
||||
{"Frexp", "%5 %5", 51, 7, {5, 5}},
|
||||
{"FrexpStruct", "%5", 52, 6, {5}},
|
||||
{"Ldexp", "%5 %5", 53, 7, {5, 5}},
|
||||
{"PackSnorm4x8", "%5", 54, 6, {5}},
|
||||
{"PackUnorm4x8", "%5", 55, 6, {5}},
|
||||
{"PackSnorm2x16", "%5", 56, 6, {5}},
|
||||
{"PackUnorm2x16", "%5", 57, 6, {5}},
|
||||
{"PackHalf2x16", "%5", 58, 6, {5}},
|
||||
{"PackDouble2x32", "%5", 59, 6, {5}},
|
||||
{"UnpackSnorm2x16", "%5", 60, 6, {5}},
|
||||
{"UnpackUnorm2x16", "%5", 61, 6, {5}},
|
||||
{"UnpackHalf2x16", "%5", 62, 6, {5}},
|
||||
{"UnpackSnorm4x8", "%5", 63, 6, {5}},
|
||||
{"UnpackUnorm4x8", "%5", 64, 6, {5}},
|
||||
{"UnpackDouble2x32", "%5", 65, 6, {5}},
|
||||
{"Length", "%5", 66, 6, {5}},
|
||||
{"Distance", "%5 %5", 67, 7, {5, 5}},
|
||||
{"Cross", "%5 %5", 68, 7, {5, 5}},
|
||||
{"Normalize", "%5", 69, 6, {5}},
|
||||
// clang-format off
|
||||
{"FaceForward", "%5 %5 %5", 70, 8, {5, 5, 5}},
|
||||
// clang-format on
|
||||
{"Reflect", "%5 %5", 71, 7, {5, 5}},
|
||||
{"Refract", "%5 %5 %5", 72, 8, {5, 5, 5}},
|
||||
{"FindILsb", "%5", 73, 6, {5}},
|
||||
{"FindSMsb", "%5", 74, 6, {5}},
|
||||
{"FindUMsb", "%5", 75, 6, {5}},
|
||||
{"InterpolateAtCentroid", "%5", 76, 6, {5}},
|
||||
// clang-format off
|
||||
{"InterpolateAtSample", "%5 %5", 77, 7, {5, 5}},
|
||||
{"InterpolateAtOffset", "%5 %5", 78, 7, {5, 5}},
|
||||
// clang-format on
|
||||
{"NMin", "%5 %5", 79, 7, {5, 5}},
|
||||
{"NMax", "%5 %5", 80, 7, {5, 5}},
|
||||
{"NClamp", "%5 %5 %5", 81, 8, {5, 5, 5}},
|
||||
})));
|
||||
|
||||
} // namespace
|
||||
} // namespace spvtools
|
||||
374
3rdparty/spirv-tools/test/ext_inst.opencl_test.cpp
vendored
374
3rdparty/spirv-tools/test/ext_inst.opencl_test.cpp
vendored
@@ -1,374 +0,0 @@
|
||||
// Copyright (c) 2015-2016 The Khronos Group Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "source/latest_version_opencl_std_header.h"
|
||||
#include "source/util/string_utils.h"
|
||||
#include "test/test_fixture.h"
|
||||
#include "test/unit_spirv.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace {
|
||||
|
||||
using spvtest::Concatenate;
|
||||
using spvtest::MakeInstruction;
|
||||
using utils::MakeVector;
|
||||
using spvtest::TextToBinaryTest;
|
||||
using testing::Eq;
|
||||
|
||||
struct InstructionCase {
|
||||
uint32_t opcode;
|
||||
std::string name;
|
||||
std::string operands;
|
||||
std::vector<uint32_t> expected_operands;
|
||||
};
|
||||
|
||||
using ExtInstOpenCLStdRoundTripTest =
|
||||
spvtest::TextToBinaryTestBase<::testing::TestWithParam<InstructionCase>>;
|
||||
|
||||
TEST_P(ExtInstOpenCLStdRoundTripTest, ParameterizedExtInst) {
|
||||
// This example should not validate.
|
||||
const std::string input =
|
||||
"%1 = OpExtInstImport \"OpenCL.std\"\n"
|
||||
"%3 = OpExtInst %2 %1 " +
|
||||
GetParam().name + " " + GetParam().operands + "\n";
|
||||
// First make sure it assembles correctly.
|
||||
EXPECT_THAT(
|
||||
CompiledInstructions(input),
|
||||
Eq(Concatenate(
|
||||
{MakeInstruction(SpvOpExtInstImport, {1}, MakeVector("OpenCL.std")),
|
||||
MakeInstruction(SpvOpExtInst, {2, 3, 1, GetParam().opcode},
|
||||
GetParam().expected_operands)})))
|
||||
<< input;
|
||||
// Now check the round trip through the disassembler.
|
||||
EXPECT_THAT(EncodeAndDecodeSuccessfully(input), input) << input;
|
||||
}
|
||||
|
||||
#define CASE1(Enum, Name) \
|
||||
{ \
|
||||
uint32_t(OpenCLLIB::Entrypoints::Enum), #Name, "%4", { 4 } \
|
||||
}
|
||||
#define CASE2(Enum, Name) \
|
||||
{ \
|
||||
uint32_t(OpenCLLIB::Entrypoints::Enum), #Name, "%4 %5", { 4, 5 } \
|
||||
}
|
||||
#define CASE3(Enum, Name) \
|
||||
{ \
|
||||
uint32_t(OpenCLLIB::Entrypoints::Enum), #Name, "%4 %5 %6", { 4, 5, 6 } \
|
||||
}
|
||||
#define CASE4(Enum, Name) \
|
||||
{ \
|
||||
uint32_t(OpenCLLIB::Entrypoints::Enum), #Name, "%4 %5 %6 %7", { \
|
||||
4, 5, 6, 7 \
|
||||
} \
|
||||
}
|
||||
#define CASE2Lit(Enum, Name, LiteralNumber) \
|
||||
{ \
|
||||
uint32_t(OpenCLLIB::Entrypoints::Enum), #Name, "%4 %5 " #LiteralNumber, { \
|
||||
4, 5, LiteralNumber \
|
||||
} \
|
||||
}
|
||||
#define CASE3Round(Enum, Name, Mode) \
|
||||
{ \
|
||||
uint32_t(OpenCLLIB::Entrypoints::Enum), #Name, "%4 %5 %6 " #Mode, { \
|
||||
4, 5, 6, uint32_t(SpvFPRoundingMode##Mode) \
|
||||
} \
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
// OpenCL.std: 2.1 Math extended instructions
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
OpenCLMath, ExtInstOpenCLStdRoundTripTest,
|
||||
::testing::ValuesIn(std::vector<InstructionCase>({
|
||||
// We are only testing the correctness of encoding and decoding here.
|
||||
// Semantic correctness should be the responsibility of validator.
|
||||
CASE1(Acos, acos), // enum value 0
|
||||
CASE1(Acosh, acosh),
|
||||
CASE1(Acospi, acospi),
|
||||
CASE1(Asin, asin),
|
||||
CASE1(Asinh, asinh),
|
||||
CASE1(Asinh, asinh),
|
||||
CASE1(Asinpi, asinpi),
|
||||
CASE1(Atan, atan),
|
||||
CASE2(Atan2, atan2),
|
||||
CASE1(Atanh, atanh),
|
||||
CASE1(Atanpi, atanpi),
|
||||
CASE2(Atan2pi, atan2pi),
|
||||
CASE1(Cbrt, cbrt),
|
||||
CASE1(Ceil, ceil),
|
||||
CASE1(Ceil, ceil),
|
||||
CASE2(Copysign, copysign),
|
||||
CASE1(Cos, cos),
|
||||
CASE1(Cosh, cosh),
|
||||
CASE1(Cospi, cospi),
|
||||
CASE1(Erfc, erfc),
|
||||
CASE1(Erf, erf),
|
||||
CASE1(Exp, exp),
|
||||
CASE1(Exp2, exp2),
|
||||
CASE1(Exp10, exp10),
|
||||
CASE1(Expm1, expm1),
|
||||
CASE1(Fabs, fabs),
|
||||
CASE2(Fdim, fdim),
|
||||
CASE1(Floor, floor),
|
||||
CASE3(Fma, fma),
|
||||
CASE2(Fmax, fmax),
|
||||
CASE2(Fmin, fmin),
|
||||
CASE2(Fmod, fmod),
|
||||
CASE2(Fract, fract),
|
||||
CASE2(Frexp, frexp),
|
||||
CASE2(Hypot, hypot),
|
||||
CASE1(Ilogb, ilogb),
|
||||
CASE2(Ldexp, ldexp),
|
||||
CASE1(Lgamma, lgamma),
|
||||
CASE2(Lgamma_r, lgamma_r),
|
||||
CASE1(Log, log),
|
||||
CASE1(Log2, log2),
|
||||
CASE1(Log10, log10),
|
||||
CASE1(Log1p, log1p),
|
||||
CASE3(Mad, mad),
|
||||
CASE2(Maxmag, maxmag),
|
||||
CASE2(Minmag, minmag),
|
||||
CASE2(Modf, modf),
|
||||
CASE1(Nan, nan),
|
||||
CASE2(Nextafter, nextafter),
|
||||
CASE2(Pow, pow),
|
||||
CASE2(Pown, pown),
|
||||
CASE2(Powr, powr),
|
||||
CASE2(Remainder, remainder),
|
||||
CASE3(Remquo, remquo),
|
||||
CASE1(Rint, rint),
|
||||
CASE2(Rootn, rootn),
|
||||
CASE1(Round, round),
|
||||
CASE1(Rsqrt, rsqrt),
|
||||
CASE1(Sin, sin),
|
||||
CASE2(Sincos, sincos),
|
||||
CASE1(Sinh, sinh),
|
||||
CASE1(Sinpi, sinpi),
|
||||
CASE1(Sqrt, sqrt),
|
||||
CASE1(Tan, tan),
|
||||
CASE1(Tanh, tanh),
|
||||
CASE1(Tanpi, tanpi),
|
||||
CASE1(Tgamma, tgamma),
|
||||
CASE1(Trunc, trunc),
|
||||
CASE1(Half_cos, half_cos),
|
||||
CASE2(Half_divide, half_divide),
|
||||
CASE1(Half_exp, half_exp),
|
||||
CASE1(Half_exp2, half_exp2),
|
||||
CASE1(Half_exp10, half_exp10),
|
||||
CASE1(Half_log, half_log),
|
||||
CASE1(Half_log2, half_log2),
|
||||
CASE1(Half_log10, half_log10),
|
||||
CASE2(Half_powr, half_powr),
|
||||
CASE1(Half_recip, half_recip),
|
||||
CASE1(Half_rsqrt, half_rsqrt),
|
||||
CASE1(Half_sin, half_sin),
|
||||
CASE1(Half_sqrt, half_sqrt),
|
||||
CASE1(Half_tan, half_tan),
|
||||
CASE1(Native_cos, native_cos),
|
||||
CASE2(Native_divide, native_divide),
|
||||
CASE1(Native_exp, native_exp),
|
||||
CASE1(Native_exp2, native_exp2),
|
||||
CASE1(Native_exp10, native_exp10),
|
||||
CASE1(Native_log, native_log),
|
||||
CASE1(Native_log10, native_log10),
|
||||
CASE2(Native_powr, native_powr),
|
||||
CASE1(Native_recip, native_recip),
|
||||
CASE1(Native_rsqrt, native_rsqrt),
|
||||
CASE1(Native_sin, native_sin),
|
||||
CASE1(Native_sqrt, native_sqrt),
|
||||
CASE1(Native_tan, native_tan), // enum value 94
|
||||
})));
|
||||
|
||||
// OpenCL.std: 2.1 Integer instructions
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
OpenCLInteger, ExtInstOpenCLStdRoundTripTest,
|
||||
::testing::ValuesIn(std::vector<InstructionCase>({
|
||||
CASE1(SAbs, s_abs), // enum value 141
|
||||
CASE2(SAbs_diff, s_abs_diff),
|
||||
CASE2(SAdd_sat, s_add_sat),
|
||||
CASE2(UAdd_sat, u_add_sat),
|
||||
CASE2(SHadd, s_hadd),
|
||||
CASE2(UHadd, u_hadd),
|
||||
CASE2(SRhadd, s_rhadd),
|
||||
CASE2(SRhadd, s_rhadd),
|
||||
CASE3(SClamp, s_clamp),
|
||||
CASE3(UClamp, u_clamp),
|
||||
CASE1(Clz, clz),
|
||||
CASE1(Ctz, ctz),
|
||||
CASE3(SMad_hi, s_mad_hi),
|
||||
CASE3(UMad_sat, u_mad_sat),
|
||||
CASE3(SMad_sat, s_mad_sat),
|
||||
CASE2(SMax, s_max),
|
||||
CASE2(UMax, u_max),
|
||||
CASE2(SMin, s_min),
|
||||
CASE2(UMin, u_min),
|
||||
CASE2(SMul_hi, s_mul_hi),
|
||||
CASE2(Rotate, rotate),
|
||||
CASE2(SSub_sat, s_sub_sat),
|
||||
CASE2(USub_sat, u_sub_sat),
|
||||
CASE2(U_Upsample, u_upsample),
|
||||
CASE2(S_Upsample, s_upsample),
|
||||
CASE1(Popcount, popcount),
|
||||
CASE3(SMad24, s_mad24),
|
||||
CASE3(UMad24, u_mad24),
|
||||
CASE2(SMul24, s_mul24),
|
||||
CASE2(UMul24, u_mul24), // enum value 170
|
||||
CASE1(UAbs, u_abs), // enum value 201
|
||||
CASE2(UAbs_diff, u_abs_diff),
|
||||
CASE2(UMul_hi, u_mul_hi),
|
||||
CASE3(UMad_hi, u_mad_hi), // enum value 204
|
||||
})));
|
||||
|
||||
// OpenCL.std: 2.3 Common instrucitons
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
OpenCLCommon, ExtInstOpenCLStdRoundTripTest,
|
||||
::testing::ValuesIn(std::vector<InstructionCase>({
|
||||
CASE3(FClamp, fclamp), // enum value 95
|
||||
CASE1(Degrees, degrees),
|
||||
CASE2(FMax_common, fmax_common),
|
||||
CASE2(FMin_common, fmin_common),
|
||||
CASE3(Mix, mix),
|
||||
CASE1(Radians, radians),
|
||||
CASE2(Step, step),
|
||||
CASE3(Smoothstep, smoothstep),
|
||||
CASE1(Sign, sign), // enum value 103
|
||||
})));
|
||||
|
||||
// OpenCL.std: 2.4 Geometric instructions
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
OpenCLGeometric, ExtInstOpenCLStdRoundTripTest,
|
||||
::testing::ValuesIn(std::vector<InstructionCase>({
|
||||
CASE2(Cross, cross), // enum value 104
|
||||
CASE2(Distance, distance),
|
||||
CASE1(Length, length),
|
||||
CASE1(Normalize, normalize),
|
||||
CASE2(Fast_distance, fast_distance),
|
||||
CASE1(Fast_length, fast_length),
|
||||
CASE1(Fast_normalize, fast_normalize), // enum value 110
|
||||
})));
|
||||
|
||||
// OpenCL.std: 2.5 Relational instructions
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
OpenCLRelational, ExtInstOpenCLStdRoundTripTest,
|
||||
::testing::ValuesIn(std::vector<InstructionCase>({
|
||||
CASE3(Bitselect, bitselect), // enum value 186
|
||||
CASE3(Select, select), // enum value 187
|
||||
})));
|
||||
|
||||
// OpenCL.std: 2.6 Vector data load and store instructions
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
OpenCLVectorLoadStore, ExtInstOpenCLStdRoundTripTest,
|
||||
::testing::ValuesIn(std::vector<InstructionCase>({
|
||||
// The last argument to Vloadn must be one of 2, 3, 4, 8, 16.
|
||||
CASE2Lit(Vloadn, vloadn, 2),
|
||||
CASE2Lit(Vloadn, vloadn, 3),
|
||||
CASE2Lit(Vloadn, vloadn, 4),
|
||||
CASE2Lit(Vloadn, vloadn, 8),
|
||||
CASE2Lit(Vloadn, vloadn, 16),
|
||||
CASE3(Vstoren, vstoren),
|
||||
CASE2(Vload_half, vload_half),
|
||||
CASE2Lit(Vload_halfn, vload_halfn, 2),
|
||||
CASE2Lit(Vload_halfn, vload_halfn, 3),
|
||||
CASE2Lit(Vload_halfn, vload_halfn, 4),
|
||||
CASE2Lit(Vload_halfn, vload_halfn, 8),
|
||||
CASE2Lit(Vload_halfn, vload_halfn, 16),
|
||||
CASE3(Vstore_half, vstore_half),
|
||||
// Try all the rounding modes.
|
||||
CASE3Round(Vstore_half_r, vstore_half_r, RTE),
|
||||
CASE3Round(Vstore_half_r, vstore_half_r, RTZ),
|
||||
CASE3Round(Vstore_half_r, vstore_half_r, RTP),
|
||||
CASE3Round(Vstore_half_r, vstore_half_r, RTN),
|
||||
CASE3(Vstore_halfn, vstore_halfn),
|
||||
CASE3Round(Vstore_halfn_r, vstore_halfn_r, RTE),
|
||||
CASE3Round(Vstore_halfn_r, vstore_halfn_r, RTZ),
|
||||
CASE3Round(Vstore_halfn_r, vstore_halfn_r, RTP),
|
||||
CASE3Round(Vstore_halfn_r, vstore_halfn_r, RTN),
|
||||
CASE2Lit(Vloada_halfn, vloada_halfn, 2),
|
||||
CASE2Lit(Vloada_halfn, vloada_halfn, 3),
|
||||
CASE2Lit(Vloada_halfn, vloada_halfn, 4),
|
||||
CASE2Lit(Vloada_halfn, vloada_halfn, 8),
|
||||
CASE2Lit(Vloada_halfn, vloada_halfn, 16),
|
||||
CASE3(Vstorea_halfn, vstorea_halfn),
|
||||
CASE3Round(Vstorea_halfn_r, vstorea_halfn_r, RTE),
|
||||
CASE3Round(Vstorea_halfn_r, vstorea_halfn_r, RTZ),
|
||||
CASE3Round(Vstorea_halfn_r, vstorea_halfn_r, RTP),
|
||||
CASE3Round(Vstorea_halfn_r, vstorea_halfn_r, RTN),
|
||||
})));
|
||||
|
||||
// OpenCL.std: 2.7 Miscellaneous vector instructions
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
OpenCLMiscellaneousVector, ExtInstOpenCLStdRoundTripTest,
|
||||
::testing::ValuesIn(std::vector<InstructionCase>({
|
||||
CASE2(Shuffle, shuffle),
|
||||
CASE3(Shuffle2, shuffle2),
|
||||
})));
|
||||
|
||||
// OpenCL.std: 2.8 Miscellaneous instructions
|
||||
|
||||
#define PREFIX uint32_t(OpenCLLIB::Entrypoints::Printf), "printf"
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
OpenCLMiscPrintf, ExtInstOpenCLStdRoundTripTest,
|
||||
::testing::ValuesIn(std::vector<InstructionCase>({
|
||||
// Printf is interesting because it takes a variable number of arguments.
|
||||
// Start with zero optional arguments.
|
||||
{PREFIX, "%4", {4}},
|
||||
{PREFIX, "%4 %5", {4, 5}},
|
||||
{PREFIX, "%4 %5 %6", {4, 5, 6}},
|
||||
{PREFIX, "%4 %5 %6 %7", {4, 5, 6, 7}},
|
||||
{PREFIX, "%4 %5 %6 %7 %8", {4, 5, 6, 7, 8}},
|
||||
{PREFIX, "%4 %5 %6 %7 %8 %9", {4, 5, 6, 7, 8, 9}},
|
||||
{PREFIX, "%4 %5 %6 %7 %8 %9 %10", {4, 5, 6, 7, 8, 9, 10}},
|
||||
{PREFIX, "%4 %5 %6 %7 %8 %9 %10 %11", {4, 5, 6, 7, 8, 9, 10, 11}},
|
||||
{PREFIX, "%4 %5 %6 %7 %8 %9 %10 %11 %12",
|
||||
{4, 5, 6, 7, 8, 9, 10, 11, 12}},
|
||||
{PREFIX, "%4 %5 %6 %7 %8 %9 %10 %11 %12 %13",
|
||||
{4, 5, 6, 7, 8, 9, 10, 11, 12, 13}},
|
||||
{PREFIX, "%4 %5 %6 %7 %8 %9 %10 %11 %12 %13 %14",
|
||||
{4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}},
|
||||
})));
|
||||
#undef PREFIX
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
OpenCLMiscPrefetch, ExtInstOpenCLStdRoundTripTest,
|
||||
::testing::ValuesIn(std::vector<InstructionCase>({
|
||||
CASE2(Prefetch, prefetch),
|
||||
})));
|
||||
|
||||
// OpenCL.std: 2.9.1 Image encoding
|
||||
// No new instructions defined in this section.
|
||||
|
||||
// OpenCL.std: 2.9.2 Sampler encoding
|
||||
// No new instructions defined in this section.
|
||||
|
||||
// OpenCL.std: 2.9.3 Image read
|
||||
// No new instructions defined in this section.
|
||||
// Use core instruction OpImageSampleExplicitLod instead.
|
||||
|
||||
// OpenCL.std: 2.9.4 Image write
|
||||
// No new instructions defined in this section.
|
||||
|
||||
// clang-format on
|
||||
|
||||
#undef CASE1
|
||||
#undef CASE2
|
||||
#undef CASE3
|
||||
#undef CASE4
|
||||
#undef CASE2Lit
|
||||
#undef CASE3Round
|
||||
|
||||
} // namespace
|
||||
} // namespace spvtools
|
||||
64
3rdparty/spirv-tools/test/fix_word_test.cpp
vendored
64
3rdparty/spirv-tools/test/fix_word_test.cpp
vendored
@@ -1,64 +0,0 @@
|
||||
// Copyright (c) 2015-2016 The Khronos Group Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "test/unit_spirv.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace {
|
||||
|
||||
TEST(FixWord, Default) {
|
||||
spv_endianness_t endian;
|
||||
if (I32_ENDIAN_HOST == I32_ENDIAN_LITTLE) {
|
||||
endian = SPV_ENDIANNESS_LITTLE;
|
||||
} else {
|
||||
endian = SPV_ENDIANNESS_BIG;
|
||||
}
|
||||
uint32_t word = 0x53780921;
|
||||
ASSERT_EQ(word, spvFixWord(word, endian));
|
||||
}
|
||||
|
||||
TEST(FixWord, Reorder) {
|
||||
spv_endianness_t endian;
|
||||
if (I32_ENDIAN_HOST == I32_ENDIAN_LITTLE) {
|
||||
endian = SPV_ENDIANNESS_BIG;
|
||||
} else {
|
||||
endian = SPV_ENDIANNESS_LITTLE;
|
||||
}
|
||||
uint32_t word = 0x53780921;
|
||||
uint32_t result = 0x21097853;
|
||||
ASSERT_EQ(result, spvFixWord(word, endian));
|
||||
}
|
||||
|
||||
TEST(FixDoubleWord, Default) {
|
||||
spv_endianness_t endian =
|
||||
(I32_ENDIAN_HOST == I32_ENDIAN_LITTLE ? SPV_ENDIANNESS_LITTLE
|
||||
: SPV_ENDIANNESS_BIG);
|
||||
uint32_t low = 0x53780921;
|
||||
uint32_t high = 0xdeadbeef;
|
||||
uint64_t result = 0xdeadbeef53780921;
|
||||
ASSERT_EQ(result, spvFixDoubleWord(low, high, endian));
|
||||
}
|
||||
|
||||
TEST(FixDoubleWord, Reorder) {
|
||||
spv_endianness_t endian =
|
||||
(I32_ENDIAN_HOST == I32_ENDIAN_LITTLE ? SPV_ENDIANNESS_BIG
|
||||
: SPV_ENDIANNESS_LITTLE);
|
||||
uint32_t low = 0x53780921;
|
||||
uint32_t high = 0xdeadbeef;
|
||||
uint64_t result = 0xefbeadde21097853;
|
||||
ASSERT_EQ(result, spvFixDoubleWord(low, high, endian));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace spvtools
|
||||
65
3rdparty/spirv-tools/test/fuzz/CMakeLists.txt
vendored
65
3rdparty/spirv-tools/test/fuzz/CMakeLists.txt
vendored
@@ -1,65 +0,0 @@
|
||||
# Copyright (c) 2019 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
if (${SPIRV_BUILD_FUZZER})
|
||||
|
||||
set(SOURCES
|
||||
fuzz_test_util.h
|
||||
|
||||
data_synonym_transformation_test.cpp
|
||||
equivalence_relation_test.cpp
|
||||
fact_manager_test.cpp
|
||||
fuzz_test_util.cpp
|
||||
fuzzer_pass_add_useful_constructs_test.cpp
|
||||
instruction_descriptor_test.cpp
|
||||
transformation_add_constant_boolean_test.cpp
|
||||
transformation_add_constant_scalar_test.cpp
|
||||
transformation_add_dead_break_test.cpp
|
||||
transformation_add_dead_continue_test.cpp
|
||||
transformation_add_no_contraction_decoration_test.cpp
|
||||
transformation_add_type_boolean_test.cpp
|
||||
transformation_add_type_float_test.cpp
|
||||
transformation_add_type_int_test.cpp
|
||||
transformation_add_type_pointer_test.cpp
|
||||
transformation_composite_construct_test.cpp
|
||||
transformation_composite_extract_test.cpp
|
||||
transformation_copy_object_test.cpp
|
||||
transformation_move_block_down_test.cpp
|
||||
transformation_replace_boolean_constant_with_constant_binary_test.cpp
|
||||
transformation_replace_constant_with_uniform_test.cpp
|
||||
transformation_replace_id_with_synonym_test.cpp
|
||||
transformation_set_function_control_test.cpp
|
||||
transformation_set_loop_control_test.cpp
|
||||
transformation_set_memory_operands_mask_test.cpp
|
||||
transformation_set_selection_control_test.cpp
|
||||
transformation_split_block_test.cpp
|
||||
transformation_vector_shuffle_test.cpp
|
||||
uniform_buffer_element_descriptor_test.cpp)
|
||||
|
||||
if (${SPIRV_ENABLE_LONG_FUZZER_TESTS})
|
||||
# These are long-running tests that depend on random seeds. We do not want
|
||||
# to run them during regular whole-project CI because they may reveal
|
||||
# spirv-fuzz bugs in changes that are totally unrelated to spirv-fuzz,
|
||||
# which would be counfounding. Instead, they should be run regularly but
|
||||
# separately.
|
||||
set(SOURCES ${SOURCES}
|
||||
fuzzer_replayer_test.cpp
|
||||
fuzzer_shrinker_test.cpp)
|
||||
endif()
|
||||
|
||||
add_spvtools_unittest(TARGET fuzz
|
||||
SRCS ${SOURCES}
|
||||
LIBS SPIRV-Tools-fuzz
|
||||
)
|
||||
endif()
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,145 +0,0 @@
|
||||
// Copyright (c) 2019 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <set>
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "source/fuzz/equivalence_relation.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
namespace {
|
||||
|
||||
struct UInt32Equals {
|
||||
bool operator()(const uint32_t* first, const uint32_t* second) const {
|
||||
return *first == *second;
|
||||
}
|
||||
};
|
||||
|
||||
struct UInt32Hash {
|
||||
size_t operator()(const uint32_t* element) const {
|
||||
return static_cast<size_t>(*element);
|
||||
}
|
||||
};
|
||||
|
||||
std::vector<uint32_t> ToUIntVector(
|
||||
const std::vector<const uint32_t*>& pointers) {
|
||||
std::vector<uint32_t> result;
|
||||
for (auto pointer : pointers) {
|
||||
result.push_back(*pointer);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
TEST(EquivalenceRelationTest, BasicTest) {
|
||||
EquivalenceRelation<uint32_t, UInt32Hash, UInt32Equals> relation;
|
||||
ASSERT_TRUE(relation.GetAllKnownValues().empty());
|
||||
|
||||
for (uint32_t element = 2; element < 80; element += 2) {
|
||||
relation.MakeEquivalent(0, element);
|
||||
relation.MakeEquivalent(element - 1, element + 1);
|
||||
}
|
||||
|
||||
for (uint32_t element = 82; element < 100; element += 2) {
|
||||
relation.MakeEquivalent(80, element);
|
||||
relation.MakeEquivalent(element - 1, element + 1);
|
||||
}
|
||||
|
||||
relation.MakeEquivalent(78, 80);
|
||||
|
||||
std::vector<uint32_t> class1;
|
||||
for (uint32_t element = 0; element < 98; element += 2) {
|
||||
ASSERT_TRUE(relation.IsEquivalent(0, element));
|
||||
ASSERT_TRUE(relation.IsEquivalent(element, element + 2));
|
||||
class1.push_back(element);
|
||||
}
|
||||
class1.push_back(98);
|
||||
|
||||
ASSERT_THAT(ToUIntVector(relation.GetEquivalenceClass(0)),
|
||||
testing::WhenSorted(class1));
|
||||
ASSERT_THAT(ToUIntVector(relation.GetEquivalenceClass(4)),
|
||||
testing::WhenSorted(class1));
|
||||
ASSERT_THAT(ToUIntVector(relation.GetEquivalenceClass(40)),
|
||||
testing::WhenSorted(class1));
|
||||
|
||||
std::vector<uint32_t> class2;
|
||||
for (uint32_t element = 1; element < 79; element += 2) {
|
||||
ASSERT_TRUE(relation.IsEquivalent(1, element));
|
||||
ASSERT_TRUE(relation.IsEquivalent(element, element + 2));
|
||||
class2.push_back(element);
|
||||
}
|
||||
class2.push_back(79);
|
||||
ASSERT_THAT(ToUIntVector(relation.GetEquivalenceClass(1)),
|
||||
testing::WhenSorted(class2));
|
||||
ASSERT_THAT(ToUIntVector(relation.GetEquivalenceClass(11)),
|
||||
testing::WhenSorted(class2));
|
||||
ASSERT_THAT(ToUIntVector(relation.GetEquivalenceClass(31)),
|
||||
testing::WhenSorted(class2));
|
||||
|
||||
std::vector<uint32_t> class3;
|
||||
for (uint32_t element = 81; element < 99; element += 2) {
|
||||
ASSERT_TRUE(relation.IsEquivalent(81, element));
|
||||
ASSERT_TRUE(relation.IsEquivalent(element, element + 2));
|
||||
class3.push_back(element);
|
||||
}
|
||||
class3.push_back(99);
|
||||
ASSERT_THAT(ToUIntVector(relation.GetEquivalenceClass(81)),
|
||||
testing::WhenSorted(class3));
|
||||
ASSERT_THAT(ToUIntVector(relation.GetEquivalenceClass(91)),
|
||||
testing::WhenSorted(class3));
|
||||
ASSERT_THAT(ToUIntVector(relation.GetEquivalenceClass(99)),
|
||||
testing::WhenSorted(class3));
|
||||
|
||||
bool first = true;
|
||||
std::vector<const uint32_t*> previous_class;
|
||||
for (auto representative : relation.GetEquivalenceClassRepresentatives()) {
|
||||
std::vector<const uint32_t*> current_class =
|
||||
relation.GetEquivalenceClass(*representative);
|
||||
ASSERT_TRUE(std::find(current_class.begin(), current_class.end(),
|
||||
representative) != current_class.end());
|
||||
if (!first) {
|
||||
ASSERT_TRUE(std::find(previous_class.begin(), previous_class.end(),
|
||||
representative) == previous_class.end());
|
||||
}
|
||||
previous_class = current_class;
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(EquivalenceRelationTest, DeterministicEquivalenceClassOrder) {
|
||||
EquivalenceRelation<uint32_t, UInt32Hash, UInt32Equals> relation1;
|
||||
EquivalenceRelation<uint32_t, UInt32Hash, UInt32Equals> relation2;
|
||||
|
||||
for (uint32_t i = 0; i < 1000; ++i) {
|
||||
if (i >= 10) {
|
||||
relation1.MakeEquivalent(i, i - 10);
|
||||
relation2.MakeEquivalent(i, i - 10);
|
||||
}
|
||||
}
|
||||
|
||||
// We constructed the equivalence relations in the same way, so we would like
|
||||
// them to have identical representatives, and identically-ordered equivalence
|
||||
// classes per representative.
|
||||
ASSERT_THAT(ToUIntVector(relation1.GetEquivalenceClassRepresentatives()),
|
||||
ToUIntVector(relation2.GetEquivalenceClassRepresentatives()));
|
||||
for (auto representative : relation1.GetEquivalenceClassRepresentatives()) {
|
||||
ASSERT_THAT(ToUIntVector(relation1.GetEquivalenceClass(*representative)),
|
||||
ToUIntVector(relation2.GetEquivalenceClass(*representative)));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
1178
3rdparty/spirv-tools/test/fuzz/fact_manager_test.cpp
vendored
1178
3rdparty/spirv-tools/test/fuzz/fact_manager_test.cpp
vendored
File diff suppressed because it is too large
Load Diff
125
3rdparty/spirv-tools/test/fuzz/fuzz_test_util.cpp
vendored
125
3rdparty/spirv-tools/test/fuzz/fuzz_test_util.cpp
vendored
@@ -1,125 +0,0 @@
|
||||
// Copyright (c) 2019 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "test/fuzz/fuzz_test_util.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
#include "tools/io.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
|
||||
bool IsEqual(const spv_target_env env,
|
||||
const std::vector<uint32_t>& expected_binary,
|
||||
const std::vector<uint32_t>& actual_binary) {
|
||||
if (expected_binary == actual_binary) {
|
||||
return true;
|
||||
}
|
||||
SpirvTools t(env);
|
||||
std::string expected_disassembled;
|
||||
std::string actual_disassembled;
|
||||
if (!t.Disassemble(expected_binary, &expected_disassembled,
|
||||
kFuzzDisassembleOption)) {
|
||||
return false;
|
||||
}
|
||||
if (!t.Disassemble(actual_binary, &actual_disassembled,
|
||||
kFuzzDisassembleOption)) {
|
||||
return false;
|
||||
}
|
||||
// Using expect gives us a string diff if the strings are not the same.
|
||||
EXPECT_EQ(expected_disassembled, actual_disassembled);
|
||||
// We then return the result of the equality comparison, to be used by an
|
||||
// assertion in the test root function.
|
||||
return expected_disassembled == actual_disassembled;
|
||||
}
|
||||
|
||||
bool IsEqual(const spv_target_env env, const std::string& expected_text,
|
||||
const std::vector<uint32_t>& actual_binary) {
|
||||
std::vector<uint32_t> expected_binary;
|
||||
SpirvTools t(env);
|
||||
if (!t.Assemble(expected_text, &expected_binary, kFuzzAssembleOption)) {
|
||||
return false;
|
||||
}
|
||||
return IsEqual(env, expected_binary, actual_binary);
|
||||
}
|
||||
|
||||
bool IsEqual(const spv_target_env env, const std::string& expected_text,
|
||||
const opt::IRContext* actual_ir) {
|
||||
std::vector<uint32_t> actual_binary;
|
||||
actual_ir->module()->ToBinary(&actual_binary, false);
|
||||
return IsEqual(env, expected_text, actual_binary);
|
||||
}
|
||||
|
||||
bool IsEqual(const spv_target_env env, const opt::IRContext* ir_1,
|
||||
const opt::IRContext* ir_2) {
|
||||
std::vector<uint32_t> binary_1;
|
||||
ir_1->module()->ToBinary(&binary_1, false);
|
||||
std::vector<uint32_t> binary_2;
|
||||
ir_2->module()->ToBinary(&binary_2, false);
|
||||
return IsEqual(env, binary_1, binary_2);
|
||||
}
|
||||
|
||||
bool IsValid(spv_target_env env, const opt::IRContext* ir) {
|
||||
std::vector<uint32_t> binary;
|
||||
ir->module()->ToBinary(&binary, false);
|
||||
SpirvTools t(env);
|
||||
return t.Validate(binary);
|
||||
}
|
||||
|
||||
std::string ToString(spv_target_env env, const opt::IRContext* ir) {
|
||||
std::vector<uint32_t> binary;
|
||||
ir->module()->ToBinary(&binary, false);
|
||||
return ToString(env, binary);
|
||||
}
|
||||
|
||||
std::string ToString(spv_target_env env, const std::vector<uint32_t>& binary) {
|
||||
SpirvTools t(env);
|
||||
std::string result;
|
||||
t.Disassemble(binary, &result, kFuzzDisassembleOption);
|
||||
return result;
|
||||
}
|
||||
|
||||
void DumpShader(opt::IRContext* context, const char* filename) {
|
||||
std::vector<uint32_t> binary;
|
||||
context->module()->ToBinary(&binary, false);
|
||||
DumpShader(binary, filename);
|
||||
}
|
||||
|
||||
void DumpShader(const std::vector<uint32_t>& binary, const char* filename) {
|
||||
auto write_file_succeeded =
|
||||
WriteFile(filename, "wb", &binary[0], binary.size());
|
||||
if (!write_file_succeeded) {
|
||||
std::cerr << "Failed to dump shader" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void DumpTransformationsJson(
|
||||
const protobufs::TransformationSequence& transformations,
|
||||
const char* filename) {
|
||||
std::string json_string;
|
||||
auto json_options = google::protobuf::util::JsonOptions();
|
||||
json_options.add_whitespace = true;
|
||||
auto json_generation_status = google::protobuf::util::MessageToJsonString(
|
||||
transformations, &json_string, json_options);
|
||||
if (json_generation_status == google::protobuf::util::Status::OK) {
|
||||
std::ofstream transformations_json_file(filename);
|
||||
transformations_json_file << json_string;
|
||||
transformations_json_file.close();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
113
3rdparty/spirv-tools/test/fuzz/fuzz_test_util.h
vendored
113
3rdparty/spirv-tools/test/fuzz/fuzz_test_util.h
vendored
@@ -1,113 +0,0 @@
|
||||
// Copyright (c) 2019 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef TEST_FUZZ_FUZZ_TEST_UTIL_H_
|
||||
#define TEST_FUZZ_FUZZ_TEST_UTIL_H_
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
|
||||
#include "source/opt/build_module.h"
|
||||
#include "source/opt/ir_context.h"
|
||||
#include "spirv-tools/libspirv.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
|
||||
// Returns true if and only if the given binaries are bit-wise equal.
|
||||
bool IsEqual(spv_target_env env, const std::vector<uint32_t>& expected_binary,
|
||||
const std::vector<uint32_t>& actual_binary);
|
||||
|
||||
// Assembles the given text and returns true if and only if the resulting binary
|
||||
// is bit-wise equal to the given binary.
|
||||
bool IsEqual(spv_target_env env, const std::string& expected_text,
|
||||
const std::vector<uint32_t>& actual_binary);
|
||||
|
||||
// Assembles the given text and turns the given IR into binary, then returns
|
||||
// true if and only if the resulting binaries are bit-wise equal.
|
||||
bool IsEqual(spv_target_env env, const std::string& expected_text,
|
||||
const opt::IRContext* actual_ir);
|
||||
|
||||
// Turns the given IRs into binaries, then returns true if and only if the
|
||||
// resulting binaries are bit-wise equal.
|
||||
bool IsEqual(spv_target_env env, const opt::IRContext* ir_1,
|
||||
const opt::IRContext* ir_2);
|
||||
|
||||
// Assembles the given IR context and returns true if and only if
|
||||
// the resulting binary is valid.
|
||||
bool IsValid(spv_target_env env, const opt::IRContext* ir);
|
||||
|
||||
// Assembles the given IR context, then returns its disassembly as a string.
|
||||
// Useful for debugging.
|
||||
std::string ToString(spv_target_env env, const opt::IRContext* ir);
|
||||
|
||||
// Returns the disassembly of the given binary as a string.
|
||||
// Useful for debugging.
|
||||
std::string ToString(spv_target_env env, const std::vector<uint32_t>& binary);
|
||||
|
||||
// Assembly options for writing fuzzer tests. It simplifies matters if
|
||||
// numeric ids do not change.
|
||||
const uint32_t kFuzzAssembleOption =
|
||||
SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS;
|
||||
// Disassembly options for writing fuzzer tests.
|
||||
const uint32_t kFuzzDisassembleOption =
|
||||
SPV_BINARY_TO_TEXT_OPTION_NO_HEADER | SPV_BINARY_TO_TEXT_OPTION_INDENT;
|
||||
|
||||
// A silent message consumer.
|
||||
const spvtools::MessageConsumer kSilentConsumer =
|
||||
[](spv_message_level_t, const char*, const spv_position_t&,
|
||||
const char*) -> void {};
|
||||
|
||||
const spvtools::MessageConsumer kConsoleMessageConsumer =
|
||||
[](spv_message_level_t level, const char*, const spv_position_t& position,
|
||||
const char* message) -> void {
|
||||
switch (level) {
|
||||
case SPV_MSG_FATAL:
|
||||
case SPV_MSG_INTERNAL_ERROR:
|
||||
case SPV_MSG_ERROR:
|
||||
std::cerr << "error: line " << position.index << ": " << message
|
||||
<< std::endl;
|
||||
break;
|
||||
case SPV_MSG_WARNING:
|
||||
std::cout << "warning: line " << position.index << ": " << message
|
||||
<< std::endl;
|
||||
break;
|
||||
case SPV_MSG_INFO:
|
||||
std::cout << "info: line " << position.index << ": " << message
|
||||
<< std::endl;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
// Dumps the SPIRV-V module in |context| to file |filename|. Useful for
|
||||
// interactive debugging.
|
||||
void DumpShader(opt::IRContext* context, const char* filename);
|
||||
|
||||
// Dumps |binary| to file |filename|. Useful for interactive debugging.
|
||||
void DumpShader(const std::vector<uint32_t>& binary, const char* filename);
|
||||
|
||||
// Dumps |transformations| to file |filename| in JSON format. Useful for
|
||||
// interactive debugging.
|
||||
void DumpTransformationsJson(
|
||||
const protobufs::TransformationSequence& transformations,
|
||||
const char* filename);
|
||||
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
|
||||
#endif // TEST_FUZZ_FUZZ_TEST_UTIL_H_
|
||||
@@ -1,393 +0,0 @@
|
||||
// Copyright (c) 2019 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "source/fuzz/fuzzer_pass_add_useful_constructs.h"
|
||||
#include "source/fuzz/pseudo_random_generator.h"
|
||||
#include "source/fuzz/uniform_buffer_element_descriptor.h"
|
||||
#include "test/fuzz/fuzz_test_util.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
namespace {
|
||||
|
||||
bool AddFactHelper(
|
||||
FactManager* fact_manager, opt::IRContext* context, uint32_t word,
|
||||
const protobufs::UniformBufferElementDescriptor& descriptor) {
|
||||
protobufs::FactConstantUniform constant_uniform_fact;
|
||||
constant_uniform_fact.add_constant_word(word);
|
||||
*constant_uniform_fact.mutable_uniform_buffer_element_descriptor() =
|
||||
descriptor;
|
||||
protobufs::Fact fact;
|
||||
*fact.mutable_constant_uniform_fact() = constant_uniform_fact;
|
||||
return fact_manager->AddFact(fact, context);
|
||||
}
|
||||
|
||||
TEST(FuzzerPassAddUsefulConstructsTest, CheckBasicStuffIsAdded) {
|
||||
// The SPIR-V came from the following empty GLSL shader:
|
||||
//
|
||||
// #version 450
|
||||
//
|
||||
// void main()
|
||||
// {
|
||||
// }
|
||||
|
||||
std::string shader = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource GLSL 450
|
||||
OpName %4 "main"
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto consumer = nullptr;
|
||||
const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
FactManager fact_manager;
|
||||
FuzzerContext fuzzer_context(MakeUnique<PseudoRandomGenerator>(0).get(), 100);
|
||||
protobufs::TransformationSequence transformation_sequence;
|
||||
|
||||
FuzzerPassAddUsefulConstructs pass(context.get(), &fact_manager,
|
||||
&fuzzer_context, &transformation_sequence);
|
||||
pass.Apply();
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
std::string after = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource GLSL 450
|
||||
OpName %4 "main"
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%100 = OpTypeBool
|
||||
%101 = OpTypeInt 32 1
|
||||
%102 = OpTypeInt 32 0
|
||||
%103 = OpTypeFloat 32
|
||||
%104 = OpConstantTrue %100
|
||||
%105 = OpConstantFalse %100
|
||||
%106 = OpConstant %101 0
|
||||
%107 = OpConstant %101 1
|
||||
%108 = OpConstant %102 0
|
||||
%109 = OpConstant %102 1
|
||||
%110 = OpConstant %103 0
|
||||
%111 = OpConstant %103 1
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
ASSERT_TRUE(IsEqual(env, after, context.get()));
|
||||
}
|
||||
|
||||
TEST(FuzzerPassAddUsefulConstructsTest,
|
||||
CheckTypesIndicesAndConstantsAddedForUniformFacts) {
|
||||
// The SPIR-V came from the following GLSL shader:
|
||||
//
|
||||
// #version 450
|
||||
//
|
||||
// struct S {
|
||||
// int x;
|
||||
// float y;
|
||||
// int z;
|
||||
// int w;
|
||||
// };
|
||||
//
|
||||
// uniform buf {
|
||||
// S s;
|
||||
// uint w[10];
|
||||
// };
|
||||
//
|
||||
// void main() {
|
||||
// }
|
||||
|
||||
std::string shader = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource GLSL 450
|
||||
OpName %4 "main"
|
||||
OpName %8 "S"
|
||||
OpMemberName %8 0 "x"
|
||||
OpMemberName %8 1 "y"
|
||||
OpMemberName %8 2 "z"
|
||||
OpMemberName %8 3 "w"
|
||||
OpName %12 "buf"
|
||||
OpMemberName %12 0 "s"
|
||||
OpMemberName %12 1 "w"
|
||||
OpName %14 ""
|
||||
OpMemberDecorate %8 0 Offset 0
|
||||
OpMemberDecorate %8 1 Offset 4
|
||||
OpMemberDecorate %8 2 Offset 8
|
||||
OpMemberDecorate %8 3 Offset 12
|
||||
OpDecorate %11 ArrayStride 16
|
||||
OpMemberDecorate %12 0 Offset 0
|
||||
OpMemberDecorate %12 1 Offset 16
|
||||
OpDecorate %12 Block
|
||||
OpDecorate %14 DescriptorSet 0
|
||||
OpDecorate %14 Binding 0
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeInt 32 1
|
||||
%7 = OpTypeFloat 32
|
||||
%8 = OpTypeStruct %6 %7 %6 %6
|
||||
%9 = OpTypeInt 32 0
|
||||
%10 = OpConstant %9 10
|
||||
%11 = OpTypeArray %9 %10
|
||||
%12 = OpTypeStruct %8 %11
|
||||
%13 = OpTypePointer Uniform %12
|
||||
%14 = OpVariable %13 Uniform
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto consumer = nullptr;
|
||||
const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
FactManager fact_manager;
|
||||
FuzzerContext fuzzer_context(MakeUnique<PseudoRandomGenerator>(0).get(), 100);
|
||||
protobufs::TransformationSequence transformation_sequence;
|
||||
|
||||
// Add some uniform facts.
|
||||
|
||||
// buf.s.x == 200
|
||||
ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), 200,
|
||||
MakeUniformBufferElementDescriptor(0, 0, {0, 0})));
|
||||
|
||||
// buf.s.y == 0.5
|
||||
const float float_value = 0.5;
|
||||
uint32_t float_value_as_uint;
|
||||
memcpy(&float_value_as_uint, &float_value, sizeof(float_value));
|
||||
ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), float_value_as_uint,
|
||||
MakeUniformBufferElementDescriptor(0, 0, {0, 1})));
|
||||
|
||||
// buf.s.z == 300
|
||||
ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), 300,
|
||||
MakeUniformBufferElementDescriptor(0, 0, {0, 2})));
|
||||
|
||||
// buf.s.w == 400
|
||||
ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), 400,
|
||||
MakeUniformBufferElementDescriptor(0, 0, {0, 3})));
|
||||
|
||||
// buf.w[6] = 22
|
||||
ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), 22,
|
||||
MakeUniformBufferElementDescriptor(0, 0, {1, 6})));
|
||||
|
||||
// buf.w[8] = 23
|
||||
ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), 23,
|
||||
MakeUniformBufferElementDescriptor(0, 0, {1, 8})));
|
||||
|
||||
// Assert some things about the module that are not true prior to adding the
|
||||
// pass
|
||||
|
||||
{
|
||||
// No uniform int pointer
|
||||
opt::analysis::Integer temp_type_signed_int(32, true);
|
||||
opt::analysis::Integer* registered_type_signed_int =
|
||||
context->get_type_mgr()
|
||||
->GetRegisteredType(&temp_type_signed_int)
|
||||
->AsInteger();
|
||||
opt::analysis::Pointer type_pointer_uniform_signed_int(
|
||||
registered_type_signed_int, SpvStorageClassUniform);
|
||||
ASSERT_EQ(0,
|
||||
context->get_type_mgr()->GetId(&type_pointer_uniform_signed_int));
|
||||
|
||||
// No uniform uint pointer
|
||||
opt::analysis::Integer temp_type_unsigned_int(32, false);
|
||||
opt::analysis::Integer* registered_type_unsigned_int =
|
||||
context->get_type_mgr()
|
||||
->GetRegisteredType(&temp_type_unsigned_int)
|
||||
->AsInteger();
|
||||
opt::analysis::Pointer type_pointer_uniform_unsigned_int(
|
||||
registered_type_unsigned_int, SpvStorageClassUniform);
|
||||
ASSERT_EQ(
|
||||
0, context->get_type_mgr()->GetId(&type_pointer_uniform_unsigned_int));
|
||||
|
||||
// No uniform float pointer
|
||||
opt::analysis::Float temp_type_float(32);
|
||||
opt::analysis::Float* registered_type_float =
|
||||
context->get_type_mgr()->GetRegisteredType(&temp_type_float)->AsFloat();
|
||||
opt::analysis::Pointer type_pointer_uniform_float(registered_type_float,
|
||||
SpvStorageClassUniform);
|
||||
ASSERT_EQ(0, context->get_type_mgr()->GetId(&type_pointer_uniform_float));
|
||||
|
||||
// No int constants 200, 300 nor 400
|
||||
opt::analysis::IntConstant int_constant_200(registered_type_signed_int,
|
||||
{200});
|
||||
opt::analysis::IntConstant int_constant_300(registered_type_signed_int,
|
||||
{300});
|
||||
opt::analysis::IntConstant int_constant_400(registered_type_signed_int,
|
||||
{400});
|
||||
ASSERT_EQ(nullptr,
|
||||
context->get_constant_mgr()->FindConstant(&int_constant_200));
|
||||
ASSERT_EQ(nullptr,
|
||||
context->get_constant_mgr()->FindConstant(&int_constant_300));
|
||||
ASSERT_EQ(nullptr,
|
||||
context->get_constant_mgr()->FindConstant(&int_constant_400));
|
||||
|
||||
// No float constant 0.5
|
||||
opt::analysis::FloatConstant float_constant_zero_point_five(
|
||||
registered_type_float, {float_value_as_uint});
|
||||
ASSERT_EQ(nullptr, context->get_constant_mgr()->FindConstant(
|
||||
&float_constant_zero_point_five));
|
||||
|
||||
// No uint constant 22
|
||||
opt::analysis::IntConstant uint_constant_22(registered_type_unsigned_int,
|
||||
{22});
|
||||
ASSERT_EQ(nullptr,
|
||||
context->get_constant_mgr()->FindConstant(&uint_constant_22));
|
||||
|
||||
// No uint constant 23
|
||||
opt::analysis::IntConstant uint_constant_23(registered_type_unsigned_int,
|
||||
{23});
|
||||
ASSERT_EQ(nullptr,
|
||||
context->get_constant_mgr()->FindConstant(&uint_constant_23));
|
||||
|
||||
// No int constants 0, 1, 2, 3, 6, 8
|
||||
opt::analysis::IntConstant int_constant_0(registered_type_signed_int, {0});
|
||||
opt::analysis::IntConstant int_constant_1(registered_type_signed_int, {1});
|
||||
opt::analysis::IntConstant int_constant_2(registered_type_signed_int, {2});
|
||||
opt::analysis::IntConstant int_constant_3(registered_type_signed_int, {3});
|
||||
opt::analysis::IntConstant int_constant_6(registered_type_signed_int, {6});
|
||||
opt::analysis::IntConstant int_constant_8(registered_type_signed_int, {8});
|
||||
ASSERT_EQ(nullptr,
|
||||
context->get_constant_mgr()->FindConstant(&int_constant_0));
|
||||
ASSERT_EQ(nullptr,
|
||||
context->get_constant_mgr()->FindConstant(&int_constant_1));
|
||||
ASSERT_EQ(nullptr,
|
||||
context->get_constant_mgr()->FindConstant(&int_constant_2));
|
||||
ASSERT_EQ(nullptr,
|
||||
context->get_constant_mgr()->FindConstant(&int_constant_3));
|
||||
ASSERT_EQ(nullptr,
|
||||
context->get_constant_mgr()->FindConstant(&int_constant_6));
|
||||
ASSERT_EQ(nullptr,
|
||||
context->get_constant_mgr()->FindConstant(&int_constant_8));
|
||||
}
|
||||
|
||||
FuzzerPassAddUsefulConstructs pass(context.get(), &fact_manager,
|
||||
&fuzzer_context, &transformation_sequence);
|
||||
pass.Apply();
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
// Now assert some things about the module that should be true following the
|
||||
// pass.
|
||||
|
||||
// We reconstruct all necessary types and constants to guard against the type
|
||||
// and constant managers for the module having been invalidated.
|
||||
|
||||
{
|
||||
// Uniform int pointer now present
|
||||
opt::analysis::Integer temp_type_signed_int(32, true);
|
||||
opt::analysis::Integer* registered_type_signed_int =
|
||||
context->get_type_mgr()
|
||||
->GetRegisteredType(&temp_type_signed_int)
|
||||
->AsInteger();
|
||||
opt::analysis::Pointer type_pointer_uniform_signed_int(
|
||||
registered_type_signed_int, SpvStorageClassUniform);
|
||||
ASSERT_NE(0,
|
||||
context->get_type_mgr()->GetId(&type_pointer_uniform_signed_int));
|
||||
|
||||
// Uniform uint pointer now present
|
||||
opt::analysis::Integer temp_type_unsigned_int(32, false);
|
||||
opt::analysis::Integer* registered_type_unsigned_int =
|
||||
context->get_type_mgr()
|
||||
->GetRegisteredType(&temp_type_unsigned_int)
|
||||
->AsInteger();
|
||||
opt::analysis::Pointer type_pointer_uniform_unsigned_int(
|
||||
registered_type_unsigned_int, SpvStorageClassUniform);
|
||||
ASSERT_NE(
|
||||
0, context->get_type_mgr()->GetId(&type_pointer_uniform_unsigned_int));
|
||||
|
||||
// Uniform float pointer now present
|
||||
opt::analysis::Float temp_type_float(32);
|
||||
opt::analysis::Float* registered_type_float =
|
||||
context->get_type_mgr()->GetRegisteredType(&temp_type_float)->AsFloat();
|
||||
opt::analysis::Pointer type_pointer_uniform_float(registered_type_float,
|
||||
SpvStorageClassUniform);
|
||||
ASSERT_NE(0, context->get_type_mgr()->GetId(&type_pointer_uniform_float));
|
||||
|
||||
// int constants 200, 300, 400 now present
|
||||
opt::analysis::IntConstant int_constant_200(registered_type_signed_int,
|
||||
{200});
|
||||
opt::analysis::IntConstant int_constant_300(registered_type_signed_int,
|
||||
{300});
|
||||
opt::analysis::IntConstant int_constant_400(registered_type_signed_int,
|
||||
{400});
|
||||
ASSERT_NE(nullptr,
|
||||
context->get_constant_mgr()->FindConstant(&int_constant_200));
|
||||
ASSERT_NE(nullptr,
|
||||
context->get_constant_mgr()->FindConstant(&int_constant_300));
|
||||
ASSERT_NE(nullptr,
|
||||
context->get_constant_mgr()->FindConstant(&int_constant_400));
|
||||
|
||||
// float constant 0.5 now present
|
||||
opt::analysis::FloatConstant float_constant_zero_point_five(
|
||||
registered_type_float, {float_value_as_uint});
|
||||
ASSERT_NE(nullptr, context->get_constant_mgr()->FindConstant(
|
||||
&float_constant_zero_point_five));
|
||||
|
||||
// uint constant 22 now present
|
||||
opt::analysis::IntConstant uint_constant_22(registered_type_unsigned_int,
|
||||
{22});
|
||||
ASSERT_NE(nullptr,
|
||||
context->get_constant_mgr()->FindConstant(&uint_constant_22));
|
||||
|
||||
// uint constant 23 now present
|
||||
opt::analysis::IntConstant uint_constant_23(registered_type_unsigned_int,
|
||||
{23});
|
||||
ASSERT_NE(nullptr,
|
||||
context->get_constant_mgr()->FindConstant(&uint_constant_23));
|
||||
|
||||
// int constants 0, 1, 2, 3, 6, 8 now present
|
||||
opt::analysis::IntConstant int_constant_0(registered_type_signed_int, {0});
|
||||
opt::analysis::IntConstant int_constant_1(registered_type_signed_int, {1});
|
||||
opt::analysis::IntConstant int_constant_2(registered_type_signed_int, {2});
|
||||
opt::analysis::IntConstant int_constant_3(registered_type_signed_int, {3});
|
||||
opt::analysis::IntConstant int_constant_6(registered_type_signed_int, {6});
|
||||
opt::analysis::IntConstant int_constant_8(registered_type_signed_int, {8});
|
||||
ASSERT_NE(nullptr,
|
||||
context->get_constant_mgr()->FindConstant(&int_constant_0));
|
||||
ASSERT_NE(nullptr,
|
||||
context->get_constant_mgr()->FindConstant(&int_constant_1));
|
||||
ASSERT_NE(nullptr,
|
||||
context->get_constant_mgr()->FindConstant(&int_constant_2));
|
||||
ASSERT_NE(nullptr,
|
||||
context->get_constant_mgr()->FindConstant(&int_constant_3));
|
||||
ASSERT_NE(nullptr,
|
||||
context->get_constant_mgr()->FindConstant(&int_constant_6));
|
||||
ASSERT_NE(nullptr,
|
||||
context->get_constant_mgr()->FindConstant(&int_constant_8));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
1629
3rdparty/spirv-tools/test/fuzz/fuzzer_replayer_test.cpp
vendored
1629
3rdparty/spirv-tools/test/fuzz/fuzzer_replayer_test.cpp
vendored
File diff suppressed because it is too large
Load Diff
1107
3rdparty/spirv-tools/test/fuzz/fuzzer_shrinker_test.cpp
vendored
1107
3rdparty/spirv-tools/test/fuzz/fuzzer_shrinker_test.cpp
vendored
File diff suppressed because it is too large
Load Diff
@@ -1,69 +0,0 @@
|
||||
// Copyright (c) 2019 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "source/fuzz/instruction_descriptor.h"
|
||||
#include "test/fuzz/fuzz_test_util.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
namespace {
|
||||
|
||||
TEST(InstructionDescriptorTest, BasicTest) {
|
||||
std::string shader = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeInt 32 0
|
||||
%7 = OpTypePointer Function %6
|
||||
%9 = OpConstant %6 0
|
||||
%10 = OpTypeInt 32 1
|
||||
%11 = OpTypePointer Function %10
|
||||
%13 = OpConstant %10 2
|
||||
%32 = OpConstant %10 0
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%164 = OpVariable %11 Function
|
||||
%165 = OpVariable %11 Function
|
||||
OpBranch %16
|
||||
%16 = OpLabel
|
||||
OpStore %164 %32
|
||||
OpStore %165 %13
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_4;
|
||||
const auto consumer = nullptr;
|
||||
const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
for (auto& function : *context->module()) {
|
||||
for (auto& block : function) {
|
||||
for (auto inst_it = block.cbegin(); inst_it != block.cend(); ++inst_it) {
|
||||
ASSERT_EQ(&*inst_it,
|
||||
FindInstruction(MakeInstructionDescriptor(block, inst_it),
|
||||
context.get()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
@@ -1,141 +0,0 @@
|
||||
// Copyright (c) 2019 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "source/fuzz/transformation_add_constant_boolean.h"
|
||||
#include "test/fuzz/fuzz_test_util.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
namespace {
|
||||
|
||||
TEST(TransformationAddConstantBooleanTest, NeitherPresentInitiallyAddBoth) {
|
||||
std::string shader = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
%2 = OpTypeVoid
|
||||
%6 = OpTypeBool
|
||||
%3 = OpTypeFunction %2
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto consumer = nullptr;
|
||||
const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
FactManager fact_manager;
|
||||
|
||||
// True and false can both be added as neither is present.
|
||||
ASSERT_TRUE(TransformationAddConstantBoolean(7, true).IsApplicable(
|
||||
context.get(), fact_manager));
|
||||
ASSERT_TRUE(TransformationAddConstantBoolean(7, false).IsApplicable(
|
||||
context.get(), fact_manager));
|
||||
|
||||
// Id 5 is already taken.
|
||||
ASSERT_FALSE(TransformationAddConstantBoolean(5, true).IsApplicable(
|
||||
context.get(), fact_manager));
|
||||
|
||||
auto add_true = TransformationAddConstantBoolean(7, true);
|
||||
auto add_false = TransformationAddConstantBoolean(8, false);
|
||||
|
||||
ASSERT_TRUE(add_true.IsApplicable(context.get(), fact_manager));
|
||||
add_true.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
// Having added true, we cannot add it again with the same id.
|
||||
ASSERT_FALSE(add_true.IsApplicable(context.get(), fact_manager));
|
||||
// But we can add it with a different id.
|
||||
auto add_true_again = TransformationAddConstantBoolean(100, true);
|
||||
ASSERT_TRUE(add_true_again.IsApplicable(context.get(), fact_manager));
|
||||
add_true_again.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
ASSERT_TRUE(add_false.IsApplicable(context.get(), fact_manager));
|
||||
add_false.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
// Having added false, we cannot add it again with the same id.
|
||||
ASSERT_FALSE(add_false.IsApplicable(context.get(), fact_manager));
|
||||
// But we can add it with a different id.
|
||||
auto add_false_again = TransformationAddConstantBoolean(101, false);
|
||||
ASSERT_TRUE(add_false_again.IsApplicable(context.get(), fact_manager));
|
||||
add_false_again.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
std::string after_transformation = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
%2 = OpTypeVoid
|
||||
%6 = OpTypeBool
|
||||
%3 = OpTypeFunction %2
|
||||
%7 = OpConstantTrue %6
|
||||
%100 = OpConstantTrue %6
|
||||
%8 = OpConstantFalse %6
|
||||
%101 = OpConstantFalse %6
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
|
||||
}
|
||||
|
||||
TEST(TransformationAddConstantBooleanTest, NoOpTypeBoolPresent) {
|
||||
std::string shader = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto consumer = nullptr;
|
||||
const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
FactManager fact_manager;
|
||||
|
||||
// Neither true nor false can be added as OpTypeBool is not present.
|
||||
ASSERT_FALSE(TransformationAddConstantBoolean(6, true).IsApplicable(
|
||||
context.get(), fact_manager));
|
||||
ASSERT_FALSE(TransformationAddConstantBoolean(6, false).IsApplicable(
|
||||
context.get(), fact_manager));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
@@ -1,187 +0,0 @@
|
||||
// Copyright (c) 2019 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "source/fuzz/transformation_add_constant_scalar.h"
|
||||
#include "test/fuzz/fuzz_test_util.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
namespace {
|
||||
|
||||
TEST(TransformationAddConstantScalarTest, BasicTest) {
|
||||
std::string shader = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
OpName %8 "x"
|
||||
OpName %12 "y"
|
||||
OpName %16 "z"
|
||||
OpDecorate %8 RelaxedPrecision
|
||||
OpDecorate %12 RelaxedPrecision
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeInt 32 1
|
||||
%7 = OpTypePointer Function %6
|
||||
%9 = OpConstant %6 1
|
||||
%10 = OpTypeInt 32 0
|
||||
%11 = OpTypePointer Function %10
|
||||
%13 = OpConstant %10 2
|
||||
%14 = OpTypeFloat 32
|
||||
%15 = OpTypePointer Function %14
|
||||
%17 = OpConstant %14 3
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%8 = OpVariable %7 Function
|
||||
%12 = OpVariable %11 Function
|
||||
%16 = OpVariable %15 Function
|
||||
OpStore %8 %9
|
||||
OpStore %12 %13
|
||||
OpStore %16 %17
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto consumer = nullptr;
|
||||
const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
FactManager fact_manager;
|
||||
|
||||
const float float_values[2] = {3.0, 30.0};
|
||||
uint32_t uint_for_float[2];
|
||||
memcpy(uint_for_float, float_values, sizeof(float_values));
|
||||
|
||||
auto add_signed_int_1 = TransformationAddConstantScalar(100, 6, {1});
|
||||
auto add_signed_int_10 = TransformationAddConstantScalar(101, 6, {10});
|
||||
auto add_unsigned_int_2 = TransformationAddConstantScalar(102, 10, {2});
|
||||
auto add_unsigned_int_20 = TransformationAddConstantScalar(103, 10, {20});
|
||||
auto add_float_3 =
|
||||
TransformationAddConstantScalar(104, 14, {uint_for_float[0]});
|
||||
auto add_float_30 =
|
||||
TransformationAddConstantScalar(105, 14, {uint_for_float[1]});
|
||||
auto bad_add_float_30_id_already_used =
|
||||
TransformationAddConstantScalar(104, 14, {uint_for_float[1]});
|
||||
auto bad_id_already_used = TransformationAddConstantScalar(1, 6, {1});
|
||||
auto bad_no_data = TransformationAddConstantScalar(100, 6, {});
|
||||
auto bad_too_much_data = TransformationAddConstantScalar(100, 6, {1, 2});
|
||||
auto bad_type_id_does_not_exist =
|
||||
TransformationAddConstantScalar(108, 2020, {uint_for_float[0]});
|
||||
auto bad_type_id_is_not_a_type = TransformationAddConstantScalar(109, 9, {0});
|
||||
auto bad_type_id_is_void = TransformationAddConstantScalar(110, 2, {0});
|
||||
auto bad_type_id_is_pointer = TransformationAddConstantScalar(111, 11, {0});
|
||||
|
||||
// Id is already in use.
|
||||
ASSERT_FALSE(bad_id_already_used.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// At least one word of data must be provided.
|
||||
ASSERT_FALSE(bad_no_data.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Cannot give two data words for a 32-bit type.
|
||||
ASSERT_FALSE(bad_too_much_data.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Type id does not exist
|
||||
ASSERT_FALSE(
|
||||
bad_type_id_does_not_exist.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Type id is not a type
|
||||
ASSERT_FALSE(
|
||||
bad_type_id_is_not_a_type.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Type id is void
|
||||
ASSERT_FALSE(bad_type_id_is_void.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Type id is pointer
|
||||
ASSERT_FALSE(
|
||||
bad_type_id_is_pointer.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
ASSERT_TRUE(add_signed_int_1.IsApplicable(context.get(), fact_manager));
|
||||
add_signed_int_1.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
ASSERT_TRUE(add_signed_int_10.IsApplicable(context.get(), fact_manager));
|
||||
add_signed_int_10.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
ASSERT_TRUE(add_unsigned_int_2.IsApplicable(context.get(), fact_manager));
|
||||
add_unsigned_int_2.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
ASSERT_TRUE(add_unsigned_int_20.IsApplicable(context.get(), fact_manager));
|
||||
add_unsigned_int_20.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
ASSERT_TRUE(add_float_3.IsApplicable(context.get(), fact_manager));
|
||||
add_float_3.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
ASSERT_TRUE(add_float_30.IsApplicable(context.get(), fact_manager));
|
||||
add_float_30.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
ASSERT_FALSE(bad_add_float_30_id_already_used.IsApplicable(context.get(),
|
||||
fact_manager));
|
||||
|
||||
std::string after_transformation = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
OpName %8 "x"
|
||||
OpName %12 "y"
|
||||
OpName %16 "z"
|
||||
OpDecorate %8 RelaxedPrecision
|
||||
OpDecorate %12 RelaxedPrecision
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeInt 32 1
|
||||
%7 = OpTypePointer Function %6
|
||||
%9 = OpConstant %6 1
|
||||
%10 = OpTypeInt 32 0
|
||||
%11 = OpTypePointer Function %10
|
||||
%13 = OpConstant %10 2
|
||||
%14 = OpTypeFloat 32
|
||||
%15 = OpTypePointer Function %14
|
||||
%17 = OpConstant %14 3
|
||||
%100 = OpConstant %6 1
|
||||
%101 = OpConstant %6 10
|
||||
%102 = OpConstant %10 2
|
||||
%103 = OpConstant %10 20
|
||||
%104 = OpConstant %14 3
|
||||
%105 = OpConstant %14 30
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%8 = OpVariable %7 Function
|
||||
%12 = OpVariable %11 Function
|
||||
%16 = OpVariable %15 Function
|
||||
OpStore %8 %9
|
||||
OpStore %12 %13
|
||||
OpStore %16 %17
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,194 +0,0 @@
|
||||
// Copyright (c) 2019 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "source/fuzz/transformation_add_no_contraction_decoration.h"
|
||||
#include "test/fuzz/fuzz_test_util.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
namespace {
|
||||
|
||||
TEST(TransformationAddNoContractionDecorationTest, BasicScenarios) {
|
||||
// This is a simple transformation and this test handles the main cases.
|
||||
|
||||
std::string shader = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
OpName %8 "x"
|
||||
OpName %10 "y"
|
||||
OpName %14 "i"
|
||||
OpDecorate %32 NoContraction
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeFloat 32
|
||||
%7 = OpTypePointer Function %6
|
||||
%9 = OpConstant %6 0
|
||||
%11 = OpConstant %6 2
|
||||
%12 = OpTypeInt 32 1
|
||||
%13 = OpTypePointer Function %12
|
||||
%15 = OpConstant %12 0
|
||||
%22 = OpConstant %12 10
|
||||
%23 = OpTypeBool
|
||||
%31 = OpConstant %6 3.5999999
|
||||
%38 = OpConstant %12 1
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%8 = OpVariable %7 Function
|
||||
%10 = OpVariable %7 Function
|
||||
%14 = OpVariable %13 Function
|
||||
OpStore %8 %9
|
||||
OpStore %10 %11
|
||||
OpStore %14 %15
|
||||
OpBranch %16
|
||||
%16 = OpLabel
|
||||
OpLoopMerge %18 %19 None
|
||||
OpBranch %20
|
||||
%20 = OpLabel
|
||||
%21 = OpLoad %12 %14
|
||||
%24 = OpSLessThan %23 %21 %22
|
||||
OpBranchConditional %24 %17 %18
|
||||
%17 = OpLabel
|
||||
%25 = OpLoad %6 %10
|
||||
%26 = OpLoad %6 %10
|
||||
%27 = OpFMul %6 %25 %26
|
||||
%28 = OpLoad %6 %8
|
||||
%29 = OpFAdd %6 %28 %27
|
||||
OpStore %8 %29
|
||||
%30 = OpLoad %6 %10
|
||||
%32 = OpFDiv %6 %30 %31
|
||||
OpStore %10 %32
|
||||
%33 = OpLoad %12 %14
|
||||
%34 = OpConvertSToF %6 %33
|
||||
%35 = OpLoad %6 %8
|
||||
%36 = OpFAdd %6 %35 %34
|
||||
OpStore %8 %36
|
||||
OpBranch %19
|
||||
%19 = OpLabel
|
||||
%37 = OpLoad %12 %14
|
||||
%39 = OpIAdd %12 %37 %38
|
||||
OpStore %14 %39
|
||||
OpBranch %16
|
||||
%18 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_4;
|
||||
const auto consumer = nullptr;
|
||||
const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
FactManager fact_manager;
|
||||
|
||||
// Invalid: 200 is not an id
|
||||
ASSERT_FALSE(TransformationAddNoContractionDecoration(200).IsApplicable(
|
||||
context.get(), fact_manager));
|
||||
// Invalid: 17 is a block id
|
||||
ASSERT_FALSE(TransformationAddNoContractionDecoration(17).IsApplicable(
|
||||
context.get(), fact_manager));
|
||||
// Invalid: 24 is not arithmetic
|
||||
ASSERT_FALSE(TransformationAddNoContractionDecoration(24).IsApplicable(
|
||||
context.get(), fact_manager));
|
||||
|
||||
// It is valid to add NoContraction to each of these ids (and it's fine to
|
||||
// have duplicates of the decoration, in the case of 32).
|
||||
for (uint32_t result_id : {32u, 32u, 27u, 29u, 39u}) {
|
||||
TransformationAddNoContractionDecoration transformation(result_id);
|
||||
ASSERT_TRUE(transformation.IsApplicable(context.get(), fact_manager));
|
||||
transformation.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
}
|
||||
|
||||
std::string after_transformation = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
OpName %8 "x"
|
||||
OpName %10 "y"
|
||||
OpName %14 "i"
|
||||
OpDecorate %32 NoContraction
|
||||
OpDecorate %32 NoContraction
|
||||
OpDecorate %32 NoContraction
|
||||
OpDecorate %27 NoContraction
|
||||
OpDecorate %29 NoContraction
|
||||
OpDecorate %39 NoContraction
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeFloat 32
|
||||
%7 = OpTypePointer Function %6
|
||||
%9 = OpConstant %6 0
|
||||
%11 = OpConstant %6 2
|
||||
%12 = OpTypeInt 32 1
|
||||
%13 = OpTypePointer Function %12
|
||||
%15 = OpConstant %12 0
|
||||
%22 = OpConstant %12 10
|
||||
%23 = OpTypeBool
|
||||
%31 = OpConstant %6 3.5999999
|
||||
%38 = OpConstant %12 1
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%8 = OpVariable %7 Function
|
||||
%10 = OpVariable %7 Function
|
||||
%14 = OpVariable %13 Function
|
||||
OpStore %8 %9
|
||||
OpStore %10 %11
|
||||
OpStore %14 %15
|
||||
OpBranch %16
|
||||
%16 = OpLabel
|
||||
OpLoopMerge %18 %19 None
|
||||
OpBranch %20
|
||||
%20 = OpLabel
|
||||
%21 = OpLoad %12 %14
|
||||
%24 = OpSLessThan %23 %21 %22
|
||||
OpBranchConditional %24 %17 %18
|
||||
%17 = OpLabel
|
||||
%25 = OpLoad %6 %10
|
||||
%26 = OpLoad %6 %10
|
||||
%27 = OpFMul %6 %25 %26
|
||||
%28 = OpLoad %6 %8
|
||||
%29 = OpFAdd %6 %28 %27
|
||||
OpStore %8 %29
|
||||
%30 = OpLoad %6 %10
|
||||
%32 = OpFDiv %6 %30 %31
|
||||
OpStore %10 %32
|
||||
%33 = OpLoad %12 %14
|
||||
%34 = OpConvertSToF %6 %33
|
||||
%35 = OpLoad %6 %8
|
||||
%36 = OpFAdd %6 %35 %34
|
||||
OpStore %8 %36
|
||||
OpBranch %19
|
||||
%19 = OpLabel
|
||||
%37 = OpLoad %12 %14
|
||||
%39 = OpIAdd %12 %37 %38
|
||||
OpStore %14 %39
|
||||
OpBranch %16
|
||||
%18 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
@@ -1,80 +0,0 @@
|
||||
// Copyright (c) 2019 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "source/fuzz/transformation_add_type_boolean.h"
|
||||
#include "test/fuzz/fuzz_test_util.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
namespace {
|
||||
|
||||
TEST(TransformationAddTypeBooleanTest, BasicTest) {
|
||||
std::string shader = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto consumer = nullptr;
|
||||
const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
FactManager fact_manager;
|
||||
|
||||
// Not applicable because id 1 is already in use.
|
||||
ASSERT_FALSE(TransformationAddTypeBoolean(1).IsApplicable(context.get(),
|
||||
fact_manager));
|
||||
|
||||
auto add_type_bool = TransformationAddTypeBoolean(100);
|
||||
ASSERT_TRUE(add_type_bool.IsApplicable(context.get(), fact_manager));
|
||||
add_type_bool.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
// Not applicable as we already have this type now.
|
||||
ASSERT_FALSE(TransformationAddTypeBoolean(101).IsApplicable(context.get(),
|
||||
fact_manager));
|
||||
|
||||
std::string after_transformation = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%100 = OpTypeBool
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
@@ -1,80 +0,0 @@
|
||||
// Copyright (c) 2019 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "source/fuzz/transformation_add_type_float.h"
|
||||
#include "test/fuzz/fuzz_test_util.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
namespace {
|
||||
|
||||
TEST(TransformationAddTypeFloatTest, BasicTest) {
|
||||
std::string shader = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto consumer = nullptr;
|
||||
const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
FactManager fact_manager;
|
||||
|
||||
// Not applicable because id 1 is already in use.
|
||||
ASSERT_FALSE(TransformationAddTypeFloat(1, 32).IsApplicable(context.get(),
|
||||
fact_manager));
|
||||
|
||||
auto add_type_float_32 = TransformationAddTypeFloat(100, 32);
|
||||
ASSERT_TRUE(add_type_float_32.IsApplicable(context.get(), fact_manager));
|
||||
add_type_float_32.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
// Not applicable as we already have this type now.
|
||||
ASSERT_FALSE(TransformationAddTypeFloat(101, 32).IsApplicable(context.get(),
|
||||
fact_manager));
|
||||
|
||||
std::string after_transformation = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%100 = OpTypeFloat 32
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
@@ -1,93 +0,0 @@
|
||||
// Copyright (c) 2019 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "source/fuzz/transformation_add_type_int.h"
|
||||
#include "test/fuzz/fuzz_test_util.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
namespace {
|
||||
|
||||
TEST(TransformationAddTypeIntTest, BasicTest) {
|
||||
std::string shader = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto consumer = nullptr;
|
||||
const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
FactManager fact_manager;
|
||||
|
||||
// Not applicable because id 1 is already in use.
|
||||
ASSERT_FALSE(TransformationAddTypeInt(1, 32, false)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
auto add_type_signed_int_32 = TransformationAddTypeInt(100, 32, true);
|
||||
auto add_type_unsigned_int_32 = TransformationAddTypeInt(101, 32, false);
|
||||
auto add_type_signed_int_32_again = TransformationAddTypeInt(102, 32, true);
|
||||
auto add_type_unsigned_int_32_again =
|
||||
TransformationAddTypeInt(103, 32, false);
|
||||
|
||||
ASSERT_TRUE(add_type_signed_int_32.IsApplicable(context.get(), fact_manager));
|
||||
add_type_signed_int_32.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
ASSERT_TRUE(
|
||||
add_type_unsigned_int_32.IsApplicable(context.get(), fact_manager));
|
||||
add_type_unsigned_int_32.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
// Not applicable as we already have these types now.
|
||||
ASSERT_FALSE(
|
||||
add_type_signed_int_32_again.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
add_type_unsigned_int_32_again.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
std::string after_transformation = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%100 = OpTypeInt 32 1
|
||||
%101 = OpTypeInt 32 0
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
@@ -1,206 +0,0 @@
|
||||
// Copyright (c) 2019 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "source/fuzz/transformation_add_type_pointer.h"
|
||||
#include "test/fuzz/fuzz_test_util.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
namespace {
|
||||
|
||||
TEST(TransformationAddTypePointerTest, BasicTest) {
|
||||
// The SPIR-V was obtained from this GLSL:
|
||||
//
|
||||
// #version 450
|
||||
//
|
||||
// int x;
|
||||
// float y;
|
||||
// vec2 z;
|
||||
//
|
||||
// struct T {
|
||||
// int a, b;
|
||||
// };
|
||||
//
|
||||
// struct S {
|
||||
// T t;
|
||||
// int u;
|
||||
// };
|
||||
//
|
||||
// void main() {
|
||||
// S myS = S(T(1, 2), 3);
|
||||
// myS.u = x;
|
||||
// }
|
||||
|
||||
std::string shader = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource GLSL 450
|
||||
OpName %4 "main"
|
||||
OpName %7 "T"
|
||||
OpMemberName %7 0 "a"
|
||||
OpMemberName %7 1 "b"
|
||||
OpName %8 "S"
|
||||
OpMemberName %8 0 "t"
|
||||
OpMemberName %8 1 "u"
|
||||
OpName %10 "myS"
|
||||
OpName %17 "x"
|
||||
OpName %23 "y"
|
||||
OpName %26 "z"
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeInt 32 1
|
||||
%7 = OpTypeStruct %6 %6
|
||||
%8 = OpTypeStruct %7 %6
|
||||
%9 = OpTypePointer Function %8
|
||||
%11 = OpConstant %6 1
|
||||
%12 = OpConstant %6 2
|
||||
%13 = OpConstantComposite %7 %11 %12
|
||||
%14 = OpConstant %6 3
|
||||
%15 = OpConstantComposite %8 %13 %14
|
||||
%16 = OpTypePointer Private %6
|
||||
%17 = OpVariable %16 Private
|
||||
%19 = OpTypePointer Function %6
|
||||
%21 = OpTypeFloat 32
|
||||
%22 = OpTypePointer Private %21
|
||||
%23 = OpVariable %22 Private
|
||||
%24 = OpTypeVector %21 2
|
||||
%25 = OpTypePointer Private %24
|
||||
%26 = OpVariable %25 Private
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%10 = OpVariable %9 Function
|
||||
OpStore %10 %15
|
||||
%18 = OpLoad %6 %17
|
||||
%20 = OpAccessChain %19 %10 %11
|
||||
OpStore %20 %18
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto consumer = nullptr;
|
||||
const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
FactManager fact_manager;
|
||||
|
||||
auto bad_type_id_does_not_exist =
|
||||
TransformationAddTypePointer(100, SpvStorageClassFunction, 101);
|
||||
auto bad_type_id_is_not_type =
|
||||
TransformationAddTypePointer(100, SpvStorageClassFunction, 23);
|
||||
auto bad_result_id_is_not_fresh =
|
||||
TransformationAddTypePointer(17, SpvStorageClassFunction, 21);
|
||||
|
||||
auto good_new_private_pointer_to_t =
|
||||
TransformationAddTypePointer(101, SpvStorageClassPrivate, 7);
|
||||
auto good_new_uniform_pointer_to_t =
|
||||
TransformationAddTypePointer(102, SpvStorageClassUniform, 7);
|
||||
auto good_another_function_pointer_to_s =
|
||||
TransformationAddTypePointer(103, SpvStorageClassFunction, 8);
|
||||
auto good_new_uniform_pointer_to_s =
|
||||
TransformationAddTypePointer(104, SpvStorageClassUniform, 8);
|
||||
auto good_another_private_pointer_to_float =
|
||||
TransformationAddTypePointer(105, SpvStorageClassPrivate, 21);
|
||||
auto good_new_private_pointer_to_private_pointer_to_float =
|
||||
TransformationAddTypePointer(106, SpvStorageClassPrivate, 105);
|
||||
auto good_new_uniform_pointer_to_vec2 =
|
||||
TransformationAddTypePointer(107, SpvStorageClassUniform, 24);
|
||||
auto good_new_private_pointer_to_uniform_pointer_to_vec2 =
|
||||
TransformationAddTypePointer(108, SpvStorageClassPrivate, 107);
|
||||
|
||||
ASSERT_FALSE(
|
||||
bad_type_id_does_not_exist.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
bad_type_id_is_not_type.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
bad_result_id_is_not_fresh.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
for (auto& transformation :
|
||||
{good_new_private_pointer_to_t, good_new_uniform_pointer_to_t,
|
||||
good_another_function_pointer_to_s, good_new_uniform_pointer_to_s,
|
||||
good_another_private_pointer_to_float,
|
||||
good_new_private_pointer_to_private_pointer_to_float,
|
||||
good_new_uniform_pointer_to_vec2,
|
||||
good_new_private_pointer_to_uniform_pointer_to_vec2}) {
|
||||
ASSERT_TRUE(transformation.IsApplicable(context.get(), fact_manager));
|
||||
transformation.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
}
|
||||
|
||||
std::string after_transformation = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource GLSL 450
|
||||
OpName %4 "main"
|
||||
OpName %7 "T"
|
||||
OpMemberName %7 0 "a"
|
||||
OpMemberName %7 1 "b"
|
||||
OpName %8 "S"
|
||||
OpMemberName %8 0 "t"
|
||||
OpMemberName %8 1 "u"
|
||||
OpName %10 "myS"
|
||||
OpName %17 "x"
|
||||
OpName %23 "y"
|
||||
OpName %26 "z"
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeInt 32 1
|
||||
%7 = OpTypeStruct %6 %6
|
||||
%8 = OpTypeStruct %7 %6
|
||||
%9 = OpTypePointer Function %8
|
||||
%11 = OpConstant %6 1
|
||||
%12 = OpConstant %6 2
|
||||
%13 = OpConstantComposite %7 %11 %12
|
||||
%14 = OpConstant %6 3
|
||||
%15 = OpConstantComposite %8 %13 %14
|
||||
%16 = OpTypePointer Private %6
|
||||
%17 = OpVariable %16 Private
|
||||
%19 = OpTypePointer Function %6
|
||||
%21 = OpTypeFloat 32
|
||||
%22 = OpTypePointer Private %21
|
||||
%23 = OpVariable %22 Private
|
||||
%24 = OpTypeVector %21 2
|
||||
%25 = OpTypePointer Private %24
|
||||
%26 = OpVariable %25 Private
|
||||
%101 = OpTypePointer Private %7
|
||||
%102 = OpTypePointer Uniform %7
|
||||
%103 = OpTypePointer Function %8
|
||||
%104 = OpTypePointer Uniform %8
|
||||
%105 = OpTypePointer Private %21
|
||||
%106 = OpTypePointer Private %105
|
||||
%107 = OpTypePointer Uniform %24
|
||||
%108 = OpTypePointer Private %107
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%10 = OpVariable %9 Function
|
||||
OpStore %10 %15
|
||||
%18 = OpLoad %6 %17
|
||||
%20 = OpAccessChain %19 %10 %11
|
||||
OpStore %20 %18
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,398 +0,0 @@
|
||||
// Copyright (c) 2019 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "source/fuzz/transformation_composite_extract.h"
|
||||
#include "source/fuzz/instruction_descriptor.h"
|
||||
#include "test/fuzz/fuzz_test_util.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
namespace {
|
||||
|
||||
TEST(TransformationCompositeExtractTest, BasicTest) {
|
||||
std::string shader = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
OpName %8 "a"
|
||||
OpName %10 "b"
|
||||
OpName %17 "FunnyPoint"
|
||||
OpMemberName %17 0 "x"
|
||||
OpMemberName %17 1 "y"
|
||||
OpMemberName %17 2 "z"
|
||||
OpName %19 "p"
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeInt 32 1
|
||||
%7 = OpTypePointer Function %6
|
||||
%12 = OpTypeBool
|
||||
%16 = OpTypeFloat 32
|
||||
%17 = OpTypeStruct %16 %16 %6
|
||||
%81 = OpTypeStruct %17 %16
|
||||
%18 = OpTypePointer Function %17
|
||||
%20 = OpConstant %6 0
|
||||
%23 = OpTypePointer Function %16
|
||||
%26 = OpConstant %6 1
|
||||
%30 = OpConstant %6 2
|
||||
%80 = OpUndef %16
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%8 = OpVariable %7 Function
|
||||
%10 = OpVariable %7 Function
|
||||
%19 = OpVariable %18 Function
|
||||
%9 = OpLoad %6 %8
|
||||
%11 = OpLoad %6 %10
|
||||
%100 = OpCompositeConstruct %17 %80 %80 %26
|
||||
%104 = OpCompositeConstruct %81 %100 %80
|
||||
%13 = OpIEqual %12 %9 %11
|
||||
OpSelectionMerge %15 None
|
||||
OpBranchConditional %13 %14 %25
|
||||
%14 = OpLabel
|
||||
%21 = OpLoad %6 %8
|
||||
%22 = OpConvertSToF %16 %21
|
||||
%101 = OpCompositeConstruct %17 %22 %80 %30
|
||||
%24 = OpAccessChain %23 %19 %20
|
||||
OpStore %24 %22
|
||||
OpBranch %15
|
||||
%25 = OpLabel
|
||||
%27 = OpLoad %6 %10
|
||||
%28 = OpConvertSToF %16 %27
|
||||
%102 = OpCompositeConstruct %17 %80 %28 %27
|
||||
%29 = OpAccessChain %23 %19 %26
|
||||
OpStore %29 %28
|
||||
OpBranch %15
|
||||
%15 = OpLabel
|
||||
%31 = OpAccessChain %23 %19 %20
|
||||
%32 = OpLoad %16 %31
|
||||
%33 = OpAccessChain %23 %19 %26
|
||||
%34 = OpLoad %16 %33
|
||||
%103 = OpCompositeConstruct %17 %34 %32 %9
|
||||
%35 = OpFAdd %16 %32 %34
|
||||
%36 = OpConvertFToS %6 %35
|
||||
%37 = OpAccessChain %7 %19 %30
|
||||
OpStore %37 %36
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_4;
|
||||
const auto consumer = nullptr;
|
||||
const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
FactManager fact_manager;
|
||||
|
||||
// Instruction does not exist.
|
||||
ASSERT_FALSE(TransformationCompositeExtract(
|
||||
MakeInstructionDescriptor(36, SpvOpIAdd, 0), 200, 101, {0})
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Id for composite is not a composite.
|
||||
ASSERT_FALSE(TransformationCompositeExtract(
|
||||
MakeInstructionDescriptor(36, SpvOpIAdd, 0), 200, 27, {})
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Composite does not dominate instruction being inserted before.
|
||||
ASSERT_FALSE(
|
||||
TransformationCompositeExtract(
|
||||
MakeInstructionDescriptor(37, SpvOpAccessChain, 0), 200, 101, {0})
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Too many indices for extraction from struct composite.
|
||||
ASSERT_FALSE(
|
||||
TransformationCompositeExtract(
|
||||
MakeInstructionDescriptor(24, SpvOpAccessChain, 0), 200, 101, {0, 0})
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Too many indices for extraction from struct composite.
|
||||
ASSERT_FALSE(
|
||||
TransformationCompositeExtract(
|
||||
MakeInstructionDescriptor(13, SpvOpIEqual, 0), 200, 104, {0, 0, 0})
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Out of bounds index for extraction from struct composite.
|
||||
ASSERT_FALSE(
|
||||
TransformationCompositeExtract(
|
||||
MakeInstructionDescriptor(13, SpvOpIEqual, 0), 200, 104, {0, 3})
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Result id already used.
|
||||
ASSERT_FALSE(TransformationCompositeExtract(
|
||||
MakeInstructionDescriptor(35, SpvOpFAdd, 0), 80, 103, {0})
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
TransformationCompositeExtract transformation_1(
|
||||
MakeInstructionDescriptor(36, SpvOpConvertFToS, 0), 201, 100, {2});
|
||||
ASSERT_TRUE(transformation_1.IsApplicable(context.get(), fact_manager));
|
||||
transformation_1.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
TransformationCompositeExtract transformation_2(
|
||||
MakeInstructionDescriptor(37, SpvOpAccessChain, 0), 202, 104, {0, 2});
|
||||
ASSERT_TRUE(transformation_2.IsApplicable(context.get(), fact_manager));
|
||||
transformation_2.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
TransformationCompositeExtract transformation_3(
|
||||
MakeInstructionDescriptor(29, SpvOpAccessChain, 0), 203, 104, {0});
|
||||
ASSERT_TRUE(transformation_3.IsApplicable(context.get(), fact_manager));
|
||||
transformation_3.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
TransformationCompositeExtract transformation_4(
|
||||
MakeInstructionDescriptor(24, SpvOpStore, 0), 204, 101, {0});
|
||||
ASSERT_TRUE(transformation_4.IsApplicable(context.get(), fact_manager));
|
||||
transformation_4.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
TransformationCompositeExtract transformation_5(
|
||||
MakeInstructionDescriptor(29, SpvOpBranch, 0), 205, 102, {2});
|
||||
ASSERT_TRUE(transformation_5.IsApplicable(context.get(), fact_manager));
|
||||
transformation_5.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
TransformationCompositeExtract transformation_6(
|
||||
MakeInstructionDescriptor(37, SpvOpReturn, 0), 206, 103, {1});
|
||||
ASSERT_TRUE(transformation_6.IsApplicable(context.get(), fact_manager));
|
||||
transformation_6.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(201, {}),
|
||||
MakeDataDescriptor(100, {2}),
|
||||
context.get()));
|
||||
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(202, {}),
|
||||
MakeDataDescriptor(104, {0, 2}),
|
||||
context.get()));
|
||||
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(203, {}),
|
||||
MakeDataDescriptor(104, {0}),
|
||||
context.get()));
|
||||
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(204, {}),
|
||||
MakeDataDescriptor(101, {0}),
|
||||
context.get()));
|
||||
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(205, {}),
|
||||
MakeDataDescriptor(102, {2}),
|
||||
context.get()));
|
||||
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(206, {}),
|
||||
MakeDataDescriptor(103, {1}),
|
||||
context.get()));
|
||||
|
||||
std::string after_transformation = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
OpName %8 "a"
|
||||
OpName %10 "b"
|
||||
OpName %17 "FunnyPoint"
|
||||
OpMemberName %17 0 "x"
|
||||
OpMemberName %17 1 "y"
|
||||
OpMemberName %17 2 "z"
|
||||
OpName %19 "p"
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeInt 32 1
|
||||
%7 = OpTypePointer Function %6
|
||||
%12 = OpTypeBool
|
||||
%16 = OpTypeFloat 32
|
||||
%17 = OpTypeStruct %16 %16 %6
|
||||
%81 = OpTypeStruct %17 %16
|
||||
%18 = OpTypePointer Function %17
|
||||
%20 = OpConstant %6 0
|
||||
%23 = OpTypePointer Function %16
|
||||
%26 = OpConstant %6 1
|
||||
%30 = OpConstant %6 2
|
||||
%80 = OpUndef %16
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%8 = OpVariable %7 Function
|
||||
%10 = OpVariable %7 Function
|
||||
%19 = OpVariable %18 Function
|
||||
%9 = OpLoad %6 %8
|
||||
%11 = OpLoad %6 %10
|
||||
%100 = OpCompositeConstruct %17 %80 %80 %26
|
||||
%104 = OpCompositeConstruct %81 %100 %80
|
||||
%13 = OpIEqual %12 %9 %11
|
||||
OpSelectionMerge %15 None
|
||||
OpBranchConditional %13 %14 %25
|
||||
%14 = OpLabel
|
||||
%21 = OpLoad %6 %8
|
||||
%22 = OpConvertSToF %16 %21
|
||||
%101 = OpCompositeConstruct %17 %22 %80 %30
|
||||
%24 = OpAccessChain %23 %19 %20
|
||||
%204 = OpCompositeExtract %16 %101 0
|
||||
OpStore %24 %22
|
||||
OpBranch %15
|
||||
%25 = OpLabel
|
||||
%27 = OpLoad %6 %10
|
||||
%28 = OpConvertSToF %16 %27
|
||||
%102 = OpCompositeConstruct %17 %80 %28 %27
|
||||
%203 = OpCompositeExtract %17 %104 0
|
||||
%29 = OpAccessChain %23 %19 %26
|
||||
OpStore %29 %28
|
||||
%205 = OpCompositeExtract %6 %102 2
|
||||
OpBranch %15
|
||||
%15 = OpLabel
|
||||
%31 = OpAccessChain %23 %19 %20
|
||||
%32 = OpLoad %16 %31
|
||||
%33 = OpAccessChain %23 %19 %26
|
||||
%34 = OpLoad %16 %33
|
||||
%103 = OpCompositeConstruct %17 %34 %32 %9
|
||||
%35 = OpFAdd %16 %32 %34
|
||||
%201 = OpCompositeExtract %6 %100 2
|
||||
%36 = OpConvertFToS %6 %35
|
||||
%202 = OpCompositeExtract %6 %104 0 2
|
||||
%37 = OpAccessChain %7 %19 %30
|
||||
OpStore %37 %36
|
||||
%206 = OpCompositeExtract %16 %103 1
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
|
||||
}
|
||||
|
||||
TEST(TransformationCompositeExtractTest, IllegalInsertionPoints) {
|
||||
std::string shader = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main" %51 %27
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
OpName %25 "buf"
|
||||
OpMemberName %25 0 "value"
|
||||
OpName %27 ""
|
||||
OpName %51 "color"
|
||||
OpMemberDecorate %25 0 Offset 0
|
||||
OpDecorate %25 Block
|
||||
OpDecorate %27 DescriptorSet 0
|
||||
OpDecorate %27 Binding 0
|
||||
OpDecorate %51 Location 0
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeFloat 32
|
||||
%7 = OpTypeVector %6 4
|
||||
%10 = OpConstant %6 0.300000012
|
||||
%11 = OpConstant %6 0.400000006
|
||||
%12 = OpConstant %6 0.5
|
||||
%13 = OpConstant %6 1
|
||||
%14 = OpConstantComposite %7 %10 %11 %12 %13
|
||||
%15 = OpTypeInt 32 1
|
||||
%18 = OpConstant %15 0
|
||||
%25 = OpTypeStruct %6
|
||||
%26 = OpTypePointer Uniform %25
|
||||
%27 = OpVariable %26 Uniform
|
||||
%28 = OpTypePointer Uniform %6
|
||||
%32 = OpTypeBool
|
||||
%103 = OpConstantTrue %32
|
||||
%34 = OpConstant %6 0.100000001
|
||||
%48 = OpConstant %15 1
|
||||
%50 = OpTypePointer Output %7
|
||||
%51 = OpVariable %50 Output
|
||||
%100 = OpTypePointer Function %6
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%101 = OpVariable %100 Function
|
||||
%102 = OpVariable %100 Function
|
||||
OpBranch %19
|
||||
%19 = OpLabel
|
||||
%60 = OpPhi %7 %14 %5 %58 %20
|
||||
%59 = OpPhi %15 %18 %5 %49 %20
|
||||
%29 = OpAccessChain %28 %27 %18
|
||||
%30 = OpLoad %6 %29
|
||||
%31 = OpConvertFToS %15 %30
|
||||
%33 = OpSLessThan %32 %59 %31
|
||||
OpLoopMerge %21 %20 None
|
||||
OpBranchConditional %33 %20 %21
|
||||
%20 = OpLabel
|
||||
%39 = OpCompositeExtract %6 %60 0
|
||||
%40 = OpFAdd %6 %39 %34
|
||||
%55 = OpCompositeInsert %7 %40 %60 0
|
||||
%44 = OpCompositeExtract %6 %60 1
|
||||
%45 = OpFSub %6 %44 %34
|
||||
%58 = OpCompositeInsert %7 %45 %55 1
|
||||
%49 = OpIAdd %15 %59 %48
|
||||
OpBranch %19
|
||||
%21 = OpLabel
|
||||
OpStore %51 %60
|
||||
OpSelectionMerge %105 None
|
||||
OpBranchConditional %103 %104 %105
|
||||
%104 = OpLabel
|
||||
OpBranch %105
|
||||
%105 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_4;
|
||||
const auto consumer = nullptr;
|
||||
const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
FactManager fact_manager;
|
||||
|
||||
// Cannot insert before the OpVariables of a function.
|
||||
ASSERT_FALSE(
|
||||
TransformationCompositeExtract(
|
||||
MakeInstructionDescriptor(101, SpvOpVariable, 0), 200, 14, {0})
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
TransformationCompositeExtract(
|
||||
MakeInstructionDescriptor(101, SpvOpVariable, 1), 200, 14, {1})
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
TransformationCompositeExtract(
|
||||
MakeInstructionDescriptor(102, SpvOpVariable, 0), 200, 14, {1})
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
// OK to insert right after the OpVariables.
|
||||
ASSERT_FALSE(TransformationCompositeExtract(
|
||||
MakeInstructionDescriptor(102, SpvOpBranch, 1), 200, 14, {1})
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Cannot insert before the OpPhis of a block.
|
||||
ASSERT_FALSE(TransformationCompositeExtract(
|
||||
MakeInstructionDescriptor(60, SpvOpPhi, 0), 200, 14, {2})
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(TransformationCompositeExtract(
|
||||
MakeInstructionDescriptor(59, SpvOpPhi, 0), 200, 14, {3})
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
// OK to insert after the OpPhis.
|
||||
ASSERT_TRUE(
|
||||
TransformationCompositeExtract(
|
||||
MakeInstructionDescriptor(59, SpvOpAccessChain, 0), 200, 14, {3})
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Cannot insert before OpLoopMerge
|
||||
ASSERT_FALSE(TransformationCompositeExtract(
|
||||
MakeInstructionDescriptor(33, SpvOpBranchConditional, 0),
|
||||
200, 14, {3})
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Cannot insert before OpSelectionMerge
|
||||
ASSERT_FALSE(TransformationCompositeExtract(
|
||||
MakeInstructionDescriptor(21, SpvOpBranchConditional, 0),
|
||||
200, 14, {2})
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
@@ -1,593 +0,0 @@
|
||||
// Copyright (c) 2019 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <algorithm>
|
||||
#include <set>
|
||||
#include <unordered_set>
|
||||
|
||||
#include "source/fuzz/data_descriptor.h"
|
||||
#include "source/fuzz/instruction_descriptor.h"
|
||||
#include "source/fuzz/transformation_copy_object.h"
|
||||
#include "test/fuzz/fuzz_test_util.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
namespace {
|
||||
|
||||
TEST(TransformationCopyObjectTest, CopyBooleanConstants) {
|
||||
std::string shader = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
%2 = OpTypeVoid
|
||||
%6 = OpTypeBool
|
||||
%7 = OpConstantTrue %6
|
||||
%8 = OpConstantFalse %6
|
||||
%3 = OpTypeFunction %2
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto consumer = nullptr;
|
||||
const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
FactManager fact_manager;
|
||||
|
||||
ASSERT_EQ(0,
|
||||
fact_manager.GetIdsForWhichSynonymsAreKnown(context.get()).size());
|
||||
|
||||
{
|
||||
TransformationCopyObject copy_true(
|
||||
7, MakeInstructionDescriptor(5, SpvOpReturn, 0), 100);
|
||||
ASSERT_TRUE(copy_true.IsApplicable(context.get(), fact_manager));
|
||||
copy_true.Apply(context.get(), &fact_manager);
|
||||
|
||||
std::vector<uint32_t> ids_for_which_synonyms_are_known =
|
||||
fact_manager.GetIdsForWhichSynonymsAreKnown(context.get());
|
||||
ASSERT_EQ(2, ids_for_which_synonyms_are_known.size());
|
||||
ASSERT_TRUE(std::find(ids_for_which_synonyms_are_known.begin(),
|
||||
ids_for_which_synonyms_are_known.end(),
|
||||
7) != ids_for_which_synonyms_are_known.end());
|
||||
ASSERT_EQ(2, fact_manager.GetSynonymsForId(7, context.get()).size());
|
||||
protobufs::DataDescriptor descriptor_100 = MakeDataDescriptor(100, {});
|
||||
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(7, {}),
|
||||
descriptor_100, context.get()));
|
||||
}
|
||||
|
||||
{
|
||||
TransformationCopyObject copy_false(
|
||||
8, MakeInstructionDescriptor(100, SpvOpReturn, 0), 101);
|
||||
ASSERT_TRUE(copy_false.IsApplicable(context.get(), fact_manager));
|
||||
copy_false.Apply(context.get(), &fact_manager);
|
||||
std::vector<uint32_t> ids_for_which_synonyms_are_known =
|
||||
fact_manager.GetIdsForWhichSynonymsAreKnown(context.get());
|
||||
ASSERT_EQ(4, ids_for_which_synonyms_are_known.size());
|
||||
ASSERT_TRUE(std::find(ids_for_which_synonyms_are_known.begin(),
|
||||
ids_for_which_synonyms_are_known.end(),
|
||||
8) != ids_for_which_synonyms_are_known.end());
|
||||
ASSERT_EQ(2, fact_manager.GetSynonymsForId(8, context.get()).size());
|
||||
protobufs::DataDescriptor descriptor_101 = MakeDataDescriptor(101, {});
|
||||
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(8, {}),
|
||||
descriptor_101, context.get()));
|
||||
}
|
||||
|
||||
{
|
||||
TransformationCopyObject copy_false_again(
|
||||
101, MakeInstructionDescriptor(5, SpvOpReturn, 0), 102);
|
||||
ASSERT_TRUE(copy_false_again.IsApplicable(context.get(), fact_manager));
|
||||
copy_false_again.Apply(context.get(), &fact_manager);
|
||||
std::vector<uint32_t> ids_for_which_synonyms_are_known =
|
||||
fact_manager.GetIdsForWhichSynonymsAreKnown(context.get());
|
||||
ASSERT_EQ(5, ids_for_which_synonyms_are_known.size());
|
||||
ASSERT_TRUE(std::find(ids_for_which_synonyms_are_known.begin(),
|
||||
ids_for_which_synonyms_are_known.end(),
|
||||
101) != ids_for_which_synonyms_are_known.end());
|
||||
ASSERT_EQ(3, fact_manager.GetSynonymsForId(101, context.get()).size());
|
||||
protobufs::DataDescriptor descriptor_102 = MakeDataDescriptor(102, {});
|
||||
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(101, {}),
|
||||
descriptor_102, context.get()));
|
||||
}
|
||||
|
||||
{
|
||||
TransformationCopyObject copy_true_again(
|
||||
7, MakeInstructionDescriptor(102, SpvOpReturn, 0), 103);
|
||||
ASSERT_TRUE(copy_true_again.IsApplicable(context.get(), fact_manager));
|
||||
copy_true_again.Apply(context.get(), &fact_manager);
|
||||
std::vector<uint32_t> ids_for_which_synonyms_are_known =
|
||||
fact_manager.GetIdsForWhichSynonymsAreKnown(context.get());
|
||||
ASSERT_EQ(6, ids_for_which_synonyms_are_known.size());
|
||||
ASSERT_TRUE(std::find(ids_for_which_synonyms_are_known.begin(),
|
||||
ids_for_which_synonyms_are_known.end(),
|
||||
7) != ids_for_which_synonyms_are_known.end());
|
||||
ASSERT_EQ(3, fact_manager.GetSynonymsForId(7, context.get()).size());
|
||||
protobufs::DataDescriptor descriptor_103 = MakeDataDescriptor(103, {});
|
||||
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(7, {}),
|
||||
descriptor_103, context.get()));
|
||||
}
|
||||
|
||||
std::string after_transformation = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
%2 = OpTypeVoid
|
||||
%6 = OpTypeBool
|
||||
%7 = OpConstantTrue %6
|
||||
%8 = OpConstantFalse %6
|
||||
%3 = OpTypeFunction %2
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%100 = OpCopyObject %6 %7
|
||||
%101 = OpCopyObject %6 %8
|
||||
%102 = OpCopyObject %6 %101
|
||||
%103 = OpCopyObject %6 %7
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
|
||||
}
|
||||
|
||||
TEST(TransformationCopyObjectTest, CheckIllegalCases) {
|
||||
// The following SPIR-V comes from this GLSL, pushed through spirv-opt
|
||||
// and then doctored a bit.
|
||||
//
|
||||
// #version 310 es
|
||||
//
|
||||
// precision highp float;
|
||||
//
|
||||
// struct S {
|
||||
// int a;
|
||||
// float b;
|
||||
// };
|
||||
//
|
||||
// layout(set = 0, binding = 2) uniform block {
|
||||
// S s;
|
||||
// lowp float f;
|
||||
// int ii;
|
||||
// } ubuf;
|
||||
//
|
||||
// layout(location = 0) out vec4 color;
|
||||
//
|
||||
// void main() {
|
||||
// float c = 0.0;
|
||||
// lowp float d = 0.0;
|
||||
// S localS = ubuf.s;
|
||||
// for (int i = 0; i < ubuf.s.a; i++) {
|
||||
// switch (ubuf.ii) {
|
||||
// case 0:
|
||||
// c += 0.1;
|
||||
// d += 0.2;
|
||||
// case 1:
|
||||
// c += 0.1;
|
||||
// if (c > d) {
|
||||
// d += 0.2;
|
||||
// } else {
|
||||
// d += c;
|
||||
// }
|
||||
// break;
|
||||
// default:
|
||||
// i += 1;
|
||||
// localS.b += d;
|
||||
// }
|
||||
// }
|
||||
// color = vec4(c, d, localS.b, 1.0);
|
||||
// }
|
||||
|
||||
std::string shader = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main" %80
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
OpName %12 "S"
|
||||
OpMemberName %12 0 "a"
|
||||
OpMemberName %12 1 "b"
|
||||
OpName %15 "S"
|
||||
OpMemberName %15 0 "a"
|
||||
OpMemberName %15 1 "b"
|
||||
OpName %16 "block"
|
||||
OpMemberName %16 0 "s"
|
||||
OpMemberName %16 1 "f"
|
||||
OpMemberName %16 2 "ii"
|
||||
OpName %18 "ubuf"
|
||||
OpName %80 "color"
|
||||
OpMemberDecorate %12 0 RelaxedPrecision
|
||||
OpMemberDecorate %15 0 RelaxedPrecision
|
||||
OpMemberDecorate %15 0 Offset 0
|
||||
OpMemberDecorate %15 1 Offset 4
|
||||
OpMemberDecorate %16 0 Offset 0
|
||||
OpMemberDecorate %16 1 RelaxedPrecision
|
||||
OpMemberDecorate %16 1 Offset 16
|
||||
OpMemberDecorate %16 2 RelaxedPrecision
|
||||
OpMemberDecorate %16 2 Offset 20
|
||||
OpDecorate %16 Block
|
||||
OpDecorate %18 DescriptorSet 0
|
||||
OpDecorate %18 Binding 2
|
||||
OpDecorate %38 RelaxedPrecision
|
||||
OpDecorate %43 RelaxedPrecision
|
||||
OpDecorate %53 RelaxedPrecision
|
||||
OpDecorate %62 RelaxedPrecision
|
||||
OpDecorate %69 RelaxedPrecision
|
||||
OpDecorate %77 RelaxedPrecision
|
||||
OpDecorate %80 Location 0
|
||||
OpDecorate %101 RelaxedPrecision
|
||||
OpDecorate %102 RelaxedPrecision
|
||||
OpDecorate %96 RelaxedPrecision
|
||||
OpDecorate %108 RelaxedPrecision
|
||||
OpDecorate %107 RelaxedPrecision
|
||||
OpDecorate %98 RelaxedPrecision
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeFloat 32
|
||||
%9 = OpConstant %6 0
|
||||
%11 = OpTypeInt 32 1
|
||||
%12 = OpTypeStruct %11 %6
|
||||
%15 = OpTypeStruct %11 %6
|
||||
%16 = OpTypeStruct %15 %6 %11
|
||||
%17 = OpTypePointer Uniform %16
|
||||
%18 = OpVariable %17 Uniform
|
||||
%19 = OpConstant %11 0
|
||||
%20 = OpTypePointer Uniform %15
|
||||
%27 = OpConstant %11 1
|
||||
%36 = OpTypePointer Uniform %11
|
||||
%39 = OpTypeBool
|
||||
%41 = OpConstant %11 2
|
||||
%48 = OpConstant %6 0.100000001
|
||||
%51 = OpConstant %6 0.200000003
|
||||
%78 = OpTypeVector %6 4
|
||||
%79 = OpTypePointer Output %78
|
||||
%80 = OpVariable %79 Output
|
||||
%85 = OpConstant %6 1
|
||||
%95 = OpUndef %12
|
||||
%112 = OpTypePointer Uniform %6
|
||||
%113 = OpTypeInt 32 0
|
||||
%114 = OpConstant %113 1
|
||||
%179 = OpTypePointer Function %39
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%180 = OpVariable %179 Function
|
||||
%181 = OpVariable %179 Function
|
||||
%182 = OpVariable %179 Function
|
||||
%21 = OpAccessChain %20 %18 %19
|
||||
%115 = OpAccessChain %112 %21 %114
|
||||
%116 = OpLoad %6 %115
|
||||
%90 = OpCompositeInsert %12 %116 %95 1
|
||||
OpBranch %30
|
||||
%30 = OpLabel
|
||||
%99 = OpPhi %12 %90 %5 %109 %47
|
||||
%98 = OpPhi %6 %9 %5 %107 %47
|
||||
%97 = OpPhi %6 %9 %5 %105 %47
|
||||
%96 = OpPhi %11 %19 %5 %77 %47
|
||||
%37 = OpAccessChain %36 %18 %19 %19
|
||||
%38 = OpLoad %11 %37
|
||||
%40 = OpSLessThan %39 %96 %38
|
||||
OpLoopMerge %32 %47 None
|
||||
OpBranchConditional %40 %31 %32
|
||||
%31 = OpLabel
|
||||
%42 = OpAccessChain %36 %18 %41
|
||||
%43 = OpLoad %11 %42
|
||||
OpSelectionMerge %45 None
|
||||
OpSwitch %43 %46 0 %44 1 %45
|
||||
%46 = OpLabel
|
||||
%69 = OpIAdd %11 %96 %27
|
||||
%72 = OpCompositeExtract %6 %99 1
|
||||
%73 = OpFAdd %6 %72 %98
|
||||
%93 = OpCompositeInsert %12 %73 %99 1
|
||||
OpBranch %47
|
||||
%44 = OpLabel
|
||||
%50 = OpFAdd %6 %97 %48
|
||||
%53 = OpFAdd %6 %98 %51
|
||||
OpBranch %45
|
||||
%45 = OpLabel
|
||||
%101 = OpPhi %6 %98 %31 %53 %44
|
||||
%100 = OpPhi %6 %97 %31 %50 %44
|
||||
%55 = OpFAdd %6 %100 %48
|
||||
%58 = OpFOrdGreaterThan %39 %55 %101
|
||||
OpSelectionMerge %60 None
|
||||
OpBranchConditional %58 %59 %63
|
||||
%59 = OpLabel
|
||||
%62 = OpFAdd %6 %101 %51
|
||||
OpBranch %60
|
||||
%63 = OpLabel
|
||||
%66 = OpFAdd %6 %101 %55
|
||||
OpBranch %60
|
||||
%60 = OpLabel
|
||||
%108 = OpPhi %6 %62 %59 %66 %63
|
||||
OpBranch %47
|
||||
%47 = OpLabel
|
||||
%109 = OpPhi %12 %93 %46 %99 %60
|
||||
%107 = OpPhi %6 %98 %46 %108 %60
|
||||
%105 = OpPhi %6 %97 %46 %55 %60
|
||||
%102 = OpPhi %11 %69 %46 %96 %60
|
||||
%77 = OpIAdd %11 %102 %27
|
||||
OpBranch %30
|
||||
%32 = OpLabel
|
||||
%84 = OpCompositeExtract %6 %99 1
|
||||
%86 = OpCompositeConstruct %78 %97 %98 %84 %85
|
||||
OpStore %80 %86
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto consumer = nullptr;
|
||||
const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
FactManager fact_manager;
|
||||
|
||||
// Inapplicable because %18 is decorated.
|
||||
ASSERT_FALSE(TransformationCopyObject(
|
||||
18, MakeInstructionDescriptor(21, SpvOpAccessChain, 0), 200)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Inapplicable because %77 is decorated.
|
||||
ASSERT_FALSE(TransformationCopyObject(
|
||||
77, MakeInstructionDescriptor(77, SpvOpBranch, 0), 200)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Inapplicable because %80 is decorated.
|
||||
ASSERT_FALSE(TransformationCopyObject(
|
||||
80, MakeInstructionDescriptor(77, SpvOpIAdd, 0), 200)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Inapplicable because %84 is not available at the requested point
|
||||
ASSERT_FALSE(
|
||||
TransformationCopyObject(
|
||||
84, MakeInstructionDescriptor(32, SpvOpCompositeExtract, 0), 200)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Fine because %84 is available at the requested point
|
||||
ASSERT_TRUE(
|
||||
TransformationCopyObject(
|
||||
84, MakeInstructionDescriptor(32, SpvOpCompositeConstruct, 0), 200)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Inapplicable because id %9 is already in use
|
||||
ASSERT_FALSE(
|
||||
TransformationCopyObject(
|
||||
84, MakeInstructionDescriptor(32, SpvOpCompositeConstruct, 0), 9)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Inapplicable because the requested point does not exist
|
||||
ASSERT_FALSE(TransformationCopyObject(
|
||||
84, MakeInstructionDescriptor(86, SpvOpReturn, 2), 200)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Inapplicable because %9 is not in a function
|
||||
ASSERT_FALSE(TransformationCopyObject(
|
||||
9, MakeInstructionDescriptor(9, SpvOpTypeInt, 0), 200)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Inapplicable because the insert point is right before, or inside, a chunk
|
||||
// of OpPhis
|
||||
ASSERT_FALSE(TransformationCopyObject(
|
||||
9, MakeInstructionDescriptor(30, SpvOpPhi, 0), 200)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(TransformationCopyObject(
|
||||
9, MakeInstructionDescriptor(99, SpvOpPhi, 1), 200)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// OK, because the insert point is just after a chunk of OpPhis.
|
||||
ASSERT_TRUE(TransformationCopyObject(
|
||||
9, MakeInstructionDescriptor(96, SpvOpAccessChain, 0), 200)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Inapplicable because the insert point is right after an OpSelectionMerge
|
||||
ASSERT_FALSE(
|
||||
TransformationCopyObject(
|
||||
9, MakeInstructionDescriptor(58, SpvOpBranchConditional, 0), 200)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// OK, because the insert point is right before the OpSelectionMerge
|
||||
ASSERT_TRUE(TransformationCopyObject(
|
||||
9, MakeInstructionDescriptor(58, SpvOpSelectionMerge, 0), 200)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Inapplicable because the insert point is right after an OpSelectionMerge
|
||||
ASSERT_FALSE(TransformationCopyObject(
|
||||
9, MakeInstructionDescriptor(43, SpvOpSwitch, 0), 200)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// OK, because the insert point is right before the OpSelectionMerge
|
||||
ASSERT_TRUE(TransformationCopyObject(
|
||||
9, MakeInstructionDescriptor(43, SpvOpSelectionMerge, 0), 200)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Inapplicable because the insert point is right after an OpLoopMerge
|
||||
ASSERT_FALSE(
|
||||
TransformationCopyObject(
|
||||
9, MakeInstructionDescriptor(40, SpvOpBranchConditional, 0), 200)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// OK, because the insert point is right before the OpLoopMerge
|
||||
ASSERT_TRUE(TransformationCopyObject(
|
||||
9, MakeInstructionDescriptor(40, SpvOpLoopMerge, 0), 200)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Inapplicable because id %300 does not exist
|
||||
ASSERT_FALSE(TransformationCopyObject(
|
||||
300, MakeInstructionDescriptor(40, SpvOpLoopMerge, 0), 200)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Inapplicable because the following instruction is OpVariable
|
||||
ASSERT_FALSE(TransformationCopyObject(
|
||||
9, MakeInstructionDescriptor(180, SpvOpVariable, 0), 200)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(TransformationCopyObject(
|
||||
9, MakeInstructionDescriptor(181, SpvOpVariable, 0), 200)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(TransformationCopyObject(
|
||||
9, MakeInstructionDescriptor(182, SpvOpVariable, 0), 200)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// OK, because this is just past the group of OpVariable instructions.
|
||||
ASSERT_TRUE(TransformationCopyObject(
|
||||
9, MakeInstructionDescriptor(182, SpvOpAccessChain, 0), 200)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
}
|
||||
|
||||
TEST(TransformationCopyObjectTest, MiscellaneousCopies) {
|
||||
// The following SPIR-V comes from this GLSL:
|
||||
//
|
||||
// #version 310 es
|
||||
//
|
||||
// precision highp float;
|
||||
//
|
||||
// float g;
|
||||
//
|
||||
// vec4 h;
|
||||
//
|
||||
// void main() {
|
||||
// int a;
|
||||
// int b;
|
||||
// b = int(g);
|
||||
// h.x = float(a);
|
||||
// }
|
||||
|
||||
std::string shader = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
OpName %8 "b"
|
||||
OpName %11 "g"
|
||||
OpName %16 "h"
|
||||
OpName %17 "a"
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeInt 32 1
|
||||
%7 = OpTypePointer Function %6
|
||||
%9 = OpTypeFloat 32
|
||||
%10 = OpTypePointer Private %9
|
||||
%11 = OpVariable %10 Private
|
||||
%14 = OpTypeVector %9 4
|
||||
%15 = OpTypePointer Private %14
|
||||
%16 = OpVariable %15 Private
|
||||
%20 = OpTypeInt 32 0
|
||||
%21 = OpConstant %20 0
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%8 = OpVariable %7 Function
|
||||
%17 = OpVariable %7 Function
|
||||
%12 = OpLoad %9 %11
|
||||
%13 = OpConvertFToS %6 %12
|
||||
OpStore %8 %13
|
||||
%18 = OpLoad %6 %17
|
||||
%19 = OpConvertSToF %9 %18
|
||||
%22 = OpAccessChain %10 %16 %21
|
||||
OpStore %22 %19
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto consumer = nullptr;
|
||||
const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
FactManager fact_manager;
|
||||
|
||||
std::vector<TransformationCopyObject> transformations = {
|
||||
TransformationCopyObject(19, MakeInstructionDescriptor(22, SpvOpStore, 0),
|
||||
100),
|
||||
TransformationCopyObject(
|
||||
22, MakeInstructionDescriptor(22, SpvOpCopyObject, 0), 101),
|
||||
TransformationCopyObject(
|
||||
12, MakeInstructionDescriptor(22, SpvOpCopyObject, 0), 102),
|
||||
TransformationCopyObject(
|
||||
11, MakeInstructionDescriptor(22, SpvOpCopyObject, 0), 103),
|
||||
TransformationCopyObject(
|
||||
16, MakeInstructionDescriptor(22, SpvOpCopyObject, 0), 104),
|
||||
TransformationCopyObject(
|
||||
8, MakeInstructionDescriptor(22, SpvOpCopyObject, 0), 105),
|
||||
TransformationCopyObject(
|
||||
17, MakeInstructionDescriptor(22, SpvOpCopyObject, 0), 106)};
|
||||
|
||||
for (auto& transformation : transformations) {
|
||||
ASSERT_TRUE(transformation.IsApplicable(context.get(), fact_manager));
|
||||
transformation.Apply(context.get(), &fact_manager);
|
||||
}
|
||||
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
std::string after_transformation = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
OpName %8 "b"
|
||||
OpName %11 "g"
|
||||
OpName %16 "h"
|
||||
OpName %17 "a"
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeInt 32 1
|
||||
%7 = OpTypePointer Function %6
|
||||
%9 = OpTypeFloat 32
|
||||
%10 = OpTypePointer Private %9
|
||||
%11 = OpVariable %10 Private
|
||||
%14 = OpTypeVector %9 4
|
||||
%15 = OpTypePointer Private %14
|
||||
%16 = OpVariable %15 Private
|
||||
%20 = OpTypeInt 32 0
|
||||
%21 = OpConstant %20 0
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%8 = OpVariable %7 Function
|
||||
%17 = OpVariable %7 Function
|
||||
%12 = OpLoad %9 %11
|
||||
%13 = OpConvertFToS %6 %12
|
||||
OpStore %8 %13
|
||||
%18 = OpLoad %6 %17
|
||||
%19 = OpConvertSToF %9 %18
|
||||
%22 = OpAccessChain %10 %16 %21
|
||||
%106 = OpCopyObject %7 %17
|
||||
%105 = OpCopyObject %7 %8
|
||||
%104 = OpCopyObject %15 %16
|
||||
%103 = OpCopyObject %10 %11
|
||||
%102 = OpCopyObject %9 %12
|
||||
%101 = OpCopyObject %10 %22
|
||||
%100 = OpCopyObject %9 %19
|
||||
OpStore %22 %19
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
@@ -1,670 +0,0 @@
|
||||
// Copyright (c) 2019 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "source/fuzz/transformation_move_block_down.h"
|
||||
#include "test/fuzz/fuzz_test_util.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
namespace {
|
||||
|
||||
TEST(TransformationMoveBlockDownTest, NoMovePossible1) {
|
||||
// Block 11 cannot be moved down as it dominates block 12.
|
||||
std::string shader = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpDecorate %8 RelaxedPrecision
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeInt 32 1
|
||||
%7 = OpTypePointer Function %6
|
||||
%9 = OpConstant %6 1
|
||||
%10 = OpConstant %6 2
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%8 = OpVariable %7 Function
|
||||
OpBranch %11
|
||||
%11 = OpLabel
|
||||
OpStore %8 %9
|
||||
OpBranch %12
|
||||
%12 = OpLabel
|
||||
OpStore %8 %10
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto consumer = nullptr;
|
||||
const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
|
||||
|
||||
FactManager fact_manager;
|
||||
|
||||
auto transformation = TransformationMoveBlockDown(11);
|
||||
ASSERT_FALSE(transformation.IsApplicable(context.get(), fact_manager));
|
||||
}
|
||||
|
||||
TEST(TransformationMoveBlockDownTest, NoMovePossible2) {
|
||||
// Block 5 cannot be moved down as it is the entry block.
|
||||
std::string shader = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpDecorate %8 RelaxedPrecision
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeInt 32 1
|
||||
%7 = OpTypePointer Function %6
|
||||
%9 = OpConstant %6 1
|
||||
%10 = OpConstant %6 2
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%8 = OpVariable %7 Function
|
||||
OpStore %8 %9
|
||||
OpStore %8 %10
|
||||
OpReturn
|
||||
%11 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto consumer = nullptr;
|
||||
const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
|
||||
|
||||
FactManager fact_manager;
|
||||
|
||||
auto transformation = TransformationMoveBlockDown(5);
|
||||
ASSERT_FALSE(transformation.IsApplicable(context.get(), fact_manager));
|
||||
}
|
||||
|
||||
TEST(TransformationMoveBlockDownTest, NoMovePossible3) {
|
||||
// Block 100 does not exist, so cannot be moved down.
|
||||
std::string shader = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpDecorate %8 RelaxedPrecision
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeInt 32 1
|
||||
%7 = OpTypePointer Function %6
|
||||
%9 = OpConstant %6 1
|
||||
%10 = OpConstant %6 2
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%8 = OpVariable %7 Function
|
||||
OpBranch %11
|
||||
%11 = OpLabel
|
||||
OpStore %8 %9
|
||||
OpBranch %12
|
||||
%12 = OpLabel
|
||||
OpStore %8 %10
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto consumer = nullptr;
|
||||
const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
|
||||
|
||||
FactManager fact_manager;
|
||||
|
||||
auto transformation = TransformationMoveBlockDown(100);
|
||||
ASSERT_FALSE(transformation.IsApplicable(context.get(), fact_manager));
|
||||
}
|
||||
|
||||
TEST(TransformationMoveBlockDownTest, NoMovePossible4) {
|
||||
// Block 12 is the last block in its function, so cannot be moved down.
|
||||
std::string shader = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpDecorate %8 RelaxedPrecision
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeInt 32 1
|
||||
%7 = OpTypePointer Function %6
|
||||
%9 = OpConstant %6 1
|
||||
%10 = OpConstant %6 2
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%8 = OpVariable %7 Function
|
||||
OpBranch %11
|
||||
%11 = OpLabel
|
||||
OpStore %8 %9
|
||||
OpBranch %12
|
||||
%12 = OpLabel
|
||||
OpStore %8 %10
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
%13 = OpFunction %2 None %3
|
||||
%14 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto consumer = nullptr;
|
||||
const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
|
||||
|
||||
FactManager fact_manager;
|
||||
|
||||
auto transformation = TransformationMoveBlockDown(12);
|
||||
ASSERT_FALSE(transformation.IsApplicable(context.get(), fact_manager));
|
||||
}
|
||||
|
||||
TEST(TransformationMoveBlockDownTest, ManyMovesPossible) {
|
||||
// The SPIR-V arising from this shader has lots of opportunities for moving
|
||||
// blocks around.
|
||||
//
|
||||
// void main() {
|
||||
// int x;
|
||||
// int y;
|
||||
// if (x < y) {
|
||||
// x = 1;
|
||||
// if (y == x) {
|
||||
// x = 3;
|
||||
// } else {
|
||||
// x = 4;
|
||||
// }
|
||||
// } else {
|
||||
// if (y < x) {
|
||||
// x = 5;
|
||||
// } else {
|
||||
// x = 6;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
std::string before_transformation = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
OpName %8 "x"
|
||||
OpName %10 "y"
|
||||
OpDecorate %8 RelaxedPrecision
|
||||
OpDecorate %9 RelaxedPrecision
|
||||
OpDecorate %10 RelaxedPrecision
|
||||
OpDecorate %11 RelaxedPrecision
|
||||
OpDecorate %17 RelaxedPrecision
|
||||
OpDecorate %18 RelaxedPrecision
|
||||
OpDecorate %26 RelaxedPrecision
|
||||
OpDecorate %27 RelaxedPrecision
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeInt 32 1
|
||||
%7 = OpTypePointer Function %6
|
||||
%12 = OpTypeBool
|
||||
%16 = OpConstant %6 1
|
||||
%22 = OpConstant %6 3
|
||||
%24 = OpConstant %6 4
|
||||
%31 = OpConstant %6 5
|
||||
%33 = OpConstant %6 6
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%8 = OpVariable %7 Function
|
||||
%10 = OpVariable %7 Function
|
||||
%9 = OpLoad %6 %8
|
||||
%11 = OpLoad %6 %10
|
||||
%13 = OpSLessThan %12 %9 %11
|
||||
OpSelectionMerge %15 None
|
||||
OpBranchConditional %13 %14 %25
|
||||
%14 = OpLabel
|
||||
OpStore %8 %16
|
||||
%17 = OpLoad %6 %10
|
||||
%18 = OpLoad %6 %8
|
||||
%19 = OpIEqual %12 %17 %18
|
||||
OpSelectionMerge %21 None
|
||||
OpBranchConditional %19 %20 %23
|
||||
%20 = OpLabel
|
||||
OpStore %8 %22
|
||||
OpBranch %21
|
||||
%23 = OpLabel
|
||||
OpStore %8 %24
|
||||
OpBranch %21
|
||||
%21 = OpLabel
|
||||
OpBranch %15
|
||||
%25 = OpLabel
|
||||
%26 = OpLoad %6 %10
|
||||
%27 = OpLoad %6 %8
|
||||
%28 = OpSLessThan %12 %26 %27
|
||||
OpSelectionMerge %30 None
|
||||
OpBranchConditional %28 %29 %32
|
||||
%29 = OpLabel
|
||||
OpStore %8 %31
|
||||
OpBranch %30
|
||||
%32 = OpLabel
|
||||
OpStore %8 %33
|
||||
OpBranch %30
|
||||
%30 = OpLabel
|
||||
OpBranch %15
|
||||
%15 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto consumer = nullptr;
|
||||
const auto context =
|
||||
BuildModule(env, consumer, before_transformation, kFuzzAssembleOption);
|
||||
|
||||
FactManager fact_manager;
|
||||
|
||||
// The block ids are: 5 14 20 23 21 25 29 32 30 15
|
||||
// We make a transformation to move each of them down, plus a transformation
|
||||
// to move a non-block, 27, down.
|
||||
auto move_down_5 = TransformationMoveBlockDown(5);
|
||||
auto move_down_14 = TransformationMoveBlockDown(14);
|
||||
auto move_down_20 = TransformationMoveBlockDown(20);
|
||||
auto move_down_23 = TransformationMoveBlockDown(23);
|
||||
auto move_down_21 = TransformationMoveBlockDown(21);
|
||||
auto move_down_25 = TransformationMoveBlockDown(25);
|
||||
auto move_down_29 = TransformationMoveBlockDown(29);
|
||||
auto move_down_32 = TransformationMoveBlockDown(32);
|
||||
auto move_down_30 = TransformationMoveBlockDown(30);
|
||||
auto move_down_15 = TransformationMoveBlockDown(15);
|
||||
auto move_down_27 = TransformationMoveBlockDown(27);
|
||||
|
||||
// Dominance is as follows:
|
||||
// 5 dominates everything else
|
||||
// 14 dominates 20, 23, 21
|
||||
// 20 dominates nothing
|
||||
// 23 dominates nothing
|
||||
// 21 dominates nothing
|
||||
// 25 dominates 29, 32, 30
|
||||
// 29 dominates nothing
|
||||
// 32 dominates nothing
|
||||
// 30 dominates nothing
|
||||
// 15 dominates nothing
|
||||
|
||||
// Current ordering: 5 14 20 23 21 25 29 32 30 15
|
||||
ASSERT_FALSE(move_down_5.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(move_down_14.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_20.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_23.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_21.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(move_down_25.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_29.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_32.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_30.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(move_down_15.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Let's bubble 20 all the way down.
|
||||
|
||||
move_down_20.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
// Current ordering: 5 14 23 20 21 25 29 32 30 15
|
||||
ASSERT_FALSE(move_down_5.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(move_down_14.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_23.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_20.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_21.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(move_down_25.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_29.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_32.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_30.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(move_down_15.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
move_down_20.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
// Current ordering: 5 14 23 21 20 25 29 32 30 15
|
||||
ASSERT_FALSE(move_down_5.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(move_down_14.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_23.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_21.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_20.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(move_down_25.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_29.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_32.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_30.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(move_down_15.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
move_down_20.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
// Current ordering: 5 14 23 21 25 20 29 32 30 15
|
||||
ASSERT_FALSE(move_down_5.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(move_down_14.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_23.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_21.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_25.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_20.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_29.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_32.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_30.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(move_down_15.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
move_down_20.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
// Current ordering: 5 14 23 21 25 29 20 32 30 15
|
||||
ASSERT_FALSE(move_down_5.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(move_down_14.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_23.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_21.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(move_down_25.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_29.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_20.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_32.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_30.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(move_down_15.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
move_down_20.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
// Current ordering: 5 14 23 21 25 29 32 20 30 15
|
||||
ASSERT_FALSE(move_down_5.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(move_down_14.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_23.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_21.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(move_down_25.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_29.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_32.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_20.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_30.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(move_down_15.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
move_down_20.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
// Current ordering: 5 14 23 21 25 29 32 30 20 15
|
||||
ASSERT_FALSE(move_down_5.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(move_down_14.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_23.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_21.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(move_down_25.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_29.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_32.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_30.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_20.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(move_down_15.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
move_down_20.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
std::string after_bubbling_20_down = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
OpName %8 "x"
|
||||
OpName %10 "y"
|
||||
OpDecorate %8 RelaxedPrecision
|
||||
OpDecorate %9 RelaxedPrecision
|
||||
OpDecorate %10 RelaxedPrecision
|
||||
OpDecorate %11 RelaxedPrecision
|
||||
OpDecorate %17 RelaxedPrecision
|
||||
OpDecorate %18 RelaxedPrecision
|
||||
OpDecorate %26 RelaxedPrecision
|
||||
OpDecorate %27 RelaxedPrecision
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeInt 32 1
|
||||
%7 = OpTypePointer Function %6
|
||||
%12 = OpTypeBool
|
||||
%16 = OpConstant %6 1
|
||||
%22 = OpConstant %6 3
|
||||
%24 = OpConstant %6 4
|
||||
%31 = OpConstant %6 5
|
||||
%33 = OpConstant %6 6
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%8 = OpVariable %7 Function
|
||||
%10 = OpVariable %7 Function
|
||||
%9 = OpLoad %6 %8
|
||||
%11 = OpLoad %6 %10
|
||||
%13 = OpSLessThan %12 %9 %11
|
||||
OpSelectionMerge %15 None
|
||||
OpBranchConditional %13 %14 %25
|
||||
%14 = OpLabel
|
||||
OpStore %8 %16
|
||||
%17 = OpLoad %6 %10
|
||||
%18 = OpLoad %6 %8
|
||||
%19 = OpIEqual %12 %17 %18
|
||||
OpSelectionMerge %21 None
|
||||
OpBranchConditional %19 %20 %23
|
||||
%23 = OpLabel
|
||||
OpStore %8 %24
|
||||
OpBranch %21
|
||||
%21 = OpLabel
|
||||
OpBranch %15
|
||||
%25 = OpLabel
|
||||
%26 = OpLoad %6 %10
|
||||
%27 = OpLoad %6 %8
|
||||
%28 = OpSLessThan %12 %26 %27
|
||||
OpSelectionMerge %30 None
|
||||
OpBranchConditional %28 %29 %32
|
||||
%29 = OpLabel
|
||||
OpStore %8 %31
|
||||
OpBranch %30
|
||||
%32 = OpLabel
|
||||
OpStore %8 %33
|
||||
OpBranch %30
|
||||
%30 = OpLabel
|
||||
OpBranch %15
|
||||
%15 = OpLabel
|
||||
OpReturn
|
||||
%20 = OpLabel
|
||||
OpStore %8 %22
|
||||
OpBranch %21
|
||||
OpFunctionEnd
|
||||
)";
|
||||
ASSERT_TRUE(IsEqual(env, after_bubbling_20_down, context.get()));
|
||||
|
||||
// Current ordering: 5 14 23 21 25 29 32 30 15 20
|
||||
ASSERT_FALSE(move_down_5.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(move_down_14.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_23.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_21.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(move_down_25.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_29.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_32.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_30.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_15.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(move_down_20.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
move_down_23.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
// Current ordering: 5 14 21 23 25 29 32 30 15 20
|
||||
ASSERT_FALSE(move_down_5.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(move_down_14.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_21.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_23.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(move_down_25.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_29.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_32.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_30.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_15.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(move_down_20.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
move_down_23.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
// Current ordering: 5 14 21 25 23 29 32 30 15 20
|
||||
ASSERT_FALSE(move_down_5.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(move_down_14.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_21.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_25.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_23.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_29.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_32.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_30.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_15.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(move_down_20.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
move_down_21.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
// Current ordering: 5 14 25 21 23 29 32 30 15 20
|
||||
ASSERT_FALSE(move_down_5.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_14.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_21.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_25.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_23.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_29.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_32.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_30.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_15.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(move_down_20.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
move_down_14.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
std::string after_more_shuffling = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
OpName %8 "x"
|
||||
OpName %10 "y"
|
||||
OpDecorate %8 RelaxedPrecision
|
||||
OpDecorate %9 RelaxedPrecision
|
||||
OpDecorate %10 RelaxedPrecision
|
||||
OpDecorate %11 RelaxedPrecision
|
||||
OpDecorate %17 RelaxedPrecision
|
||||
OpDecorate %18 RelaxedPrecision
|
||||
OpDecorate %26 RelaxedPrecision
|
||||
OpDecorate %27 RelaxedPrecision
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeInt 32 1
|
||||
%7 = OpTypePointer Function %6
|
||||
%12 = OpTypeBool
|
||||
%16 = OpConstant %6 1
|
||||
%22 = OpConstant %6 3
|
||||
%24 = OpConstant %6 4
|
||||
%31 = OpConstant %6 5
|
||||
%33 = OpConstant %6 6
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%8 = OpVariable %7 Function
|
||||
%10 = OpVariable %7 Function
|
||||
%9 = OpLoad %6 %8
|
||||
%11 = OpLoad %6 %10
|
||||
%13 = OpSLessThan %12 %9 %11
|
||||
OpSelectionMerge %15 None
|
||||
OpBranchConditional %13 %14 %25
|
||||
%25 = OpLabel
|
||||
%26 = OpLoad %6 %10
|
||||
%27 = OpLoad %6 %8
|
||||
%28 = OpSLessThan %12 %26 %27
|
||||
OpSelectionMerge %30 None
|
||||
OpBranchConditional %28 %29 %32
|
||||
%14 = OpLabel
|
||||
OpStore %8 %16
|
||||
%17 = OpLoad %6 %10
|
||||
%18 = OpLoad %6 %8
|
||||
%19 = OpIEqual %12 %17 %18
|
||||
OpSelectionMerge %21 None
|
||||
OpBranchConditional %19 %20 %23
|
||||
%21 = OpLabel
|
||||
OpBranch %15
|
||||
%23 = OpLabel
|
||||
OpStore %8 %24
|
||||
OpBranch %21
|
||||
%29 = OpLabel
|
||||
OpStore %8 %31
|
||||
OpBranch %30
|
||||
%32 = OpLabel
|
||||
OpStore %8 %33
|
||||
OpBranch %30
|
||||
%30 = OpLabel
|
||||
OpBranch %15
|
||||
%15 = OpLabel
|
||||
OpReturn
|
||||
%20 = OpLabel
|
||||
OpStore %8 %22
|
||||
OpBranch %21
|
||||
OpFunctionEnd
|
||||
)";
|
||||
ASSERT_TRUE(IsEqual(env, after_more_shuffling, context.get()));
|
||||
|
||||
// Final ordering: 5 25 14 21 23 29 32 30 15 20
|
||||
ASSERT_FALSE(move_down_5.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_25.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(move_down_14.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_21.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_23.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_29.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_32.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_30.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(move_down_15.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(move_down_20.IsApplicable(context.get(), fact_manager));
|
||||
}
|
||||
|
||||
TEST(TransformationMoveBlockDownTest, DoNotMoveUnreachable) {
|
||||
// Block 6 is unreachable, so cannot be moved down.
|
||||
std::string shader = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%10 = OpTypeInt 32 1
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
OpReturn
|
||||
%6 = OpLabel
|
||||
%7 = OpUndef %10
|
||||
OpBranch %8
|
||||
%8 = OpLabel
|
||||
%9 = OpCopyObject %10 %7
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto consumer = nullptr;
|
||||
const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
FactManager fact_manager;
|
||||
|
||||
auto transformation = TransformationMoveBlockDown(6);
|
||||
ASSERT_FALSE(transformation.IsApplicable(context.get(), fact_manager));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
@@ -1,655 +0,0 @@
|
||||
// Copyright (c) 2019 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "source/fuzz/transformation_replace_boolean_constant_with_constant_binary.h"
|
||||
|
||||
#include "source/fuzz/fuzzer_util.h"
|
||||
#include "source/fuzz/id_use_descriptor.h"
|
||||
#include "source/fuzz/instruction_descriptor.h"
|
||||
#include "test/fuzz/fuzz_test_util.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
namespace {
|
||||
|
||||
TEST(TransformationReplaceBooleanConstantWithConstantBinaryTest,
|
||||
BasicReplacements) {
|
||||
// The test came from the following pseudo-GLSL, where int64 and uint64 denote
|
||||
// 64-bit integer types (they were replaced with int and uint during
|
||||
// translation to SPIR-V, and the generated SPIR-V has been doctored to
|
||||
// accommodate them).
|
||||
//
|
||||
// #version 450
|
||||
//
|
||||
// void main() {
|
||||
// double d1, d2;
|
||||
// d1 = 1.0;
|
||||
// d2 = 2.0;
|
||||
// float f1, f2;
|
||||
// f1 = 4.0;
|
||||
// f2 = 8.0;
|
||||
// int i1, i2;
|
||||
// i1 = 100;
|
||||
// i2 = 200;
|
||||
//
|
||||
// uint u1, u2;
|
||||
// u1 = 300u;
|
||||
// u2 = 400u;
|
||||
//
|
||||
// int64 i64_1, i64_2;
|
||||
// i64_1 = 500;
|
||||
// i64_2 = 600;
|
||||
//
|
||||
// uint64 u64_1, u64_2;
|
||||
// u64_1 = 700u;
|
||||
// u64_2 = 800u;
|
||||
//
|
||||
// bool b, c, d, e;
|
||||
// b = true;
|
||||
// c = false;
|
||||
// d = true || c;
|
||||
// c = c && false;
|
||||
// }
|
||||
std::string shader = R"(
|
||||
OpCapability Shader
|
||||
OpCapability Float64
|
||||
OpCapability Int64
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource GLSL 450
|
||||
OpName %4 "main"
|
||||
OpName %8 "d1"
|
||||
OpName %10 "d2"
|
||||
OpName %14 "f1"
|
||||
OpName %16 "f2"
|
||||
OpName %20 "i1"
|
||||
OpName %22 "i2"
|
||||
OpName %26 "u1"
|
||||
OpName %28 "u2"
|
||||
OpName %30 "i64_1"
|
||||
OpName %32 "i64_2"
|
||||
OpName %34 "u64_1"
|
||||
OpName %36 "u64_2"
|
||||
OpName %40 "b"
|
||||
OpName %42 "c"
|
||||
OpName %44 "d"
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeFloat 64
|
||||
%7 = OpTypePointer Function %6
|
||||
%9 = OpConstant %6 1
|
||||
%11 = OpConstant %6 2
|
||||
%12 = OpTypeFloat 32
|
||||
%13 = OpTypePointer Function %12
|
||||
%15 = OpConstant %12 4
|
||||
%17 = OpConstant %12 8
|
||||
%18 = OpTypeInt 32 1
|
||||
%60 = OpTypeInt 64 1
|
||||
%61 = OpTypePointer Function %60
|
||||
%19 = OpTypePointer Function %18
|
||||
%21 = OpConstant %18 -100
|
||||
%23 = OpConstant %18 200
|
||||
%24 = OpTypeInt 32 0
|
||||
%62 = OpTypeInt 64 0
|
||||
%63 = OpTypePointer Function %62
|
||||
%25 = OpTypePointer Function %24
|
||||
%27 = OpConstant %24 300
|
||||
%29 = OpConstant %24 400
|
||||
%31 = OpConstant %60 -600
|
||||
%33 = OpConstant %60 -500
|
||||
%35 = OpConstant %62 700
|
||||
%37 = OpConstant %62 800
|
||||
%38 = OpTypeBool
|
||||
%39 = OpTypePointer Function %38
|
||||
%41 = OpConstantTrue %38
|
||||
%43 = OpConstantFalse %38
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%8 = OpVariable %7 Function
|
||||
%10 = OpVariable %7 Function
|
||||
%14 = OpVariable %13 Function
|
||||
%16 = OpVariable %13 Function
|
||||
%20 = OpVariable %19 Function
|
||||
%22 = OpVariable %19 Function
|
||||
%26 = OpVariable %25 Function
|
||||
%28 = OpVariable %25 Function
|
||||
%30 = OpVariable %61 Function
|
||||
%32 = OpVariable %61 Function
|
||||
%34 = OpVariable %63 Function
|
||||
%36 = OpVariable %63 Function
|
||||
%40 = OpVariable %39 Function
|
||||
%42 = OpVariable %39 Function
|
||||
%44 = OpVariable %39 Function
|
||||
OpStore %8 %9
|
||||
OpStore %10 %11
|
||||
OpStore %14 %15
|
||||
OpStore %16 %17
|
||||
OpStore %20 %21
|
||||
OpStore %22 %23
|
||||
OpStore %26 %27
|
||||
OpStore %28 %29
|
||||
OpStore %30 %31
|
||||
OpStore %32 %33
|
||||
OpStore %34 %35
|
||||
OpStore %36 %37
|
||||
OpStore %40 %41
|
||||
OpStore %42 %43
|
||||
%45 = OpLoad %38 %42
|
||||
%46 = OpLogicalOr %38 %41 %45
|
||||
OpStore %44 %46
|
||||
%47 = OpLoad %38 %42
|
||||
%48 = OpLogicalAnd %38 %47 %43
|
||||
OpStore %42 %48
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto consumer = nullptr;
|
||||
const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
FactManager fact_manager;
|
||||
|
||||
std::vector<protobufs::IdUseDescriptor> uses_of_true = {
|
||||
MakeIdUseDescriptor(41, MakeInstructionDescriptor(44, SpvOpStore, 12), 1),
|
||||
MakeIdUseDescriptor(41, MakeInstructionDescriptor(46, SpvOpLogicalOr, 0),
|
||||
0)};
|
||||
|
||||
std::vector<protobufs::IdUseDescriptor> uses_of_false = {
|
||||
MakeIdUseDescriptor(43, MakeInstructionDescriptor(44, SpvOpStore, 13), 1),
|
||||
MakeIdUseDescriptor(43, MakeInstructionDescriptor(48, SpvOpLogicalAnd, 0),
|
||||
1)};
|
||||
|
||||
const uint32_t fresh_id = 100;
|
||||
|
||||
std::vector<SpvOp> fp_gt_opcodes = {
|
||||
SpvOpFOrdGreaterThan, SpvOpFOrdGreaterThanEqual, SpvOpFUnordGreaterThan,
|
||||
SpvOpFUnordGreaterThanEqual};
|
||||
|
||||
std::vector<SpvOp> fp_lt_opcodes = {SpvOpFOrdLessThan, SpvOpFOrdLessThanEqual,
|
||||
SpvOpFUnordLessThan,
|
||||
SpvOpFUnordLessThanEqual};
|
||||
|
||||
std::vector<SpvOp> int_gt_opcodes = {SpvOpSGreaterThan,
|
||||
SpvOpSGreaterThanEqual};
|
||||
|
||||
std::vector<SpvOp> int_lt_opcodes = {SpvOpSLessThan, SpvOpSLessThanEqual};
|
||||
|
||||
std::vector<SpvOp> uint_gt_opcodes = {SpvOpUGreaterThan,
|
||||
SpvOpUGreaterThanEqual};
|
||||
|
||||
std::vector<SpvOp> uint_lt_opcodes = {SpvOpULessThan, SpvOpULessThanEqual};
|
||||
|
||||
#define CHECK_OPERATOR(USE_DESCRIPTOR, LHS_ID, RHS_ID, OPCODE, FRESH_ID) \
|
||||
ASSERT_TRUE(TransformationReplaceBooleanConstantWithConstantBinary( \
|
||||
USE_DESCRIPTOR, LHS_ID, RHS_ID, OPCODE, FRESH_ID) \
|
||||
.IsApplicable(context.get(), fact_manager)); \
|
||||
ASSERT_FALSE(TransformationReplaceBooleanConstantWithConstantBinary( \
|
||||
USE_DESCRIPTOR, RHS_ID, LHS_ID, OPCODE, FRESH_ID) \
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
#define CHECK_TRANSFORMATION_APPLICABILITY(GT_OPCODES, LT_OPCODES, SMALL_ID, \
|
||||
LARGE_ID) \
|
||||
for (auto gt_opcode : GT_OPCODES) { \
|
||||
for (auto& true_use : uses_of_true) { \
|
||||
CHECK_OPERATOR(true_use, LARGE_ID, SMALL_ID, gt_opcode, fresh_id); \
|
||||
} \
|
||||
for (auto& false_use : uses_of_false) { \
|
||||
CHECK_OPERATOR(false_use, SMALL_ID, LARGE_ID, gt_opcode, fresh_id); \
|
||||
} \
|
||||
} \
|
||||
for (auto lt_opcode : LT_OPCODES) { \
|
||||
for (auto& true_use : uses_of_true) { \
|
||||
CHECK_OPERATOR(true_use, SMALL_ID, LARGE_ID, lt_opcode, fresh_id); \
|
||||
} \
|
||||
for (auto& false_use : uses_of_false) { \
|
||||
CHECK_OPERATOR(false_use, LARGE_ID, SMALL_ID, lt_opcode, fresh_id); \
|
||||
} \
|
||||
}
|
||||
|
||||
// Float
|
||||
{ CHECK_TRANSFORMATION_APPLICABILITY(fp_gt_opcodes, fp_lt_opcodes, 15, 17); }
|
||||
|
||||
// Double
|
||||
{ CHECK_TRANSFORMATION_APPLICABILITY(fp_gt_opcodes, fp_lt_opcodes, 9, 11); }
|
||||
|
||||
// Int32
|
||||
{
|
||||
CHECK_TRANSFORMATION_APPLICABILITY(int_gt_opcodes, int_lt_opcodes, 21, 23);
|
||||
}
|
||||
|
||||
// Int64
|
||||
{
|
||||
CHECK_TRANSFORMATION_APPLICABILITY(int_gt_opcodes, int_lt_opcodes, 31, 33);
|
||||
}
|
||||
|
||||
// Uint32
|
||||
{
|
||||
CHECK_TRANSFORMATION_APPLICABILITY(uint_gt_opcodes, uint_lt_opcodes, 27,
|
||||
29);
|
||||
}
|
||||
|
||||
// Uint64
|
||||
{
|
||||
CHECK_TRANSFORMATION_APPLICABILITY(uint_gt_opcodes, uint_lt_opcodes, 35,
|
||||
37);
|
||||
}
|
||||
|
||||
// Target id is not fresh
|
||||
ASSERT_FALSE(TransformationReplaceBooleanConstantWithConstantBinary(
|
||||
uses_of_true[0], 15, 17, SpvOpFOrdLessThan, 15)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// LHS id does not exist
|
||||
ASSERT_FALSE(TransformationReplaceBooleanConstantWithConstantBinary(
|
||||
uses_of_true[0], 300, 17, SpvOpFOrdLessThan, 200)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// RHS id does not exist
|
||||
ASSERT_FALSE(TransformationReplaceBooleanConstantWithConstantBinary(
|
||||
uses_of_true[0], 15, 300, SpvOpFOrdLessThan, 200)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// LHS and RHS ids do not match type
|
||||
ASSERT_FALSE(TransformationReplaceBooleanConstantWithConstantBinary(
|
||||
uses_of_true[0], 11, 17, SpvOpFOrdLessThan, 200)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Opcode not appropriate
|
||||
ASSERT_FALSE(TransformationReplaceBooleanConstantWithConstantBinary(
|
||||
uses_of_true[0], 15, 17, SpvOpFDiv, 200)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
auto replace_true_with_double_comparison =
|
||||
TransformationReplaceBooleanConstantWithConstantBinary(
|
||||
uses_of_true[0], 11, 9, SpvOpFUnordGreaterThan, 100);
|
||||
auto replace_true_with_uint32_comparison =
|
||||
TransformationReplaceBooleanConstantWithConstantBinary(
|
||||
uses_of_true[1], 27, 29, SpvOpULessThanEqual, 101);
|
||||
auto replace_false_with_float_comparison =
|
||||
TransformationReplaceBooleanConstantWithConstantBinary(
|
||||
uses_of_false[0], 17, 15, SpvOpFOrdLessThan, 102);
|
||||
auto replace_false_with_sint64_comparison =
|
||||
TransformationReplaceBooleanConstantWithConstantBinary(
|
||||
uses_of_false[1], 33, 31, SpvOpSLessThan, 103);
|
||||
|
||||
ASSERT_TRUE(replace_true_with_double_comparison.IsApplicable(context.get(),
|
||||
fact_manager));
|
||||
replace_true_with_double_comparison.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
ASSERT_TRUE(replace_true_with_uint32_comparison.IsApplicable(context.get(),
|
||||
fact_manager));
|
||||
replace_true_with_uint32_comparison.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
ASSERT_TRUE(replace_false_with_float_comparison.IsApplicable(context.get(),
|
||||
fact_manager));
|
||||
replace_false_with_float_comparison.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
ASSERT_TRUE(replace_false_with_sint64_comparison.IsApplicable(context.get(),
|
||||
fact_manager));
|
||||
replace_false_with_sint64_comparison.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
std::string after = R"(
|
||||
OpCapability Shader
|
||||
OpCapability Float64
|
||||
OpCapability Int64
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource GLSL 450
|
||||
OpName %4 "main"
|
||||
OpName %8 "d1"
|
||||
OpName %10 "d2"
|
||||
OpName %14 "f1"
|
||||
OpName %16 "f2"
|
||||
OpName %20 "i1"
|
||||
OpName %22 "i2"
|
||||
OpName %26 "u1"
|
||||
OpName %28 "u2"
|
||||
OpName %30 "i64_1"
|
||||
OpName %32 "i64_2"
|
||||
OpName %34 "u64_1"
|
||||
OpName %36 "u64_2"
|
||||
OpName %40 "b"
|
||||
OpName %42 "c"
|
||||
OpName %44 "d"
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeFloat 64
|
||||
%7 = OpTypePointer Function %6
|
||||
%9 = OpConstant %6 1
|
||||
%11 = OpConstant %6 2
|
||||
%12 = OpTypeFloat 32
|
||||
%13 = OpTypePointer Function %12
|
||||
%15 = OpConstant %12 4
|
||||
%17 = OpConstant %12 8
|
||||
%18 = OpTypeInt 32 1
|
||||
%60 = OpTypeInt 64 1
|
||||
%61 = OpTypePointer Function %60
|
||||
%19 = OpTypePointer Function %18
|
||||
%21 = OpConstant %18 -100
|
||||
%23 = OpConstant %18 200
|
||||
%24 = OpTypeInt 32 0
|
||||
%62 = OpTypeInt 64 0
|
||||
%63 = OpTypePointer Function %62
|
||||
%25 = OpTypePointer Function %24
|
||||
%27 = OpConstant %24 300
|
||||
%29 = OpConstant %24 400
|
||||
%31 = OpConstant %60 -600
|
||||
%33 = OpConstant %60 -500
|
||||
%35 = OpConstant %62 700
|
||||
%37 = OpConstant %62 800
|
||||
%38 = OpTypeBool
|
||||
%39 = OpTypePointer Function %38
|
||||
%41 = OpConstantTrue %38
|
||||
%43 = OpConstantFalse %38
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%8 = OpVariable %7 Function
|
||||
%10 = OpVariable %7 Function
|
||||
%14 = OpVariable %13 Function
|
||||
%16 = OpVariable %13 Function
|
||||
%20 = OpVariable %19 Function
|
||||
%22 = OpVariable %19 Function
|
||||
%26 = OpVariable %25 Function
|
||||
%28 = OpVariable %25 Function
|
||||
%30 = OpVariable %61 Function
|
||||
%32 = OpVariable %61 Function
|
||||
%34 = OpVariable %63 Function
|
||||
%36 = OpVariable %63 Function
|
||||
%40 = OpVariable %39 Function
|
||||
%42 = OpVariable %39 Function
|
||||
%44 = OpVariable %39 Function
|
||||
OpStore %8 %9
|
||||
OpStore %10 %11
|
||||
OpStore %14 %15
|
||||
OpStore %16 %17
|
||||
OpStore %20 %21
|
||||
OpStore %22 %23
|
||||
OpStore %26 %27
|
||||
OpStore %28 %29
|
||||
OpStore %30 %31
|
||||
OpStore %32 %33
|
||||
OpStore %34 %35
|
||||
OpStore %36 %37
|
||||
%100 = OpFUnordGreaterThan %38 %11 %9
|
||||
OpStore %40 %100
|
||||
%102 = OpFOrdLessThan %38 %17 %15
|
||||
OpStore %42 %102
|
||||
%45 = OpLoad %38 %42
|
||||
%101 = OpULessThanEqual %38 %27 %29
|
||||
%46 = OpLogicalOr %38 %101 %45
|
||||
OpStore %44 %46
|
||||
%47 = OpLoad %38 %42
|
||||
%103 = OpSLessThan %38 %33 %31
|
||||
%48 = OpLogicalAnd %38 %47 %103
|
||||
OpStore %42 %48
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
ASSERT_TRUE(IsEqual(env, after, context.get()));
|
||||
|
||||
if (std::numeric_limits<double>::has_quiet_NaN) {
|
||||
double quiet_nan_double = std::numeric_limits<double>::quiet_NaN();
|
||||
uint32_t words[2];
|
||||
memcpy(words, &quiet_nan_double, sizeof(double));
|
||||
opt::Instruction::OperandList operands = {
|
||||
{SPV_OPERAND_TYPE_LITERAL_INTEGER, {words[0]}},
|
||||
{SPV_OPERAND_TYPE_LITERAL_INTEGER, {words[1]}}};
|
||||
context->module()->AddGlobalValue(MakeUnique<opt::Instruction>(
|
||||
context.get(), SpvOpConstant, 6, 200, operands));
|
||||
fuzzerutil::UpdateModuleIdBound(context.get(), 200);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
// The transformation is not applicable because %200 is NaN.
|
||||
ASSERT_FALSE(TransformationReplaceBooleanConstantWithConstantBinary(
|
||||
uses_of_true[0], 11, 200, SpvOpFOrdLessThan, 300)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
}
|
||||
if (std::numeric_limits<double>::has_infinity) {
|
||||
double positive_infinity_double = std::numeric_limits<double>::infinity();
|
||||
uint32_t words[2];
|
||||
memcpy(words, &positive_infinity_double, sizeof(double));
|
||||
opt::Instruction::OperandList operands = {
|
||||
{SPV_OPERAND_TYPE_LITERAL_INTEGER, {words[0]}},
|
||||
{SPV_OPERAND_TYPE_LITERAL_INTEGER, {words[1]}}};
|
||||
context->module()->AddGlobalValue(MakeUnique<opt::Instruction>(
|
||||
context.get(), SpvOpConstant, 6, 201, operands));
|
||||
fuzzerutil::UpdateModuleIdBound(context.get(), 201);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
// Even though the double constant %11 is less than the infinity %201, the
|
||||
// transformation is restricted to only apply to finite values.
|
||||
ASSERT_FALSE(TransformationReplaceBooleanConstantWithConstantBinary(
|
||||
uses_of_true[0], 11, 201, SpvOpFOrdLessThan, 300)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
}
|
||||
if (std::numeric_limits<float>::has_infinity) {
|
||||
float positive_infinity_float = std::numeric_limits<float>::infinity();
|
||||
float negative_infinity_float = -1 * positive_infinity_float;
|
||||
uint32_t words_positive_infinity[1];
|
||||
uint32_t words_negative_infinity[1];
|
||||
memcpy(words_positive_infinity, &positive_infinity_float, sizeof(float));
|
||||
memcpy(words_negative_infinity, &negative_infinity_float, sizeof(float));
|
||||
opt::Instruction::OperandList operands_positive_infinity = {
|
||||
{SPV_OPERAND_TYPE_LITERAL_INTEGER, {words_positive_infinity[0]}}};
|
||||
context->module()->AddGlobalValue(MakeUnique<opt::Instruction>(
|
||||
context.get(), SpvOpConstant, 12, 202, operands_positive_infinity));
|
||||
fuzzerutil::UpdateModuleIdBound(context.get(), 202);
|
||||
opt::Instruction::OperandList operands = {
|
||||
{SPV_OPERAND_TYPE_LITERAL_INTEGER, {words_negative_infinity[0]}}};
|
||||
context->module()->AddGlobalValue(MakeUnique<opt::Instruction>(
|
||||
context.get(), SpvOpConstant, 12, 203, operands));
|
||||
fuzzerutil::UpdateModuleIdBound(context.get(), 203);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
// Even though the negative infinity at %203 is less than the positive
|
||||
// infinity %202, the transformation is restricted to only apply to finite
|
||||
// values.
|
||||
ASSERT_FALSE(TransformationReplaceBooleanConstantWithConstantBinary(
|
||||
uses_of_true[0], 203, 202, SpvOpFOrdLessThan, 300)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(TransformationReplaceBooleanConstantWithConstantBinaryTest,
|
||||
MergeInstructions) {
|
||||
// The test came from the following GLSL:
|
||||
//
|
||||
// void main() {
|
||||
// int x = 1;
|
||||
// int y = 2;
|
||||
// if (true) {
|
||||
// x = 2;
|
||||
// }
|
||||
// while(false) {
|
||||
// y = 2;
|
||||
// }
|
||||
// }
|
||||
|
||||
std::string shader = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource GLSL 450
|
||||
OpName %4 "main"
|
||||
OpName %8 "x"
|
||||
OpName %10 "y"
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeInt 32 1
|
||||
%7 = OpTypePointer Function %6
|
||||
%9 = OpConstant %6 1
|
||||
%11 = OpConstant %6 2
|
||||
%12 = OpTypeBool
|
||||
%13 = OpConstantTrue %12
|
||||
%21 = OpConstantFalse %12
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%8 = OpVariable %7 Function
|
||||
%10 = OpVariable %7 Function
|
||||
OpStore %8 %9
|
||||
OpStore %10 %11
|
||||
OpSelectionMerge %15 None
|
||||
OpBranchConditional %13 %14 %15
|
||||
%14 = OpLabel
|
||||
OpStore %8 %11
|
||||
OpBranch %15
|
||||
%15 = OpLabel
|
||||
OpBranch %16
|
||||
%16 = OpLabel
|
||||
OpLoopMerge %18 %19 None
|
||||
OpBranchConditional %21 %17 %18
|
||||
%17 = OpLabel
|
||||
OpStore %10 %11
|
||||
OpBranch %19
|
||||
%19 = OpLabel
|
||||
OpBranch %16
|
||||
%18 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto consumer = nullptr;
|
||||
const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
FactManager fact_manager;
|
||||
|
||||
auto use_of_true_in_if = MakeIdUseDescriptor(
|
||||
13, MakeInstructionDescriptor(10, SpvOpBranchConditional, 0), 0);
|
||||
auto use_of_false_in_while = MakeIdUseDescriptor(
|
||||
21, MakeInstructionDescriptor(16, SpvOpBranchConditional, 0), 0);
|
||||
|
||||
auto replacement_1 = TransformationReplaceBooleanConstantWithConstantBinary(
|
||||
use_of_true_in_if, 9, 11, SpvOpSLessThan, 100);
|
||||
auto replacement_2 = TransformationReplaceBooleanConstantWithConstantBinary(
|
||||
use_of_false_in_while, 9, 11, SpvOpSGreaterThanEqual, 101);
|
||||
|
||||
ASSERT_TRUE(replacement_1.IsApplicable(context.get(), fact_manager));
|
||||
replacement_1.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
ASSERT_TRUE(replacement_2.IsApplicable(context.get(), fact_manager));
|
||||
replacement_2.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
std::string after = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource GLSL 450
|
||||
OpName %4 "main"
|
||||
OpName %8 "x"
|
||||
OpName %10 "y"
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeInt 32 1
|
||||
%7 = OpTypePointer Function %6
|
||||
%9 = OpConstant %6 1
|
||||
%11 = OpConstant %6 2
|
||||
%12 = OpTypeBool
|
||||
%13 = OpConstantTrue %12
|
||||
%21 = OpConstantFalse %12
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%8 = OpVariable %7 Function
|
||||
%10 = OpVariable %7 Function
|
||||
OpStore %8 %9
|
||||
OpStore %10 %11
|
||||
%100 = OpSLessThan %12 %9 %11
|
||||
OpSelectionMerge %15 None
|
||||
OpBranchConditional %100 %14 %15
|
||||
%14 = OpLabel
|
||||
OpStore %8 %11
|
||||
OpBranch %15
|
||||
%15 = OpLabel
|
||||
OpBranch %16
|
||||
%16 = OpLabel
|
||||
%101 = OpSGreaterThanEqual %12 %9 %11
|
||||
OpLoopMerge %18 %19 None
|
||||
OpBranchConditional %101 %17 %18
|
||||
%17 = OpLabel
|
||||
OpStore %10 %11
|
||||
OpBranch %19
|
||||
%19 = OpLabel
|
||||
OpBranch %16
|
||||
%18 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
ASSERT_TRUE(IsEqual(env, after, context.get()));
|
||||
}
|
||||
|
||||
TEST(TransformationReplaceBooleanConstantWithConstantBinaryTest, OpPhi) {
|
||||
// Hand-written SPIR-V to check applicability of the transformation on an
|
||||
// OpPhi argument.
|
||||
|
||||
std::string shader = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeBool
|
||||
%7 = OpTypePointer Function %6
|
||||
%9 = OpConstantTrue %6
|
||||
%16 = OpConstantFalse %6
|
||||
%10 = OpTypeInt 32 1
|
||||
%11 = OpTypePointer Function %10
|
||||
%13 = OpConstant %10 0
|
||||
%15 = OpConstant %10 1
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
OpSelectionMerge %20 None
|
||||
OpBranchConditional %9 %21 %22
|
||||
%21 = OpLabel
|
||||
OpBranch %20
|
||||
%22 = OpLabel
|
||||
OpBranch %20
|
||||
%20 = OpLabel
|
||||
%23 = OpPhi %6 %9 %21 %16 %22
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto consumer = nullptr;
|
||||
const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
FactManager fact_manager;
|
||||
|
||||
auto replacement = TransformationReplaceBooleanConstantWithConstantBinary(
|
||||
MakeIdUseDescriptor(9, MakeInstructionDescriptor(23, SpvOpPhi, 0), 0), 13,
|
||||
15, SpvOpSLessThan, 100);
|
||||
|
||||
ASSERT_FALSE(replacement.IsApplicable(context.get(), fact_manager));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,251 +0,0 @@
|
||||
// Copyright (c) 2019 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "source/fuzz/transformation_set_function_control.h"
|
||||
#include "test/fuzz/fuzz_test_util.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
namespace {
|
||||
|
||||
TEST(TransformationSetFunctionControlTest, VariousScenarios) {
|
||||
// This is a simple transformation; this test captures the important things
|
||||
// to check for.
|
||||
|
||||
std::string shader = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main" %54
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
OpName %11 "foo(i1;i1;"
|
||||
OpName %9 "a"
|
||||
OpName %10 "b"
|
||||
OpName %13 "bar("
|
||||
OpName %17 "baz(i1;"
|
||||
OpName %16 "x"
|
||||
OpName %21 "boo(i1;i1;"
|
||||
OpName %19 "a"
|
||||
OpName %20 "b"
|
||||
OpName %29 "g"
|
||||
OpName %42 "param"
|
||||
OpName %44 "param"
|
||||
OpName %45 "param"
|
||||
OpName %48 "param"
|
||||
OpName %49 "param"
|
||||
OpName %54 "color"
|
||||
OpDecorate %54 Location 0
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeInt 32 1
|
||||
%7 = OpTypePointer Function %6
|
||||
%8 = OpTypeFunction %6 %7 %7
|
||||
%15 = OpTypeFunction %6 %7
|
||||
%28 = OpTypePointer Private %6
|
||||
%29 = OpVariable %28 Private
|
||||
%30 = OpConstant %6 2
|
||||
%31 = OpConstant %6 5
|
||||
%51 = OpTypeFloat 32
|
||||
%52 = OpTypeVector %51 4
|
||||
%53 = OpTypePointer Output %52
|
||||
%54 = OpVariable %53 Output
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%42 = OpVariable %7 Function
|
||||
%44 = OpVariable %7 Function
|
||||
%45 = OpVariable %7 Function
|
||||
%48 = OpVariable %7 Function
|
||||
%49 = OpVariable %7 Function
|
||||
%41 = OpFunctionCall %2 %13
|
||||
OpStore %42 %30
|
||||
%43 = OpFunctionCall %6 %17 %42
|
||||
OpStore %44 %31
|
||||
%46 = OpLoad %6 %29
|
||||
OpStore %45 %46
|
||||
%47 = OpFunctionCall %6 %21 %44 %45
|
||||
OpStore %48 %43
|
||||
OpStore %49 %47
|
||||
%50 = OpFunctionCall %6 %11 %48 %49
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
%11 = OpFunction %6 Const %8
|
||||
%9 = OpFunctionParameter %7
|
||||
%10 = OpFunctionParameter %7
|
||||
%12 = OpLabel
|
||||
%23 = OpLoad %6 %9
|
||||
%24 = OpLoad %6 %10
|
||||
%25 = OpIAdd %6 %23 %24
|
||||
OpReturnValue %25
|
||||
OpFunctionEnd
|
||||
%13 = OpFunction %2 Inline %3
|
||||
%14 = OpLabel
|
||||
OpStore %29 %30
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
%17 = OpFunction %6 Pure|DontInline %15
|
||||
%16 = OpFunctionParameter %7
|
||||
%18 = OpLabel
|
||||
%32 = OpLoad %6 %16
|
||||
%33 = OpIAdd %6 %31 %32
|
||||
OpReturnValue %33
|
||||
OpFunctionEnd
|
||||
%21 = OpFunction %6 DontInline %8
|
||||
%19 = OpFunctionParameter %7
|
||||
%20 = OpFunctionParameter %7
|
||||
%22 = OpLabel
|
||||
%36 = OpLoad %6 %19
|
||||
%37 = OpLoad %6 %20
|
||||
%38 = OpIMul %6 %36 %37
|
||||
OpReturnValue %38
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto consumer = nullptr;
|
||||
const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
|
||||
|
||||
FactManager fact_manager;
|
||||
|
||||
// %36 is not a function
|
||||
ASSERT_FALSE(TransformationSetFunctionControl(36, SpvFunctionControlMaskNone)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
// Cannot add the Pure function control to %4 as it did not already have it
|
||||
ASSERT_FALSE(TransformationSetFunctionControl(4, SpvFunctionControlPureMask)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
// Cannot add the Const function control to %21 as it did not already
|
||||
// have it
|
||||
ASSERT_FALSE(TransformationSetFunctionControl(21, SpvFunctionControlConstMask)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Set to None, removing Const
|
||||
TransformationSetFunctionControl transformation1(11,
|
||||
SpvFunctionControlMaskNone);
|
||||
ASSERT_TRUE(transformation1.IsApplicable(context.get(), fact_manager));
|
||||
transformation1.Apply(context.get(), &fact_manager);
|
||||
|
||||
// Set to Inline; silly to do it on an entry point, but it is allowed
|
||||
TransformationSetFunctionControl transformation2(
|
||||
4, SpvFunctionControlInlineMask);
|
||||
ASSERT_TRUE(transformation2.IsApplicable(context.get(), fact_manager));
|
||||
transformation2.Apply(context.get(), &fact_manager);
|
||||
|
||||
// Set to Pure, removing DontInline
|
||||
TransformationSetFunctionControl transformation3(17,
|
||||
SpvFunctionControlPureMask);
|
||||
ASSERT_TRUE(transformation3.IsApplicable(context.get(), fact_manager));
|
||||
transformation3.Apply(context.get(), &fact_manager);
|
||||
|
||||
// Change from Inline to DontInline
|
||||
TransformationSetFunctionControl transformation4(
|
||||
13, SpvFunctionControlDontInlineMask);
|
||||
ASSERT_TRUE(transformation4.IsApplicable(context.get(), fact_manager));
|
||||
transformation4.Apply(context.get(), &fact_manager);
|
||||
|
||||
std::string after_transformation = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main" %54
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
OpName %11 "foo(i1;i1;"
|
||||
OpName %9 "a"
|
||||
OpName %10 "b"
|
||||
OpName %13 "bar("
|
||||
OpName %17 "baz(i1;"
|
||||
OpName %16 "x"
|
||||
OpName %21 "boo(i1;i1;"
|
||||
OpName %19 "a"
|
||||
OpName %20 "b"
|
||||
OpName %29 "g"
|
||||
OpName %42 "param"
|
||||
OpName %44 "param"
|
||||
OpName %45 "param"
|
||||
OpName %48 "param"
|
||||
OpName %49 "param"
|
||||
OpName %54 "color"
|
||||
OpDecorate %54 Location 0
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeInt 32 1
|
||||
%7 = OpTypePointer Function %6
|
||||
%8 = OpTypeFunction %6 %7 %7
|
||||
%15 = OpTypeFunction %6 %7
|
||||
%28 = OpTypePointer Private %6
|
||||
%29 = OpVariable %28 Private
|
||||
%30 = OpConstant %6 2
|
||||
%31 = OpConstant %6 5
|
||||
%51 = OpTypeFloat 32
|
||||
%52 = OpTypeVector %51 4
|
||||
%53 = OpTypePointer Output %52
|
||||
%54 = OpVariable %53 Output
|
||||
%4 = OpFunction %2 Inline %3
|
||||
%5 = OpLabel
|
||||
%42 = OpVariable %7 Function
|
||||
%44 = OpVariable %7 Function
|
||||
%45 = OpVariable %7 Function
|
||||
%48 = OpVariable %7 Function
|
||||
%49 = OpVariable %7 Function
|
||||
%41 = OpFunctionCall %2 %13
|
||||
OpStore %42 %30
|
||||
%43 = OpFunctionCall %6 %17 %42
|
||||
OpStore %44 %31
|
||||
%46 = OpLoad %6 %29
|
||||
OpStore %45 %46
|
||||
%47 = OpFunctionCall %6 %21 %44 %45
|
||||
OpStore %48 %43
|
||||
OpStore %49 %47
|
||||
%50 = OpFunctionCall %6 %11 %48 %49
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
%11 = OpFunction %6 None %8
|
||||
%9 = OpFunctionParameter %7
|
||||
%10 = OpFunctionParameter %7
|
||||
%12 = OpLabel
|
||||
%23 = OpLoad %6 %9
|
||||
%24 = OpLoad %6 %10
|
||||
%25 = OpIAdd %6 %23 %24
|
||||
OpReturnValue %25
|
||||
OpFunctionEnd
|
||||
%13 = OpFunction %2 DontInline %3
|
||||
%14 = OpLabel
|
||||
OpStore %29 %30
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
%17 = OpFunction %6 Pure %15
|
||||
%16 = OpFunctionParameter %7
|
||||
%18 = OpLabel
|
||||
%32 = OpLoad %6 %16
|
||||
%33 = OpIAdd %6 %31 %32
|
||||
OpReturnValue %33
|
||||
OpFunctionEnd
|
||||
%21 = OpFunction %6 DontInline %8
|
||||
%19 = OpFunctionParameter %7
|
||||
%20 = OpFunctionParameter %7
|
||||
%22 = OpLabel
|
||||
%36 = OpLoad %6 %19
|
||||
%37 = OpLoad %6 %20
|
||||
%38 = OpIMul %6 %36 %37
|
||||
OpReturnValue %38
|
||||
OpFunctionEnd
|
||||
)";
|
||||
ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
@@ -1,968 +0,0 @@
|
||||
// Copyright (c) 2019 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "source/fuzz/transformation_set_loop_control.h"
|
||||
#include "test/fuzz/fuzz_test_util.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
namespace {
|
||||
|
||||
TEST(TransformationSetLoopControlTest, VariousScenarios) {
|
||||
// This test features loops with various different controls, and goes through
|
||||
// a number of acceptable and unacceptable transformations to those controls.
|
||||
|
||||
std::string shader = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeInt 32 1
|
||||
%7 = OpTypePointer Function %6
|
||||
%9 = OpConstant %6 0
|
||||
%16 = OpConstant %6 100
|
||||
%17 = OpTypeBool
|
||||
%20 = OpConstant %6 1
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%8 = OpVariable %7 Function
|
||||
%22 = OpVariable %7 Function
|
||||
%32 = OpVariable %7 Function
|
||||
%42 = OpVariable %7 Function
|
||||
%52 = OpVariable %7 Function
|
||||
%62 = OpVariable %7 Function
|
||||
%72 = OpVariable %7 Function
|
||||
%82 = OpVariable %7 Function
|
||||
%92 = OpVariable %7 Function
|
||||
%102 = OpVariable %7 Function
|
||||
%112 = OpVariable %7 Function
|
||||
%122 = OpVariable %7 Function
|
||||
OpStore %8 %9
|
||||
OpBranch %10
|
||||
%10 = OpLabel
|
||||
%132 = OpPhi %6 %9 %5 %21 %13
|
||||
OpLoopMerge %12 %13 None
|
||||
OpBranch %14
|
||||
%14 = OpLabel
|
||||
%18 = OpSLessThan %17 %132 %16
|
||||
OpBranchConditional %18 %11 %12
|
||||
%11 = OpLabel
|
||||
OpBranch %13
|
||||
%13 = OpLabel
|
||||
%21 = OpIAdd %6 %132 %20
|
||||
OpStore %8 %21
|
||||
OpBranch %10
|
||||
%12 = OpLabel
|
||||
OpStore %22 %9
|
||||
OpBranch %23
|
||||
%23 = OpLabel
|
||||
%133 = OpPhi %6 %9 %12 %31 %26
|
||||
OpLoopMerge %25 %26 Unroll
|
||||
OpBranch %27
|
||||
%27 = OpLabel
|
||||
%29 = OpSLessThan %17 %133 %16
|
||||
OpBranchConditional %29 %24 %25
|
||||
%24 = OpLabel
|
||||
OpBranch %26
|
||||
%26 = OpLabel
|
||||
%31 = OpIAdd %6 %133 %20
|
||||
OpStore %22 %31
|
||||
OpBranch %23
|
||||
%25 = OpLabel
|
||||
OpStore %32 %9
|
||||
OpBranch %33
|
||||
%33 = OpLabel
|
||||
%134 = OpPhi %6 %9 %25 %41 %36
|
||||
OpLoopMerge %35 %36 DontUnroll
|
||||
OpBranch %37
|
||||
%37 = OpLabel
|
||||
%39 = OpSLessThan %17 %134 %16
|
||||
OpBranchConditional %39 %34 %35
|
||||
%34 = OpLabel
|
||||
OpBranch %36
|
||||
%36 = OpLabel
|
||||
%41 = OpIAdd %6 %134 %20
|
||||
OpStore %32 %41
|
||||
OpBranch %33
|
||||
%35 = OpLabel
|
||||
OpStore %42 %9
|
||||
OpBranch %43
|
||||
%43 = OpLabel
|
||||
%135 = OpPhi %6 %9 %35 %51 %46
|
||||
OpLoopMerge %45 %46 DependencyInfinite
|
||||
OpBranch %47
|
||||
%47 = OpLabel
|
||||
%49 = OpSLessThan %17 %135 %16
|
||||
OpBranchConditional %49 %44 %45
|
||||
%44 = OpLabel
|
||||
OpBranch %46
|
||||
%46 = OpLabel
|
||||
%51 = OpIAdd %6 %135 %20
|
||||
OpStore %42 %51
|
||||
OpBranch %43
|
||||
%45 = OpLabel
|
||||
OpStore %52 %9
|
||||
OpBranch %53
|
||||
%53 = OpLabel
|
||||
%136 = OpPhi %6 %9 %45 %61 %56
|
||||
OpLoopMerge %55 %56 DependencyLength 3
|
||||
OpBranch %57
|
||||
%57 = OpLabel
|
||||
%59 = OpSLessThan %17 %136 %16
|
||||
OpBranchConditional %59 %54 %55
|
||||
%54 = OpLabel
|
||||
OpBranch %56
|
||||
%56 = OpLabel
|
||||
%61 = OpIAdd %6 %136 %20
|
||||
OpStore %52 %61
|
||||
OpBranch %53
|
||||
%55 = OpLabel
|
||||
OpStore %62 %9
|
||||
OpBranch %63
|
||||
%63 = OpLabel
|
||||
%137 = OpPhi %6 %9 %55 %71 %66
|
||||
OpLoopMerge %65 %66 MinIterations 10
|
||||
OpBranch %67
|
||||
%67 = OpLabel
|
||||
%69 = OpSLessThan %17 %137 %16
|
||||
OpBranchConditional %69 %64 %65
|
||||
%64 = OpLabel
|
||||
OpBranch %66
|
||||
%66 = OpLabel
|
||||
%71 = OpIAdd %6 %137 %20
|
||||
OpStore %62 %71
|
||||
OpBranch %63
|
||||
%65 = OpLabel
|
||||
OpStore %72 %9
|
||||
OpBranch %73
|
||||
%73 = OpLabel
|
||||
%138 = OpPhi %6 %9 %65 %81 %76
|
||||
OpLoopMerge %75 %76 MaxIterations 50
|
||||
OpBranch %77
|
||||
%77 = OpLabel
|
||||
%79 = OpSLessThan %17 %138 %16
|
||||
OpBranchConditional %79 %74 %75
|
||||
%74 = OpLabel
|
||||
OpBranch %76
|
||||
%76 = OpLabel
|
||||
%81 = OpIAdd %6 %138 %20
|
||||
OpStore %72 %81
|
||||
OpBranch %73
|
||||
%75 = OpLabel
|
||||
OpStore %82 %9
|
||||
OpBranch %83
|
||||
%83 = OpLabel
|
||||
%139 = OpPhi %6 %9 %75 %91 %86
|
||||
OpLoopMerge %85 %86 IterationMultiple 4
|
||||
OpBranch %87
|
||||
%87 = OpLabel
|
||||
%89 = OpSLessThan %17 %139 %16
|
||||
OpBranchConditional %89 %84 %85
|
||||
%84 = OpLabel
|
||||
OpBranch %86
|
||||
%86 = OpLabel
|
||||
%91 = OpIAdd %6 %139 %20
|
||||
OpStore %82 %91
|
||||
OpBranch %83
|
||||
%85 = OpLabel
|
||||
OpStore %92 %9
|
||||
OpBranch %93
|
||||
%93 = OpLabel
|
||||
%140 = OpPhi %6 %9 %85 %101 %96
|
||||
OpLoopMerge %95 %96 PeelCount 2
|
||||
OpBranch %97
|
||||
%97 = OpLabel
|
||||
%99 = OpSLessThan %17 %140 %16
|
||||
OpBranchConditional %99 %94 %95
|
||||
%94 = OpLabel
|
||||
OpBranch %96
|
||||
%96 = OpLabel
|
||||
%101 = OpIAdd %6 %140 %20
|
||||
OpStore %92 %101
|
||||
OpBranch %93
|
||||
%95 = OpLabel
|
||||
OpStore %102 %9
|
||||
OpBranch %103
|
||||
%103 = OpLabel
|
||||
%141 = OpPhi %6 %9 %95 %111 %106
|
||||
OpLoopMerge %105 %106 PartialCount 3
|
||||
OpBranch %107
|
||||
%107 = OpLabel
|
||||
%109 = OpSLessThan %17 %141 %16
|
||||
OpBranchConditional %109 %104 %105
|
||||
%104 = OpLabel
|
||||
OpBranch %106
|
||||
%106 = OpLabel
|
||||
%111 = OpIAdd %6 %141 %20
|
||||
OpStore %102 %111
|
||||
OpBranch %103
|
||||
%105 = OpLabel
|
||||
OpStore %112 %9
|
||||
OpBranch %113
|
||||
%113 = OpLabel
|
||||
%142 = OpPhi %6 %9 %105 %121 %116
|
||||
OpLoopMerge %115 %116 Unroll|PeelCount|PartialCount 3 4
|
||||
OpBranch %117
|
||||
%117 = OpLabel
|
||||
%119 = OpSLessThan %17 %142 %16
|
||||
OpBranchConditional %119 %114 %115
|
||||
%114 = OpLabel
|
||||
OpBranch %116
|
||||
%116 = OpLabel
|
||||
%121 = OpIAdd %6 %142 %20
|
||||
OpStore %112 %121
|
||||
OpBranch %113
|
||||
%115 = OpLabel
|
||||
OpStore %122 %9
|
||||
OpBranch %123
|
||||
%123 = OpLabel
|
||||
%143 = OpPhi %6 %9 %115 %131 %126
|
||||
OpLoopMerge %125 %126 DependencyLength|MinIterations|MaxIterations|IterationMultiple|PeelCount|PartialCount 2 5 90 4 7 14
|
||||
OpBranch %127
|
||||
%127 = OpLabel
|
||||
%129 = OpSLessThan %17 %143 %16
|
||||
OpBranchConditional %129 %124 %125
|
||||
%124 = OpLabel
|
||||
OpBranch %126
|
||||
%126 = OpLabel
|
||||
%131 = OpIAdd %6 %143 %20
|
||||
OpStore %122 %131
|
||||
OpBranch %123
|
||||
%125 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_4;
|
||||
const auto consumer = nullptr;
|
||||
const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
|
||||
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
FactManager fact_manager;
|
||||
|
||||
// These are the loop headers together with the selection controls of their
|
||||
// merge instructions:
|
||||
// %10 None
|
||||
// %23 Unroll
|
||||
// %33 DontUnroll
|
||||
// %43 DependencyInfinite
|
||||
// %53 DependencyLength 3
|
||||
// %63 MinIterations 10
|
||||
// %73 MaxIterations 50
|
||||
// %83 IterationMultiple 4
|
||||
// %93 PeelCount 2
|
||||
// %103 PartialCount 3
|
||||
// %113 Unroll|PeelCount|PartialCount 3 4
|
||||
// %123
|
||||
// DependencyLength|MinIterations|MaxIterations|IterationMultiple|PeelCount|PartialCount
|
||||
// 2 5 90 4 7 14
|
||||
|
||||
ASSERT_TRUE(TransformationSetLoopControl(10, SpvLoopControlMaskNone, 0, 0)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(TransformationSetLoopControl(10, SpvLoopControlUnrollMask, 0, 0)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
TransformationSetLoopControl(10, SpvLoopControlDontUnrollMask, 0, 0)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(TransformationSetLoopControl(
|
||||
10, SpvLoopControlDependencyInfiniteMask, 0, 0)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
TransformationSetLoopControl(10, SpvLoopControlDependencyLengthMask, 0, 0)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
TransformationSetLoopControl(10, SpvLoopControlMinIterationsMask, 0, 0)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
TransformationSetLoopControl(10, SpvLoopControlMaxIterationsMask, 0, 0)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(TransformationSetLoopControl(
|
||||
10, SpvLoopControlIterationMultipleMask, 0, 0)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
TransformationSetLoopControl(10, SpvLoopControlPeelCountMask, 3, 0)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
TransformationSetLoopControl(10, SpvLoopControlPeelCountMask, 3, 3)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
TransformationSetLoopControl(10, SpvLoopControlPartialCountMask, 0, 3)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
TransformationSetLoopControl(10, SpvLoopControlPartialCountMask, 3, 3)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(TransformationSetLoopControl(
|
||||
10,
|
||||
SpvLoopControlPeelCountMask | SpvLoopControlPartialCountMask,
|
||||
3, 3)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(TransformationSetLoopControl(10,
|
||||
SpvLoopControlUnrollMask |
|
||||
SpvLoopControlPeelCountMask |
|
||||
SpvLoopControlPartialCountMask,
|
||||
3, 3)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(TransformationSetLoopControl(10,
|
||||
SpvLoopControlDontUnrollMask |
|
||||
SpvLoopControlPeelCountMask |
|
||||
SpvLoopControlPartialCountMask,
|
||||
3, 3)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
ASSERT_TRUE(TransformationSetLoopControl(23, SpvLoopControlMaskNone, 0, 0)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(TransformationSetLoopControl(23, SpvLoopControlUnrollMask, 0, 0)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
TransformationSetLoopControl(23, SpvLoopControlDontUnrollMask, 0, 0)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(TransformationSetLoopControl(
|
||||
23,
|
||||
SpvLoopControlPeelCountMask | SpvLoopControlPartialCountMask,
|
||||
3, 3)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
TransformationSetLoopControl(23, SpvLoopControlMaxIterationsMask, 2, 3)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
ASSERT_TRUE(TransformationSetLoopControl(33, SpvLoopControlMaskNone, 0, 0)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(TransformationSetLoopControl(33, SpvLoopControlUnrollMask, 0, 0)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
TransformationSetLoopControl(33, SpvLoopControlDontUnrollMask, 0, 0)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
TransformationSetLoopControl(33, SpvLoopControlMinIterationsMask, 0, 0)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
TransformationSetLoopControl(
|
||||
33, SpvLoopControlUnrollMask | SpvLoopControlPeelCountMask, 5, 0)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(TransformationSetLoopControl(33,
|
||||
SpvLoopControlDontUnrollMask |
|
||||
SpvLoopControlPartialCountMask,
|
||||
0, 10)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
ASSERT_TRUE(TransformationSetLoopControl(43, SpvLoopControlMaskNone, 0, 0)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(TransformationSetLoopControl(43, SpvLoopControlUnrollMask, 0, 0)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
TransformationSetLoopControl(43, SpvLoopControlDontUnrollMask, 0, 0)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(TransformationSetLoopControl(
|
||||
43,
|
||||
SpvLoopControlMaskNone | SpvLoopControlDependencyInfiniteMask,
|
||||
0, 0)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
TransformationSetLoopControl(
|
||||
43, SpvLoopControlUnrollMask | SpvLoopControlDependencyInfiniteMask,
|
||||
0, 0)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
TransformationSetLoopControl(
|
||||
43,
|
||||
SpvLoopControlDontUnrollMask | SpvLoopControlDependencyInfiniteMask,
|
||||
0, 0)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
TransformationSetLoopControl(43,
|
||||
SpvLoopControlDependencyInfiniteMask |
|
||||
SpvLoopControlDependencyLengthMask,
|
||||
0, 0)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
TransformationSetLoopControl(
|
||||
43, SpvLoopControlUnrollMask | SpvLoopControlPeelCountMask, 5, 0)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
ASSERT_TRUE(TransformationSetLoopControl(53, SpvLoopControlMaskNone, 0, 0)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(TransformationSetLoopControl(53, SpvLoopControlUnrollMask, 0, 0)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
TransformationSetLoopControl(53, SpvLoopControlDontUnrollMask, 0, 0)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
TransformationSetLoopControl(53, SpvLoopControlMaxIterationsMask, 0, 0)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
TransformationSetLoopControl(
|
||||
53, SpvLoopControlMaskNone | SpvLoopControlDependencyLengthMask, 0, 0)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
TransformationSetLoopControl(
|
||||
53, SpvLoopControlUnrollMask | SpvLoopControlDependencyInfiniteMask,
|
||||
0, 0)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
TransformationSetLoopControl(
|
||||
53, SpvLoopControlDontUnrollMask | SpvLoopControlDependencyLengthMask,
|
||||
0, 0)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
TransformationSetLoopControl(53,
|
||||
SpvLoopControlDependencyInfiniteMask |
|
||||
SpvLoopControlDependencyLengthMask,
|
||||
0, 0)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
TransformationSetLoopControl(
|
||||
53,
|
||||
SpvLoopControlUnrollMask | SpvLoopControlDependencyLengthMask |
|
||||
SpvLoopControlPeelCountMask | SpvLoopControlPartialCountMask,
|
||||
5, 3)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
ASSERT_TRUE(TransformationSetLoopControl(63, SpvLoopControlMaskNone, 0, 0)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(TransformationSetLoopControl(63, SpvLoopControlUnrollMask, 0, 0)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
TransformationSetLoopControl(63, SpvLoopControlDontUnrollMask, 0, 0)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(TransformationSetLoopControl(63,
|
||||
SpvLoopControlUnrollMask |
|
||||
SpvLoopControlMinIterationsMask |
|
||||
SpvLoopControlPeelCountMask |
|
||||
SpvLoopControlPartialCountMask,
|
||||
5, 3)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(TransformationSetLoopControl(63,
|
||||
SpvLoopControlUnrollMask |
|
||||
SpvLoopControlMinIterationsMask |
|
||||
SpvLoopControlPeelCountMask,
|
||||
23, 0)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(TransformationSetLoopControl(
|
||||
63,
|
||||
SpvLoopControlUnrollMask | SpvLoopControlMinIterationsMask |
|
||||
SpvLoopControlPeelCountMask,
|
||||
2, 23)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
ASSERT_TRUE(TransformationSetLoopControl(73, SpvLoopControlMaskNone, 0, 0)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(TransformationSetLoopControl(73, SpvLoopControlUnrollMask, 0, 0)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
TransformationSetLoopControl(73, SpvLoopControlDontUnrollMask, 0, 0)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(TransformationSetLoopControl(
|
||||
73,
|
||||
SpvLoopControlUnrollMask | SpvLoopControlMinIterationsMask |
|
||||
SpvLoopControlPeelCountMask |
|
||||
SpvLoopControlPartialCountMask,
|
||||
5, 3)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(TransformationSetLoopControl(73,
|
||||
SpvLoopControlUnrollMask |
|
||||
SpvLoopControlMaxIterationsMask |
|
||||
SpvLoopControlPeelCountMask,
|
||||
23, 0)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(TransformationSetLoopControl(
|
||||
73,
|
||||
SpvLoopControlUnrollMask | SpvLoopControlMaxIterationsMask |
|
||||
SpvLoopControlPeelCountMask,
|
||||
2, 23)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
ASSERT_TRUE(TransformationSetLoopControl(83, SpvLoopControlMaskNone, 0, 0)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(TransformationSetLoopControl(83, SpvLoopControlUnrollMask, 0, 0)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
TransformationSetLoopControl(83, SpvLoopControlDontUnrollMask, 0, 0)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(TransformationSetLoopControl(
|
||||
83,
|
||||
SpvLoopControlUnrollMask | SpvLoopControlMinIterationsMask |
|
||||
SpvLoopControlPeelCountMask |
|
||||
SpvLoopControlPartialCountMask,
|
||||
5, 3)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
TransformationSetLoopControl(83,
|
||||
SpvLoopControlUnrollMask |
|
||||
SpvLoopControlIterationMultipleMask |
|
||||
SpvLoopControlPeelCountMask,
|
||||
23, 0)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
TransformationSetLoopControl(83,
|
||||
SpvLoopControlUnrollMask |
|
||||
SpvLoopControlIterationMultipleMask |
|
||||
SpvLoopControlPeelCountMask,
|
||||
2, 23)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
ASSERT_TRUE(TransformationSetLoopControl(93, SpvLoopControlMaskNone, 0, 0)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(TransformationSetLoopControl(93, SpvLoopControlUnrollMask, 0, 0)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
TransformationSetLoopControl(93, SpvLoopControlDontUnrollMask, 0, 0)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
TransformationSetLoopControl(93, SpvLoopControlPeelCountMask, 8, 0)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
TransformationSetLoopControl(93, SpvLoopControlPeelCountMask, 8, 8)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
TransformationSetLoopControl(93, SpvLoopControlPartialCountMask, 0, 8)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(TransformationSetLoopControl(
|
||||
93,
|
||||
SpvLoopControlPeelCountMask | SpvLoopControlPartialCountMask,
|
||||
16, 8)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
ASSERT_TRUE(TransformationSetLoopControl(103, SpvLoopControlMaskNone, 0, 0)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(TransformationSetLoopControl(103, SpvLoopControlUnrollMask, 0, 0)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
TransformationSetLoopControl(103, SpvLoopControlDontUnrollMask, 0, 0)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
TransformationSetLoopControl(103, SpvLoopControlPartialCountMask, 0, 60)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(TransformationSetLoopControl(103,
|
||||
SpvLoopControlDontUnrollMask |
|
||||
SpvLoopControlPartialCountMask,
|
||||
0, 60)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
ASSERT_TRUE(TransformationSetLoopControl(113, SpvLoopControlMaskNone, 0, 0)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(TransformationSetLoopControl(113, SpvLoopControlUnrollMask, 0, 0)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
TransformationSetLoopControl(113, SpvLoopControlDontUnrollMask, 0, 0)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
TransformationSetLoopControl(113, SpvLoopControlPeelCountMask, 12, 0)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
TransformationSetLoopControl(
|
||||
113,
|
||||
SpvLoopControlIterationMultipleMask | SpvLoopControlPeelCountMask, 12,
|
||||
0)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
ASSERT_TRUE(TransformationSetLoopControl(123, SpvLoopControlMaskNone, 0, 0)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(TransformationSetLoopControl(123, SpvLoopControlUnrollMask, 0, 0)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
TransformationSetLoopControl(123, SpvLoopControlDontUnrollMask, 0, 0)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
TransformationSetLoopControl(
|
||||
123,
|
||||
SpvLoopControlMinIterationsMask | SpvLoopControlMaxIterationsMask |
|
||||
SpvLoopControlIterationMultipleMask |
|
||||
SpvLoopControlPeelCountMask | SpvLoopControlPartialCountMask,
|
||||
7, 8)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(TransformationSetLoopControl(123,
|
||||
SpvLoopControlUnrollMask |
|
||||
SpvLoopControlMinIterationsMask |
|
||||
SpvLoopControlMaxIterationsMask |
|
||||
SpvLoopControlPartialCountMask,
|
||||
0, 9)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(TransformationSetLoopControl(
|
||||
123,
|
||||
SpvLoopControlUnrollMask | SpvLoopControlMinIterationsMask |
|
||||
SpvLoopControlMaxIterationsMask |
|
||||
SpvLoopControlPartialCountMask,
|
||||
7, 9)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
TransformationSetLoopControl(
|
||||
123,
|
||||
SpvLoopControlDontUnrollMask | SpvLoopControlMinIterationsMask |
|
||||
SpvLoopControlMaxIterationsMask | SpvLoopControlPartialCountMask,
|
||||
7, 9)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
TransformationSetLoopControl(10,
|
||||
SpvLoopControlUnrollMask |
|
||||
SpvLoopControlPeelCountMask |
|
||||
SpvLoopControlPartialCountMask,
|
||||
3, 3)
|
||||
.Apply(context.get(), &fact_manager);
|
||||
TransformationSetLoopControl(23, SpvLoopControlDontUnrollMask, 0, 0)
|
||||
.Apply(context.get(), &fact_manager);
|
||||
TransformationSetLoopControl(33, SpvLoopControlUnrollMask, 0, 0)
|
||||
.Apply(context.get(), &fact_manager);
|
||||
TransformationSetLoopControl(
|
||||
43, SpvLoopControlDontUnrollMask | SpvLoopControlDependencyInfiniteMask,
|
||||
0, 0)
|
||||
.Apply(context.get(), &fact_manager);
|
||||
TransformationSetLoopControl(53, SpvLoopControlMaskNone, 0, 0)
|
||||
.Apply(context.get(), &fact_manager);
|
||||
TransformationSetLoopControl(63,
|
||||
SpvLoopControlUnrollMask |
|
||||
SpvLoopControlMinIterationsMask |
|
||||
SpvLoopControlPeelCountMask,
|
||||
23, 0)
|
||||
.Apply(context.get(), &fact_manager);
|
||||
TransformationSetLoopControl(73,
|
||||
SpvLoopControlUnrollMask |
|
||||
SpvLoopControlMaxIterationsMask |
|
||||
SpvLoopControlPeelCountMask,
|
||||
23, 0)
|
||||
.Apply(context.get(), &fact_manager);
|
||||
TransformationSetLoopControl(83, SpvLoopControlDontUnrollMask, 0, 0)
|
||||
.Apply(context.get(), &fact_manager);
|
||||
TransformationSetLoopControl(
|
||||
93, SpvLoopControlPeelCountMask | SpvLoopControlPartialCountMask, 16, 8)
|
||||
.Apply(context.get(), &fact_manager);
|
||||
TransformationSetLoopControl(103, SpvLoopControlPartialCountMask, 0, 60)
|
||||
.Apply(context.get(), &fact_manager);
|
||||
TransformationSetLoopControl(113, SpvLoopControlPeelCountMask, 12, 0)
|
||||
.Apply(context.get(), &fact_manager);
|
||||
TransformationSetLoopControl(
|
||||
123,
|
||||
SpvLoopControlUnrollMask | SpvLoopControlMinIterationsMask |
|
||||
SpvLoopControlMaxIterationsMask | SpvLoopControlPartialCountMask,
|
||||
0, 9)
|
||||
.Apply(context.get(), &fact_manager);
|
||||
|
||||
std::string after_transformation = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeInt 32 1
|
||||
%7 = OpTypePointer Function %6
|
||||
%9 = OpConstant %6 0
|
||||
%16 = OpConstant %6 100
|
||||
%17 = OpTypeBool
|
||||
%20 = OpConstant %6 1
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%8 = OpVariable %7 Function
|
||||
%22 = OpVariable %7 Function
|
||||
%32 = OpVariable %7 Function
|
||||
%42 = OpVariable %7 Function
|
||||
%52 = OpVariable %7 Function
|
||||
%62 = OpVariable %7 Function
|
||||
%72 = OpVariable %7 Function
|
||||
%82 = OpVariable %7 Function
|
||||
%92 = OpVariable %7 Function
|
||||
%102 = OpVariable %7 Function
|
||||
%112 = OpVariable %7 Function
|
||||
%122 = OpVariable %7 Function
|
||||
OpStore %8 %9
|
||||
OpBranch %10
|
||||
%10 = OpLabel
|
||||
%132 = OpPhi %6 %9 %5 %21 %13
|
||||
OpLoopMerge %12 %13 Unroll|PeelCount|PartialCount 3 3
|
||||
OpBranch %14
|
||||
%14 = OpLabel
|
||||
%18 = OpSLessThan %17 %132 %16
|
||||
OpBranchConditional %18 %11 %12
|
||||
%11 = OpLabel
|
||||
OpBranch %13
|
||||
%13 = OpLabel
|
||||
%21 = OpIAdd %6 %132 %20
|
||||
OpStore %8 %21
|
||||
OpBranch %10
|
||||
%12 = OpLabel
|
||||
OpStore %22 %9
|
||||
OpBranch %23
|
||||
%23 = OpLabel
|
||||
%133 = OpPhi %6 %9 %12 %31 %26
|
||||
OpLoopMerge %25 %26 DontUnroll
|
||||
OpBranch %27
|
||||
%27 = OpLabel
|
||||
%29 = OpSLessThan %17 %133 %16
|
||||
OpBranchConditional %29 %24 %25
|
||||
%24 = OpLabel
|
||||
OpBranch %26
|
||||
%26 = OpLabel
|
||||
%31 = OpIAdd %6 %133 %20
|
||||
OpStore %22 %31
|
||||
OpBranch %23
|
||||
%25 = OpLabel
|
||||
OpStore %32 %9
|
||||
OpBranch %33
|
||||
%33 = OpLabel
|
||||
%134 = OpPhi %6 %9 %25 %41 %36
|
||||
OpLoopMerge %35 %36 Unroll
|
||||
OpBranch %37
|
||||
%37 = OpLabel
|
||||
%39 = OpSLessThan %17 %134 %16
|
||||
OpBranchConditional %39 %34 %35
|
||||
%34 = OpLabel
|
||||
OpBranch %36
|
||||
%36 = OpLabel
|
||||
%41 = OpIAdd %6 %134 %20
|
||||
OpStore %32 %41
|
||||
OpBranch %33
|
||||
%35 = OpLabel
|
||||
OpStore %42 %9
|
||||
OpBranch %43
|
||||
%43 = OpLabel
|
||||
%135 = OpPhi %6 %9 %35 %51 %46
|
||||
OpLoopMerge %45 %46 DontUnroll|DependencyInfinite
|
||||
OpBranch %47
|
||||
%47 = OpLabel
|
||||
%49 = OpSLessThan %17 %135 %16
|
||||
OpBranchConditional %49 %44 %45
|
||||
%44 = OpLabel
|
||||
OpBranch %46
|
||||
%46 = OpLabel
|
||||
%51 = OpIAdd %6 %135 %20
|
||||
OpStore %42 %51
|
||||
OpBranch %43
|
||||
%45 = OpLabel
|
||||
OpStore %52 %9
|
||||
OpBranch %53
|
||||
%53 = OpLabel
|
||||
%136 = OpPhi %6 %9 %45 %61 %56
|
||||
OpLoopMerge %55 %56 None
|
||||
OpBranch %57
|
||||
%57 = OpLabel
|
||||
%59 = OpSLessThan %17 %136 %16
|
||||
OpBranchConditional %59 %54 %55
|
||||
%54 = OpLabel
|
||||
OpBranch %56
|
||||
%56 = OpLabel
|
||||
%61 = OpIAdd %6 %136 %20
|
||||
OpStore %52 %61
|
||||
OpBranch %53
|
||||
%55 = OpLabel
|
||||
OpStore %62 %9
|
||||
OpBranch %63
|
||||
%63 = OpLabel
|
||||
%137 = OpPhi %6 %9 %55 %71 %66
|
||||
OpLoopMerge %65 %66 Unroll|MinIterations|PeelCount 10 23
|
||||
OpBranch %67
|
||||
%67 = OpLabel
|
||||
%69 = OpSLessThan %17 %137 %16
|
||||
OpBranchConditional %69 %64 %65
|
||||
%64 = OpLabel
|
||||
OpBranch %66
|
||||
%66 = OpLabel
|
||||
%71 = OpIAdd %6 %137 %20
|
||||
OpStore %62 %71
|
||||
OpBranch %63
|
||||
%65 = OpLabel
|
||||
OpStore %72 %9
|
||||
OpBranch %73
|
||||
%73 = OpLabel
|
||||
%138 = OpPhi %6 %9 %65 %81 %76
|
||||
OpLoopMerge %75 %76 Unroll|MaxIterations|PeelCount 50 23
|
||||
OpBranch %77
|
||||
%77 = OpLabel
|
||||
%79 = OpSLessThan %17 %138 %16
|
||||
OpBranchConditional %79 %74 %75
|
||||
%74 = OpLabel
|
||||
OpBranch %76
|
||||
%76 = OpLabel
|
||||
%81 = OpIAdd %6 %138 %20
|
||||
OpStore %72 %81
|
||||
OpBranch %73
|
||||
%75 = OpLabel
|
||||
OpStore %82 %9
|
||||
OpBranch %83
|
||||
%83 = OpLabel
|
||||
%139 = OpPhi %6 %9 %75 %91 %86
|
||||
OpLoopMerge %85 %86 DontUnroll
|
||||
OpBranch %87
|
||||
%87 = OpLabel
|
||||
%89 = OpSLessThan %17 %139 %16
|
||||
OpBranchConditional %89 %84 %85
|
||||
%84 = OpLabel
|
||||
OpBranch %86
|
||||
%86 = OpLabel
|
||||
%91 = OpIAdd %6 %139 %20
|
||||
OpStore %82 %91
|
||||
OpBranch %83
|
||||
%85 = OpLabel
|
||||
OpStore %92 %9
|
||||
OpBranch %93
|
||||
%93 = OpLabel
|
||||
%140 = OpPhi %6 %9 %85 %101 %96
|
||||
OpLoopMerge %95 %96 PeelCount|PartialCount 16 8
|
||||
OpBranch %97
|
||||
%97 = OpLabel
|
||||
%99 = OpSLessThan %17 %140 %16
|
||||
OpBranchConditional %99 %94 %95
|
||||
%94 = OpLabel
|
||||
OpBranch %96
|
||||
%96 = OpLabel
|
||||
%101 = OpIAdd %6 %140 %20
|
||||
OpStore %92 %101
|
||||
OpBranch %93
|
||||
%95 = OpLabel
|
||||
OpStore %102 %9
|
||||
OpBranch %103
|
||||
%103 = OpLabel
|
||||
%141 = OpPhi %6 %9 %95 %111 %106
|
||||
OpLoopMerge %105 %106 PartialCount 60
|
||||
OpBranch %107
|
||||
%107 = OpLabel
|
||||
%109 = OpSLessThan %17 %141 %16
|
||||
OpBranchConditional %109 %104 %105
|
||||
%104 = OpLabel
|
||||
OpBranch %106
|
||||
%106 = OpLabel
|
||||
%111 = OpIAdd %6 %141 %20
|
||||
OpStore %102 %111
|
||||
OpBranch %103
|
||||
%105 = OpLabel
|
||||
OpStore %112 %9
|
||||
OpBranch %113
|
||||
%113 = OpLabel
|
||||
%142 = OpPhi %6 %9 %105 %121 %116
|
||||
OpLoopMerge %115 %116 PeelCount 12
|
||||
OpBranch %117
|
||||
%117 = OpLabel
|
||||
%119 = OpSLessThan %17 %142 %16
|
||||
OpBranchConditional %119 %114 %115
|
||||
%114 = OpLabel
|
||||
OpBranch %116
|
||||
%116 = OpLabel
|
||||
%121 = OpIAdd %6 %142 %20
|
||||
OpStore %112 %121
|
||||
OpBranch %113
|
||||
%115 = OpLabel
|
||||
OpStore %122 %9
|
||||
OpBranch %123
|
||||
%123 = OpLabel
|
||||
%143 = OpPhi %6 %9 %115 %131 %126
|
||||
OpLoopMerge %125 %126 Unroll|MinIterations|MaxIterations|PartialCount 5 90 9
|
||||
OpBranch %127
|
||||
%127 = OpLabel
|
||||
%129 = OpSLessThan %17 %143 %16
|
||||
OpBranchConditional %129 %124 %125
|
||||
%124 = OpLabel
|
||||
OpBranch %126
|
||||
%126 = OpLabel
|
||||
%131 = OpIAdd %6 %143 %20
|
||||
OpStore %122 %131
|
||||
OpBranch %123
|
||||
%125 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
|
||||
}
|
||||
|
||||
TEST(TransformationSetLoopControlTest, CheckSPIRVVersionsRespected) {
|
||||
// This test checks that we do not allow introducing PeelCount and
|
||||
// PartialCount loop controls if the SPIR-V version being used does not
|
||||
// support them.
|
||||
|
||||
std::string shader = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
OpName %8 "i"
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeInt 32 1
|
||||
%7 = OpTypePointer Function %6
|
||||
%9 = OpConstant %6 0
|
||||
%16 = OpConstant %6 10
|
||||
%17 = OpTypeBool
|
||||
%20 = OpConstant %6 1
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%8 = OpVariable %7 Function
|
||||
OpStore %8 %9
|
||||
OpBranch %10
|
||||
%10 = OpLabel
|
||||
OpLoopMerge %12 %13 None
|
||||
OpBranch %14
|
||||
%14 = OpLabel
|
||||
%15 = OpLoad %6 %8
|
||||
%18 = OpSLessThan %17 %15 %16
|
||||
OpBranchConditional %18 %11 %12
|
||||
%11 = OpLabel
|
||||
OpBranch %13
|
||||
%13 = OpLabel
|
||||
%19 = OpLoad %6 %8
|
||||
%21 = OpIAdd %6 %19 %20
|
||||
OpStore %8 %21
|
||||
OpBranch %10
|
||||
%12 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const auto consumer = nullptr;
|
||||
const auto context_1_0 =
|
||||
BuildModule(SPV_ENV_UNIVERSAL_1_0, consumer, shader, kFuzzAssembleOption);
|
||||
const auto context_1_1 =
|
||||
BuildModule(SPV_ENV_UNIVERSAL_1_1, consumer, shader, kFuzzAssembleOption);
|
||||
const auto context_1_2 =
|
||||
BuildModule(SPV_ENV_UNIVERSAL_1_2, consumer, shader, kFuzzAssembleOption);
|
||||
const auto context_1_3 =
|
||||
BuildModule(SPV_ENV_UNIVERSAL_1_3, consumer, shader, kFuzzAssembleOption);
|
||||
const auto context_1_4 =
|
||||
BuildModule(SPV_ENV_UNIVERSAL_1_4, consumer, shader, kFuzzAssembleOption);
|
||||
const auto context_1_5 =
|
||||
BuildModule(SPV_ENV_UNIVERSAL_1_5, consumer, shader, kFuzzAssembleOption);
|
||||
|
||||
FactManager fact_manager;
|
||||
|
||||
TransformationSetLoopControl set_peel_and_partial(
|
||||
10, SpvLoopControlPeelCountMask | SpvLoopControlPartialCountMask, 4, 4);
|
||||
|
||||
// PeelCount and PartialCount were introduced in SPIRV 1.4, so are not valid
|
||||
// in the context of older versions.
|
||||
ASSERT_FALSE(
|
||||
set_peel_and_partial.IsApplicable(context_1_0.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
set_peel_and_partial.IsApplicable(context_1_1.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
set_peel_and_partial.IsApplicable(context_1_2.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
set_peel_and_partial.IsApplicable(context_1_3.get(), fact_manager));
|
||||
|
||||
ASSERT_TRUE(
|
||||
set_peel_and_partial.IsApplicable(context_1_4.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
set_peel_and_partial.IsApplicable(context_1_5.get(), fact_manager));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
@@ -1,432 +0,0 @@
|
||||
// Copyright (c) 2019 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "source/fuzz/transformation_set_memory_operands_mask.h"
|
||||
#include "source/fuzz/instruction_descriptor.h"
|
||||
#include "test/fuzz/fuzz_test_util.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
namespace {
|
||||
|
||||
TEST(TransformationSetMemoryOperandsMaskTest, PreSpirv14) {
|
||||
std::string shader = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
OpName %7 "Point3D"
|
||||
OpMemberName %7 0 "x"
|
||||
OpMemberName %7 1 "y"
|
||||
OpMemberName %7 2 "z"
|
||||
OpName %12 "global_points"
|
||||
OpName %15 "block"
|
||||
OpMemberName %15 0 "in_points"
|
||||
OpMemberName %15 1 "in_point"
|
||||
OpName %17 ""
|
||||
OpName %133 "local_points"
|
||||
OpMemberDecorate %7 0 Offset 0
|
||||
OpMemberDecorate %7 1 Offset 4
|
||||
OpMemberDecorate %7 2 Offset 8
|
||||
OpDecorate %10 ArrayStride 16
|
||||
OpMemberDecorate %15 0 Offset 0
|
||||
OpMemberDecorate %15 1 Offset 192
|
||||
OpDecorate %15 Block
|
||||
OpDecorate %17 DescriptorSet 0
|
||||
OpDecorate %17 Binding 0
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeFloat 32
|
||||
%7 = OpTypeStruct %6 %6 %6
|
||||
%8 = OpTypeInt 32 0
|
||||
%9 = OpConstant %8 12
|
||||
%10 = OpTypeArray %7 %9
|
||||
%11 = OpTypePointer Private %10
|
||||
%12 = OpVariable %11 Private
|
||||
%15 = OpTypeStruct %10 %7
|
||||
%16 = OpTypePointer Uniform %15
|
||||
%17 = OpVariable %16 Uniform
|
||||
%18 = OpTypeInt 32 1
|
||||
%19 = OpConstant %18 0
|
||||
%20 = OpTypePointer Uniform %10
|
||||
%24 = OpTypePointer Private %7
|
||||
%27 = OpTypePointer Private %6
|
||||
%30 = OpConstant %18 1
|
||||
%132 = OpTypePointer Function %10
|
||||
%135 = OpTypePointer Uniform %7
|
||||
%145 = OpTypePointer Function %7
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%133 = OpVariable %132 Function
|
||||
%21 = OpAccessChain %20 %17 %19
|
||||
OpCopyMemory %12 %21 Aligned 16
|
||||
OpCopyMemory %133 %12 Volatile
|
||||
%136 = OpAccessChain %135 %17 %30
|
||||
%138 = OpAccessChain %24 %12 %19
|
||||
OpCopyMemory %138 %136 None
|
||||
%146 = OpAccessChain %145 %133 %30
|
||||
%147 = OpLoad %7 %146 Volatile|Nontemporal|Aligned 16
|
||||
%148 = OpAccessChain %24 %12 %19
|
||||
OpStore %148 %147 Nontemporal
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto consumer = nullptr;
|
||||
const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
FactManager fact_manager;
|
||||
|
||||
// Not OK: the instruction is not a memory access.
|
||||
ASSERT_FALSE(TransformationSetMemoryOperandsMask(
|
||||
MakeInstructionDescriptor(21, SpvOpAccessChain, 0),
|
||||
SpvMemoryAccessMaskNone, 0)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Not OK to remove Aligned
|
||||
ASSERT_FALSE(TransformationSetMemoryOperandsMask(
|
||||
MakeInstructionDescriptor(147, SpvOpLoad, 0),
|
||||
SpvMemoryAccessVolatileMask | SpvMemoryAccessNontemporalMask,
|
||||
0)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
TransformationSetMemoryOperandsMask transformation1(
|
||||
MakeInstructionDescriptor(147, SpvOpLoad, 0),
|
||||
SpvMemoryAccessAlignedMask | SpvMemoryAccessVolatileMask, 0);
|
||||
ASSERT_TRUE(transformation1.IsApplicable(context.get(), fact_manager));
|
||||
transformation1.Apply(context.get(), &fact_manager);
|
||||
|
||||
// Not OK to remove Aligned
|
||||
ASSERT_FALSE(TransformationSetMemoryOperandsMask(
|
||||
MakeInstructionDescriptor(21, SpvOpCopyMemory, 0),
|
||||
SpvMemoryAccessMaskNone, 0)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// OK: leaves the mask as is
|
||||
ASSERT_TRUE(TransformationSetMemoryOperandsMask(
|
||||
MakeInstructionDescriptor(21, SpvOpCopyMemory, 0),
|
||||
SpvMemoryAccessAlignedMask, 0)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// OK: adds Nontemporal and Volatile
|
||||
TransformationSetMemoryOperandsMask transformation2(
|
||||
MakeInstructionDescriptor(21, SpvOpCopyMemory, 0),
|
||||
SpvMemoryAccessAlignedMask | SpvMemoryAccessNontemporalMask |
|
||||
SpvMemoryAccessVolatileMask,
|
||||
0);
|
||||
ASSERT_TRUE(transformation2.IsApplicable(context.get(), fact_manager));
|
||||
transformation2.Apply(context.get(), &fact_manager);
|
||||
|
||||
// Not OK to remove Volatile
|
||||
ASSERT_FALSE(TransformationSetMemoryOperandsMask(
|
||||
MakeInstructionDescriptor(21, SpvOpCopyMemory, 1),
|
||||
SpvMemoryAccessNontemporalMask, 0)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Not OK to add Aligned
|
||||
ASSERT_FALSE(TransformationSetMemoryOperandsMask(
|
||||
MakeInstructionDescriptor(21, SpvOpCopyMemory, 1),
|
||||
SpvMemoryAccessAlignedMask | SpvMemoryAccessVolatileMask, 0)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// OK: adds Nontemporal
|
||||
TransformationSetMemoryOperandsMask transformation3(
|
||||
MakeInstructionDescriptor(21, SpvOpCopyMemory, 1),
|
||||
SpvMemoryAccessNontemporalMask | SpvMemoryAccessVolatileMask, 0);
|
||||
ASSERT_TRUE(transformation3.IsApplicable(context.get(), fact_manager));
|
||||
transformation3.Apply(context.get(), &fact_manager);
|
||||
|
||||
// OK: adds Nontemporal and Volatile
|
||||
TransformationSetMemoryOperandsMask transformation4(
|
||||
MakeInstructionDescriptor(138, SpvOpCopyMemory, 0),
|
||||
SpvMemoryAccessNontemporalMask | SpvMemoryAccessVolatileMask, 0);
|
||||
ASSERT_TRUE(transformation4.IsApplicable(context.get(), fact_manager));
|
||||
transformation4.Apply(context.get(), &fact_manager);
|
||||
|
||||
// OK: removes Nontemporal, adds Volatile
|
||||
TransformationSetMemoryOperandsMask transformation5(
|
||||
MakeInstructionDescriptor(148, SpvOpStore, 0),
|
||||
SpvMemoryAccessVolatileMask, 0);
|
||||
ASSERT_TRUE(transformation5.IsApplicable(context.get(), fact_manager));
|
||||
transformation5.Apply(context.get(), &fact_manager);
|
||||
|
||||
std::string after_transformation = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
OpName %7 "Point3D"
|
||||
OpMemberName %7 0 "x"
|
||||
OpMemberName %7 1 "y"
|
||||
OpMemberName %7 2 "z"
|
||||
OpName %12 "global_points"
|
||||
OpName %15 "block"
|
||||
OpMemberName %15 0 "in_points"
|
||||
OpMemberName %15 1 "in_point"
|
||||
OpName %17 ""
|
||||
OpName %133 "local_points"
|
||||
OpMemberDecorate %7 0 Offset 0
|
||||
OpMemberDecorate %7 1 Offset 4
|
||||
OpMemberDecorate %7 2 Offset 8
|
||||
OpDecorate %10 ArrayStride 16
|
||||
OpMemberDecorate %15 0 Offset 0
|
||||
OpMemberDecorate %15 1 Offset 192
|
||||
OpDecorate %15 Block
|
||||
OpDecorate %17 DescriptorSet 0
|
||||
OpDecorate %17 Binding 0
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeFloat 32
|
||||
%7 = OpTypeStruct %6 %6 %6
|
||||
%8 = OpTypeInt 32 0
|
||||
%9 = OpConstant %8 12
|
||||
%10 = OpTypeArray %7 %9
|
||||
%11 = OpTypePointer Private %10
|
||||
%12 = OpVariable %11 Private
|
||||
%15 = OpTypeStruct %10 %7
|
||||
%16 = OpTypePointer Uniform %15
|
||||
%17 = OpVariable %16 Uniform
|
||||
%18 = OpTypeInt 32 1
|
||||
%19 = OpConstant %18 0
|
||||
%20 = OpTypePointer Uniform %10
|
||||
%24 = OpTypePointer Private %7
|
||||
%27 = OpTypePointer Private %6
|
||||
%30 = OpConstant %18 1
|
||||
%132 = OpTypePointer Function %10
|
||||
%135 = OpTypePointer Uniform %7
|
||||
%145 = OpTypePointer Function %7
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%133 = OpVariable %132 Function
|
||||
%21 = OpAccessChain %20 %17 %19
|
||||
OpCopyMemory %12 %21 Aligned|Nontemporal|Volatile 16
|
||||
OpCopyMemory %133 %12 Nontemporal|Volatile
|
||||
%136 = OpAccessChain %135 %17 %30
|
||||
%138 = OpAccessChain %24 %12 %19
|
||||
OpCopyMemory %138 %136 Nontemporal|Volatile
|
||||
%146 = OpAccessChain %145 %133 %30
|
||||
%147 = OpLoad %7 %146 Aligned|Volatile 16
|
||||
%148 = OpAccessChain %24 %12 %19
|
||||
OpStore %148 %147 Volatile
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
|
||||
}
|
||||
|
||||
TEST(TransformationSetMemoryOperandsMaskTest, Spirv14) {
|
||||
std::string shader = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main" %12 %17
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
OpName %7 "Point3D"
|
||||
OpMemberName %7 0 "x"
|
||||
OpMemberName %7 1 "y"
|
||||
OpMemberName %7 2 "z"
|
||||
OpName %12 "global_points"
|
||||
OpName %15 "block"
|
||||
OpMemberName %15 0 "in_points"
|
||||
OpMemberName %15 1 "in_point"
|
||||
OpName %17 ""
|
||||
OpName %133 "local_points"
|
||||
OpMemberDecorate %7 0 Offset 0
|
||||
OpMemberDecorate %7 1 Offset 4
|
||||
OpMemberDecorate %7 2 Offset 8
|
||||
OpDecorate %10 ArrayStride 16
|
||||
OpMemberDecorate %15 0 Offset 0
|
||||
OpMemberDecorate %15 1 Offset 192
|
||||
OpDecorate %15 Block
|
||||
OpDecorate %17 DescriptorSet 0
|
||||
OpDecorate %17 Binding 0
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeFloat 32
|
||||
%7 = OpTypeStruct %6 %6 %6
|
||||
%8 = OpTypeInt 32 0
|
||||
%9 = OpConstant %8 12
|
||||
%10 = OpTypeArray %7 %9
|
||||
%11 = OpTypePointer Private %10
|
||||
%12 = OpVariable %11 Private
|
||||
%15 = OpTypeStruct %10 %7
|
||||
%16 = OpTypePointer Uniform %15
|
||||
%17 = OpVariable %16 Uniform
|
||||
%18 = OpTypeInt 32 1
|
||||
%19 = OpConstant %18 0
|
||||
%20 = OpTypePointer Uniform %10
|
||||
%24 = OpTypePointer Private %7
|
||||
%27 = OpTypePointer Private %6
|
||||
%30 = OpConstant %18 1
|
||||
%132 = OpTypePointer Function %10
|
||||
%135 = OpTypePointer Uniform %7
|
||||
%145 = OpTypePointer Function %7
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%133 = OpVariable %132 Function
|
||||
%21 = OpAccessChain %20 %17 %19
|
||||
OpCopyMemory %12 %21 Aligned 16 Nontemporal|Aligned 16
|
||||
OpCopyMemory %133 %12 Volatile
|
||||
%136 = OpAccessChain %135 %17 %30
|
||||
%138 = OpAccessChain %24 %12 %19
|
||||
OpCopyMemory %138 %136 None Aligned 16
|
||||
OpCopyMemory %138 %136 Aligned 16
|
||||
%146 = OpAccessChain %145 %133 %30
|
||||
%147 = OpLoad %7 %146 Volatile|Nontemporal|Aligned 16
|
||||
%148 = OpAccessChain %24 %12 %19
|
||||
OpStore %148 %147 Nontemporal
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_4;
|
||||
const auto consumer = nullptr;
|
||||
const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
FactManager fact_manager;
|
||||
|
||||
TransformationSetMemoryOperandsMask transformation1(
|
||||
MakeInstructionDescriptor(21, SpvOpCopyMemory, 0),
|
||||
SpvMemoryAccessAlignedMask | SpvMemoryAccessVolatileMask, 1);
|
||||
// Bad: cannot remove aligned
|
||||
ASSERT_FALSE(TransformationSetMemoryOperandsMask(
|
||||
MakeInstructionDescriptor(21, SpvOpCopyMemory, 0),
|
||||
SpvMemoryAccessVolatileMask, 1)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(transformation1.IsApplicable(context.get(), fact_manager));
|
||||
transformation1.Apply(context.get(), &fact_manager);
|
||||
|
||||
TransformationSetMemoryOperandsMask transformation2(
|
||||
MakeInstructionDescriptor(21, SpvOpCopyMemory, 1),
|
||||
SpvMemoryAccessNontemporalMask | SpvMemoryAccessVolatileMask, 1);
|
||||
// Bad: cannot remove volatile
|
||||
ASSERT_FALSE(TransformationSetMemoryOperandsMask(
|
||||
MakeInstructionDescriptor(21, SpvOpCopyMemory, 1),
|
||||
SpvMemoryAccessNontemporalMask, 0)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(transformation2.IsApplicable(context.get(), fact_manager));
|
||||
transformation2.Apply(context.get(), &fact_manager);
|
||||
|
||||
TransformationSetMemoryOperandsMask transformation3(
|
||||
MakeInstructionDescriptor(138, SpvOpCopyMemory, 0),
|
||||
SpvMemoryAccessAlignedMask | SpvMemoryAccessNontemporalMask, 1);
|
||||
// Bad: the first mask is None, so Aligned cannot be added to it.
|
||||
ASSERT_FALSE(TransformationSetMemoryOperandsMask(
|
||||
MakeInstructionDescriptor(138, SpvOpCopyMemory, 0),
|
||||
SpvMemoryAccessAlignedMask | SpvMemoryAccessNontemporalMask,
|
||||
0)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(transformation3.IsApplicable(context.get(), fact_manager));
|
||||
transformation3.Apply(context.get(), &fact_manager);
|
||||
|
||||
TransformationSetMemoryOperandsMask transformation4(
|
||||
MakeInstructionDescriptor(138, SpvOpCopyMemory, 1),
|
||||
SpvMemoryAccessVolatileMask, 1);
|
||||
ASSERT_TRUE(transformation4.IsApplicable(context.get(), fact_manager));
|
||||
transformation4.Apply(context.get(), &fact_manager);
|
||||
|
||||
TransformationSetMemoryOperandsMask transformation5(
|
||||
MakeInstructionDescriptor(147, SpvOpLoad, 0),
|
||||
SpvMemoryAccessVolatileMask | SpvMemoryAccessAlignedMask, 0);
|
||||
ASSERT_TRUE(transformation5.IsApplicable(context.get(), fact_manager));
|
||||
transformation5.Apply(context.get(), &fact_manager);
|
||||
|
||||
TransformationSetMemoryOperandsMask transformation6(
|
||||
MakeInstructionDescriptor(148, SpvOpStore, 0), SpvMemoryAccessMaskNone,
|
||||
0);
|
||||
ASSERT_TRUE(transformation6.IsApplicable(context.get(), fact_manager));
|
||||
transformation6.Apply(context.get(), &fact_manager);
|
||||
|
||||
std::string after_transformation = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main" %12 %17
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
OpName %7 "Point3D"
|
||||
OpMemberName %7 0 "x"
|
||||
OpMemberName %7 1 "y"
|
||||
OpMemberName %7 2 "z"
|
||||
OpName %12 "global_points"
|
||||
OpName %15 "block"
|
||||
OpMemberName %15 0 "in_points"
|
||||
OpMemberName %15 1 "in_point"
|
||||
OpName %17 ""
|
||||
OpName %133 "local_points"
|
||||
OpMemberDecorate %7 0 Offset 0
|
||||
OpMemberDecorate %7 1 Offset 4
|
||||
OpMemberDecorate %7 2 Offset 8
|
||||
OpDecorate %10 ArrayStride 16
|
||||
OpMemberDecorate %15 0 Offset 0
|
||||
OpMemberDecorate %15 1 Offset 192
|
||||
OpDecorate %15 Block
|
||||
OpDecorate %17 DescriptorSet 0
|
||||
OpDecorate %17 Binding 0
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeFloat 32
|
||||
%7 = OpTypeStruct %6 %6 %6
|
||||
%8 = OpTypeInt 32 0
|
||||
%9 = OpConstant %8 12
|
||||
%10 = OpTypeArray %7 %9
|
||||
%11 = OpTypePointer Private %10
|
||||
%12 = OpVariable %11 Private
|
||||
%15 = OpTypeStruct %10 %7
|
||||
%16 = OpTypePointer Uniform %15
|
||||
%17 = OpVariable %16 Uniform
|
||||
%18 = OpTypeInt 32 1
|
||||
%19 = OpConstant %18 0
|
||||
%20 = OpTypePointer Uniform %10
|
||||
%24 = OpTypePointer Private %7
|
||||
%27 = OpTypePointer Private %6
|
||||
%30 = OpConstant %18 1
|
||||
%132 = OpTypePointer Function %10
|
||||
%135 = OpTypePointer Uniform %7
|
||||
%145 = OpTypePointer Function %7
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%133 = OpVariable %132 Function
|
||||
%21 = OpAccessChain %20 %17 %19
|
||||
OpCopyMemory %12 %21 Aligned 16 Aligned|Volatile 16
|
||||
OpCopyMemory %133 %12 Volatile Nontemporal|Volatile
|
||||
%136 = OpAccessChain %135 %17 %30
|
||||
%138 = OpAccessChain %24 %12 %19
|
||||
OpCopyMemory %138 %136 None Aligned|Nontemporal 16
|
||||
OpCopyMemory %138 %136 Aligned 16 Volatile
|
||||
%146 = OpAccessChain %145 %133 %30
|
||||
%147 = OpLoad %7 %146 Volatile|Aligned 16
|
||||
%148 = OpAccessChain %24 %12 %19
|
||||
OpStore %148 %147 None
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
@@ -1,219 +0,0 @@
|
||||
// Copyright (c) 2019 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "source/fuzz/transformation_set_selection_control.h"
|
||||
#include "test/fuzz/fuzz_test_util.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
namespace {
|
||||
|
||||
TEST(TransformationSetSelectionControlTest, VariousScenarios) {
|
||||
// This is a simple transformation; this test captures the important things
|
||||
// to check for.
|
||||
|
||||
std::string shader = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
OpName %8 "i"
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeInt 32 1
|
||||
%7 = OpTypePointer Function %6
|
||||
%9 = OpConstant %6 0
|
||||
%16 = OpConstant %6 10
|
||||
%17 = OpTypeBool
|
||||
%20 = OpConstant %6 3
|
||||
%25 = OpConstant %6 1
|
||||
%28 = OpConstant %6 2
|
||||
%38 = OpConstant %6 4
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%8 = OpVariable %7 Function
|
||||
OpStore %8 %9
|
||||
OpBranch %10
|
||||
%10 = OpLabel
|
||||
OpLoopMerge %12 %13 None
|
||||
OpBranch %14
|
||||
%14 = OpLabel
|
||||
%15 = OpLoad %6 %8
|
||||
%18 = OpSLessThan %17 %15 %16
|
||||
OpBranchConditional %18 %11 %12
|
||||
%11 = OpLabel
|
||||
%19 = OpLoad %6 %8
|
||||
%21 = OpSGreaterThan %17 %19 %20
|
||||
OpSelectionMerge %23 Flatten
|
||||
OpBranchConditional %21 %22 %23
|
||||
%22 = OpLabel
|
||||
%24 = OpLoad %6 %8
|
||||
%26 = OpIAdd %6 %24 %25
|
||||
OpStore %8 %26
|
||||
OpBranch %23
|
||||
%23 = OpLabel
|
||||
%27 = OpLoad %6 %8
|
||||
%29 = OpSLessThan %17 %27 %28
|
||||
OpSelectionMerge %31 DontFlatten
|
||||
OpBranchConditional %29 %30 %31
|
||||
%30 = OpLabel
|
||||
%32 = OpLoad %6 %8
|
||||
%33 = OpISub %6 %32 %25
|
||||
OpStore %8 %33
|
||||
OpBranch %31
|
||||
%31 = OpLabel
|
||||
%34 = OpLoad %6 %8
|
||||
OpSelectionMerge %37 None
|
||||
OpSwitch %34 %36 0 %35
|
||||
%36 = OpLabel
|
||||
OpBranch %37
|
||||
%35 = OpLabel
|
||||
%39 = OpLoad %6 %8
|
||||
%40 = OpIAdd %6 %39 %38
|
||||
OpStore %8 %40
|
||||
OpBranch %36
|
||||
%37 = OpLabel
|
||||
OpBranch %13
|
||||
%13 = OpLabel
|
||||
%43 = OpLoad %6 %8
|
||||
%44 = OpIAdd %6 %43 %25
|
||||
OpStore %8 %44
|
||||
OpBranch %10
|
||||
%12 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto consumer = nullptr;
|
||||
const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
|
||||
|
||||
FactManager fact_manager;
|
||||
|
||||
// %44 is not a block
|
||||
ASSERT_FALSE(
|
||||
TransformationSetSelectionControl(44, SpvSelectionControlFlattenMask)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
// %13 does not end with OpSelectionMerge
|
||||
ASSERT_FALSE(
|
||||
TransformationSetSelectionControl(13, SpvSelectionControlMaskNone)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
// %10 ends in OpLoopMerge, not OpSelectionMerge
|
||||
ASSERT_FALSE(
|
||||
TransformationSetSelectionControl(10, SpvSelectionControlMaskNone)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
TransformationSetSelectionControl transformation1(
|
||||
11, SpvSelectionControlDontFlattenMask);
|
||||
ASSERT_TRUE(transformation1.IsApplicable(context.get(), fact_manager));
|
||||
transformation1.Apply(context.get(), &fact_manager);
|
||||
|
||||
TransformationSetSelectionControl transformation2(
|
||||
23, SpvSelectionControlFlattenMask);
|
||||
ASSERT_TRUE(transformation2.IsApplicable(context.get(), fact_manager));
|
||||
transformation2.Apply(context.get(), &fact_manager);
|
||||
|
||||
TransformationSetSelectionControl transformation3(
|
||||
31, SpvSelectionControlMaskNone);
|
||||
ASSERT_TRUE(transformation3.IsApplicable(context.get(), fact_manager));
|
||||
transformation3.Apply(context.get(), &fact_manager);
|
||||
|
||||
TransformationSetSelectionControl transformation4(
|
||||
31, SpvSelectionControlFlattenMask);
|
||||
ASSERT_TRUE(transformation4.IsApplicable(context.get(), fact_manager));
|
||||
transformation4.Apply(context.get(), &fact_manager);
|
||||
|
||||
std::string after_transformation = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
OpName %8 "i"
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeInt 32 1
|
||||
%7 = OpTypePointer Function %6
|
||||
%9 = OpConstant %6 0
|
||||
%16 = OpConstant %6 10
|
||||
%17 = OpTypeBool
|
||||
%20 = OpConstant %6 3
|
||||
%25 = OpConstant %6 1
|
||||
%28 = OpConstant %6 2
|
||||
%38 = OpConstant %6 4
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%8 = OpVariable %7 Function
|
||||
OpStore %8 %9
|
||||
OpBranch %10
|
||||
%10 = OpLabel
|
||||
OpLoopMerge %12 %13 None
|
||||
OpBranch %14
|
||||
%14 = OpLabel
|
||||
%15 = OpLoad %6 %8
|
||||
%18 = OpSLessThan %17 %15 %16
|
||||
OpBranchConditional %18 %11 %12
|
||||
%11 = OpLabel
|
||||
%19 = OpLoad %6 %8
|
||||
%21 = OpSGreaterThan %17 %19 %20
|
||||
OpSelectionMerge %23 DontFlatten
|
||||
OpBranchConditional %21 %22 %23
|
||||
%22 = OpLabel
|
||||
%24 = OpLoad %6 %8
|
||||
%26 = OpIAdd %6 %24 %25
|
||||
OpStore %8 %26
|
||||
OpBranch %23
|
||||
%23 = OpLabel
|
||||
%27 = OpLoad %6 %8
|
||||
%29 = OpSLessThan %17 %27 %28
|
||||
OpSelectionMerge %31 Flatten
|
||||
OpBranchConditional %29 %30 %31
|
||||
%30 = OpLabel
|
||||
%32 = OpLoad %6 %8
|
||||
%33 = OpISub %6 %32 %25
|
||||
OpStore %8 %33
|
||||
OpBranch %31
|
||||
%31 = OpLabel
|
||||
%34 = OpLoad %6 %8
|
||||
OpSelectionMerge %37 Flatten
|
||||
OpSwitch %34 %36 0 %35
|
||||
%36 = OpLabel
|
||||
OpBranch %37
|
||||
%35 = OpLabel
|
||||
%39 = OpLoad %6 %8
|
||||
%40 = OpIAdd %6 %39 %38
|
||||
OpStore %8 %40
|
||||
OpBranch %36
|
||||
%37 = OpLabel
|
||||
OpBranch %13
|
||||
%13 = OpLabel
|
||||
%43 = OpLoad %6 %8
|
||||
%44 = OpIAdd %6 %43 %25
|
||||
OpStore %8 %44
|
||||
OpBranch %10
|
||||
%12 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
@@ -1,779 +0,0 @@
|
||||
// Copyright (c) 2019 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "source/fuzz/transformation_split_block.h"
|
||||
#include "source/fuzz/instruction_descriptor.h"
|
||||
#include "test/fuzz/fuzz_test_util.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
namespace {
|
||||
|
||||
TEST(TransformationSplitBlockTest, NotApplicable) {
|
||||
// The SPIR-V in this test came from the following fragment shader, with
|
||||
// local store elimination applied to get some OpPhi instructions.
|
||||
//
|
||||
// void main() {
|
||||
// int x;
|
||||
// int i;
|
||||
// for (i = 0; i < 100; i++) {
|
||||
// x += i;
|
||||
// }
|
||||
// }
|
||||
|
||||
std::string shader = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
OpName %8 "i"
|
||||
OpName %19 "x"
|
||||
OpDecorate %8 RelaxedPrecision
|
||||
OpDecorate %19 RelaxedPrecision
|
||||
OpDecorate %22 RelaxedPrecision
|
||||
OpDecorate %25 RelaxedPrecision
|
||||
OpDecorate %26 RelaxedPrecision
|
||||
OpDecorate %27 RelaxedPrecision
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeInt 32 1
|
||||
%7 = OpTypePointer Function %6
|
||||
%9 = OpConstant %6 0
|
||||
%16 = OpConstant %6 100
|
||||
%17 = OpTypeBool
|
||||
%24 = OpConstant %6 1
|
||||
%28 = OpUndef %6
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%8 = OpVariable %7 Function
|
||||
%19 = OpVariable %7 Function
|
||||
OpStore %8 %9
|
||||
OpBranch %10
|
||||
%10 = OpLabel
|
||||
%27 = OpPhi %6 %28 %5 %22 %13
|
||||
%26 = OpPhi %6 %9 %5 %25 %13
|
||||
OpLoopMerge %12 %13 None
|
||||
OpBranch %14
|
||||
%14 = OpLabel
|
||||
%18 = OpSLessThan %17 %26 %16
|
||||
OpBranchConditional %18 %11 %12
|
||||
%11 = OpLabel
|
||||
%22 = OpIAdd %6 %27 %26
|
||||
OpStore %19 %22
|
||||
OpBranch %13
|
||||
%13 = OpLabel
|
||||
%25 = OpIAdd %6 %26 %24
|
||||
OpStore %8 %25
|
||||
OpBranch %10
|
||||
%12 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto consumer = nullptr;
|
||||
const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
|
||||
|
||||
FactManager fact_manager;
|
||||
|
||||
// No split before OpVariable
|
||||
ASSERT_FALSE(TransformationSplitBlock(
|
||||
MakeInstructionDescriptor(8, SpvOpVariable, 0), 100)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(TransformationSplitBlock(
|
||||
MakeInstructionDescriptor(8, SpvOpVariable, 1), 100)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// No split before OpLabel
|
||||
ASSERT_FALSE(TransformationSplitBlock(
|
||||
MakeInstructionDescriptor(14, SpvOpLabel, 0), 100)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// No split if base instruction is outside a function
|
||||
ASSERT_FALSE(
|
||||
TransformationSplitBlock(MakeInstructionDescriptor(1, SpvOpLabel, 0), 100)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(TransformationSplitBlock(
|
||||
MakeInstructionDescriptor(1, SpvOpExecutionMode, 0), 100)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// No split if block is loop header
|
||||
ASSERT_FALSE(
|
||||
TransformationSplitBlock(MakeInstructionDescriptor(27, SpvOpPhi, 0), 100)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
TransformationSplitBlock(MakeInstructionDescriptor(27, SpvOpPhi, 1), 100)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// No split if base instruction does not exist
|
||||
ASSERT_FALSE(
|
||||
TransformationSplitBlock(MakeInstructionDescriptor(88, SpvOpIAdd, 0), 100)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(TransformationSplitBlock(
|
||||
MakeInstructionDescriptor(88, SpvOpIMul, 22), 100)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// No split if too many instructions with the desired opcode are skipped
|
||||
ASSERT_FALSE(
|
||||
TransformationSplitBlock(
|
||||
MakeInstructionDescriptor(18, SpvOpBranchConditional, 1), 100)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// No split if id in use
|
||||
ASSERT_FALSE(TransformationSplitBlock(
|
||||
MakeInstructionDescriptor(18, SpvOpSLessThan, 0), 27)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(TransformationSplitBlock(
|
||||
MakeInstructionDescriptor(18, SpvOpSLessThan, 0), 14)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
}
|
||||
|
||||
TEST(TransformationSplitBlockTest, SplitBlockSeveralTimes) {
|
||||
// The SPIR-V in this test came from the following fragment shader:
|
||||
//
|
||||
// void main() {
|
||||
// int a;
|
||||
// int b;
|
||||
// a = 1;
|
||||
// b = a;
|
||||
// a = b;
|
||||
// b = 2;
|
||||
// b++;
|
||||
// }
|
||||
|
||||
std::string shader = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
OpName %8 "a"
|
||||
OpName %10 "b"
|
||||
OpDecorate %8 RelaxedPrecision
|
||||
OpDecorate %10 RelaxedPrecision
|
||||
OpDecorate %11 RelaxedPrecision
|
||||
OpDecorate %12 RelaxedPrecision
|
||||
OpDecorate %14 RelaxedPrecision
|
||||
OpDecorate %15 RelaxedPrecision
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeInt 32 1
|
||||
%7 = OpTypePointer Function %6
|
||||
%9 = OpConstant %6 1
|
||||
%13 = OpConstant %6 2
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%8 = OpVariable %7 Function
|
||||
%10 = OpVariable %7 Function
|
||||
OpStore %8 %9
|
||||
%11 = OpLoad %6 %8
|
||||
OpStore %10 %11
|
||||
%12 = OpLoad %6 %10
|
||||
OpStore %8 %12
|
||||
OpStore %10 %13
|
||||
%14 = OpLoad %6 %10
|
||||
%15 = OpIAdd %6 %14 %9
|
||||
OpStore %10 %15
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto consumer = nullptr;
|
||||
const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
|
||||
|
||||
FactManager fact_manager;
|
||||
|
||||
auto split_1 = TransformationSplitBlock(
|
||||
MakeInstructionDescriptor(5, SpvOpStore, 0), 100);
|
||||
ASSERT_TRUE(split_1.IsApplicable(context.get(), fact_manager));
|
||||
split_1.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
std::string after_split_1 = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
OpName %8 "a"
|
||||
OpName %10 "b"
|
||||
OpDecorate %8 RelaxedPrecision
|
||||
OpDecorate %10 RelaxedPrecision
|
||||
OpDecorate %11 RelaxedPrecision
|
||||
OpDecorate %12 RelaxedPrecision
|
||||
OpDecorate %14 RelaxedPrecision
|
||||
OpDecorate %15 RelaxedPrecision
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeInt 32 1
|
||||
%7 = OpTypePointer Function %6
|
||||
%9 = OpConstant %6 1
|
||||
%13 = OpConstant %6 2
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%8 = OpVariable %7 Function
|
||||
%10 = OpVariable %7 Function
|
||||
OpBranch %100
|
||||
%100 = OpLabel
|
||||
OpStore %8 %9
|
||||
%11 = OpLoad %6 %8
|
||||
OpStore %10 %11
|
||||
%12 = OpLoad %6 %10
|
||||
OpStore %8 %12
|
||||
OpStore %10 %13
|
||||
%14 = OpLoad %6 %10
|
||||
%15 = OpIAdd %6 %14 %9
|
||||
OpStore %10 %15
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
ASSERT_TRUE(IsEqual(env, after_split_1, context.get()));
|
||||
|
||||
auto split_2 = TransformationSplitBlock(
|
||||
MakeInstructionDescriptor(11, SpvOpStore, 0), 101);
|
||||
ASSERT_TRUE(split_2.IsApplicable(context.get(), fact_manager));
|
||||
split_2.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
std::string after_split_2 = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
OpName %8 "a"
|
||||
OpName %10 "b"
|
||||
OpDecorate %8 RelaxedPrecision
|
||||
OpDecorate %10 RelaxedPrecision
|
||||
OpDecorate %11 RelaxedPrecision
|
||||
OpDecorate %12 RelaxedPrecision
|
||||
OpDecorate %14 RelaxedPrecision
|
||||
OpDecorate %15 RelaxedPrecision
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeInt 32 1
|
||||
%7 = OpTypePointer Function %6
|
||||
%9 = OpConstant %6 1
|
||||
%13 = OpConstant %6 2
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%8 = OpVariable %7 Function
|
||||
%10 = OpVariable %7 Function
|
||||
OpBranch %100
|
||||
%100 = OpLabel
|
||||
OpStore %8 %9
|
||||
%11 = OpLoad %6 %8
|
||||
OpBranch %101
|
||||
%101 = OpLabel
|
||||
OpStore %10 %11
|
||||
%12 = OpLoad %6 %10
|
||||
OpStore %8 %12
|
||||
OpStore %10 %13
|
||||
%14 = OpLoad %6 %10
|
||||
%15 = OpIAdd %6 %14 %9
|
||||
OpStore %10 %15
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
ASSERT_TRUE(IsEqual(env, after_split_2, context.get()));
|
||||
|
||||
auto split_3 = TransformationSplitBlock(
|
||||
MakeInstructionDescriptor(14, SpvOpLoad, 0), 102);
|
||||
ASSERT_TRUE(split_3.IsApplicable(context.get(), fact_manager));
|
||||
split_3.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
std::string after_split_3 = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
OpName %8 "a"
|
||||
OpName %10 "b"
|
||||
OpDecorate %8 RelaxedPrecision
|
||||
OpDecorate %10 RelaxedPrecision
|
||||
OpDecorate %11 RelaxedPrecision
|
||||
OpDecorate %12 RelaxedPrecision
|
||||
OpDecorate %14 RelaxedPrecision
|
||||
OpDecorate %15 RelaxedPrecision
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeInt 32 1
|
||||
%7 = OpTypePointer Function %6
|
||||
%9 = OpConstant %6 1
|
||||
%13 = OpConstant %6 2
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%8 = OpVariable %7 Function
|
||||
%10 = OpVariable %7 Function
|
||||
OpBranch %100
|
||||
%100 = OpLabel
|
||||
OpStore %8 %9
|
||||
%11 = OpLoad %6 %8
|
||||
OpBranch %101
|
||||
%101 = OpLabel
|
||||
OpStore %10 %11
|
||||
%12 = OpLoad %6 %10
|
||||
OpStore %8 %12
|
||||
OpStore %10 %13
|
||||
OpBranch %102
|
||||
%102 = OpLabel
|
||||
%14 = OpLoad %6 %10
|
||||
%15 = OpIAdd %6 %14 %9
|
||||
OpStore %10 %15
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
ASSERT_TRUE(IsEqual(env, after_split_3, context.get()));
|
||||
}
|
||||
|
||||
TEST(TransformationSplitBlockTest, SplitBlockBeforeSelectBranch) {
|
||||
// The SPIR-V in this test came from the following fragment shader:
|
||||
//
|
||||
// void main() {
|
||||
// int x, y;
|
||||
// x = 2;
|
||||
// if (x < y) {
|
||||
// y = 3;
|
||||
// } else {
|
||||
// y = 4;
|
||||
// }
|
||||
// }
|
||||
|
||||
std::string shader = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
OpName %8 "x"
|
||||
OpName %11 "y"
|
||||
OpDecorate %8 RelaxedPrecision
|
||||
OpDecorate %10 RelaxedPrecision
|
||||
OpDecorate %11 RelaxedPrecision
|
||||
OpDecorate %12 RelaxedPrecision
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeInt 32 1
|
||||
%7 = OpTypePointer Function %6
|
||||
%9 = OpConstant %6 2
|
||||
%13 = OpTypeBool
|
||||
%17 = OpConstant %6 3
|
||||
%19 = OpConstant %6 4
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%8 = OpVariable %7 Function
|
||||
%11 = OpVariable %7 Function
|
||||
OpStore %8 %9
|
||||
%10 = OpLoad %6 %8
|
||||
%12 = OpLoad %6 %11
|
||||
%14 = OpSLessThan %13 %10 %12
|
||||
OpSelectionMerge %16 None
|
||||
OpBranchConditional %14 %15 %18
|
||||
%15 = OpLabel
|
||||
OpStore %11 %17
|
||||
OpBranch %16
|
||||
%18 = OpLabel
|
||||
OpStore %11 %19
|
||||
OpBranch %16
|
||||
%16 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto consumer = nullptr;
|
||||
const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
|
||||
|
||||
FactManager fact_manager;
|
||||
|
||||
// Illegal to split between the merge and the conditional branch.
|
||||
ASSERT_FALSE(
|
||||
TransformationSplitBlock(
|
||||
MakeInstructionDescriptor(14, SpvOpBranchConditional, 0), 100)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
TransformationSplitBlock(
|
||||
MakeInstructionDescriptor(12, SpvOpBranchConditional, 0), 100)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
auto split = TransformationSplitBlock(
|
||||
MakeInstructionDescriptor(14, SpvOpSelectionMerge, 0), 100);
|
||||
ASSERT_TRUE(split.IsApplicable(context.get(), fact_manager));
|
||||
split.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
std::string after_split = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
OpName %8 "x"
|
||||
OpName %11 "y"
|
||||
OpDecorate %8 RelaxedPrecision
|
||||
OpDecorate %10 RelaxedPrecision
|
||||
OpDecorate %11 RelaxedPrecision
|
||||
OpDecorate %12 RelaxedPrecision
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeInt 32 1
|
||||
%7 = OpTypePointer Function %6
|
||||
%9 = OpConstant %6 2
|
||||
%13 = OpTypeBool
|
||||
%17 = OpConstant %6 3
|
||||
%19 = OpConstant %6 4
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%8 = OpVariable %7 Function
|
||||
%11 = OpVariable %7 Function
|
||||
OpStore %8 %9
|
||||
%10 = OpLoad %6 %8
|
||||
%12 = OpLoad %6 %11
|
||||
%14 = OpSLessThan %13 %10 %12
|
||||
OpBranch %100
|
||||
%100 = OpLabel
|
||||
OpSelectionMerge %16 None
|
||||
OpBranchConditional %14 %15 %18
|
||||
%15 = OpLabel
|
||||
OpStore %11 %17
|
||||
OpBranch %16
|
||||
%18 = OpLabel
|
||||
OpStore %11 %19
|
||||
OpBranch %16
|
||||
%16 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
ASSERT_TRUE(IsEqual(env, after_split, context.get()));
|
||||
}
|
||||
|
||||
TEST(TransformationSplitBlockTest, SplitBlockBeforeSwitchBranch) {
|
||||
// The SPIR-V in this test came from the following fragment shader:
|
||||
//
|
||||
// void main() {
|
||||
// int x, y;
|
||||
// switch (y) {
|
||||
// case 1:
|
||||
// x = 2;
|
||||
// case 2:
|
||||
// break;
|
||||
// case 3:
|
||||
// x = 4;
|
||||
// default:
|
||||
// x = 6;
|
||||
// }
|
||||
// }
|
||||
|
||||
std::string shader = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
OpName %8 "y"
|
||||
OpName %15 "x"
|
||||
OpDecorate %8 RelaxedPrecision
|
||||
OpDecorate %9 RelaxedPrecision
|
||||
OpDecorate %15 RelaxedPrecision
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeInt 32 1
|
||||
%7 = OpTypePointer Function %6
|
||||
%16 = OpConstant %6 2
|
||||
%18 = OpConstant %6 4
|
||||
%19 = OpConstant %6 6
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%8 = OpVariable %7 Function
|
||||
%15 = OpVariable %7 Function
|
||||
%9 = OpLoad %6 %8
|
||||
OpSelectionMerge %14 None
|
||||
OpSwitch %9 %13 1 %10 2 %11 3 %12
|
||||
%13 = OpLabel
|
||||
OpStore %15 %19
|
||||
OpBranch %14
|
||||
%10 = OpLabel
|
||||
OpStore %15 %16
|
||||
OpBranch %11
|
||||
%11 = OpLabel
|
||||
OpBranch %14
|
||||
%12 = OpLabel
|
||||
OpStore %15 %18
|
||||
OpBranch %13
|
||||
%14 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto consumer = nullptr;
|
||||
const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
|
||||
|
||||
FactManager fact_manager;
|
||||
|
||||
// Illegal to split between the merge and the conditional branch.
|
||||
ASSERT_FALSE(TransformationSplitBlock(
|
||||
MakeInstructionDescriptor(9, SpvOpSwitch, 0), 100)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(TransformationSplitBlock(
|
||||
MakeInstructionDescriptor(15, SpvOpSwitch, 0), 100)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
auto split = TransformationSplitBlock(
|
||||
MakeInstructionDescriptor(9, SpvOpSelectionMerge, 0), 100);
|
||||
ASSERT_TRUE(split.IsApplicable(context.get(), fact_manager));
|
||||
split.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
std::string after_split = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
OpName %8 "y"
|
||||
OpName %15 "x"
|
||||
OpDecorate %8 RelaxedPrecision
|
||||
OpDecorate %9 RelaxedPrecision
|
||||
OpDecorate %15 RelaxedPrecision
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeInt 32 1
|
||||
%7 = OpTypePointer Function %6
|
||||
%16 = OpConstant %6 2
|
||||
%18 = OpConstant %6 4
|
||||
%19 = OpConstant %6 6
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%8 = OpVariable %7 Function
|
||||
%15 = OpVariable %7 Function
|
||||
%9 = OpLoad %6 %8
|
||||
OpBranch %100
|
||||
%100 = OpLabel
|
||||
OpSelectionMerge %14 None
|
||||
OpSwitch %9 %13 1 %10 2 %11 3 %12
|
||||
%13 = OpLabel
|
||||
OpStore %15 %19
|
||||
OpBranch %14
|
||||
%10 = OpLabel
|
||||
OpStore %15 %16
|
||||
OpBranch %11
|
||||
%11 = OpLabel
|
||||
OpBranch %14
|
||||
%12 = OpLabel
|
||||
OpStore %15 %18
|
||||
OpBranch %13
|
||||
%14 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
ASSERT_TRUE(IsEqual(env, after_split, context.get()));
|
||||
}
|
||||
|
||||
TEST(TransformationSplitBlockTest, NoSplitDuringOpPhis) {
|
||||
// The SPIR-V in this test came from the following fragment shader, with
|
||||
// local store elimination applied to get some OpPhi instructions.
|
||||
//
|
||||
// void main() {
|
||||
// int x;
|
||||
// int i;
|
||||
// for (i = 0; i < 100; i++) {
|
||||
// x += i;
|
||||
// }
|
||||
// }
|
||||
|
||||
std::string shader = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
OpName %8 "i"
|
||||
OpName %19 "x"
|
||||
OpDecorate %8 RelaxedPrecision
|
||||
OpDecorate %19 RelaxedPrecision
|
||||
OpDecorate %22 RelaxedPrecision
|
||||
OpDecorate %25 RelaxedPrecision
|
||||
OpDecorate %26 RelaxedPrecision
|
||||
OpDecorate %27 RelaxedPrecision
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeInt 32 1
|
||||
%7 = OpTypePointer Function %6
|
||||
%9 = OpConstant %6 0
|
||||
%16 = OpConstant %6 100
|
||||
%17 = OpTypeBool
|
||||
%24 = OpConstant %6 1
|
||||
%28 = OpUndef %6
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%8 = OpVariable %7 Function
|
||||
%19 = OpVariable %7 Function
|
||||
OpStore %8 %9
|
||||
OpBranch %10
|
||||
%10 = OpLabel
|
||||
%27 = OpPhi %6 %28 %5 %22 %13
|
||||
%26 = OpPhi %6 %9 %5 %25 %13
|
||||
OpBranch %50
|
||||
%50 = OpLabel
|
||||
OpLoopMerge %12 %13 None
|
||||
OpBranch %14
|
||||
%14 = OpLabel
|
||||
%18 = OpSLessThan %17 %26 %16
|
||||
OpBranchConditional %18 %11 %12
|
||||
%11 = OpLabel
|
||||
%22 = OpIAdd %6 %27 %26
|
||||
OpStore %19 %22
|
||||
OpBranch %13
|
||||
%13 = OpLabel
|
||||
%25 = OpIAdd %6 %26 %24
|
||||
OpStore %8 %25
|
||||
OpBranch %50
|
||||
%12 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto consumer = nullptr;
|
||||
const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
|
||||
|
||||
FactManager fact_manager;
|
||||
|
||||
// We cannot split before OpPhi instructions, since the number of incoming
|
||||
// blocks may not appropriately match after splitting.
|
||||
ASSERT_FALSE(
|
||||
TransformationSplitBlock(MakeInstructionDescriptor(26, SpvOpPhi, 0), 100)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
TransformationSplitBlock(MakeInstructionDescriptor(27, SpvOpPhi, 0), 100)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
TransformationSplitBlock(MakeInstructionDescriptor(27, SpvOpPhi, 1), 100)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
}
|
||||
|
||||
TEST(TransformationSplitBlockTest, SplitOpPhiWithSinglePredecessor) {
|
||||
std::string shader = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
OpName %8 "x"
|
||||
OpName %10 "y"
|
||||
OpDecorate %8 RelaxedPrecision
|
||||
OpDecorate %10 RelaxedPrecision
|
||||
OpDecorate %11 RelaxedPrecision
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeInt 32 1
|
||||
%7 = OpTypePointer Function %6
|
||||
%9 = OpConstant %6 1
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%8 = OpVariable %7 Function
|
||||
%10 = OpVariable %7 Function
|
||||
OpStore %8 %9
|
||||
%11 = OpLoad %6 %8
|
||||
OpBranch %20
|
||||
%20 = OpLabel
|
||||
%21 = OpPhi %6 %11 %5
|
||||
OpStore %10 %21
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_3;
|
||||
const auto consumer = nullptr;
|
||||
const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
|
||||
|
||||
FactManager fact_manager;
|
||||
|
||||
ASSERT_TRUE(
|
||||
TransformationSplitBlock(MakeInstructionDescriptor(21, SpvOpPhi, 0), 100)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
// An equivalent transformation to the above, just described with respect to a
|
||||
// different base instruction.
|
||||
auto split =
|
||||
TransformationSplitBlock(MakeInstructionDescriptor(20, SpvOpPhi, 0), 100);
|
||||
ASSERT_TRUE(split.IsApplicable(context.get(), fact_manager));
|
||||
split.Apply(context.get(), &fact_manager);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
std::string after_split = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
OpName %8 "x"
|
||||
OpName %10 "y"
|
||||
OpDecorate %8 RelaxedPrecision
|
||||
OpDecorate %10 RelaxedPrecision
|
||||
OpDecorate %11 RelaxedPrecision
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeInt 32 1
|
||||
%7 = OpTypePointer Function %6
|
||||
%9 = OpConstant %6 1
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%8 = OpVariable %7 Function
|
||||
%10 = OpVariable %7 Function
|
||||
OpStore %8 %9
|
||||
%11 = OpLoad %6 %8
|
||||
OpBranch %20
|
||||
%20 = OpLabel
|
||||
OpBranch %100
|
||||
%100 = OpLabel
|
||||
%21 = OpPhi %6 %11 %20
|
||||
OpStore %10 %21
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
ASSERT_TRUE(IsEqual(env, after_split, context.get()));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
@@ -1,532 +0,0 @@
|
||||
// Copyright (c) 2019 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "source/fuzz/transformation_vector_shuffle.h"
|
||||
#include "source/fuzz/instruction_descriptor.h"
|
||||
#include "test/fuzz/fuzz_test_util.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
namespace {
|
||||
|
||||
TEST(TransformationVectorShuffle, BasicTest) {
|
||||
std::string shader = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeBool
|
||||
%7 = OpTypeVector %6 2
|
||||
%10 = OpConstantTrue %6
|
||||
%11 = OpConstantFalse %6
|
||||
%12 = OpConstantComposite %7 %10 %11
|
||||
%112 = OpUndef %7
|
||||
%13 = OpTypeVector %6 3
|
||||
%16 = OpConstantComposite %13 %10 %11 %10
|
||||
%17 = OpTypeVector %6 4
|
||||
%20 = OpConstantComposite %17 %10 %11 %10 %11
|
||||
%21 = OpTypeInt 32 1
|
||||
%22 = OpTypeVector %21 2
|
||||
%25 = OpConstant %21 1
|
||||
%26 = OpConstant %21 0
|
||||
%27 = OpConstantComposite %22 %25 %26
|
||||
%28 = OpTypeVector %21 3
|
||||
%31 = OpConstantComposite %28 %25 %26 %25
|
||||
%32 = OpTypeVector %21 4
|
||||
%33 = OpTypePointer Function %32
|
||||
%35 = OpConstantComposite %32 %25 %26 %25 %26
|
||||
%36 = OpTypeInt 32 0
|
||||
%37 = OpTypeVector %36 2
|
||||
%40 = OpConstant %36 1
|
||||
%41 = OpConstant %36 0
|
||||
%42 = OpConstantComposite %37 %40 %41
|
||||
%43 = OpTypeVector %36 3
|
||||
%46 = OpConstantComposite %43 %40 %41 %40
|
||||
%47 = OpTypeVector %36 4
|
||||
%50 = OpConstantComposite %47 %40 %41 %40 %41
|
||||
%51 = OpTypeFloat 32
|
||||
%55 = OpConstant %51 1
|
||||
%56 = OpConstant %51 0
|
||||
%58 = OpTypeVector %51 3
|
||||
%61 = OpConstantComposite %58 %55 %56 %55
|
||||
%62 = OpTypeVector %51 4
|
||||
%65 = OpConstantComposite %62 %55 %56 %55 %56
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
OpSelectionMerge %100 None
|
||||
OpBranchConditional %10 %101 %102
|
||||
%101 = OpLabel
|
||||
%103 = OpCompositeConstruct %62 %55 %55 %55 %56
|
||||
OpBranch %100
|
||||
%102 = OpLabel
|
||||
OpBranch %100
|
||||
%100 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_4;
|
||||
const auto consumer = nullptr;
|
||||
const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
FactManager fact_manager;
|
||||
|
||||
fact_manager.AddFactDataSynonym(MakeDataDescriptor(10, {}),
|
||||
MakeDataDescriptor(12, {0}), context.get());
|
||||
fact_manager.AddFactDataSynonym(MakeDataDescriptor(11, {}),
|
||||
MakeDataDescriptor(12, {1}), context.get());
|
||||
|
||||
fact_manager.AddFactDataSynonym(MakeDataDescriptor(10, {}),
|
||||
MakeDataDescriptor(16, {0}), context.get());
|
||||
fact_manager.AddFactDataSynonym(MakeDataDescriptor(11, {}),
|
||||
MakeDataDescriptor(16, {1}), context.get());
|
||||
fact_manager.AddFactDataSynonym(MakeDataDescriptor(10, {}),
|
||||
MakeDataDescriptor(16, {2}), context.get());
|
||||
|
||||
fact_manager.AddFactDataSynonym(MakeDataDescriptor(10, {}),
|
||||
MakeDataDescriptor(20, {0}), context.get());
|
||||
fact_manager.AddFactDataSynonym(MakeDataDescriptor(11, {}),
|
||||
MakeDataDescriptor(20, {1}), context.get());
|
||||
fact_manager.AddFactDataSynonym(MakeDataDescriptor(10, {}),
|
||||
MakeDataDescriptor(20, {2}), context.get());
|
||||
fact_manager.AddFactDataSynonym(MakeDataDescriptor(11, {}),
|
||||
MakeDataDescriptor(20, {3}), context.get());
|
||||
|
||||
fact_manager.AddFactDataSynonym(MakeDataDescriptor(25, {}),
|
||||
MakeDataDescriptor(27, {0}), context.get());
|
||||
fact_manager.AddFactDataSynonym(MakeDataDescriptor(26, {}),
|
||||
MakeDataDescriptor(27, {1}), context.get());
|
||||
|
||||
fact_manager.AddFactDataSynonym(MakeDataDescriptor(25, {}),
|
||||
MakeDataDescriptor(31, {0}), context.get());
|
||||
fact_manager.AddFactDataSynonym(MakeDataDescriptor(26, {}),
|
||||
MakeDataDescriptor(31, {1}), context.get());
|
||||
fact_manager.AddFactDataSynonym(MakeDataDescriptor(25, {}),
|
||||
MakeDataDescriptor(31, {2}), context.get());
|
||||
|
||||
fact_manager.AddFactDataSynonym(MakeDataDescriptor(25, {}),
|
||||
MakeDataDescriptor(35, {0}), context.get());
|
||||
fact_manager.AddFactDataSynonym(MakeDataDescriptor(26, {}),
|
||||
MakeDataDescriptor(35, {1}), context.get());
|
||||
fact_manager.AddFactDataSynonym(MakeDataDescriptor(25, {}),
|
||||
MakeDataDescriptor(35, {2}), context.get());
|
||||
fact_manager.AddFactDataSynonym(MakeDataDescriptor(26, {}),
|
||||
MakeDataDescriptor(35, {3}), context.get());
|
||||
|
||||
fact_manager.AddFactDataSynonym(MakeDataDescriptor(40, {}),
|
||||
MakeDataDescriptor(42, {0}), context.get());
|
||||
fact_manager.AddFactDataSynonym(MakeDataDescriptor(41, {}),
|
||||
MakeDataDescriptor(42, {1}), context.get());
|
||||
|
||||
fact_manager.AddFactDataSynonym(MakeDataDescriptor(40, {}),
|
||||
MakeDataDescriptor(46, {0}), context.get());
|
||||
fact_manager.AddFactDataSynonym(MakeDataDescriptor(41, {}),
|
||||
MakeDataDescriptor(46, {1}), context.get());
|
||||
fact_manager.AddFactDataSynonym(MakeDataDescriptor(40, {}),
|
||||
MakeDataDescriptor(46, {2}), context.get());
|
||||
|
||||
fact_manager.AddFactDataSynonym(MakeDataDescriptor(40, {}),
|
||||
MakeDataDescriptor(50, {0}), context.get());
|
||||
fact_manager.AddFactDataSynonym(MakeDataDescriptor(41, {}),
|
||||
MakeDataDescriptor(50, {1}), context.get());
|
||||
fact_manager.AddFactDataSynonym(MakeDataDescriptor(40, {}),
|
||||
MakeDataDescriptor(50, {2}), context.get());
|
||||
fact_manager.AddFactDataSynonym(MakeDataDescriptor(41, {}),
|
||||
MakeDataDescriptor(50, {3}), context.get());
|
||||
|
||||
fact_manager.AddFactDataSynonym(MakeDataDescriptor(55, {}),
|
||||
MakeDataDescriptor(61, {0}), context.get());
|
||||
fact_manager.AddFactDataSynonym(MakeDataDescriptor(56, {}),
|
||||
MakeDataDescriptor(61, {1}), context.get());
|
||||
fact_manager.AddFactDataSynonym(MakeDataDescriptor(55, {}),
|
||||
MakeDataDescriptor(61, {2}), context.get());
|
||||
|
||||
fact_manager.AddFactDataSynonym(MakeDataDescriptor(55, {}),
|
||||
MakeDataDescriptor(65, {0}), context.get());
|
||||
fact_manager.AddFactDataSynonym(MakeDataDescriptor(56, {}),
|
||||
MakeDataDescriptor(65, {1}), context.get());
|
||||
fact_manager.AddFactDataSynonym(MakeDataDescriptor(55, {}),
|
||||
MakeDataDescriptor(65, {2}), context.get());
|
||||
fact_manager.AddFactDataSynonym(MakeDataDescriptor(56, {}),
|
||||
MakeDataDescriptor(65, {3}), context.get());
|
||||
|
||||
// %103 does not dominate the return instruction.
|
||||
ASSERT_FALSE(TransformationVectorShuffle(
|
||||
MakeInstructionDescriptor(100, SpvOpReturn, 0), 200, 103, 65,
|
||||
{3, 5, 7})
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Illegal to shuffle a bvec2 and a vec3
|
||||
ASSERT_FALSE(TransformationVectorShuffle(
|
||||
MakeInstructionDescriptor(100, SpvOpReturn, 0), 200, 112, 61,
|
||||
{0, 2, 4})
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Illegal to shuffle an ivec2 and a uvec4
|
||||
ASSERT_FALSE(TransformationVectorShuffle(
|
||||
MakeInstructionDescriptor(100, SpvOpReturn, 0), 200, 27, 50,
|
||||
{1, 3, 5})
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Vector 1 does not exist
|
||||
ASSERT_FALSE(TransformationVectorShuffle(
|
||||
MakeInstructionDescriptor(100, SpvOpReturn, 0), 200, 300, 50,
|
||||
{1, 3, 5})
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Vector 2 does not exist
|
||||
ASSERT_FALSE(TransformationVectorShuffle(
|
||||
MakeInstructionDescriptor(100, SpvOpReturn, 0), 200, 27, 300,
|
||||
{1, 3, 5})
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Index out of range
|
||||
ASSERT_FALSE(
|
||||
TransformationVectorShuffle(
|
||||
MakeInstructionDescriptor(100, SpvOpReturn, 0), 200, 12, 112, {0, 20})
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Too many indices
|
||||
ASSERT_FALSE(TransformationVectorShuffle(
|
||||
MakeInstructionDescriptor(100, SpvOpReturn, 0), 200, 12, 112,
|
||||
{0, 1, 0, 1, 0, 1, 0, 1})
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Too few indices
|
||||
ASSERT_FALSE(
|
||||
TransformationVectorShuffle(
|
||||
MakeInstructionDescriptor(100, SpvOpReturn, 0), 200, 12, 112, {})
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Too few indices again
|
||||
ASSERT_FALSE(
|
||||
TransformationVectorShuffle(
|
||||
MakeInstructionDescriptor(100, SpvOpReturn, 0), 200, 12, 112, {0})
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Indices define unknown type: we do not have vec2
|
||||
ASSERT_FALSE(
|
||||
TransformationVectorShuffle(
|
||||
MakeInstructionDescriptor(100, SpvOpReturn, 0), 200, 65, 65, {0, 1})
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// The instruction to insert before does not exist
|
||||
ASSERT_FALSE(TransformationVectorShuffle(
|
||||
MakeInstructionDescriptor(100, SpvOpCompositeConstruct, 1),
|
||||
201, 20, 12, {0xFFFFFFFF, 3, 5})
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// The 'fresh' id is already in use
|
||||
ASSERT_FALSE(
|
||||
TransformationVectorShuffle(
|
||||
MakeInstructionDescriptor(100, SpvOpReturn, 0), 12, 12, 112, {})
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
protobufs::DataDescriptor temp_dd;
|
||||
|
||||
TransformationVectorShuffle transformation1(
|
||||
MakeInstructionDescriptor(100, SpvOpReturn, 0), 200, 12, 112, {1, 0});
|
||||
ASSERT_TRUE(transformation1.IsApplicable(context.get(), fact_manager));
|
||||
transformation1.Apply(context.get(), &fact_manager);
|
||||
temp_dd = MakeDataDescriptor(200, {0});
|
||||
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(11, {}), temp_dd,
|
||||
context.get()));
|
||||
temp_dd = MakeDataDescriptor(200, {1});
|
||||
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(10, {}), temp_dd,
|
||||
context.get()));
|
||||
|
||||
TransformationVectorShuffle transformation2(
|
||||
MakeInstructionDescriptor(100, SpvOpReturn, 0), 201, 20, 12,
|
||||
{0xFFFFFFFF, 3, 5});
|
||||
ASSERT_TRUE(transformation2.IsApplicable(context.get(), fact_manager));
|
||||
transformation2.Apply(context.get(), &fact_manager);
|
||||
temp_dd = MakeDataDescriptor(201, {1});
|
||||
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(11, {}), temp_dd,
|
||||
context.get()));
|
||||
temp_dd = MakeDataDescriptor(201, {2});
|
||||
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(11, {}), temp_dd,
|
||||
context.get()));
|
||||
|
||||
TransformationVectorShuffle transformation3(
|
||||
MakeInstructionDescriptor(100, SpvOpReturn, 0), 202, 27, 35, {5, 4, 1});
|
||||
ASSERT_TRUE(transformation3.IsApplicable(context.get(), fact_manager));
|
||||
transformation3.Apply(context.get(), &fact_manager);
|
||||
temp_dd = MakeDataDescriptor(202, {0});
|
||||
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(26, {}), temp_dd,
|
||||
context.get()));
|
||||
temp_dd = MakeDataDescriptor(202, {1});
|
||||
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(25, {}), temp_dd,
|
||||
context.get()));
|
||||
temp_dd = MakeDataDescriptor(202, {2});
|
||||
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(26, {}), temp_dd,
|
||||
context.get()));
|
||||
|
||||
TransformationVectorShuffle transformation4(
|
||||
MakeInstructionDescriptor(100, SpvOpReturn, 0), 203, 42, 46, {0, 1});
|
||||
ASSERT_TRUE(transformation4.IsApplicable(context.get(), fact_manager));
|
||||
transformation4.Apply(context.get(), &fact_manager);
|
||||
temp_dd = MakeDataDescriptor(203, {0});
|
||||
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {}), temp_dd,
|
||||
context.get()));
|
||||
temp_dd = MakeDataDescriptor(203, {1});
|
||||
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(41, {}), temp_dd,
|
||||
context.get()));
|
||||
|
||||
TransformationVectorShuffle transformation5(
|
||||
MakeInstructionDescriptor(100, SpvOpReturn, 0), 204, 42, 46, {2, 3, 4});
|
||||
ASSERT_TRUE(transformation5.IsApplicable(context.get(), fact_manager));
|
||||
transformation5.Apply(context.get(), &fact_manager);
|
||||
temp_dd = MakeDataDescriptor(204, {0});
|
||||
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {}), temp_dd,
|
||||
context.get()));
|
||||
temp_dd = MakeDataDescriptor(204, {1});
|
||||
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(41, {}), temp_dd,
|
||||
context.get()));
|
||||
temp_dd = MakeDataDescriptor(204, {2});
|
||||
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {}), temp_dd,
|
||||
context.get()));
|
||||
|
||||
TransformationVectorShuffle transformation6(
|
||||
MakeInstructionDescriptor(100, SpvOpReturn, 0), 205, 42, 42,
|
||||
{0, 1, 2, 3});
|
||||
ASSERT_TRUE(transformation6.IsApplicable(context.get(), fact_manager));
|
||||
transformation6.Apply(context.get(), &fact_manager);
|
||||
temp_dd = MakeDataDescriptor(205, {0});
|
||||
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {}), temp_dd,
|
||||
context.get()));
|
||||
temp_dd = MakeDataDescriptor(205, {1});
|
||||
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(41, {}), temp_dd,
|
||||
context.get()));
|
||||
temp_dd = MakeDataDescriptor(205, {2});
|
||||
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {}), temp_dd,
|
||||
context.get()));
|
||||
temp_dd = MakeDataDescriptor(205, {3});
|
||||
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(41, {}), temp_dd,
|
||||
context.get()));
|
||||
|
||||
// swizzle vec4 from vec4 and vec4 using some undefs
|
||||
TransformationVectorShuffle transformation7(
|
||||
MakeInstructionDescriptor(100, SpvOpReturn, 0), 206, 65, 65,
|
||||
{0xFFFFFFFF, 3, 6, 0xFFFFFFFF});
|
||||
ASSERT_TRUE(transformation7.IsApplicable(context.get(), fact_manager));
|
||||
transformation7.Apply(context.get(), &fact_manager);
|
||||
temp_dd = MakeDataDescriptor(206, {1});
|
||||
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(56, {}), temp_dd,
|
||||
context.get()));
|
||||
|
||||
std::string after_transformation = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main"
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeBool
|
||||
%7 = OpTypeVector %6 2
|
||||
%10 = OpConstantTrue %6
|
||||
%11 = OpConstantFalse %6
|
||||
%12 = OpConstantComposite %7 %10 %11
|
||||
%112 = OpUndef %7
|
||||
%13 = OpTypeVector %6 3
|
||||
%16 = OpConstantComposite %13 %10 %11 %10
|
||||
%17 = OpTypeVector %6 4
|
||||
%20 = OpConstantComposite %17 %10 %11 %10 %11
|
||||
%21 = OpTypeInt 32 1
|
||||
%22 = OpTypeVector %21 2
|
||||
%25 = OpConstant %21 1
|
||||
%26 = OpConstant %21 0
|
||||
%27 = OpConstantComposite %22 %25 %26
|
||||
%28 = OpTypeVector %21 3
|
||||
%31 = OpConstantComposite %28 %25 %26 %25
|
||||
%32 = OpTypeVector %21 4
|
||||
%33 = OpTypePointer Function %32
|
||||
%35 = OpConstantComposite %32 %25 %26 %25 %26
|
||||
%36 = OpTypeInt 32 0
|
||||
%37 = OpTypeVector %36 2
|
||||
%40 = OpConstant %36 1
|
||||
%41 = OpConstant %36 0
|
||||
%42 = OpConstantComposite %37 %40 %41
|
||||
%43 = OpTypeVector %36 3
|
||||
%46 = OpConstantComposite %43 %40 %41 %40
|
||||
%47 = OpTypeVector %36 4
|
||||
%50 = OpConstantComposite %47 %40 %41 %40 %41
|
||||
%51 = OpTypeFloat 32
|
||||
%55 = OpConstant %51 1
|
||||
%56 = OpConstant %51 0
|
||||
%58 = OpTypeVector %51 3
|
||||
%61 = OpConstantComposite %58 %55 %56 %55
|
||||
%62 = OpTypeVector %51 4
|
||||
%65 = OpConstantComposite %62 %55 %56 %55 %56
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
OpSelectionMerge %100 None
|
||||
OpBranchConditional %10 %101 %102
|
||||
%101 = OpLabel
|
||||
%103 = OpCompositeConstruct %62 %55 %55 %55 %56
|
||||
OpBranch %100
|
||||
%102 = OpLabel
|
||||
OpBranch %100
|
||||
%100 = OpLabel
|
||||
%200 = OpVectorShuffle %7 %12 %112 1 0
|
||||
%201 = OpVectorShuffle %13 %20 %12 0xFFFFFFFF 3 5
|
||||
%202 = OpVectorShuffle %28 %27 %35 5 4 1
|
||||
%203 = OpVectorShuffle %37 %42 %46 0 1
|
||||
%204 = OpVectorShuffle %43 %42 %46 2 3 4
|
||||
%205 = OpVectorShuffle %47 %42 %42 0 1 2 3
|
||||
%206 = OpVectorShuffle %62 %65 %65 0xFFFFFFFF 3 6 0xFFFFFFFF
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
|
||||
}
|
||||
|
||||
TEST(TransformationVectorShuffleTest, IllegalInsertionPoints) {
|
||||
std::string shader = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main" %51 %27
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %4 "main"
|
||||
OpName %25 "buf"
|
||||
OpMemberName %25 0 "value"
|
||||
OpName %27 ""
|
||||
OpName %51 "color"
|
||||
OpMemberDecorate %25 0 Offset 0
|
||||
OpDecorate %25 Block
|
||||
OpDecorate %27 DescriptorSet 0
|
||||
OpDecorate %27 Binding 0
|
||||
OpDecorate %51 Location 0
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%6 = OpTypeFloat 32
|
||||
%7 = OpTypeVector %6 4
|
||||
%150 = OpTypeVector %6 2
|
||||
%10 = OpConstant %6 0.300000012
|
||||
%11 = OpConstant %6 0.400000006
|
||||
%12 = OpConstant %6 0.5
|
||||
%13 = OpConstant %6 1
|
||||
%14 = OpConstantComposite %7 %10 %11 %12 %13
|
||||
%15 = OpTypeInt 32 1
|
||||
%18 = OpConstant %15 0
|
||||
%25 = OpTypeStruct %6
|
||||
%26 = OpTypePointer Uniform %25
|
||||
%27 = OpVariable %26 Uniform
|
||||
%28 = OpTypePointer Uniform %6
|
||||
%32 = OpTypeBool
|
||||
%103 = OpConstantTrue %32
|
||||
%34 = OpConstant %6 0.100000001
|
||||
%48 = OpConstant %15 1
|
||||
%50 = OpTypePointer Output %7
|
||||
%51 = OpVariable %50 Output
|
||||
%100 = OpTypePointer Function %6
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%101 = OpVariable %100 Function
|
||||
%102 = OpVariable %100 Function
|
||||
OpBranch %19
|
||||
%19 = OpLabel
|
||||
%60 = OpPhi %7 %14 %5 %58 %20
|
||||
%59 = OpPhi %15 %18 %5 %49 %20
|
||||
%29 = OpAccessChain %28 %27 %18
|
||||
%30 = OpLoad %6 %29
|
||||
%31 = OpConvertFToS %15 %30
|
||||
%33 = OpSLessThan %32 %59 %31
|
||||
OpLoopMerge %21 %20 None
|
||||
OpBranchConditional %33 %20 %21
|
||||
%20 = OpLabel
|
||||
%39 = OpCompositeExtract %6 %60 0
|
||||
%40 = OpFAdd %6 %39 %34
|
||||
%55 = OpCompositeInsert %7 %40 %60 0
|
||||
%44 = OpCompositeExtract %6 %60 1
|
||||
%45 = OpFSub %6 %44 %34
|
||||
%58 = OpCompositeInsert %7 %45 %55 1
|
||||
%49 = OpIAdd %15 %59 %48
|
||||
OpBranch %19
|
||||
%21 = OpLabel
|
||||
OpStore %51 %60
|
||||
OpSelectionMerge %105 None
|
||||
OpBranchConditional %103 %104 %105
|
||||
%104 = OpLabel
|
||||
OpBranch %105
|
||||
%105 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const auto env = SPV_ENV_UNIVERSAL_1_4;
|
||||
const auto consumer = nullptr;
|
||||
const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
|
||||
ASSERT_TRUE(IsValid(env, context.get()));
|
||||
|
||||
FactManager fact_manager;
|
||||
|
||||
// Cannot insert before the OpVariables of a function.
|
||||
ASSERT_FALSE(
|
||||
TransformationVectorShuffle(
|
||||
MakeInstructionDescriptor(101, SpvOpVariable, 0), 200, 14, 14, {0, 1})
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
TransformationVectorShuffle(
|
||||
MakeInstructionDescriptor(101, SpvOpVariable, 1), 200, 14, 14, {1, 2})
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
TransformationVectorShuffle(
|
||||
MakeInstructionDescriptor(102, SpvOpVariable, 0), 200, 14, 14, {1, 2})
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
// OK to insert right after the OpVariables.
|
||||
ASSERT_FALSE(
|
||||
TransformationVectorShuffle(
|
||||
MakeInstructionDescriptor(102, SpvOpBranch, 1), 200, 14, 14, {1, 1})
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Cannot insert before the OpPhis of a block.
|
||||
ASSERT_FALSE(
|
||||
TransformationVectorShuffle(MakeInstructionDescriptor(60, SpvOpPhi, 0),
|
||||
200, 14, 14, {2, 0})
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
TransformationVectorShuffle(MakeInstructionDescriptor(59, SpvOpPhi, 0),
|
||||
200, 14, 14, {3, 0})
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
// OK to insert after the OpPhis.
|
||||
ASSERT_TRUE(TransformationVectorShuffle(
|
||||
MakeInstructionDescriptor(59, SpvOpAccessChain, 0), 200, 14,
|
||||
14, {3, 4})
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Cannot insert before OpLoopMerge
|
||||
ASSERT_FALSE(TransformationVectorShuffle(
|
||||
MakeInstructionDescriptor(33, SpvOpBranchConditional, 0),
|
||||
200, 14, 14, {3})
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Cannot insert before OpSelectionMerge
|
||||
ASSERT_FALSE(TransformationVectorShuffle(
|
||||
MakeInstructionDescriptor(21, SpvOpBranchConditional, 0),
|
||||
200, 14, 14, {2})
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
@@ -1,84 +0,0 @@
|
||||
// Copyright (c) 2019 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "source/fuzz/uniform_buffer_element_descriptor.h"
|
||||
#include "test/fuzz/fuzz_test_util.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
namespace {
|
||||
|
||||
TEST(UniformBufferElementDescriptorTest, TestEquality) {
|
||||
// Test that equality works as expected for various buffer element
|
||||
// descriptors.
|
||||
|
||||
protobufs::UniformBufferElementDescriptor descriptor1 =
|
||||
MakeUniformBufferElementDescriptor(0, 0, {1, 2, 3});
|
||||
protobufs::UniformBufferElementDescriptor descriptor2 =
|
||||
MakeUniformBufferElementDescriptor(0, 0, {1, 2, 3});
|
||||
protobufs::UniformBufferElementDescriptor descriptor3 =
|
||||
MakeUniformBufferElementDescriptor(0, 1, {1, 2, 3});
|
||||
protobufs::UniformBufferElementDescriptor descriptor4 =
|
||||
MakeUniformBufferElementDescriptor(1, 0, {1, 2, 3});
|
||||
protobufs::UniformBufferElementDescriptor descriptor5 =
|
||||
MakeUniformBufferElementDescriptor(1, 1, {1, 2, 3});
|
||||
protobufs::UniformBufferElementDescriptor descriptor6 =
|
||||
MakeUniformBufferElementDescriptor(0, 0, {1, 2, 4});
|
||||
protobufs::UniformBufferElementDescriptor descriptor7 =
|
||||
MakeUniformBufferElementDescriptor(0, 0, {1, 2});
|
||||
|
||||
ASSERT_TRUE(
|
||||
UniformBufferElementDescriptorEquals()(&descriptor1, &descriptor1));
|
||||
ASSERT_TRUE(
|
||||
UniformBufferElementDescriptorEquals()(&descriptor1, &descriptor2));
|
||||
ASSERT_TRUE(
|
||||
UniformBufferElementDescriptorEquals()(&descriptor3, &descriptor3));
|
||||
ASSERT_TRUE(
|
||||
UniformBufferElementDescriptorEquals()(&descriptor4, &descriptor4));
|
||||
ASSERT_TRUE(
|
||||
UniformBufferElementDescriptorEquals()(&descriptor5, &descriptor5));
|
||||
ASSERT_TRUE(
|
||||
UniformBufferElementDescriptorEquals()(&descriptor6, &descriptor6));
|
||||
ASSERT_TRUE(
|
||||
UniformBufferElementDescriptorEquals()(&descriptor7, &descriptor7));
|
||||
|
||||
ASSERT_FALSE(
|
||||
UniformBufferElementDescriptorEquals()(&descriptor1, &descriptor3));
|
||||
ASSERT_FALSE(
|
||||
UniformBufferElementDescriptorEquals()(&descriptor3, &descriptor1));
|
||||
|
||||
ASSERT_FALSE(
|
||||
UniformBufferElementDescriptorEquals()(&descriptor1, &descriptor4));
|
||||
ASSERT_FALSE(
|
||||
UniformBufferElementDescriptorEquals()(&descriptor4, &descriptor1));
|
||||
|
||||
ASSERT_FALSE(
|
||||
UniformBufferElementDescriptorEquals()(&descriptor1, &descriptor5));
|
||||
ASSERT_FALSE(
|
||||
UniformBufferElementDescriptorEquals()(&descriptor5, &descriptor1));
|
||||
|
||||
ASSERT_FALSE(
|
||||
UniformBufferElementDescriptorEquals()(&descriptor1, &descriptor6));
|
||||
ASSERT_FALSE(
|
||||
UniformBufferElementDescriptorEquals()(&descriptor6, &descriptor1));
|
||||
|
||||
ASSERT_FALSE(
|
||||
UniformBufferElementDescriptorEquals()(&descriptor1, &descriptor7));
|
||||
ASSERT_FALSE(
|
||||
UniformBufferElementDescriptorEquals()(&descriptor7, &descriptor1));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace fuzz
|
||||
} // namespace spvtools
|
||||
215
3rdparty/spirv-tools/test/fuzzers/BUILD.gn
vendored
215
3rdparty/spirv-tools/test/fuzzers/BUILD.gn
vendored
@@ -1,215 +0,0 @@
|
||||
# Copyright 2018 Google Inc. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import("//testing/libfuzzer/fuzzer_test.gni")
|
||||
import("//testing/test.gni")
|
||||
|
||||
config("fuzzer_config") {
|
||||
configs = [ "../..:spvtools_internal_config" ]
|
||||
}
|
||||
|
||||
group("fuzzers") {
|
||||
testonly = true
|
||||
deps = []
|
||||
|
||||
if (!build_with_chromium || use_fuzzing_engine) {
|
||||
deps += [ ":fuzzers_bin" ]
|
||||
}
|
||||
}
|
||||
|
||||
if (!build_with_chromium || use_fuzzing_engine) {
|
||||
group("fuzzers_bin") {
|
||||
testonly = true
|
||||
|
||||
deps = [
|
||||
":spvtools_as_fuzzer",
|
||||
":spvtools_binary_parser_fuzzer",
|
||||
":spvtools_dis_fuzzer",
|
||||
":spvtools_opt_legalization_fuzzer",
|
||||
":spvtools_opt_performance_fuzzer",
|
||||
":spvtools_opt_size_fuzzer",
|
||||
":spvtools_opt_webgputovulkan_fuzzer",
|
||||
":spvtools_opt_vulkantowebgpu_fuzzer",
|
||||
":spvtools_val_fuzzer",
|
||||
":spvtools_val_webgpu_fuzzer",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
template("spvtools_fuzzer") {
|
||||
source_set(target_name) {
|
||||
testonly = true
|
||||
sources = invoker.sources
|
||||
deps = [
|
||||
"../..:spvtools",
|
||||
"../..:spvtools_opt",
|
||||
"../..:spvtools_val",
|
||||
]
|
||||
if (defined(invoker.deps)) {
|
||||
deps += invoker.deps
|
||||
}
|
||||
|
||||
configs -= [ "//build/config/compiler:chromium_code" ]
|
||||
configs += [
|
||||
"//build/config/compiler:no_chromium_code",
|
||||
":fuzzer_config",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
spvtools_fuzzer("spvtools_as_fuzzer_src") {
|
||||
sources = [
|
||||
"spvtools_as_fuzzer.cpp",
|
||||
]
|
||||
}
|
||||
|
||||
spvtools_fuzzer("spvtools_binary_parser_fuzzer_src") {
|
||||
sources = [
|
||||
"spvtools_binary_parser_fuzzer.cpp",
|
||||
]
|
||||
}
|
||||
|
||||
spvtools_fuzzer("spvtools_dis_fuzzer_src") {
|
||||
sources = [
|
||||
"spvtools_dis_fuzzer.cpp",
|
||||
]
|
||||
}
|
||||
|
||||
spvtools_fuzzer("spvtools_opt_performance_fuzzer_src") {
|
||||
sources = [
|
||||
"spvtools_opt_performance_fuzzer.cpp",
|
||||
]
|
||||
}
|
||||
|
||||
spvtools_fuzzer("spvtools_opt_legalization_fuzzer_src") {
|
||||
sources = [
|
||||
"spvtools_opt_legalization_fuzzer.cpp",
|
||||
]
|
||||
}
|
||||
|
||||
spvtools_fuzzer("spvtools_opt_size_fuzzer_src") {
|
||||
sources = [
|
||||
"spvtools_opt_size_fuzzer.cpp",
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
spvtools_fuzzer("spvtools_opt_webgputovulkan_fuzzer_src") {
|
||||
sources = [
|
||||
"spvtools_opt_webgputovulkan_fuzzer.cpp",
|
||||
]
|
||||
}
|
||||
|
||||
spvtools_fuzzer("spvtools_opt_vulkantowebgpu_fuzzer_src") {
|
||||
sources = [
|
||||
"spvtools_opt_vulkantowebgpu_fuzzer.cpp",
|
||||
]
|
||||
}
|
||||
|
||||
spvtools_fuzzer("spvtools_val_fuzzer_src") {
|
||||
sources = [
|
||||
"spvtools_val_fuzzer.cpp",
|
||||
]
|
||||
}
|
||||
|
||||
spvtools_fuzzer("spvtools_val_webgpu_fuzzer_src") {
|
||||
sources = [
|
||||
"spvtools_val_webgpu_fuzzer.cpp",
|
||||
]
|
||||
}
|
||||
|
||||
if (!build_with_chromium || use_fuzzing_engine) {
|
||||
fuzzer_test("spvtools_as_fuzzer") {
|
||||
sources = []
|
||||
deps = [
|
||||
":spvtools_as_fuzzer_src",
|
||||
]
|
||||
# Intentionally doesn't use the seed corpus, because it consumes
|
||||
# part of the input as not part of the file.
|
||||
}
|
||||
|
||||
fuzzer_test("spvtools_binary_parser_fuzzer") {
|
||||
sources = []
|
||||
deps = [
|
||||
":spvtools_binary_parser_fuzzer_src",
|
||||
]
|
||||
# Intentionally doesn't use the seed corpus, because it consumes
|
||||
# part of the input as not part of the file.
|
||||
}
|
||||
|
||||
fuzzer_test("spvtools_dis_fuzzer") {
|
||||
sources = []
|
||||
deps = [
|
||||
":spvtools_dis_fuzzer_src",
|
||||
]
|
||||
# Intentionally doesn't use the seed corpus, because it consumes
|
||||
# part of the input as not part of the file.
|
||||
}
|
||||
|
||||
fuzzer_test("spvtools_opt_performance_fuzzer") {
|
||||
sources = []
|
||||
deps = [
|
||||
":spvtools_opt_performance_fuzzer_src",
|
||||
]
|
||||
seed_corpus = "corpora/spv"
|
||||
}
|
||||
|
||||
fuzzer_test("spvtools_opt_legalization_fuzzer") {
|
||||
sources = []
|
||||
deps = [
|
||||
":spvtools_opt_legalization_fuzzer_src",
|
||||
]
|
||||
seed_corpus = "corpora/spv"
|
||||
}
|
||||
|
||||
fuzzer_test("spvtools_opt_size_fuzzer") {
|
||||
sources = []
|
||||
deps = [
|
||||
":spvtools_opt_size_fuzzer_src",
|
||||
]
|
||||
seed_corpus = "corpora/spv"
|
||||
}
|
||||
|
||||
fuzzer_test("spvtools_opt_webgputovulkan_fuzzer") {
|
||||
sources = []
|
||||
deps = [
|
||||
":spvtools_opt_webgputovulkan_fuzzer_src",
|
||||
]
|
||||
seed_corpus = "corpora/spv"
|
||||
}
|
||||
|
||||
fuzzer_test("spvtools_opt_vulkantowebgpu_fuzzer") {
|
||||
sources = []
|
||||
deps = [
|
||||
":spvtools_opt_vulkantowebgpu_fuzzer_src",
|
||||
]
|
||||
seed_corpus = "corpora/spv"
|
||||
}
|
||||
|
||||
fuzzer_test("spvtools_val_fuzzer") {
|
||||
sources = []
|
||||
deps = [
|
||||
":spvtools_val_fuzzer_src",
|
||||
]
|
||||
seed_corpus = "corpora/spv"
|
||||
}
|
||||
|
||||
fuzzer_test("spvtools_val_webgpu_fuzzer") {
|
||||
sources = []
|
||||
deps = [
|
||||
":spvtools_val_webgpu_fuzzer_src",
|
||||
]
|
||||
seed_corpus = "corpora/spv"
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -1,72 +0,0 @@
|
||||
// Copyright (c) 2019 Google Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring> // memcpy
|
||||
#include <vector>
|
||||
|
||||
#include "source/spirv_target_env.h"
|
||||
#include "spirv-tools/libspirv.hpp"
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
||||
if (size < sizeof(spv_target_env) + 1) return 0;
|
||||
|
||||
const spv_context context =
|
||||
spvContextCreate(*reinterpret_cast<const spv_target_env*>(data));
|
||||
if (context == nullptr) return 0;
|
||||
|
||||
data += sizeof(spv_target_env);
|
||||
size -= sizeof(spv_target_env);
|
||||
|
||||
std::vector<uint32_t> input;
|
||||
|
||||
std::vector<char> input_str;
|
||||
size_t char_count = input.size() * sizeof(uint32_t) / sizeof(char);
|
||||
input_str.resize(char_count);
|
||||
memcpy(input_str.data(), input.data(), input.size() * sizeof(uint32_t));
|
||||
|
||||
spv_binary binary = nullptr;
|
||||
spv_diagnostic diagnostic = nullptr;
|
||||
spvTextToBinaryWithOptions(context, input_str.data(), input_str.size(),
|
||||
SPV_TEXT_TO_BINARY_OPTION_NONE, &binary,
|
||||
&diagnostic);
|
||||
if (diagnostic) {
|
||||
spvDiagnosticPrint(diagnostic);
|
||||
spvDiagnosticDestroy(diagnostic);
|
||||
diagnostic = nullptr;
|
||||
}
|
||||
|
||||
if (binary) {
|
||||
spvBinaryDestroy(binary);
|
||||
binary = nullptr;
|
||||
}
|
||||
|
||||
spvTextToBinaryWithOptions(context, input_str.data(), input_str.size(),
|
||||
SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS,
|
||||
&binary, &diagnostic);
|
||||
if (diagnostic) {
|
||||
spvDiagnosticPrint(diagnostic);
|
||||
spvDiagnosticDestroy(diagnostic);
|
||||
diagnostic = nullptr;
|
||||
}
|
||||
|
||||
if (binary) {
|
||||
spvBinaryDestroy(binary);
|
||||
binary = nullptr;
|
||||
}
|
||||
|
||||
spvContextDestroy(context);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
// Copyright (c) 2018 Google Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
#include "spirv-tools/libspirv.hpp"
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
||||
if (size < sizeof(spv_target_env) + 1) return 0;
|
||||
|
||||
const spv_context context =
|
||||
spvContextCreate(*reinterpret_cast<const spv_target_env*>(data));
|
||||
if (context == nullptr) return 0;
|
||||
|
||||
data += sizeof(spv_target_env);
|
||||
size -= sizeof(spv_target_env);
|
||||
|
||||
std::vector<uint32_t> input;
|
||||
input.resize(size >> 2);
|
||||
|
||||
size_t count = 0;
|
||||
for (size_t i = 0; (i + 3) < size; i += 4) {
|
||||
input[count++] = data[i] | (data[i + 1] << 8) | (data[i + 2] << 16) |
|
||||
(data[i + 3]) << 24;
|
||||
}
|
||||
|
||||
spvBinaryParse(context, nullptr, input.data(), input.size(), nullptr, nullptr,
|
||||
nullptr);
|
||||
|
||||
spvContextDestroy(context);
|
||||
return 0;
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
// Copyright (c) 2019 Google Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring> // memcpy
|
||||
#include <vector>
|
||||
|
||||
#include "source/spirv_target_env.h"
|
||||
#include "spirv-tools/libspirv.hpp"
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
||||
if (size < sizeof(spv_target_env) + 1) return 0;
|
||||
|
||||
const spv_context context =
|
||||
spvContextCreate(*reinterpret_cast<const spv_target_env*>(data));
|
||||
if (context == nullptr) return 0;
|
||||
|
||||
data += sizeof(spv_target_env);
|
||||
size -= sizeof(spv_target_env);
|
||||
|
||||
std::vector<uint32_t> input;
|
||||
input.resize(size >> 2);
|
||||
size_t count = 0;
|
||||
for (size_t i = 0; (i + 3) < size; i += 4) {
|
||||
input[count++] = data[i] | (data[i + 1] << 8) | (data[i + 2] << 16) |
|
||||
(data[i + 3]) << 24;
|
||||
}
|
||||
|
||||
std::vector<char> input_str;
|
||||
size_t char_count = input.size() * sizeof(uint32_t) / sizeof(char);
|
||||
input_str.resize(char_count);
|
||||
memcpy(input_str.data(), input.data(), input.size() * sizeof(uint32_t));
|
||||
|
||||
spv_text text = nullptr;
|
||||
spv_diagnostic diagnostic = nullptr;
|
||||
|
||||
for (uint32_t options = SPV_BINARY_TO_TEXT_OPTION_NONE;
|
||||
options <
|
||||
(SPV_BINARY_TO_TEXT_OPTION_PRINT | SPV_BINARY_TO_TEXT_OPTION_COLOR |
|
||||
SPV_BINARY_TO_TEXT_OPTION_INDENT |
|
||||
SPV_BINARY_TO_TEXT_OPTION_SHOW_BYTE_OFFSET |
|
||||
SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
|
||||
SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
|
||||
options++) {
|
||||
spvBinaryToText(context, input.data(), input.size(), options, &text,
|
||||
&diagnostic);
|
||||
if (diagnostic) {
|
||||
spvDiagnosticDestroy(diagnostic);
|
||||
diagnostic = nullptr;
|
||||
}
|
||||
|
||||
if (text) {
|
||||
spvTextDestroy(text);
|
||||
text = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
spvContextDestroy(context);
|
||||
return 0;
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
// Copyright (c) 2018 Google Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
#include "spirv-tools/optimizer.hpp"
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
||||
spvtools::Optimizer optimizer(SPV_ENV_UNIVERSAL_1_3);
|
||||
optimizer.SetMessageConsumer([](spv_message_level_t, const char*,
|
||||
const spv_position_t&, const char*) {});
|
||||
|
||||
std::vector<uint32_t> input;
|
||||
input.resize(size >> 2);
|
||||
|
||||
size_t count = 0;
|
||||
for (size_t i = 0; (i + 3) < size; i += 4) {
|
||||
input[count++] = data[i] | (data[i + 1] << 8) | (data[i + 2] << 16) |
|
||||
(data[i + 3]) << 24;
|
||||
}
|
||||
|
||||
optimizer.RegisterLegalizationPasses();
|
||||
optimizer.Run(input.data(), input.size(), &input);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
// Copyright (c) 2018 Google Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
#include "spirv-tools/optimizer.hpp"
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
||||
spvtools::Optimizer optimizer(SPV_ENV_UNIVERSAL_1_3);
|
||||
optimizer.SetMessageConsumer([](spv_message_level_t, const char*,
|
||||
const spv_position_t&, const char*) {});
|
||||
|
||||
std::vector<uint32_t> input;
|
||||
input.resize(size >> 2);
|
||||
|
||||
size_t count = 0;
|
||||
for (size_t i = 0; (i + 3) < size; i += 4) {
|
||||
input[count++] = data[i] | (data[i + 1] << 8) | (data[i + 2] << 16) |
|
||||
(data[i + 3]) << 24;
|
||||
}
|
||||
|
||||
optimizer.RegisterPerformancePasses();
|
||||
optimizer.Run(input.data(), input.size(), &input);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
// Copyright (c) 2018 Google Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
#include "spirv-tools/optimizer.hpp"
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
||||
spvtools::Optimizer optimizer(SPV_ENV_UNIVERSAL_1_3);
|
||||
optimizer.SetMessageConsumer([](spv_message_level_t, const char*,
|
||||
const spv_position_t&, const char*) {});
|
||||
|
||||
std::vector<uint32_t> input;
|
||||
input.resize(size >> 2);
|
||||
|
||||
size_t count = 0;
|
||||
for (size_t i = 0; (i + 3) < size; i += 4) {
|
||||
input[count++] = data[i] | (data[i + 1] << 8) | (data[i + 2] << 16) |
|
||||
(data[i + 3]) << 24;
|
||||
}
|
||||
|
||||
optimizer.RegisterSizePasses();
|
||||
optimizer.Run(input.data(), input.size(), &input);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
// Copyright (c) 2019 Google Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
#include "spirv-tools/optimizer.hpp"
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
||||
spvtools::Optimizer optimizer(SPV_ENV_VULKAN_1_1);
|
||||
optimizer.SetMessageConsumer([](spv_message_level_t, const char*,
|
||||
const spv_position_t&, const char*) {});
|
||||
|
||||
std::vector<uint32_t> input;
|
||||
input.resize(size >> 2);
|
||||
|
||||
size_t count = 0;
|
||||
for (size_t i = 0; (i + 3) < size; i += 4) {
|
||||
input[count++] = data[i] | (data[i + 1] << 8) | (data[i + 2] << 16) |
|
||||
(data[i + 3]) << 24;
|
||||
}
|
||||
|
||||
optimizer.RegisterVulkanToWebGPUPasses();
|
||||
optimizer.Run(input.data(), input.size(), &input);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
// Copyright (c) 2019 Google Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
#include "spirv-tools/optimizer.hpp"
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
||||
spvtools::Optimizer optimizer(SPV_ENV_WEBGPU_0);
|
||||
optimizer.SetMessageConsumer([](spv_message_level_t, const char*,
|
||||
const spv_position_t&, const char*) {});
|
||||
|
||||
std::vector<uint32_t> input;
|
||||
input.resize(size >> 2);
|
||||
|
||||
size_t count = 0;
|
||||
for (size_t i = 0; (i + 3) < size; i += 4) {
|
||||
input[count++] = data[i] | (data[i + 1] << 8) | (data[i + 2] << 16) |
|
||||
(data[i + 3]) << 24;
|
||||
}
|
||||
|
||||
optimizer.RegisterWebGPUToVulkanPasses();
|
||||
optimizer.Run(input.data(), input.size(), &input);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
// Copyright (c) 2018 Google Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
#include "spirv-tools/libspirv.hpp"
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
||||
spvtools::SpirvTools tools(SPV_ENV_UNIVERSAL_1_3);
|
||||
tools.SetMessageConsumer([](spv_message_level_t, const char*,
|
||||
const spv_position_t&, const char*) {});
|
||||
|
||||
std::vector<uint32_t> input;
|
||||
input.resize(size >> 2);
|
||||
|
||||
size_t count = 0;
|
||||
for (size_t i = 0; (i + 3) < size; i += 4) {
|
||||
input[count++] = data[i] | (data[i + 1] << 8) | (data[i + 2] << 16) |
|
||||
(data[i + 3]) << 24;
|
||||
}
|
||||
|
||||
tools.Validate(input);
|
||||
return 0;
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
// Copyright (c) 2019 Google Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
#include "spirv-tools/libspirv.hpp"
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
||||
spvtools::SpirvTools tools(SPV_ENV_WEBGPU_0);
|
||||
tools.SetMessageConsumer([](spv_message_level_t, const char*,
|
||||
const spv_position_t&, const char*) {});
|
||||
|
||||
std::vector<uint32_t> input;
|
||||
input.resize(size >> 2);
|
||||
|
||||
size_t count = 0;
|
||||
for (size_t i = 0; (i + 3) < size; i += 4) {
|
||||
input[count++] = data[i] | (data[i + 1] << 8) | (data[i + 2] << 16) |
|
||||
(data[i + 3]) << 24;
|
||||
}
|
||||
|
||||
tools.Validate(input);
|
||||
return 0;
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
// Copyright (c) 2015-2016 The Khronos Group Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "source/opcode.h"
|
||||
#include "test/unit_spirv.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace {
|
||||
|
||||
using ::spvtest::EnumCase;
|
||||
using ::testing::Eq;
|
||||
using GeneratorMagicNumberTest =
|
||||
::testing::TestWithParam<EnumCase<spv_generator_t>>;
|
||||
|
||||
TEST_P(GeneratorMagicNumberTest, Single) {
|
||||
EXPECT_THAT(std::string(spvGeneratorStr(GetParam().value())),
|
||||
GetParam().name());
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
Registered, GeneratorMagicNumberTest,
|
||||
::testing::ValuesIn(std::vector<EnumCase<spv_generator_t>>{
|
||||
{SPV_GENERATOR_KHRONOS, "Khronos"},
|
||||
{SPV_GENERATOR_LUNARG, "LunarG"},
|
||||
{SPV_GENERATOR_VALVE, "Valve"},
|
||||
{SPV_GENERATOR_CODEPLAY, "Codeplay"},
|
||||
{SPV_GENERATOR_NVIDIA, "NVIDIA"},
|
||||
{SPV_GENERATOR_ARM, "ARM"},
|
||||
{SPV_GENERATOR_KHRONOS_LLVM_TRANSLATOR,
|
||||
"Khronos LLVM/SPIR-V Translator"},
|
||||
{SPV_GENERATOR_KHRONOS_ASSEMBLER, "Khronos SPIR-V Tools Assembler"},
|
||||
{SPV_GENERATOR_KHRONOS_GLSLANG, "Khronos Glslang Reference Front End"},
|
||||
}));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
Unregistered, GeneratorMagicNumberTest,
|
||||
::testing::ValuesIn(std::vector<EnumCase<spv_generator_t>>{
|
||||
// We read registered entries from the SPIR-V XML Registry file
|
||||
// which can change over time.
|
||||
{spv_generator_t(1000), "Unknown"},
|
||||
{spv_generator_t(9999), "Unknown"},
|
||||
}));
|
||||
|
||||
} // namespace
|
||||
} // namespace spvtools
|
||||
1331
3rdparty/spirv-tools/test/hex_float_test.cpp
vendored
1331
3rdparty/spirv-tools/test/hex_float_test.cpp
vendored
File diff suppressed because it is too large
Load Diff
291
3rdparty/spirv-tools/test/immediate_int_test.cpp
vendored
291
3rdparty/spirv-tools/test/immediate_int_test.cpp
vendored
@@ -1,291 +0,0 @@
|
||||
// Copyright (c) 2015-2016 The Khronos Group Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <cassert>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "source/util/bitutils.h"
|
||||
#include "test/test_fixture.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace utils {
|
||||
namespace {
|
||||
|
||||
using spvtest::Concatenate;
|
||||
using spvtest::MakeInstruction;
|
||||
using spvtest::ScopedContext;
|
||||
using spvtest::TextToBinaryTest;
|
||||
using ::testing::ElementsAre;
|
||||
using ::testing::Eq;
|
||||
using ::testing::HasSubstr;
|
||||
using ::testing::StrEq;
|
||||
|
||||
TEST_F(TextToBinaryTest, ImmediateIntOpCode) {
|
||||
SetText("!0x00FF00FF");
|
||||
ASSERT_EQ(SPV_SUCCESS, spvTextToBinary(ScopedContext().context, text.str,
|
||||
text.length, &binary, &diagnostic));
|
||||
EXPECT_EQ(0x00FF00FFu, binary->code[5]);
|
||||
if (diagnostic) {
|
||||
spvDiagnosticPrint(diagnostic);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(TextToBinaryTest, ImmediateIntOperand) {
|
||||
SetText("OpCapability !0x00FF00FF");
|
||||
EXPECT_EQ(SPV_SUCCESS, spvTextToBinary(ScopedContext().context, text.str,
|
||||
text.length, &binary, &diagnostic));
|
||||
EXPECT_EQ(0x00FF00FFu, binary->code[6]);
|
||||
if (diagnostic) {
|
||||
spvDiagnosticPrint(diagnostic);
|
||||
}
|
||||
}
|
||||
|
||||
using ImmediateIntTest = TextToBinaryTest;
|
||||
|
||||
TEST_F(ImmediateIntTest, AnyWordInSimpleStatement) {
|
||||
EXPECT_THAT(CompiledInstructions("!0x00040018 %a %b %123"),
|
||||
Eq(MakeInstruction(SpvOpTypeMatrix, {1, 2, 3})));
|
||||
EXPECT_THAT(CompiledInstructions("!0x00040018 !1 %b %123"),
|
||||
Eq(MakeInstruction(SpvOpTypeMatrix, {1, 1, 2})));
|
||||
EXPECT_THAT(CompiledInstructions("%a = OpTypeMatrix !2 %123"),
|
||||
Eq(MakeInstruction(SpvOpTypeMatrix, {1, 2, 2})));
|
||||
EXPECT_THAT(CompiledInstructions("%a = OpTypeMatrix %b !123"),
|
||||
Eq(MakeInstruction(SpvOpTypeMatrix, {1, 2, 123})));
|
||||
EXPECT_THAT(CompiledInstructions("!0x00040018 %a !2 %123"),
|
||||
Eq(MakeInstruction(SpvOpTypeMatrix, {1, 2, 2})));
|
||||
EXPECT_THAT(CompiledInstructions("!0x00040018 !1 %b !123"),
|
||||
Eq(MakeInstruction(SpvOpTypeMatrix, {1, 1, 123})));
|
||||
EXPECT_THAT(CompiledInstructions("!0x00040018 !1 !2 !123"),
|
||||
Eq(MakeInstruction(SpvOpTypeMatrix, {1, 2, 123})));
|
||||
}
|
||||
|
||||
TEST_F(ImmediateIntTest, AnyWordAfterEqualsAndOpCode) {
|
||||
EXPECT_THAT(CompiledInstructions("%a = OpArrayLength !2 %c 123"),
|
||||
Eq(MakeInstruction(SpvOpArrayLength, {2, 1, 2, 123})));
|
||||
EXPECT_THAT(CompiledInstructions("%a = OpArrayLength %b !3 123"),
|
||||
Eq(MakeInstruction(SpvOpArrayLength, {1, 2, 3, 123})));
|
||||
EXPECT_THAT(CompiledInstructions("%a = OpArrayLength %b %c !123"),
|
||||
Eq(MakeInstruction(SpvOpArrayLength, {1, 2, 3, 123})));
|
||||
EXPECT_THAT(CompiledInstructions("%a = OpArrayLength %b !3 !123"),
|
||||
Eq(MakeInstruction(SpvOpArrayLength, {1, 2, 3, 123})));
|
||||
EXPECT_THAT(CompiledInstructions("%a = OpArrayLength !2 !3 123"),
|
||||
Eq(MakeInstruction(SpvOpArrayLength, {2, 1, 3, 123})));
|
||||
EXPECT_THAT(CompiledInstructions("%a = OpArrayLength !2 !3 !123"),
|
||||
Eq(MakeInstruction(SpvOpArrayLength, {2, 1, 3, 123})));
|
||||
}
|
||||
|
||||
TEST_F(ImmediateIntTest, ResultIdInAssignment) {
|
||||
EXPECT_EQ("!2 not allowed before =.",
|
||||
CompileFailure("!2 = OpArrayLength %12 %1 123"));
|
||||
EXPECT_EQ("!2 not allowed before =.",
|
||||
CompileFailure("!2 = !0x00040044 %12 %1 123"));
|
||||
}
|
||||
|
||||
TEST_F(ImmediateIntTest, OpCodeInAssignment) {
|
||||
EXPECT_EQ("Invalid Opcode prefix '!0x00040044'.",
|
||||
CompileFailure("%2 = !0x00040044 %12 %1 123"));
|
||||
}
|
||||
|
||||
// Literal integers after !<integer> are handled correctly.
|
||||
TEST_F(ImmediateIntTest, IntegerFollowingImmediate) {
|
||||
const SpirvVector original = CompiledInstructions("%1 = OpTypeInt 8 1");
|
||||
EXPECT_EQ(original, CompiledInstructions("!0x00040015 1 8 1"));
|
||||
EXPECT_EQ(original, CompiledInstructions("!0x00040015 !1 8 1"));
|
||||
|
||||
// With !<integer>, we can (and can only) accept 32-bit number literals,
|
||||
// even when we declare the return type is 64-bit.
|
||||
EXPECT_EQ(Concatenate({
|
||||
MakeInstruction(SpvOpTypeInt, {1, 64, 0}),
|
||||
MakeInstruction(SpvOpConstant, {1, 2, 4294967295}),
|
||||
}),
|
||||
CompiledInstructions("%i64 = OpTypeInt 64 0\n"
|
||||
"!0x0004002b %i64 !2 4294967295"));
|
||||
// 64-bit integer literal.
|
||||
EXPECT_EQ("Invalid word following !<integer>: 5000000000",
|
||||
CompileFailure("%2 = OpConstant !1 5000000000"));
|
||||
EXPECT_EQ("Invalid word following !<integer>: 5000000000",
|
||||
CompileFailure("%i64 = OpTypeInt 64 0\n"
|
||||
"!0x0005002b %i64 !2 5000000000"));
|
||||
|
||||
// Negative integer.
|
||||
EXPECT_EQ(CompiledInstructions("%i64 = OpTypeInt 32 1\n"
|
||||
"%2 = OpConstant %i64 -123"),
|
||||
CompiledInstructions("%i64 = OpTypeInt 32 1\n"
|
||||
"!0x0004002b %i64 !2 -123"));
|
||||
|
||||
// TODO(deki): uncomment assertions below and make them pass.
|
||||
// Hex value(s).
|
||||
// EXPECT_EQ(CompileSuccessfully("%1 = OpConstant %10 0x12345678"),
|
||||
// CompileSuccessfully("OpConstant %10 !1 0x12345678", kCAF));
|
||||
// EXPECT_EQ(
|
||||
// CompileSuccessfully("%1 = OpConstant %10 0x12345678 0x87654321"),
|
||||
// CompileSuccessfully("OpConstant %10 !1 0x12345678 0x87654321", kCAF));
|
||||
}
|
||||
|
||||
// Literal floats after !<integer> are handled correctly.
|
||||
TEST_F(ImmediateIntTest, FloatFollowingImmediate) {
|
||||
EXPECT_EQ(
|
||||
CompiledInstructions("%1 = OpTypeFloat 32\n%2 = OpConstant %1 0.123"),
|
||||
CompiledInstructions("%1 = OpTypeFloat 32\n!0x0004002b %1 !2 0.123"));
|
||||
EXPECT_EQ(
|
||||
CompiledInstructions("%1 = OpTypeFloat 32\n%2 = OpConstant %1 -0.5"),
|
||||
CompiledInstructions("%1 = OpTypeFloat 32\n!0x0004002b %1 !2 -0.5"));
|
||||
EXPECT_EQ(
|
||||
CompiledInstructions("%1 = OpTypeFloat 32\n%2 = OpConstant %1 0.123"),
|
||||
CompiledInstructions("%1 = OpTypeFloat 32\n!0x0004002b %1 %2 0.123"));
|
||||
EXPECT_EQ(
|
||||
CompiledInstructions("%1 = OpTypeFloat 32\n%2 = OpConstant %1 -0.5"),
|
||||
CompiledInstructions("%1 = OpTypeFloat 32\n!0x0004002b %1 %2 -0.5"));
|
||||
|
||||
EXPECT_EQ(Concatenate({
|
||||
MakeInstruction(SpvOpTypeInt, {1, 64, 0}),
|
||||
MakeInstruction(SpvOpConstant, {1, 2, 0xb, 0xa}),
|
||||
MakeInstruction(SpvOpSwitch,
|
||||
{2, 1234, BitwiseCast<uint32_t>(2.5f), 3}),
|
||||
}),
|
||||
CompiledInstructions("%i64 = OpTypeInt 64 0\n"
|
||||
"%big = OpConstant %i64 0xa0000000b\n"
|
||||
"OpSwitch %big !1234 2.5 %target\n"));
|
||||
}
|
||||
|
||||
// Literal strings after !<integer> are handled correctly.
|
||||
TEST_F(ImmediateIntTest, StringFollowingImmediate) {
|
||||
// Try a variety of strings, including empty and single-character.
|
||||
for (std::string name : {"", "s", "longish", "really looooooooooooooooong"}) {
|
||||
const SpirvVector original =
|
||||
CompiledInstructions("OpMemberName %10 4 \"" + name + "\"");
|
||||
EXPECT_EQ(original,
|
||||
CompiledInstructions("OpMemberName %10 !4 \"" + name + "\""))
|
||||
<< name;
|
||||
EXPECT_EQ(original,
|
||||
CompiledInstructions("OpMemberName !1 !4 \"" + name + "\""))
|
||||
<< name;
|
||||
const uint16_t wordCount = static_cast<uint16_t>(4 + name.size() / 4);
|
||||
const uint32_t firstWord = spvOpcodeMake(wordCount, SpvOpMemberName);
|
||||
EXPECT_EQ(original, CompiledInstructions("!" + std::to_string(firstWord) +
|
||||
" %10 !4 \"" + name + "\""))
|
||||
<< name;
|
||||
}
|
||||
}
|
||||
|
||||
// IDs after !<integer> are handled correctly.
|
||||
TEST_F(ImmediateIntTest, IdFollowingImmediate) {
|
||||
EXPECT_EQ(CompileSuccessfully("%123 = OpDecorationGroup"),
|
||||
CompileSuccessfully("!0x00020049 %123"));
|
||||
EXPECT_EQ(CompileSuccessfully("%group = OpDecorationGroup"),
|
||||
CompileSuccessfully("!0x00020049 %group"));
|
||||
}
|
||||
|
||||
// !<integer> after !<integer> is handled correctly.
|
||||
TEST_F(ImmediateIntTest, ImmediateFollowingImmediate) {
|
||||
const SpirvVector original = CompiledInstructions("%a = OpTypeMatrix %b 7");
|
||||
EXPECT_EQ(original, CompiledInstructions("%a = OpTypeMatrix !2 !7"));
|
||||
EXPECT_EQ(original, CompiledInstructions("!0x00040018 %a !2 !7"));
|
||||
}
|
||||
|
||||
TEST_F(ImmediateIntTest, InvalidStatement) {
|
||||
EXPECT_THAT(Subvector(CompileSuccessfully("!4 !3 !2 !1"), kFirstInstruction),
|
||||
ElementsAre(4, 3, 2, 1));
|
||||
}
|
||||
|
||||
TEST_F(ImmediateIntTest, InvalidStatementBetweenValidOnes) {
|
||||
EXPECT_THAT(Subvector(CompileSuccessfully(
|
||||
"%10 = OpTypeFloat 32 !5 !6 !7 OpEmitVertex"),
|
||||
kFirstInstruction),
|
||||
ElementsAre(spvOpcodeMake(3, SpvOpTypeFloat), 1, 32, 5, 6, 7,
|
||||
spvOpcodeMake(1, SpvOpEmitVertex)));
|
||||
}
|
||||
|
||||
TEST_F(ImmediateIntTest, NextOpcodeRecognized) {
|
||||
const SpirvVector original = CompileSuccessfully(R"(
|
||||
%1 = OpLoad %10 %2 Volatile
|
||||
%4 = OpCompositeInsert %11 %1 %3 0 1 2
|
||||
)");
|
||||
const SpirvVector alternate = CompileSuccessfully(R"(
|
||||
%1 = OpLoad %10 %2 !1
|
||||
%4 = OpCompositeInsert %11 %1 %3 0 1 2
|
||||
)");
|
||||
EXPECT_EQ(original, alternate);
|
||||
}
|
||||
|
||||
TEST_F(ImmediateIntTest, WrongLengthButNextOpcodeStillRecognized) {
|
||||
const SpirvVector original = CompileSuccessfully(R"(
|
||||
%1 = OpLoad %10 %2 Volatile
|
||||
OpCopyMemorySized %3 %4 %1
|
||||
)");
|
||||
const SpirvVector alternate = CompileSuccessfully(R"(
|
||||
!0x0002003D %10 %1 %2 !1
|
||||
OpCopyMemorySized %3 %4 %1
|
||||
)");
|
||||
EXPECT_EQ(0x0002003Du, alternate[kFirstInstruction]);
|
||||
EXPECT_EQ(Subvector(original, kFirstInstruction + 1),
|
||||
Subvector(alternate, kFirstInstruction + 1));
|
||||
}
|
||||
|
||||
// Like NextOpcodeRecognized, but next statement is in assignment form.
|
||||
TEST_F(ImmediateIntTest, NextAssignmentRecognized) {
|
||||
const SpirvVector original = CompileSuccessfully(R"(
|
||||
%1 = OpLoad %10 %2 None
|
||||
%4 = OpFunctionCall %10 %3 %123
|
||||
)");
|
||||
const SpirvVector alternate = CompileSuccessfully(R"(
|
||||
%1 = OpLoad %10 %2 !0
|
||||
%4 = OpFunctionCall %10 %3 %123
|
||||
)");
|
||||
EXPECT_EQ(original, alternate);
|
||||
}
|
||||
|
||||
// Two instructions in a row each have !<integer> opcode.
|
||||
TEST_F(ImmediateIntTest, ConsecutiveImmediateOpcodes) {
|
||||
const SpirvVector original = CompileSuccessfully(R"(
|
||||
%1 = OpConstantSampler %10 Clamp 78 Linear
|
||||
%4 = OpFRem %11 %3 %2
|
||||
%5 = OpIsValidEvent %12 %2
|
||||
)");
|
||||
const SpirvVector alternate = CompileSuccessfully(R"(
|
||||
!0x0006002D %10 %1 !2 78 !1
|
||||
!0x0005008C %11 %4 %3 %2
|
||||
%5 = OpIsValidEvent %12 %2
|
||||
)");
|
||||
EXPECT_EQ(original, alternate);
|
||||
}
|
||||
|
||||
// !<integer> followed by, eg, an enum or '=' or a random bareword.
|
||||
TEST_F(ImmediateIntTest, ForbiddenOperands) {
|
||||
EXPECT_THAT(CompileFailure("OpMemoryModel !0 OpenCL"), HasSubstr("OpenCL"));
|
||||
EXPECT_THAT(CompileFailure("!1 %0 = !2"), HasSubstr("="));
|
||||
EXPECT_THAT(CompileFailure("OpMemoryModel !0 random_bareword"),
|
||||
HasSubstr("random_bareword"));
|
||||
// Immediate integers longer than one 32-bit word.
|
||||
EXPECT_THAT(CompileFailure("!5000000000"), HasSubstr("5000000000"));
|
||||
EXPECT_THAT(CompileFailure("!999999999999999999"),
|
||||
HasSubstr("999999999999999999"));
|
||||
EXPECT_THAT(CompileFailure("!0x00020049 !5000000000"),
|
||||
HasSubstr("5000000000"));
|
||||
// Negative numbers.
|
||||
EXPECT_THAT(CompileFailure("!0x00020049 !-123"), HasSubstr("-123"));
|
||||
}
|
||||
|
||||
TEST_F(ImmediateIntTest, NotInteger) {
|
||||
EXPECT_THAT(CompileFailure("!abc"), StrEq("Invalid immediate integer: !abc"));
|
||||
EXPECT_THAT(CompileFailure("!12.3"),
|
||||
StrEq("Invalid immediate integer: !12.3"));
|
||||
EXPECT_THAT(CompileFailure("!12K"), StrEq("Invalid immediate integer: !12K"));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace utils
|
||||
} // namespace spvtools
|
||||
@@ -1,25 +0,0 @@
|
||||
// Copyright (c) 2015-2016 The Khronos Group Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "test/unit_spirv.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace {
|
||||
|
||||
TEST(Macros, BitShiftInnerParens) { ASSERT_EQ(65536, SPV_BIT(2 << 3)); }
|
||||
|
||||
TEST(Macros, BitShiftOuterParens) { ASSERT_EQ(15, SPV_BIT(4) - 1); }
|
||||
|
||||
} // namespace
|
||||
} // namespace spvtools
|
||||
28
3rdparty/spirv-tools/test/link/CMakeLists.txt
vendored
28
3rdparty/spirv-tools/test/link/CMakeLists.txt
vendored
@@ -1,28 +0,0 @@
|
||||
# Copyright (c) 2017 Pierre Moreau
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
|
||||
add_spvtools_unittest(TARGET link
|
||||
SRCS
|
||||
binary_version_test.cpp
|
||||
entry_points_test.cpp
|
||||
global_values_amount_test.cpp
|
||||
ids_limit_test.cpp
|
||||
matching_imports_to_exports_test.cpp
|
||||
memory_model_test.cpp
|
||||
partial_linkage_test.cpp
|
||||
unique_ids_test.cpp
|
||||
type_match_test.cpp
|
||||
LIBS SPIRV-Tools-opt SPIRV-Tools-link
|
||||
)
|
||||
@@ -1,60 +0,0 @@
|
||||
// Copyright (c) 2017 Pierre Moreau
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "test/link/linker_fixture.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace {
|
||||
|
||||
using BinaryVersion = spvtest::LinkerTest;
|
||||
|
||||
TEST_F(BinaryVersion, LinkerChoosesMaxSpirvVersion) {
|
||||
// clang-format off
|
||||
spvtest::Binaries binaries = {
|
||||
{
|
||||
SpvMagicNumber,
|
||||
0x00000300u,
|
||||
SPV_GENERATOR_CODEPLAY,
|
||||
1u, // NOTE: Bound
|
||||
0u // NOTE: Schema; reserved
|
||||
},
|
||||
{
|
||||
SpvMagicNumber,
|
||||
0x00000600u,
|
||||
SPV_GENERATOR_CODEPLAY,
|
||||
1u, // NOTE: Bound
|
||||
0u // NOTE: Schema; reserved
|
||||
},
|
||||
{
|
||||
SpvMagicNumber,
|
||||
0x00000100u,
|
||||
SPV_GENERATOR_CODEPLAY,
|
||||
1u, // NOTE: Bound
|
||||
0u // NOTE: Schema; reserved
|
||||
}
|
||||
};
|
||||
// clang-format on
|
||||
spvtest::Binary linked_binary;
|
||||
|
||||
ASSERT_EQ(SPV_SUCCESS, Link(binaries, &linked_binary));
|
||||
EXPECT_THAT(GetErrorMessage(), std::string());
|
||||
|
||||
EXPECT_EQ(0x00000600u, linked_binary[1]);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace spvtools
|
||||
@@ -1,94 +0,0 @@
|
||||
// Copyright (c) 2017 Pierre Moreau
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "test/link/linker_fixture.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace {
|
||||
|
||||
using ::testing::HasSubstr;
|
||||
|
||||
class EntryPoints : public spvtest::LinkerTest {};
|
||||
|
||||
TEST_F(EntryPoints, SameModelDifferentName) {
|
||||
const std::string body1 = R"(
|
||||
OpEntryPoint GLCompute %3 "foo"
|
||||
%1 = OpTypeVoid
|
||||
%2 = OpTypeFunction %1
|
||||
%3 = OpFunction %1 None %2
|
||||
OpFunctionEnd
|
||||
)";
|
||||
const std::string body2 = R"(
|
||||
OpEntryPoint GLCompute %3 "bar"
|
||||
%1 = OpTypeVoid
|
||||
%2 = OpTypeFunction %1
|
||||
%3 = OpFunction %1 None %2
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
spvtest::Binary linked_binary;
|
||||
EXPECT_EQ(SPV_SUCCESS, AssembleAndLink({body1, body2}, &linked_binary));
|
||||
EXPECT_THAT(GetErrorMessage(), std::string());
|
||||
}
|
||||
|
||||
TEST_F(EntryPoints, DifferentModelSameName) {
|
||||
const std::string body1 = R"(
|
||||
OpEntryPoint GLCompute %3 "foo"
|
||||
%1 = OpTypeVoid
|
||||
%2 = OpTypeFunction %1
|
||||
%3 = OpFunction %1 None %2
|
||||
OpFunctionEnd
|
||||
)";
|
||||
const std::string body2 = R"(
|
||||
OpEntryPoint Vertex %3 "foo"
|
||||
%1 = OpTypeVoid
|
||||
%2 = OpTypeFunction %1
|
||||
%3 = OpFunction %1 None %2
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
spvtest::Binary linked_binary;
|
||||
EXPECT_EQ(SPV_SUCCESS, AssembleAndLink({body1, body2}, &linked_binary));
|
||||
EXPECT_THAT(GetErrorMessage(), std::string());
|
||||
}
|
||||
|
||||
TEST_F(EntryPoints, SameModelAndName) {
|
||||
const std::string body1 = R"(
|
||||
OpEntryPoint GLCompute %3 "foo"
|
||||
%1 = OpTypeVoid
|
||||
%2 = OpTypeFunction %1
|
||||
%3 = OpFunction %1 None %2
|
||||
OpFunctionEnd
|
||||
)";
|
||||
const std::string body2 = R"(
|
||||
OpEntryPoint GLCompute %3 "foo"
|
||||
%1 = OpTypeVoid
|
||||
%2 = OpTypeFunction %1
|
||||
%3 = OpFunction %1 None %2
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
spvtest::Binary linked_binary;
|
||||
EXPECT_EQ(SPV_ERROR_INTERNAL,
|
||||
AssembleAndLink({body1, body2}, &linked_binary));
|
||||
EXPECT_THAT(GetErrorMessage(),
|
||||
HasSubstr("The entry point \"foo\", with execution model "
|
||||
"GLCompute, was already defined."));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace spvtools
|
||||
@@ -1,153 +0,0 @@
|
||||
// Copyright (c) 2017 Pierre Moreau
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "test/link/linker_fixture.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace {
|
||||
|
||||
using ::testing::HasSubstr;
|
||||
|
||||
class EntryPointsAmountTest : public spvtest::LinkerTest {
|
||||
public:
|
||||
EntryPointsAmountTest() { binaries.reserve(0xFFFF); }
|
||||
|
||||
void SetUp() override {
|
||||
binaries.push_back({SpvMagicNumber,
|
||||
SpvVersion,
|
||||
SPV_GENERATOR_CODEPLAY,
|
||||
10u, // NOTE: Bound
|
||||
0u, // NOTE: Schema; reserved
|
||||
|
||||
3u << SpvWordCountShift | SpvOpTypeFloat,
|
||||
1u, // NOTE: Result ID
|
||||
32u, // NOTE: Width
|
||||
|
||||
4u << SpvWordCountShift | SpvOpTypePointer,
|
||||
2u, // NOTE: Result ID
|
||||
SpvStorageClassInput,
|
||||
1u, // NOTE: Type ID
|
||||
|
||||
2u << SpvWordCountShift | SpvOpTypeVoid,
|
||||
3u, // NOTE: Result ID
|
||||
|
||||
3u << SpvWordCountShift | SpvOpTypeFunction,
|
||||
4u, // NOTE: Result ID
|
||||
3u, // NOTE: Return type
|
||||
|
||||
5u << SpvWordCountShift | SpvOpFunction,
|
||||
3u, // NOTE: Result type
|
||||
5u, // NOTE: Result ID
|
||||
SpvFunctionControlMaskNone,
|
||||
4u, // NOTE: Function type
|
||||
|
||||
2u << SpvWordCountShift | SpvOpLabel,
|
||||
6u, // NOTE: Result ID
|
||||
|
||||
4u << SpvWordCountShift | SpvOpVariable,
|
||||
2u, // NOTE: Type ID
|
||||
7u, // NOTE: Result ID
|
||||
SpvStorageClassFunction,
|
||||
|
||||
4u << SpvWordCountShift | SpvOpVariable,
|
||||
2u, // NOTE: Type ID
|
||||
8u, // NOTE: Result ID
|
||||
SpvStorageClassFunction,
|
||||
|
||||
4u << SpvWordCountShift | SpvOpVariable,
|
||||
2u, // NOTE: Type ID
|
||||
9u, // NOTE: Result ID
|
||||
SpvStorageClassFunction,
|
||||
|
||||
1u << SpvWordCountShift | SpvOpReturn,
|
||||
|
||||
1u << SpvWordCountShift | SpvOpFunctionEnd});
|
||||
for (size_t i = 0u; i < 2u; ++i) {
|
||||
spvtest::Binary binary = {
|
||||
SpvMagicNumber,
|
||||
SpvVersion,
|
||||
SPV_GENERATOR_CODEPLAY,
|
||||
103u, // NOTE: Bound
|
||||
0u, // NOTE: Schema; reserved
|
||||
|
||||
3u << SpvWordCountShift | SpvOpTypeFloat,
|
||||
1u, // NOTE: Result ID
|
||||
32u, // NOTE: Width
|
||||
|
||||
4u << SpvWordCountShift | SpvOpTypePointer,
|
||||
2u, // NOTE: Result ID
|
||||
SpvStorageClassInput,
|
||||
1u // NOTE: Type ID
|
||||
};
|
||||
|
||||
for (uint32_t j = 0u; j < 0xFFFFu / 2u; ++j) {
|
||||
binary.push_back(4u << SpvWordCountShift | SpvOpVariable);
|
||||
binary.push_back(2u); // NOTE: Type ID
|
||||
binary.push_back(j + 3u); // NOTE: Result ID
|
||||
binary.push_back(SpvStorageClassInput);
|
||||
}
|
||||
binaries.push_back(binary);
|
||||
}
|
||||
}
|
||||
void TearDown() override { binaries.clear(); }
|
||||
|
||||
spvtest::Binaries binaries;
|
||||
};
|
||||
|
||||
TEST_F(EntryPointsAmountTest, UnderLimit) {
|
||||
spvtest::Binary linked_binary;
|
||||
|
||||
EXPECT_EQ(SPV_SUCCESS, Link(binaries, &linked_binary));
|
||||
EXPECT_THAT(GetErrorMessage(), std::string());
|
||||
}
|
||||
|
||||
TEST_F(EntryPointsAmountTest, OverLimit) {
|
||||
binaries.push_back({SpvMagicNumber,
|
||||
SpvVersion,
|
||||
SPV_GENERATOR_CODEPLAY,
|
||||
5u, // NOTE: Bound
|
||||
0u, // NOTE: Schema; reserved
|
||||
|
||||
3u << SpvWordCountShift | SpvOpTypeFloat,
|
||||
1u, // NOTE: Result ID
|
||||
32u, // NOTE: Width
|
||||
|
||||
4u << SpvWordCountShift | SpvOpTypePointer,
|
||||
2u, // NOTE: Result ID
|
||||
SpvStorageClassInput,
|
||||
1u, // NOTE: Type ID
|
||||
|
||||
4u << SpvWordCountShift | SpvOpVariable,
|
||||
2u, // NOTE: Type ID
|
||||
3u, // NOTE: Result ID
|
||||
SpvStorageClassInput,
|
||||
|
||||
4u << SpvWordCountShift | SpvOpVariable,
|
||||
2u, // NOTE: Type ID
|
||||
4u, // NOTE: Result ID
|
||||
SpvStorageClassInput});
|
||||
|
||||
spvtest::Binary linked_binary;
|
||||
|
||||
EXPECT_EQ(SPV_ERROR_INTERNAL, Link(binaries, &linked_binary));
|
||||
EXPECT_THAT(GetErrorMessage(),
|
||||
HasSubstr("The limit of global values, 65535, was exceeded; "
|
||||
"65536 global values were found."));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace spvtools
|
||||
@@ -1,72 +0,0 @@
|
||||
// Copyright (c) 2017 Pierre Moreau
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "test/link/linker_fixture.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace {
|
||||
|
||||
using ::testing::HasSubstr;
|
||||
using IdsLimit = spvtest::LinkerTest;
|
||||
|
||||
TEST_F(IdsLimit, UnderLimit) {
|
||||
spvtest::Binaries binaries = {
|
||||
{
|
||||
SpvMagicNumber, SpvVersion, SPV_GENERATOR_CODEPLAY,
|
||||
0x2FFFFFu, // NOTE: Bound
|
||||
0u, // NOTE: Schema; reserved
|
||||
},
|
||||
{
|
||||
SpvMagicNumber, SpvVersion, SPV_GENERATOR_CODEPLAY,
|
||||
0x100000u, // NOTE: Bound
|
||||
0u, // NOTE: Schema; reserved
|
||||
}};
|
||||
spvtest::Binary linked_binary;
|
||||
|
||||
ASSERT_EQ(SPV_SUCCESS, Link(binaries, &linked_binary));
|
||||
EXPECT_THAT(GetErrorMessage(), std::string());
|
||||
EXPECT_EQ(0x3FFFFEu, linked_binary[3]);
|
||||
}
|
||||
|
||||
TEST_F(IdsLimit, OverLimit) {
|
||||
spvtest::Binaries binaries = {
|
||||
{
|
||||
SpvMagicNumber, SpvVersion, SPV_GENERATOR_CODEPLAY,
|
||||
0x2FFFFFu, // NOTE: Bound
|
||||
0u, // NOTE: Schema; reserved
|
||||
},
|
||||
{
|
||||
SpvMagicNumber, SpvVersion, SPV_GENERATOR_CODEPLAY,
|
||||
0x100000u, // NOTE: Bound
|
||||
0u, // NOTE: Schema; reserved
|
||||
},
|
||||
{
|
||||
SpvMagicNumber, SpvVersion, SPV_GENERATOR_CODEPLAY,
|
||||
3u, // NOTE: Bound
|
||||
0u, // NOTE: Schema; reserved
|
||||
}};
|
||||
|
||||
spvtest::Binary linked_binary;
|
||||
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_ID, Link(binaries, &linked_binary));
|
||||
EXPECT_THAT(GetErrorMessage(),
|
||||
HasSubstr("The limit of IDs, 4194303, was exceeded: 4194304 is "
|
||||
"the current ID bound."));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace spvtools
|
||||
222
3rdparty/spirv-tools/test/link/linker_fixture.h
vendored
222
3rdparty/spirv-tools/test/link/linker_fixture.h
vendored
@@ -1,222 +0,0 @@
|
||||
// Copyright (c) 2017 Pierre Moreau
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef TEST_LINK_LINKER_FIXTURE_H_
|
||||
#define TEST_LINK_LINKER_FIXTURE_H_
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "effcee/effcee.h"
|
||||
#include "re2/re2.h"
|
||||
#include "source/spirv_constant.h"
|
||||
#include "spirv-tools/linker.hpp"
|
||||
#include "test/unit_spirv.h"
|
||||
|
||||
namespace spvtest {
|
||||
|
||||
using Binary = std::vector<uint32_t>;
|
||||
using Binaries = std::vector<Binary>;
|
||||
|
||||
class LinkerTest : public ::testing::Test {
|
||||
public:
|
||||
LinkerTest()
|
||||
: context_(SPV_ENV_UNIVERSAL_1_2),
|
||||
tools_(SPV_ENV_UNIVERSAL_1_2),
|
||||
assemble_options_(spvtools::SpirvTools::kDefaultAssembleOption),
|
||||
disassemble_options_(spvtools::SpirvTools::kDefaultDisassembleOption) {
|
||||
const auto consumer = [this](spv_message_level_t level, const char*,
|
||||
const spv_position_t& position,
|
||||
const char* message) {
|
||||
if (!error_message_.empty()) error_message_ += "\n";
|
||||
switch (level) {
|
||||
case SPV_MSG_FATAL:
|
||||
case SPV_MSG_INTERNAL_ERROR:
|
||||
case SPV_MSG_ERROR:
|
||||
error_message_ += "ERROR";
|
||||
break;
|
||||
case SPV_MSG_WARNING:
|
||||
error_message_ += "WARNING";
|
||||
break;
|
||||
case SPV_MSG_INFO:
|
||||
error_message_ += "INFO";
|
||||
break;
|
||||
case SPV_MSG_DEBUG:
|
||||
error_message_ += "DEBUG";
|
||||
break;
|
||||
}
|
||||
error_message_ += ": " + std::to_string(position.index) + ": " + message;
|
||||
};
|
||||
context_.SetMessageConsumer(consumer);
|
||||
tools_.SetMessageConsumer(consumer);
|
||||
}
|
||||
|
||||
void TearDown() override { error_message_.clear(); }
|
||||
|
||||
// Assembles each of the given strings into SPIR-V binaries before linking
|
||||
// them together. SPV_ERROR_INVALID_TEXT is returned if the assembling failed
|
||||
// for any of the input strings, and SPV_ERROR_INVALID_POINTER if
|
||||
// |linked_binary| is a null pointer.
|
||||
spv_result_t AssembleAndLink(
|
||||
const std::vector<std::string>& bodies, spvtest::Binary* linked_binary,
|
||||
spvtools::LinkerOptions options = spvtools::LinkerOptions()) {
|
||||
if (!linked_binary) return SPV_ERROR_INVALID_POINTER;
|
||||
|
||||
spvtest::Binaries binaries(bodies.size());
|
||||
for (size_t i = 0u; i < bodies.size(); ++i)
|
||||
if (!tools_.Assemble(bodies[i], binaries.data() + i, assemble_options_))
|
||||
return SPV_ERROR_INVALID_TEXT;
|
||||
|
||||
return spvtools::Link(context_, binaries, linked_binary, options);
|
||||
}
|
||||
|
||||
// Assembles and links a vector of SPIR-V bodies based on the |templateBody|.
|
||||
// Template arguments to be replaced are written as {a,b,...}.
|
||||
// SPV_ERROR_INVALID_TEXT is returned if the assembling failed for any of the
|
||||
// resulting bodies (or errors in the template), and SPV_ERROR_INVALID_POINTER
|
||||
// if |linked_binary| is a null pointer.
|
||||
spv_result_t ExpandAndLink(
|
||||
const std::string& templateBody, spvtest::Binary* linked_binary,
|
||||
spvtools::LinkerOptions options = spvtools::LinkerOptions()) {
|
||||
if (!linked_binary) return SPV_ERROR_INVALID_POINTER;
|
||||
|
||||
// Find out how many template arguments there are, we assume they all have
|
||||
// the same number. We'll error later if they don't.
|
||||
re2::StringPiece temp(templateBody);
|
||||
re2::StringPiece x;
|
||||
int cnt = 0;
|
||||
if (!RE2::FindAndConsume(&temp, "{")) return SPV_ERROR_INVALID_TEXT;
|
||||
while (RE2::FindAndConsume(&temp, "([,}])", &x) && x[0] == ',') cnt++;
|
||||
cnt++;
|
||||
if (cnt <= 1) return SPV_ERROR_INVALID_TEXT;
|
||||
|
||||
// Construct a regex for a single common strip and template expansion.
|
||||
std::string regex("([^{]*){");
|
||||
for (int i = 0; i < cnt; i++) regex += (i > 0) ? ",([^,]*)" : "([^,]*)";
|
||||
regex += "}";
|
||||
RE2 pattern(regex);
|
||||
|
||||
// Prepare the RE2::Args for processing.
|
||||
re2::StringPiece common;
|
||||
std::vector<re2::StringPiece> variants(cnt);
|
||||
std::vector<RE2::Arg> args(cnt + 1);
|
||||
args[0] = RE2::Arg(&common);
|
||||
std::vector<RE2::Arg*> pargs(cnt + 1);
|
||||
pargs[0] = &args[0];
|
||||
for (int i = 0; i < cnt; i++) {
|
||||
args[i + 1] = RE2::Arg(&variants[i]);
|
||||
pargs[i + 1] = &args[i + 1];
|
||||
}
|
||||
|
||||
// Reset and construct the bodies bit by bit.
|
||||
std::vector<std::string> bodies(cnt);
|
||||
re2::StringPiece temp2(templateBody);
|
||||
while (RE2::ConsumeN(&temp2, pattern, pargs.data(), cnt + 1)) {
|
||||
for (int i = 0; i < cnt; i++) {
|
||||
bodies[i].append(common.begin(), common.end());
|
||||
bodies[i].append(variants[i].begin(), variants[i].end());
|
||||
}
|
||||
}
|
||||
RE2::Consume(&temp2, "([^{]*)", &common);
|
||||
for (int i = 0; i < cnt; i++)
|
||||
bodies[i].append(common.begin(), common.end());
|
||||
|
||||
// Run through the assemble and link stages of the process.
|
||||
return AssembleAndLink(bodies, linked_binary, options);
|
||||
}
|
||||
|
||||
// Expand the |templateBody| and link the results as with ExpandAndLink,
|
||||
// then disassemble and test that the result matches the |expected|.
|
||||
void ExpandAndCheck(
|
||||
const std::string& templateBody, const std::string& expected,
|
||||
const spvtools::LinkerOptions options = spvtools::LinkerOptions()) {
|
||||
spvtest::Binary linked_binary;
|
||||
spv_result_t res = ExpandAndLink(templateBody, &linked_binary, options);
|
||||
EXPECT_EQ(SPV_SUCCESS, res) << GetErrorMessage() << "\nExpanded from:\n"
|
||||
<< templateBody;
|
||||
if (res == SPV_SUCCESS) {
|
||||
std::string result;
|
||||
EXPECT_TRUE(
|
||||
tools_.Disassemble(linked_binary, &result, disassemble_options_))
|
||||
<< GetErrorMessage();
|
||||
EXPECT_EQ(expected, result);
|
||||
}
|
||||
}
|
||||
|
||||
// An alternative to ExpandAndCheck, which uses the |templateBody| as the
|
||||
// match pattern for the disassembled linked result.
|
||||
void ExpandAndMatch(
|
||||
const std::string& templateBody,
|
||||
const spvtools::LinkerOptions options = spvtools::LinkerOptions()) {
|
||||
spvtest::Binary linked_binary;
|
||||
spv_result_t res = ExpandAndLink(templateBody, &linked_binary, options);
|
||||
EXPECT_EQ(SPV_SUCCESS, res) << GetErrorMessage() << "\nExpanded from:\n"
|
||||
<< templateBody;
|
||||
if (res == SPV_SUCCESS) {
|
||||
std::string result;
|
||||
EXPECT_TRUE(
|
||||
tools_.Disassemble(linked_binary, &result, disassemble_options_))
|
||||
<< GetErrorMessage();
|
||||
auto match_res = effcee::Match(result, templateBody);
|
||||
EXPECT_EQ(effcee::Result::Status::Ok, match_res.status())
|
||||
<< match_res.message() << "\nExpanded from:\n"
|
||||
<< templateBody << "\nChecking result:\n"
|
||||
<< result;
|
||||
}
|
||||
}
|
||||
|
||||
// Links the given SPIR-V binaries together; SPV_ERROR_INVALID_POINTER is
|
||||
// returned if |linked_binary| is a null pointer.
|
||||
spv_result_t Link(
|
||||
const spvtest::Binaries& binaries, spvtest::Binary* linked_binary,
|
||||
spvtools::LinkerOptions options = spvtools::LinkerOptions()) {
|
||||
if (!linked_binary) return SPV_ERROR_INVALID_POINTER;
|
||||
return spvtools::Link(context_, binaries, linked_binary, options);
|
||||
}
|
||||
|
||||
// Disassembles |binary| and outputs the result in |text|. If |text| is a
|
||||
// null pointer, SPV_ERROR_INVALID_POINTER is returned.
|
||||
spv_result_t Disassemble(const spvtest::Binary& binary, std::string* text) {
|
||||
if (!text) return SPV_ERROR_INVALID_POINTER;
|
||||
return tools_.Disassemble(binary, text, disassemble_options_)
|
||||
? SPV_SUCCESS
|
||||
: SPV_ERROR_INVALID_BINARY;
|
||||
}
|
||||
|
||||
// Sets the options for the assembler.
|
||||
void SetAssembleOptions(uint32_t assemble_options) {
|
||||
assemble_options_ = assemble_options;
|
||||
}
|
||||
|
||||
// Sets the options used by the disassembler.
|
||||
void SetDisassembleOptions(uint32_t disassemble_options) {
|
||||
disassemble_options_ = disassemble_options;
|
||||
}
|
||||
|
||||
// Returns the accumulated error messages for the test.
|
||||
std::string GetErrorMessage() const { return error_message_; }
|
||||
|
||||
private:
|
||||
spvtools::Context context_;
|
||||
spvtools::SpirvTools
|
||||
tools_; // An instance for calling SPIRV-Tools functionalities.
|
||||
uint32_t assemble_options_;
|
||||
uint32_t disassemble_options_;
|
||||
std::string error_message_;
|
||||
};
|
||||
|
||||
} // namespace spvtest
|
||||
|
||||
#endif // TEST_LINK_LINKER_FIXTURE_H_
|
||||
@@ -1,403 +0,0 @@
|
||||
// Copyright (c) 2017 Pierre Moreau
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "test/link/linker_fixture.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace {
|
||||
|
||||
using ::testing::HasSubstr;
|
||||
using MatchingImportsToExports = spvtest::LinkerTest;
|
||||
|
||||
TEST_F(MatchingImportsToExports, Default) {
|
||||
const std::string body1 = R"(
|
||||
OpCapability Linkage
|
||||
OpDecorate %1 LinkageAttributes "foo" Import
|
||||
%2 = OpTypeFloat 32
|
||||
%1 = OpVariable %2 Uniform
|
||||
%3 = OpVariable %2 Input
|
||||
)";
|
||||
const std::string body2 = R"(
|
||||
OpCapability Linkage
|
||||
OpDecorate %1 LinkageAttributes "foo" Export
|
||||
%2 = OpTypeFloat 32
|
||||
%3 = OpConstant %2 42
|
||||
%1 = OpVariable %2 Uniform %3
|
||||
)";
|
||||
|
||||
spvtest::Binary linked_binary;
|
||||
EXPECT_EQ(SPV_SUCCESS, AssembleAndLink({body1, body2}, &linked_binary))
|
||||
<< GetErrorMessage();
|
||||
|
||||
const std::string expected_res =
|
||||
R"(OpModuleProcessed "Linked by SPIR-V Tools Linker"
|
||||
%1 = OpTypeFloat 32
|
||||
%2 = OpVariable %1 Input
|
||||
%3 = OpConstant %1 42
|
||||
%4 = OpVariable %1 Uniform %3
|
||||
)";
|
||||
std::string res_body;
|
||||
SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
|
||||
EXPECT_EQ(SPV_SUCCESS, Disassemble(linked_binary, &res_body))
|
||||
<< GetErrorMessage();
|
||||
EXPECT_EQ(expected_res, res_body);
|
||||
}
|
||||
|
||||
TEST_F(MatchingImportsToExports, NotALibraryExtraExports) {
|
||||
const std::string body = R"(
|
||||
OpCapability Linkage
|
||||
OpDecorate %1 LinkageAttributes "foo" Export
|
||||
%2 = OpTypeFloat 32
|
||||
%1 = OpVariable %2 Uniform
|
||||
)";
|
||||
|
||||
spvtest::Binary linked_binary;
|
||||
EXPECT_EQ(SPV_SUCCESS, AssembleAndLink({body}, &linked_binary))
|
||||
<< GetErrorMessage();
|
||||
|
||||
const std::string expected_res =
|
||||
R"(OpModuleProcessed "Linked by SPIR-V Tools Linker"
|
||||
%1 = OpTypeFloat 32
|
||||
%2 = OpVariable %1 Uniform
|
||||
)";
|
||||
std::string res_body;
|
||||
SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
|
||||
EXPECT_EQ(SPV_SUCCESS, Disassemble(linked_binary, &res_body))
|
||||
<< GetErrorMessage();
|
||||
EXPECT_EQ(expected_res, res_body);
|
||||
}
|
||||
|
||||
TEST_F(MatchingImportsToExports, LibraryExtraExports) {
|
||||
const std::string body = R"(
|
||||
OpCapability Linkage
|
||||
OpDecorate %1 LinkageAttributes "foo" Export
|
||||
%2 = OpTypeFloat 32
|
||||
%1 = OpVariable %2 Uniform
|
||||
)";
|
||||
|
||||
spvtest::Binary linked_binary;
|
||||
LinkerOptions options;
|
||||
options.SetCreateLibrary(true);
|
||||
EXPECT_EQ(SPV_SUCCESS, AssembleAndLink({body}, &linked_binary, options))
|
||||
<< GetErrorMessage();
|
||||
|
||||
const std::string expected_res = R"(OpCapability Linkage
|
||||
OpModuleProcessed "Linked by SPIR-V Tools Linker"
|
||||
OpDecorate %1 LinkageAttributes "foo" Export
|
||||
%2 = OpTypeFloat 32
|
||||
%1 = OpVariable %2 Uniform
|
||||
)";
|
||||
std::string res_body;
|
||||
SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
|
||||
EXPECT_EQ(SPV_SUCCESS, Disassemble(linked_binary, &res_body))
|
||||
<< GetErrorMessage();
|
||||
EXPECT_EQ(expected_res, res_body);
|
||||
}
|
||||
|
||||
TEST_F(MatchingImportsToExports, UnresolvedImports) {
|
||||
const std::string body1 = R"(
|
||||
OpCapability Linkage
|
||||
OpDecorate %1 LinkageAttributes "foo" Import
|
||||
%2 = OpTypeFloat 32
|
||||
%1 = OpVariable %2 Uniform
|
||||
)";
|
||||
const std::string body2 = R"()";
|
||||
|
||||
spvtest::Binary linked_binary;
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_BINARY,
|
||||
AssembleAndLink({body1, body2}, &linked_binary));
|
||||
EXPECT_THAT(GetErrorMessage(),
|
||||
HasSubstr("Unresolved external reference to \"foo\"."));
|
||||
}
|
||||
|
||||
TEST_F(MatchingImportsToExports, TypeMismatch) {
|
||||
const std::string body1 = R"(
|
||||
OpCapability Linkage
|
||||
OpDecorate %1 LinkageAttributes "foo" Import
|
||||
%2 = OpTypeFloat 32
|
||||
%1 = OpVariable %2 Uniform
|
||||
%3 = OpVariable %2 Input
|
||||
)";
|
||||
const std::string body2 = R"(
|
||||
OpCapability Linkage
|
||||
OpDecorate %1 LinkageAttributes "foo" Export
|
||||
%2 = OpTypeInt 32 0
|
||||
%3 = OpConstant %2 42
|
||||
%1 = OpVariable %2 Uniform %3
|
||||
)";
|
||||
|
||||
spvtest::Binary linked_binary;
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_BINARY,
|
||||
AssembleAndLink({body1, body2}, &linked_binary))
|
||||
<< GetErrorMessage();
|
||||
EXPECT_THAT(
|
||||
GetErrorMessage(),
|
||||
HasSubstr("Type mismatch on symbol \"foo\" between imported "
|
||||
"variable/function %1 and exported variable/function %4"));
|
||||
}
|
||||
|
||||
TEST_F(MatchingImportsToExports, MultipleDefinitions) {
|
||||
const std::string body1 = R"(
|
||||
OpCapability Linkage
|
||||
OpDecorate %1 LinkageAttributes "foo" Import
|
||||
%2 = OpTypeFloat 32
|
||||
%1 = OpVariable %2 Uniform
|
||||
%3 = OpVariable %2 Input
|
||||
)";
|
||||
const std::string body2 = R"(
|
||||
OpCapability Linkage
|
||||
OpDecorate %1 LinkageAttributes "foo" Export
|
||||
%2 = OpTypeFloat 32
|
||||
%3 = OpConstant %2 42
|
||||
%1 = OpVariable %2 Uniform %3
|
||||
)";
|
||||
const std::string body3 = R"(
|
||||
OpCapability Linkage
|
||||
OpDecorate %1 LinkageAttributes "foo" Export
|
||||
%2 = OpTypeFloat 32
|
||||
%3 = OpConstant %2 -1
|
||||
%1 = OpVariable %2 Uniform %3
|
||||
)";
|
||||
|
||||
spvtest::Binary linked_binary;
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_BINARY,
|
||||
AssembleAndLink({body1, body2, body3}, &linked_binary))
|
||||
<< GetErrorMessage();
|
||||
EXPECT_THAT(GetErrorMessage(),
|
||||
HasSubstr("Too many external references, 2, were found "
|
||||
"for \"foo\"."));
|
||||
}
|
||||
|
||||
TEST_F(MatchingImportsToExports, SameNameDifferentTypes) {
|
||||
const std::string body1 = R"(
|
||||
OpCapability Linkage
|
||||
OpDecorate %1 LinkageAttributes "foo" Import
|
||||
%2 = OpTypeFloat 32
|
||||
%1 = OpVariable %2 Uniform
|
||||
%3 = OpVariable %2 Input
|
||||
)";
|
||||
const std::string body2 = R"(
|
||||
OpCapability Linkage
|
||||
OpDecorate %1 LinkageAttributes "foo" Export
|
||||
%2 = OpTypeInt 32 0
|
||||
%3 = OpConstant %2 42
|
||||
%1 = OpVariable %2 Uniform %3
|
||||
)";
|
||||
const std::string body3 = R"(
|
||||
OpCapability Linkage
|
||||
OpDecorate %1 LinkageAttributes "foo" Export
|
||||
%2 = OpTypeFloat 32
|
||||
%3 = OpConstant %2 12
|
||||
%1 = OpVariable %2 Uniform %3
|
||||
)";
|
||||
|
||||
spvtest::Binary linked_binary;
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_BINARY,
|
||||
AssembleAndLink({body1, body2, body3}, &linked_binary))
|
||||
<< GetErrorMessage();
|
||||
EXPECT_THAT(GetErrorMessage(),
|
||||
HasSubstr("Too many external references, 2, were found "
|
||||
"for \"foo\"."));
|
||||
}
|
||||
|
||||
TEST_F(MatchingImportsToExports, DecorationMismatch) {
|
||||
const std::string body1 = R"(
|
||||
OpCapability Linkage
|
||||
OpDecorate %1 LinkageAttributes "foo" Import
|
||||
OpDecorate %2 Constant
|
||||
%2 = OpTypeFloat 32
|
||||
%1 = OpVariable %2 Uniform
|
||||
%3 = OpVariable %2 Input
|
||||
)";
|
||||
const std::string body2 = R"(
|
||||
OpCapability Linkage
|
||||
OpDecorate %1 LinkageAttributes "foo" Export
|
||||
%2 = OpTypeFloat 32
|
||||
%3 = OpConstant %2 42
|
||||
%1 = OpVariable %2 Uniform %3
|
||||
)";
|
||||
|
||||
spvtest::Binary linked_binary;
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_BINARY,
|
||||
AssembleAndLink({body1, body2}, &linked_binary))
|
||||
<< GetErrorMessage();
|
||||
EXPECT_THAT(
|
||||
GetErrorMessage(),
|
||||
HasSubstr("Type mismatch on symbol \"foo\" between imported "
|
||||
"variable/function %1 and exported variable/function %4"));
|
||||
}
|
||||
|
||||
TEST_F(MatchingImportsToExports,
|
||||
FuncParamAttrDifferButStillMatchExportToImport) {
|
||||
const std::string body1 = R"(
|
||||
OpCapability Kernel
|
||||
OpCapability Linkage
|
||||
OpDecorate %1 LinkageAttributes "foo" Import
|
||||
OpDecorate %2 FuncParamAttr Zext
|
||||
%3 = OpTypeVoid
|
||||
%4 = OpTypeInt 32 0
|
||||
%5 = OpTypeFunction %3 %4
|
||||
%1 = OpFunction %3 None %5
|
||||
%2 = OpFunctionParameter %4
|
||||
OpFunctionEnd
|
||||
)";
|
||||
const std::string body2 = R"(
|
||||
OpCapability Kernel
|
||||
OpCapability Linkage
|
||||
OpDecorate %1 LinkageAttributes "foo" Export
|
||||
OpDecorate %2 FuncParamAttr Sext
|
||||
%3 = OpTypeVoid
|
||||
%4 = OpTypeInt 32 0
|
||||
%5 = OpTypeFunction %3 %4
|
||||
%1 = OpFunction %3 None %5
|
||||
%2 = OpFunctionParameter %4
|
||||
%6 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
spvtest::Binary linked_binary;
|
||||
EXPECT_EQ(SPV_SUCCESS, AssembleAndLink({body1, body2}, &linked_binary))
|
||||
<< GetErrorMessage();
|
||||
|
||||
const std::string expected_res = R"(OpCapability Kernel
|
||||
OpModuleProcessed "Linked by SPIR-V Tools Linker"
|
||||
OpDecorate %1 FuncParamAttr Sext
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeInt 32 0
|
||||
%4 = OpTypeFunction %2 %3
|
||||
%5 = OpFunction %2 None %4
|
||||
%1 = OpFunctionParameter %3
|
||||
%6 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
std::string res_body;
|
||||
SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
|
||||
EXPECT_EQ(SPV_SUCCESS, Disassemble(linked_binary, &res_body))
|
||||
<< GetErrorMessage();
|
||||
EXPECT_EQ(expected_res, res_body);
|
||||
}
|
||||
|
||||
TEST_F(MatchingImportsToExports, FunctionCtrl) {
|
||||
const std::string body1 = R"(
|
||||
OpCapability Linkage
|
||||
OpDecorate %1 LinkageAttributes "foo" Import
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%4 = OpTypeFloat 32
|
||||
%5 = OpVariable %4 Uniform
|
||||
%1 = OpFunction %2 None %3
|
||||
OpFunctionEnd
|
||||
)";
|
||||
const std::string body2 = R"(
|
||||
OpCapability Linkage
|
||||
OpDecorate %1 LinkageAttributes "foo" Export
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%1 = OpFunction %2 Inline %3
|
||||
%4 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
spvtest::Binary linked_binary;
|
||||
EXPECT_EQ(SPV_SUCCESS, AssembleAndLink({body1, body2}, &linked_binary))
|
||||
<< GetErrorMessage();
|
||||
|
||||
const std::string expected_res =
|
||||
R"(OpModuleProcessed "Linked by SPIR-V Tools Linker"
|
||||
%1 = OpTypeVoid
|
||||
%2 = OpTypeFunction %1
|
||||
%3 = OpTypeFloat 32
|
||||
%4 = OpVariable %3 Uniform
|
||||
%5 = OpFunction %1 Inline %2
|
||||
%6 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
std::string res_body;
|
||||
SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
|
||||
EXPECT_EQ(SPV_SUCCESS, Disassemble(linked_binary, &res_body))
|
||||
<< GetErrorMessage();
|
||||
EXPECT_EQ(expected_res, res_body);
|
||||
}
|
||||
|
||||
TEST_F(MatchingImportsToExports, UseExportedFuncParamAttr) {
|
||||
const std::string body1 = R"(
|
||||
OpCapability Kernel
|
||||
OpCapability Linkage
|
||||
OpDecorate %1 LinkageAttributes "foo" Import
|
||||
OpDecorate %2 FuncParamAttr Zext
|
||||
%2 = OpDecorationGroup
|
||||
OpGroupDecorate %2 %3 %4
|
||||
%5 = OpTypeVoid
|
||||
%6 = OpTypeInt 32 0
|
||||
%7 = OpTypeFunction %5 %6
|
||||
%1 = OpFunction %5 None %7
|
||||
%3 = OpFunctionParameter %6
|
||||
OpFunctionEnd
|
||||
%8 = OpFunction %5 None %7
|
||||
%4 = OpFunctionParameter %6
|
||||
OpFunctionEnd
|
||||
)";
|
||||
const std::string body2 = R"(
|
||||
OpCapability Kernel
|
||||
OpCapability Linkage
|
||||
OpDecorate %1 LinkageAttributes "foo" Export
|
||||
OpDecorate %2 FuncParamAttr Sext
|
||||
%3 = OpTypeVoid
|
||||
%4 = OpTypeInt 32 0
|
||||
%5 = OpTypeFunction %3 %4
|
||||
%1 = OpFunction %3 None %5
|
||||
%2 = OpFunctionParameter %4
|
||||
%6 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
spvtest::Binary linked_binary;
|
||||
EXPECT_EQ(SPV_SUCCESS, AssembleAndLink({body1, body2}, &linked_binary))
|
||||
<< GetErrorMessage();
|
||||
|
||||
const std::string expected_res = R"(OpCapability Kernel
|
||||
OpModuleProcessed "Linked by SPIR-V Tools Linker"
|
||||
OpDecorate %1 FuncParamAttr Zext
|
||||
%1 = OpDecorationGroup
|
||||
OpGroupDecorate %1 %2
|
||||
OpDecorate %3 FuncParamAttr Sext
|
||||
%4 = OpTypeVoid
|
||||
%5 = OpTypeInt 32 0
|
||||
%6 = OpTypeFunction %4 %5
|
||||
%7 = OpFunction %4 None %6
|
||||
%2 = OpFunctionParameter %5
|
||||
OpFunctionEnd
|
||||
%8 = OpFunction %4 None %6
|
||||
%3 = OpFunctionParameter %5
|
||||
%9 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
std::string res_body;
|
||||
SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
|
||||
EXPECT_EQ(SPV_SUCCESS, Disassemble(linked_binary, &res_body))
|
||||
<< GetErrorMessage();
|
||||
EXPECT_EQ(expected_res, res_body);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace spvtools
|
||||
@@ -1,74 +0,0 @@
|
||||
// Copyright (c) 2017 Pierre Moreau
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "test/link/linker_fixture.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace {
|
||||
|
||||
using ::testing::HasSubstr;
|
||||
using MemoryModel = spvtest::LinkerTest;
|
||||
|
||||
TEST_F(MemoryModel, Default) {
|
||||
const std::string body1 = R"(
|
||||
OpMemoryModel Logical Simple
|
||||
)";
|
||||
const std::string body2 = R"(
|
||||
OpMemoryModel Logical Simple
|
||||
)";
|
||||
|
||||
spvtest::Binary linked_binary;
|
||||
ASSERT_EQ(SPV_SUCCESS, AssembleAndLink({body1, body2}, &linked_binary));
|
||||
EXPECT_THAT(GetErrorMessage(), std::string());
|
||||
|
||||
EXPECT_EQ(SpvAddressingModelLogical, linked_binary[6]);
|
||||
EXPECT_EQ(SpvMemoryModelSimple, linked_binary[7]);
|
||||
}
|
||||
|
||||
TEST_F(MemoryModel, AddressingMismatch) {
|
||||
const std::string body1 = R"(
|
||||
OpMemoryModel Logical Simple
|
||||
)";
|
||||
const std::string body2 = R"(
|
||||
OpMemoryModel Physical32 Simple
|
||||
)";
|
||||
|
||||
spvtest::Binary linked_binary;
|
||||
EXPECT_EQ(SPV_ERROR_INTERNAL,
|
||||
AssembleAndLink({body1, body2}, &linked_binary));
|
||||
EXPECT_THAT(
|
||||
GetErrorMessage(),
|
||||
HasSubstr("Conflicting addressing models: Logical vs Physical32."));
|
||||
}
|
||||
|
||||
TEST_F(MemoryModel, MemoryMismatch) {
|
||||
const std::string body1 = R"(
|
||||
OpMemoryModel Logical Simple
|
||||
)";
|
||||
const std::string body2 = R"(
|
||||
OpMemoryModel Logical GLSL450
|
||||
)";
|
||||
|
||||
spvtest::Binary linked_binary;
|
||||
EXPECT_EQ(SPV_ERROR_INTERNAL,
|
||||
AssembleAndLink({body1, body2}, &linked_binary));
|
||||
EXPECT_THAT(GetErrorMessage(),
|
||||
HasSubstr("Conflicting memory models: Simple vs GLSL450."));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace spvtools
|
||||
@@ -1,89 +0,0 @@
|
||||
// Copyright (c) 2018 Pierre Moreau
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "test/link/linker_fixture.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace {
|
||||
|
||||
using ::testing::HasSubstr;
|
||||
using PartialLinkage = spvtest::LinkerTest;
|
||||
|
||||
TEST_F(PartialLinkage, Allowed) {
|
||||
const std::string body1 = R"(
|
||||
OpCapability Linkage
|
||||
OpDecorate %1 LinkageAttributes "foo" Import
|
||||
OpDecorate %2 LinkageAttributes "bar" Import
|
||||
%3 = OpTypeFloat 32
|
||||
%1 = OpVariable %3 Uniform
|
||||
%2 = OpVariable %3 Uniform
|
||||
)";
|
||||
const std::string body2 = R"(
|
||||
OpCapability Linkage
|
||||
OpDecorate %1 LinkageAttributes "bar" Export
|
||||
%2 = OpTypeFloat 32
|
||||
%3 = OpConstant %2 3.1415
|
||||
%1 = OpVariable %2 Uniform %3
|
||||
)";
|
||||
|
||||
spvtest::Binary linked_binary;
|
||||
LinkerOptions linker_options;
|
||||
linker_options.SetAllowPartialLinkage(true);
|
||||
ASSERT_EQ(SPV_SUCCESS,
|
||||
AssembleAndLink({body1, body2}, &linked_binary, linker_options));
|
||||
|
||||
const std::string expected_res = R"(OpCapability Linkage
|
||||
OpModuleProcessed "Linked by SPIR-V Tools Linker"
|
||||
OpDecorate %1 LinkageAttributes "foo" Import
|
||||
%2 = OpTypeFloat 32
|
||||
%1 = OpVariable %2 Uniform
|
||||
%3 = OpConstant %2 3.1415
|
||||
%4 = OpVariable %2 Uniform %3
|
||||
)";
|
||||
std::string res_body;
|
||||
SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
|
||||
ASSERT_EQ(SPV_SUCCESS, Disassemble(linked_binary, &res_body))
|
||||
<< GetErrorMessage();
|
||||
EXPECT_EQ(expected_res, res_body);
|
||||
}
|
||||
|
||||
TEST_F(PartialLinkage, Disallowed) {
|
||||
const std::string body1 = R"(
|
||||
OpCapability Linkage
|
||||
OpDecorate %1 LinkageAttributes "foo" Import
|
||||
OpDecorate %2 LinkageAttributes "bar" Import
|
||||
%3 = OpTypeFloat 32
|
||||
%1 = OpVariable %3 Uniform
|
||||
%2 = OpVariable %3 Uniform
|
||||
)";
|
||||
const std::string body2 = R"(
|
||||
OpCapability Linkage
|
||||
OpDecorate %1 LinkageAttributes "bar" Export
|
||||
%2 = OpTypeFloat 32
|
||||
%3 = OpConstant %2 3.1415
|
||||
%1 = OpVariable %2 Uniform %3
|
||||
)";
|
||||
|
||||
spvtest::Binary linked_binary;
|
||||
EXPECT_EQ(SPV_ERROR_INVALID_BINARY,
|
||||
AssembleAndLink({body1, body2}, &linked_binary));
|
||||
EXPECT_THAT(GetErrorMessage(),
|
||||
HasSubstr("Unresolved external reference to \"foo\"."));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace spvtools
|
||||
148
3rdparty/spirv-tools/test/link/type_match_test.cpp
vendored
148
3rdparty/spirv-tools/test/link/type_match_test.cpp
vendored
@@ -1,148 +0,0 @@
|
||||
// Copyright (c) 2019 The Khronos Group Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "test/link/linker_fixture.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace {
|
||||
|
||||
using TypeMatch = spvtest::LinkerTest;
|
||||
|
||||
// Basic types
|
||||
#define PartInt(D, N) D(N) " = OpTypeInt 32 0"
|
||||
#define PartFloat(D, N) D(N) " = OpTypeFloat 32"
|
||||
#define PartOpaque(D, N) D(N) " = OpTypeOpaque \"bar\""
|
||||
#define PartSampler(D, N) D(N) " = OpTypeSampler"
|
||||
#define PartEvent(D, N) D(N) " = OpTypeEvent"
|
||||
#define PartDeviceEvent(D, N) D(N) " = OpTypeDeviceEvent"
|
||||
#define PartReserveId(D, N) D(N) " = OpTypeReserveId"
|
||||
#define PartQueue(D, N) D(N) " = OpTypeQueue"
|
||||
#define PartPipe(D, N) D(N) " = OpTypePipe ReadWrite"
|
||||
#define PartPipeStorage(D, N) D(N) " = OpTypePipeStorage"
|
||||
#define PartNamedBarrier(D, N) D(N) " = OpTypeNamedBarrier"
|
||||
|
||||
// Compound types
|
||||
#define PartVector(DR, DA, N, T) DR(N) " = OpTypeVector " DA(T) " 3"
|
||||
#define PartMatrix(DR, DA, N, T) DR(N) " = OpTypeMatrix " DA(T) " 4"
|
||||
#define PartImage(DR, DA, N, T) \
|
||||
DR(N) " = OpTypeImage " DA(T) " 2D 0 0 0 0 Rgba32f"
|
||||
#define PartSampledImage(DR, DA, N, T) DR(N) " = OpTypeSampledImage " DA(T)
|
||||
#define PartArray(DR, DA, N, T) DR(N) " = OpTypeArray " DA(T) " " DA(const)
|
||||
#define PartRuntimeArray(DR, DA, N, T) DR(N) " = OpTypeRuntimeArray " DA(T)
|
||||
#define PartStruct(DR, DA, N, T) DR(N) " = OpTypeStruct " DA(T) " " DA(T)
|
||||
#define PartPointer(DR, DA, N, T) DR(N) " = OpTypePointer Workgroup " DA(T)
|
||||
#define PartFunction(DR, DA, N, T) DR(N) " = OpTypeFunction " DA(T) " " DA(T)
|
||||
|
||||
#define CheckDecoRes(S) "[[" #S ":%\\w+]]"
|
||||
#define CheckDecoArg(S) "[[" #S "]]"
|
||||
#define InstDeco(S) "%" #S
|
||||
|
||||
#define MatchPart1(F, N) \
|
||||
"; CHECK: " Part##F(CheckDecoRes, N) "\n" Part##F(InstDeco, N) "\n"
|
||||
#define MatchPart2(F, N, T) \
|
||||
"; CHECK: " Part##F(CheckDecoRes, CheckDecoArg, N, T) "\n" Part##F( \
|
||||
InstDeco, InstDeco, N, T) "\n"
|
||||
|
||||
#define MatchF(N, CODE) \
|
||||
TEST_F(TypeMatch, N) { \
|
||||
const std::string base = \
|
||||
"OpCapability Linkage\n" \
|
||||
"OpCapability NamedBarrier\n" \
|
||||
"OpCapability PipeStorage\n" \
|
||||
"OpCapability Pipes\n" \
|
||||
"OpCapability DeviceEnqueue\n" \
|
||||
"OpCapability Kernel\n" \
|
||||
"OpCapability Shader\n" \
|
||||
"OpCapability Addresses\n" \
|
||||
"OpDecorate %var LinkageAttributes \"foo\" " \
|
||||
"{Import,Export}\n" \
|
||||
"; CHECK: [[baseint:%\\w+]] = OpTypeInt 32 1\n" \
|
||||
"%baseint = OpTypeInt 32 1\n" \
|
||||
"; CHECK: [[const:%\\w+]] = OpConstant [[baseint]] 3\n" \
|
||||
"%const = OpConstant %baseint 3\n" CODE \
|
||||
"; CHECK: OpVariable [[type]] Uniform\n" \
|
||||
"%var = OpVariable %type Uniform"; \
|
||||
ExpandAndMatch(base); \
|
||||
}
|
||||
|
||||
#define Match1(T) MatchF(Type##T, MatchPart1(T, type))
|
||||
#define Match2(T, A) \
|
||||
MatchF(T##OfType##A, MatchPart1(A, a) MatchPart2(T, type, a))
|
||||
#define Match3(T, A, B) \
|
||||
MatchF(T##Of##A##Of##B, \
|
||||
MatchPart1(B, b) MatchPart2(A, a, b) MatchPart2(T, type, a))
|
||||
|
||||
// clang-format off
|
||||
// Basic types
|
||||
Match1(Int)
|
||||
Match1(Float)
|
||||
Match1(Opaque)
|
||||
Match1(Sampler)
|
||||
Match1(Event)
|
||||
Match1(DeviceEvent)
|
||||
Match1(ReserveId)
|
||||
Match1(Queue)
|
||||
Match1(Pipe)
|
||||
Match1(PipeStorage)
|
||||
Match1(NamedBarrier)
|
||||
|
||||
// Simpler (restricted) compound types
|
||||
Match2(Vector, Float)
|
||||
Match3(Matrix, Vector, Float)
|
||||
Match2(Image, Float)
|
||||
|
||||
// Unrestricted compound types
|
||||
#define MatchCompounds1(A) \
|
||||
Match2(RuntimeArray, A) \
|
||||
Match2(Struct, A) \
|
||||
Match2(Pointer, A) \
|
||||
Match2(Function, A) \
|
||||
Match2(Array, A)
|
||||
#define MatchCompounds2(A, B) \
|
||||
Match3(RuntimeArray, A, B) \
|
||||
Match3(Struct, A, B) \
|
||||
Match3(Pointer, A, B) \
|
||||
Match3(Function, A, B) \
|
||||
Match3(Array, A, B)
|
||||
|
||||
MatchCompounds1(Float)
|
||||
MatchCompounds2(Array, Float)
|
||||
MatchCompounds2(RuntimeArray, Float)
|
||||
MatchCompounds2(Struct, Float)
|
||||
MatchCompounds2(Pointer, Float)
|
||||
MatchCompounds2(Function, Float)
|
||||
// clang-format on
|
||||
|
||||
// ForwardPointer tests, which don't fit into the previous mold
|
||||
#define MatchFpF(N, CODE) \
|
||||
MatchF(N, \
|
||||
"; CHECK: OpTypeForwardPointer [[type:%\\w+]] Workgroup\n" \
|
||||
"OpTypeForwardPointer %type Workgroup\n" CODE \
|
||||
"; CHECK: [[type]] = OpTypePointer Workgroup [[realtype]]\n" \
|
||||
"%type = OpTypePointer Workgroup %realtype\n")
|
||||
#define MatchFp1(T) MatchFpF(ForwardPointerOf##T, MatchPart1(T, realtype))
|
||||
#define MatchFp2(T, A) \
|
||||
MatchFpF(ForwardPointerOf##T, MatchPart1(A, a) MatchPart2(T, realtype, a))
|
||||
|
||||
// clang-format off
|
||||
MatchFp1(Float)
|
||||
MatchFp2(Array, Float)
|
||||
MatchFp2(RuntimeArray, Float)
|
||||
MatchFp2(Struct, Float)
|
||||
MatchFp2(Function, Float)
|
||||
// clang-format on
|
||||
|
||||
} // namespace
|
||||
} // namespace spvtools
|
||||
142
3rdparty/spirv-tools/test/link/unique_ids_test.cpp
vendored
142
3rdparty/spirv-tools/test/link/unique_ids_test.cpp
vendored
@@ -1,142 +0,0 @@
|
||||
// Copyright (c) 2017 Google Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "test/link/linker_fixture.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace {
|
||||
|
||||
using UniqueIds = spvtest::LinkerTest;
|
||||
|
||||
TEST_F(UniqueIds, UniquelyMerged) {
|
||||
std::vector<std::string> bodies(2);
|
||||
bodies[0] =
|
||||
// clang-format off
|
||||
"OpCapability Shader\n"
|
||||
"%1 = OpExtInstImport \"GLSL.std.450\"\n"
|
||||
"OpMemoryModel Logical GLSL450\n"
|
||||
"OpEntryPoint Vertex %main \"main\"\n"
|
||||
"OpSource ESSL 310\n"
|
||||
"OpName %main \"main\"\n"
|
||||
"OpName %f_ \"f(\"\n"
|
||||
"OpName %gv1 \"gv1\"\n"
|
||||
"OpName %gv2 \"gv2\"\n"
|
||||
"OpName %lv1 \"lv1\"\n"
|
||||
"OpName %lv2 \"lv2\"\n"
|
||||
"OpName %lv1_0 \"lv1\"\n"
|
||||
"%void = OpTypeVoid\n"
|
||||
"%10 = OpTypeFunction %void\n"
|
||||
"%float = OpTypeFloat 32\n"
|
||||
"%12 = OpTypeFunction %float\n"
|
||||
"%_ptr_Private_float = OpTypePointer Private %float\n"
|
||||
"%gv1 = OpVariable %_ptr_Private_float Private\n"
|
||||
"%float_10 = OpConstant %float 10\n"
|
||||
"%gv2 = OpVariable %_ptr_Private_float Private\n"
|
||||
"%float_100 = OpConstant %float 100\n"
|
||||
"%_ptr_Function_float = OpTypePointer Function %float\n"
|
||||
"%main = OpFunction %void None %10\n"
|
||||
"%17 = OpLabel\n"
|
||||
"%lv1_0 = OpVariable %_ptr_Function_float Function\n"
|
||||
"OpStore %gv1 %float_10\n"
|
||||
"OpStore %gv2 %float_100\n"
|
||||
"%18 = OpLoad %float %gv1\n"
|
||||
"%19 = OpLoad %float %gv2\n"
|
||||
"%20 = OpFSub %float %18 %19\n"
|
||||
"OpStore %lv1_0 %20\n"
|
||||
"OpReturn\n"
|
||||
"OpFunctionEnd\n"
|
||||
"%f_ = OpFunction %float None %12\n"
|
||||
"%21 = OpLabel\n"
|
||||
"%lv1 = OpVariable %_ptr_Function_float Function\n"
|
||||
"%lv2 = OpVariable %_ptr_Function_float Function\n"
|
||||
"%22 = OpLoad %float %gv1\n"
|
||||
"%23 = OpLoad %float %gv2\n"
|
||||
"%24 = OpFAdd %float %22 %23\n"
|
||||
"OpStore %lv1 %24\n"
|
||||
"%25 = OpLoad %float %gv1\n"
|
||||
"%26 = OpLoad %float %gv2\n"
|
||||
"%27 = OpFMul %float %25 %26\n"
|
||||
"OpStore %lv2 %27\n"
|
||||
"%28 = OpLoad %float %lv1\n"
|
||||
"%29 = OpLoad %float %lv2\n"
|
||||
"%30 = OpFDiv %float %28 %29\n"
|
||||
"OpReturnValue %30\n"
|
||||
"OpFunctionEnd\n";
|
||||
// clang-format on
|
||||
bodies[1] =
|
||||
// clang-format off
|
||||
"OpCapability Shader\n"
|
||||
"%1 = OpExtInstImport \"GLSL.std.450\"\n"
|
||||
"OpMemoryModel Logical GLSL450\n"
|
||||
"OpSource ESSL 310\n"
|
||||
"OpName %main \"main2\"\n"
|
||||
"OpName %f_ \"f(\"\n"
|
||||
"OpName %gv1 \"gv12\"\n"
|
||||
"OpName %gv2 \"gv22\"\n"
|
||||
"OpName %lv1 \"lv12\"\n"
|
||||
"OpName %lv2 \"lv22\"\n"
|
||||
"OpName %lv1_0 \"lv12\"\n"
|
||||
"%void = OpTypeVoid\n"
|
||||
"%10 = OpTypeFunction %void\n"
|
||||
"%float = OpTypeFloat 32\n"
|
||||
"%12 = OpTypeFunction %float\n"
|
||||
"%_ptr_Private_float = OpTypePointer Private %float\n"
|
||||
"%gv1 = OpVariable %_ptr_Private_float Private\n"
|
||||
"%float_10 = OpConstant %float 10\n"
|
||||
"%gv2 = OpVariable %_ptr_Private_float Private\n"
|
||||
"%float_100 = OpConstant %float 100\n"
|
||||
"%_ptr_Function_float = OpTypePointer Function %float\n"
|
||||
"%main = OpFunction %void None %10\n"
|
||||
"%17 = OpLabel\n"
|
||||
"%lv1_0 = OpVariable %_ptr_Function_float Function\n"
|
||||
"OpStore %gv1 %float_10\n"
|
||||
"OpStore %gv2 %float_100\n"
|
||||
"%18 = OpLoad %float %gv1\n"
|
||||
"%19 = OpLoad %float %gv2\n"
|
||||
"%20 = OpFSub %float %18 %19\n"
|
||||
"OpStore %lv1_0 %20\n"
|
||||
"OpReturn\n"
|
||||
"OpFunctionEnd\n"
|
||||
"%f_ = OpFunction %float None %12\n"
|
||||
"%21 = OpLabel\n"
|
||||
"%lv1 = OpVariable %_ptr_Function_float Function\n"
|
||||
"%lv2 = OpVariable %_ptr_Function_float Function\n"
|
||||
"%22 = OpLoad %float %gv1\n"
|
||||
"%23 = OpLoad %float %gv2\n"
|
||||
"%24 = OpFAdd %float %22 %23\n"
|
||||
"OpStore %lv1 %24\n"
|
||||
"%25 = OpLoad %float %gv1\n"
|
||||
"%26 = OpLoad %float %gv2\n"
|
||||
"%27 = OpFMul %float %25 %26\n"
|
||||
"OpStore %lv2 %27\n"
|
||||
"%28 = OpLoad %float %lv1\n"
|
||||
"%29 = OpLoad %float %lv2\n"
|
||||
"%30 = OpFDiv %float %28 %29\n"
|
||||
"OpReturnValue %30\n"
|
||||
"OpFunctionEnd\n";
|
||||
// clang-format on
|
||||
|
||||
spvtest::Binary linked_binary;
|
||||
LinkerOptions options;
|
||||
options.SetVerifyIds(true);
|
||||
spv_result_t res = AssembleAndLink(bodies, &linked_binary, options);
|
||||
EXPECT_EQ(SPV_SUCCESS, res);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace spvtools
|
||||
53
3rdparty/spirv-tools/test/log_test.cpp
vendored
53
3rdparty/spirv-tools/test/log_test.cpp
vendored
@@ -1,53 +0,0 @@
|
||||
// Copyright (c) 2016 Google Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "source/opt/log.h"
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace {
|
||||
|
||||
using ::testing::MatchesRegex;
|
||||
|
||||
TEST(Log, Unimplemented) {
|
||||
int invocation = 0;
|
||||
auto consumer = [&invocation](spv_message_level_t level, const char* source,
|
||||
const spv_position_t&, const char* message) {
|
||||
++invocation;
|
||||
EXPECT_EQ(SPV_MSG_INTERNAL_ERROR, level);
|
||||
EXPECT_THAT(source, MatchesRegex(".*log_test.cpp$"));
|
||||
EXPECT_STREQ("unimplemented: the-ultimite-feature", message);
|
||||
};
|
||||
|
||||
SPIRV_UNIMPLEMENTED(consumer, "the-ultimite-feature");
|
||||
EXPECT_EQ(1, invocation);
|
||||
}
|
||||
|
||||
TEST(Log, Unreachable) {
|
||||
int invocation = 0;
|
||||
auto consumer = [&invocation](spv_message_level_t level, const char* source,
|
||||
const spv_position_t&, const char* message) {
|
||||
++invocation;
|
||||
EXPECT_EQ(SPV_MSG_INTERNAL_ERROR, level);
|
||||
EXPECT_THAT(source, MatchesRegex(".*log_test.cpp$"));
|
||||
EXPECT_STREQ("unreachable", message);
|
||||
};
|
||||
|
||||
SPIRV_UNREACHABLE(consumer);
|
||||
EXPECT_EQ(1, invocation);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace spvtools
|
||||
347
3rdparty/spirv-tools/test/name_mapper_test.cpp
vendored
347
3rdparty/spirv-tools/test/name_mapper_test.cpp
vendored
@@ -1,347 +0,0 @@
|
||||
// Copyright (c) 2016 Google Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "source/name_mapper.h"
|
||||
#include "test/test_fixture.h"
|
||||
#include "test/unit_spirv.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace {
|
||||
|
||||
using spvtest::ScopedContext;
|
||||
using ::testing::Eq;
|
||||
|
||||
TEST(TrivialNameTest, Samples) {
|
||||
auto mapper = GetTrivialNameMapper();
|
||||
EXPECT_EQ(mapper(1), "1");
|
||||
EXPECT_EQ(mapper(1999), "1999");
|
||||
EXPECT_EQ(mapper(1024), "1024");
|
||||
}
|
||||
|
||||
// A test case for the name mappers that actually look at an assembled module.
|
||||
struct NameIdCase {
|
||||
std::string assembly; // Input assembly text
|
||||
uint32_t id;
|
||||
std::string expected_name;
|
||||
};
|
||||
|
||||
using FriendlyNameTest =
|
||||
spvtest::TextToBinaryTestBase<::testing::TestWithParam<NameIdCase>>;
|
||||
|
||||
TEST_P(FriendlyNameTest, SingleMapping) {
|
||||
ScopedContext context(SPV_ENV_UNIVERSAL_1_1);
|
||||
auto words = CompileSuccessfully(GetParam().assembly, SPV_ENV_UNIVERSAL_1_1);
|
||||
auto friendly_mapper =
|
||||
FriendlyNameMapper(context.context, words.data(), words.size());
|
||||
NameMapper mapper = friendly_mapper.GetNameMapper();
|
||||
EXPECT_THAT(mapper(GetParam().id), Eq(GetParam().expected_name))
|
||||
<< GetParam().assembly << std::endl
|
||||
<< " for id " << GetParam().id;
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(ScalarType, FriendlyNameTest,
|
||||
::testing::ValuesIn(std::vector<NameIdCase>{
|
||||
{"%1 = OpTypeVoid", 1, "void"},
|
||||
{"%1 = OpTypeBool", 1, "bool"},
|
||||
{"%1 = OpTypeInt 8 0", 1, "uchar"},
|
||||
{"%1 = OpTypeInt 8 1", 1, "char"},
|
||||
{"%1 = OpTypeInt 16 0", 1, "ushort"},
|
||||
{"%1 = OpTypeInt 16 1", 1, "short"},
|
||||
{"%1 = OpTypeInt 32 0", 1, "uint"},
|
||||
{"%1 = OpTypeInt 32 1", 1, "int"},
|
||||
{"%1 = OpTypeInt 64 0", 1, "ulong"},
|
||||
{"%1 = OpTypeInt 64 1", 1, "long"},
|
||||
{"%1 = OpTypeInt 1 0", 1, "u1"},
|
||||
{"%1 = OpTypeInt 1 1", 1, "i1"},
|
||||
{"%1 = OpTypeInt 33 0", 1, "u33"},
|
||||
{"%1 = OpTypeInt 33 1", 1, "i33"},
|
||||
|
||||
{"%1 = OpTypeFloat 16", 1, "half"},
|
||||
{"%1 = OpTypeFloat 32", 1, "float"},
|
||||
{"%1 = OpTypeFloat 64", 1, "double"},
|
||||
{"%1 = OpTypeFloat 10", 1, "fp10"},
|
||||
{"%1 = OpTypeFloat 55", 1, "fp55"},
|
||||
}));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
VectorType, FriendlyNameTest,
|
||||
::testing::ValuesIn(std::vector<NameIdCase>{
|
||||
{"%1 = OpTypeBool %2 = OpTypeVector %1 1", 2, "v1bool"},
|
||||
{"%1 = OpTypeBool %2 = OpTypeVector %1 2", 2, "v2bool"},
|
||||
{"%1 = OpTypeBool %2 = OpTypeVector %1 3", 2, "v3bool"},
|
||||
{"%1 = OpTypeBool %2 = OpTypeVector %1 4", 2, "v4bool"},
|
||||
|
||||
{"%1 = OpTypeInt 8 0 %2 = OpTypeVector %1 2", 2, "v2uchar"},
|
||||
{"%1 = OpTypeInt 16 1 %2 = OpTypeVector %1 3", 2, "v3short"},
|
||||
{"%1 = OpTypeInt 32 0 %2 = OpTypeVector %1 4", 2, "v4uint"},
|
||||
{"%1 = OpTypeInt 64 1 %2 = OpTypeVector %1 3", 2, "v3long"},
|
||||
{"%1 = OpTypeInt 20 0 %2 = OpTypeVector %1 4", 2, "v4u20"},
|
||||
{"%1 = OpTypeInt 21 1 %2 = OpTypeVector %1 3", 2, "v3i21"},
|
||||
|
||||
{"%1 = OpTypeFloat 32 %2 = OpTypeVector %1 2", 2, "v2float"},
|
||||
// OpName overrides the element name.
|
||||
{"OpName %1 \"time\" %1 = OpTypeFloat 32 %2 = OpTypeVector %1 2", 2,
|
||||
"v2time"},
|
||||
}));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
MatrixType, FriendlyNameTest,
|
||||
::testing::ValuesIn(std::vector<NameIdCase>{
|
||||
{"%1 = OpTypeBool %2 = OpTypeVector %1 2 %3 = OpTypeMatrix %2 2", 3,
|
||||
"mat2v2bool"},
|
||||
{"%1 = OpTypeFloat 32 %2 = OpTypeVector %1 2 %3 = OpTypeMatrix %2 3", 3,
|
||||
"mat3v2float"},
|
||||
{"%1 = OpTypeFloat 32 %2 = OpTypeVector %1 2 %3 = OpTypeMatrix %2 4", 3,
|
||||
"mat4v2float"},
|
||||
{"OpName %1 \"time\" %1 = OpTypeFloat 32 %2 = OpTypeVector %1 2 %3 = "
|
||||
"OpTypeMatrix %2 4",
|
||||
3, "mat4v2time"},
|
||||
{"OpName %2 \"lat_long\" %1 = OpTypeFloat 32 %2 = OpTypeVector %1 2 %3 "
|
||||
"= OpTypeMatrix %2 4",
|
||||
3, "mat4lat_long"},
|
||||
}));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
OpName, FriendlyNameTest,
|
||||
::testing::ValuesIn(std::vector<NameIdCase>{
|
||||
{"OpName %1 \"abcdefg\"", 1, "abcdefg"},
|
||||
{"OpName %1 \"Hello world!\"", 1, "Hello_world_"},
|
||||
{"OpName %1 \"0123456789\"", 1, "0123456789"},
|
||||
{"OpName %1 \"_\"", 1, "_"},
|
||||
// An empty string is not valid for SPIR-V assembly IDs.
|
||||
{"OpName %1 \"\"", 1, "_"},
|
||||
// Test uniqueness when presented with things mapping to "_"
|
||||
{"OpName %1 \"\" OpName %2 \"\"", 1, "_"},
|
||||
{"OpName %1 \"\" OpName %2 \"\"", 2, "__0"},
|
||||
{"OpName %1 \"\" OpName %2 \"\" OpName %3 \"_\"", 3, "__1"},
|
||||
// Test uniqueness of names that are forced to be
|
||||
// numbers.
|
||||
{"OpName %1 \"2\" OpName %2 \"2\"", 1, "2"},
|
||||
{"OpName %1 \"2\" OpName %2 \"2\"", 2, "2_0"},
|
||||
// Test uniqueness in the face of forward references
|
||||
// for Ids that don't already have friendly names.
|
||||
// In particular, the first OpDecorate assigns the name, and
|
||||
// the second one can't override it.
|
||||
{"OpDecorate %1 Volatile OpDecorate %1 Restrict", 1, "1"},
|
||||
// But a forced name can override the name that
|
||||
// would have been assigned via the OpDecorate
|
||||
// forward reference.
|
||||
{"OpName %1 \"mememe\" OpDecorate %1 Volatile OpDecorate %1 Restrict",
|
||||
1, "mememe"},
|
||||
// OpName can override other inferences. We assume valid instruction
|
||||
// ordering, where OpName precedes type definitions.
|
||||
{"OpName %1 \"myfloat\" %1 = OpTypeFloat 32", 1, "myfloat"},
|
||||
}));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
UniquenessHeuristic, FriendlyNameTest,
|
||||
::testing::ValuesIn(std::vector<NameIdCase>{
|
||||
{"%1 = OpTypeVoid %2 = OpTypeVoid %3 = OpTypeVoid", 1, "void"},
|
||||
{"%1 = OpTypeVoid %2 = OpTypeVoid %3 = OpTypeVoid", 2, "void_0"},
|
||||
{"%1 = OpTypeVoid %2 = OpTypeVoid %3 = OpTypeVoid", 3, "void_1"},
|
||||
}));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(Arrays, FriendlyNameTest,
|
||||
::testing::ValuesIn(std::vector<NameIdCase>{
|
||||
{"OpName %2 \"FortyTwo\" %1 = OpTypeFloat 32 "
|
||||
"%2 = OpConstant %1 42 %3 = OpTypeArray %1 %2",
|
||||
3, "_arr_float_FortyTwo"},
|
||||
{"%1 = OpTypeInt 32 0 "
|
||||
"%2 = OpTypeRuntimeArray %1",
|
||||
2, "_runtimearr_uint"},
|
||||
}));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(Structs, FriendlyNameTest,
|
||||
::testing::ValuesIn(std::vector<NameIdCase>{
|
||||
{"%1 = OpTypeBool "
|
||||
"%2 = OpTypeStruct %1 %1 %1",
|
||||
2, "_struct_2"},
|
||||
{"%1 = OpTypeBool "
|
||||
"%2 = OpTypeStruct %1 %1 %1 "
|
||||
"%3 = OpTypeStruct %2 %2",
|
||||
3, "_struct_3"},
|
||||
}));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
Pointer, FriendlyNameTest,
|
||||
::testing::ValuesIn(std::vector<NameIdCase>{
|
||||
{"%1 = OpTypeFloat 32 %2 = OpTypePointer Workgroup %1", 2,
|
||||
"_ptr_Workgroup_float"},
|
||||
{"%1 = OpTypeBool %2 = OpTypePointer Private %1", 2,
|
||||
"_ptr_Private_bool"},
|
||||
// OpTypeForwardPointer doesn't force generation of the name for its
|
||||
// target type.
|
||||
{"%1 = OpTypeBool OpTypeForwardPointer %2 Private %2 = OpTypePointer "
|
||||
"Private %1",
|
||||
2, "_ptr_Private_bool"},
|
||||
}));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(ExoticTypes, FriendlyNameTest,
|
||||
::testing::ValuesIn(std::vector<NameIdCase>{
|
||||
{"%1 = OpTypeEvent", 1, "Event"},
|
||||
{"%1 = OpTypeDeviceEvent", 1, "DeviceEvent"},
|
||||
{"%1 = OpTypeReserveId", 1, "ReserveId"},
|
||||
{"%1 = OpTypeQueue", 1, "Queue"},
|
||||
{"%1 = OpTypeOpaque \"hello world!\"", 1,
|
||||
"Opaque_hello_world_"},
|
||||
{"%1 = OpTypePipe ReadOnly", 1, "PipeReadOnly"},
|
||||
{"%1 = OpTypePipe WriteOnly", 1, "PipeWriteOnly"},
|
||||
{"%1 = OpTypePipe ReadWrite", 1, "PipeReadWrite"},
|
||||
{"%1 = OpTypePipeStorage", 1, "PipeStorage"},
|
||||
{"%1 = OpTypeNamedBarrier", 1, "NamedBarrier"},
|
||||
}));
|
||||
|
||||
// Makes a test case for a BuiltIn variable declaration.
|
||||
NameIdCase BuiltInCase(std::string assembly_name, std::string expected) {
|
||||
return NameIdCase{std::string("OpDecorate %1 BuiltIn ") + assembly_name +
|
||||
" %1 = OpVariable %2 Input",
|
||||
1, expected};
|
||||
}
|
||||
|
||||
// Makes a test case for a BuiltIn variable declaration. In this overload,
|
||||
// the expected result is the same as the assembly name.
|
||||
NameIdCase BuiltInCase(std::string assembly_name) {
|
||||
return BuiltInCase(assembly_name, assembly_name);
|
||||
}
|
||||
|
||||
// Makes a test case for a BuiltIn variable declaration. In this overload,
|
||||
// the expected result is the same as the assembly name, but with a "gl_"
|
||||
// prefix.
|
||||
NameIdCase BuiltInGLCase(std::string assembly_name) {
|
||||
return BuiltInCase(assembly_name, std::string("gl_") + assembly_name);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
BuiltIns, FriendlyNameTest,
|
||||
::testing::ValuesIn(std::vector<NameIdCase>{
|
||||
BuiltInGLCase("Position"),
|
||||
BuiltInGLCase("PointSize"),
|
||||
BuiltInGLCase("ClipDistance"),
|
||||
BuiltInGLCase("CullDistance"),
|
||||
BuiltInCase("VertexId", "gl_VertexID"),
|
||||
BuiltInCase("InstanceId", "gl_InstanceID"),
|
||||
BuiltInCase("PrimitiveId", "gl_PrimitiveID"),
|
||||
BuiltInCase("InvocationId", "gl_InvocationID"),
|
||||
BuiltInGLCase("Layer"),
|
||||
BuiltInGLCase("ViewportIndex"),
|
||||
BuiltInGLCase("TessLevelOuter"),
|
||||
BuiltInGLCase("TessLevelInner"),
|
||||
BuiltInGLCase("TessCoord"),
|
||||
BuiltInGLCase("PatchVertices"),
|
||||
BuiltInGLCase("FragCoord"),
|
||||
BuiltInGLCase("PointCoord"),
|
||||
BuiltInGLCase("FrontFacing"),
|
||||
BuiltInCase("SampleId", "gl_SampleID"),
|
||||
BuiltInGLCase("SamplePosition"),
|
||||
BuiltInGLCase("SampleMask"),
|
||||
BuiltInGLCase("FragDepth"),
|
||||
BuiltInGLCase("HelperInvocation"),
|
||||
BuiltInCase("NumWorkgroups", "gl_NumWorkGroups"),
|
||||
BuiltInCase("WorkgroupSize", "gl_WorkGroupSize"),
|
||||
BuiltInCase("WorkgroupId", "gl_WorkGroupID"),
|
||||
BuiltInCase("LocalInvocationId", "gl_LocalInvocationID"),
|
||||
BuiltInCase("GlobalInvocationId", "gl_GlobalInvocationID"),
|
||||
BuiltInGLCase("LocalInvocationIndex"),
|
||||
BuiltInCase("WorkDim"),
|
||||
BuiltInCase("GlobalSize"),
|
||||
BuiltInCase("EnqueuedWorkgroupSize"),
|
||||
BuiltInCase("GlobalOffset"),
|
||||
BuiltInCase("GlobalLinearId"),
|
||||
BuiltInCase("SubgroupSize"),
|
||||
BuiltInCase("SubgroupMaxSize"),
|
||||
BuiltInCase("NumSubgroups"),
|
||||
BuiltInCase("NumEnqueuedSubgroups"),
|
||||
BuiltInCase("SubgroupId"),
|
||||
BuiltInCase("SubgroupLocalInvocationId"),
|
||||
BuiltInGLCase("VertexIndex"),
|
||||
BuiltInGLCase("InstanceIndex"),
|
||||
BuiltInCase("SubgroupEqMaskKHR"),
|
||||
BuiltInCase("SubgroupGeMaskKHR"),
|
||||
BuiltInCase("SubgroupGtMaskKHR"),
|
||||
BuiltInCase("SubgroupLeMaskKHR"),
|
||||
BuiltInCase("SubgroupLtMaskKHR"),
|
||||
}));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(DebugNameOverridesBuiltin, FriendlyNameTest,
|
||||
::testing::ValuesIn(std::vector<NameIdCase>{
|
||||
{"OpName %1 \"foo\" OpDecorate %1 BuiltIn WorkDim "
|
||||
"%1 = OpVariable %2 Input",
|
||||
1, "foo"}}));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
SimpleIntegralConstants, FriendlyNameTest,
|
||||
::testing::ValuesIn(std::vector<NameIdCase>{
|
||||
{"%1 = OpTypeInt 32 0 %2 = OpConstant %1 0", 2, "uint_0"},
|
||||
{"%1 = OpTypeInt 32 0 %2 = OpConstant %1 1", 2, "uint_1"},
|
||||
{"%1 = OpTypeInt 32 0 %2 = OpConstant %1 2", 2, "uint_2"},
|
||||
{"%1 = OpTypeInt 32 0 %2 = OpConstant %1 9", 2, "uint_9"},
|
||||
{"%1 = OpTypeInt 32 0 %2 = OpConstant %1 42", 2, "uint_42"},
|
||||
{"%1 = OpTypeInt 32 1 %2 = OpConstant %1 0", 2, "int_0"},
|
||||
{"%1 = OpTypeInt 32 1 %2 = OpConstant %1 1", 2, "int_1"},
|
||||
{"%1 = OpTypeInt 32 1 %2 = OpConstant %1 2", 2, "int_2"},
|
||||
{"%1 = OpTypeInt 32 1 %2 = OpConstant %1 9", 2, "int_9"},
|
||||
{"%1 = OpTypeInt 32 1 %2 = OpConstant %1 42", 2, "int_42"},
|
||||
{"%1 = OpTypeInt 32 1 %2 = OpConstant %1 -42", 2, "int_n42"},
|
||||
// Exotic bit widths
|
||||
{"%1 = OpTypeInt 33 0 %2 = OpConstant %1 0", 2, "u33_0"},
|
||||
{"%1 = OpTypeInt 33 1 %2 = OpConstant %1 10", 2, "i33_10"},
|
||||
{"%1 = OpTypeInt 33 1 %2 = OpConstant %1 -19", 2, "i33_n19"},
|
||||
}));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
SimpleFloatConstants, FriendlyNameTest,
|
||||
::testing::ValuesIn(std::vector<NameIdCase>{
|
||||
{"%1 = OpTypeFloat 16\n%2 = OpConstant %1 0x1.ff4p+16", 2,
|
||||
"half_0x1_ff4p_16"},
|
||||
{"%1 = OpTypeFloat 16\n%2 = OpConstant %1 -0x1.d2cp-10", 2,
|
||||
"half_n0x1_d2cpn10"},
|
||||
// 32-bit floats
|
||||
{"%1 = OpTypeFloat 32\n%2 = OpConstant %1 -3.125", 2, "float_n3_125"},
|
||||
{"%1 = OpTypeFloat 32\n%2 = OpConstant %1 0x1.8p+128", 2,
|
||||
"float_0x1_8p_128"}, // NaN
|
||||
{"%1 = OpTypeFloat 32\n%2 = OpConstant %1 -0x1.0002p+128", 2,
|
||||
"float_n0x1_0002p_128"}, // NaN
|
||||
{"%1 = OpTypeFloat 32\n%2 = OpConstant %1 0x1p+128", 2,
|
||||
"float_0x1p_128"}, // Inf
|
||||
{"%1 = OpTypeFloat 32\n%2 = OpConstant %1 -0x1p+128", 2,
|
||||
"float_n0x1p_128"}, // -Inf
|
||||
// 64-bit floats
|
||||
{"%1 = OpTypeFloat 64\n%2 = OpConstant %1 -3.125", 2, "double_n3_125"},
|
||||
{"%1 = OpTypeFloat 64\n%2 = OpConstant %1 0x1.ffffffffffffap-1023", 2,
|
||||
"double_0x1_ffffffffffffapn1023"}, // small normal
|
||||
{"%1 = OpTypeFloat 64\n%2 = OpConstant %1 -0x1.ffffffffffffap-1023", 2,
|
||||
"double_n0x1_ffffffffffffapn1023"},
|
||||
{"%1 = OpTypeFloat 64\n%2 = OpConstant %1 0x1.8p+1024", 2,
|
||||
"double_0x1_8p_1024"}, // NaN
|
||||
{"%1 = OpTypeFloat 64\n%2 = OpConstant %1 -0x1.0002p+1024", 2,
|
||||
"double_n0x1_0002p_1024"}, // NaN
|
||||
{"%1 = OpTypeFloat 64\n%2 = OpConstant %1 0x1p+1024", 2,
|
||||
"double_0x1p_1024"}, // Inf
|
||||
{"%1 = OpTypeFloat 64\n%2 = OpConstant %1 -0x1p+1024", 2,
|
||||
"double_n0x1p_1024"}, // -Inf
|
||||
}));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
BooleanConstants, FriendlyNameTest,
|
||||
::testing::ValuesIn(std::vector<NameIdCase>{
|
||||
{"%1 = OpTypeBool\n%2 = OpConstantTrue %1", 2, "true"},
|
||||
{"%1 = OpTypeBool\n%2 = OpConstantFalse %1", 2, "false"},
|
||||
}));
|
||||
|
||||
} // namespace
|
||||
} // namespace spvtools
|
||||
87
3rdparty/spirv-tools/test/named_id_test.cpp
vendored
87
3rdparty/spirv-tools/test/named_id_test.cpp
vendored
@@ -1,87 +0,0 @@
|
||||
// Copyright (c) 2015-2016 The Khronos Group Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "test/test_fixture.h"
|
||||
#include "test/unit_spirv.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace {
|
||||
|
||||
using NamedIdTest = spvtest::TextToBinaryTest;
|
||||
|
||||
TEST_F(NamedIdTest, Default) {
|
||||
const std::string input = R"(
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical Simple
|
||||
OpEntryPoint Vertex %main "foo"
|
||||
%void = OpTypeVoid
|
||||
%fnMain = OpTypeFunction %void
|
||||
%main = OpFunction %void None %fnMain
|
||||
%lbMain = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd)";
|
||||
const std::string output =
|
||||
"OpCapability Shader\n"
|
||||
"OpMemoryModel Logical Simple\n"
|
||||
"OpEntryPoint Vertex %1 \"foo\"\n"
|
||||
"%2 = OpTypeVoid\n"
|
||||
"%3 = OpTypeFunction %2\n"
|
||||
"%1 = OpFunction %2 None %3\n"
|
||||
"%4 = OpLabel\n"
|
||||
"OpReturn\n"
|
||||
"OpFunctionEnd\n";
|
||||
EXPECT_EQ(output, EncodeAndDecodeSuccessfully(input));
|
||||
}
|
||||
|
||||
struct IdCheckCase {
|
||||
std::string id;
|
||||
bool valid;
|
||||
};
|
||||
|
||||
using IdValidityTest =
|
||||
spvtest::TextToBinaryTestBase<::testing::TestWithParam<IdCheckCase>>;
|
||||
|
||||
TEST_P(IdValidityTest, IdTypes) {
|
||||
const std::string input = GetParam().id + " = OpTypeVoid";
|
||||
SetText(input);
|
||||
if (GetParam().valid) {
|
||||
CompileSuccessfully(input);
|
||||
} else {
|
||||
CompileFailure(input);
|
||||
}
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
ValidAndInvalidIds, IdValidityTest,
|
||||
::testing::ValuesIn(std::vector<IdCheckCase>(
|
||||
{{"%1", true}, {"%2abc", true}, {"%3Def", true},
|
||||
{"%4GHI", true}, {"%5_j_k", true}, {"%6J_M", true},
|
||||
{"%n", true}, {"%O", true}, {"%p7", true},
|
||||
{"%Q8", true}, {"%R_S", true}, {"%T_10_U", true},
|
||||
{"%V_11", true}, {"%W_X_13", true}, {"%_A", true},
|
||||
{"%_", true}, {"%__", true}, {"%A_", true},
|
||||
{"%_A_", true},
|
||||
|
||||
{"%@", false}, {"%!", false}, {"%ABC!", false},
|
||||
{"%__A__@", false}, {"%%", false}, {"%-", false},
|
||||
{"%foo_@_bar", false}, {"%", false},
|
||||
|
||||
{"5", false}, {"32", false}, {"foo", false},
|
||||
{"a%bar", false}})));
|
||||
|
||||
} // namespace
|
||||
} // namespace spvtools
|
||||
44
3rdparty/spirv-tools/test/opcode_make_test.cpp
vendored
44
3rdparty/spirv-tools/test/opcode_make_test.cpp
vendored
@@ -1,44 +0,0 @@
|
||||
// Copyright (c) 2015-2016 The Khronos Group Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "test/unit_spirv.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace {
|
||||
|
||||
// A sampling of word counts. Covers extreme points well, and all bit
|
||||
// positions, and some combinations of bit positions.
|
||||
const uint16_t kSampleWordCounts[] = {
|
||||
0, 1, 2, 3, 4, 8, 16, 32, 64, 127, 128,
|
||||
256, 511, 512, 1024, 2048, 4096, 8192, 16384, 32768, 0xfffe, 0xffff};
|
||||
|
||||
// A sampling of opcode values. Covers the lower values well, a few samples
|
||||
// around the number of core instructions (as of this writing), and some
|
||||
// higher values.
|
||||
const uint16_t kSampleOpcodes[] = {0, 1, 2, 3, 4, 100,
|
||||
300, 305, 1023, 0xfffe, 0xffff};
|
||||
|
||||
TEST(OpcodeMake, Samples) {
|
||||
for (auto wordCount : kSampleWordCounts) {
|
||||
for (auto opcode : kSampleOpcodes) {
|
||||
uint32_t word = 0;
|
||||
word |= uint32_t(opcode);
|
||||
word |= uint32_t(wordCount) << 16;
|
||||
EXPECT_EQ(word, spvOpcodeMake(wordCount, SpvOp(opcode)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace spvtools
|
||||
@@ -1,78 +0,0 @@
|
||||
// Copyright (c) 2015-2016 The Khronos Group Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "test/unit_spirv.h"
|
||||
|
||||
#include "source/enum_set.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace {
|
||||
|
||||
using spvtest::ElementsIn;
|
||||
|
||||
// Capabilities required by an Opcode.
|
||||
struct ExpectedOpCodeCapabilities {
|
||||
SpvOp opcode;
|
||||
CapabilitySet capabilities;
|
||||
};
|
||||
|
||||
using OpcodeTableCapabilitiesTest =
|
||||
::testing::TestWithParam<ExpectedOpCodeCapabilities>;
|
||||
|
||||
TEST_P(OpcodeTableCapabilitiesTest, TableEntryMatchesExpectedCapabilities) {
|
||||
auto env = SPV_ENV_UNIVERSAL_1_1;
|
||||
spv_opcode_table opcodeTable;
|
||||
ASSERT_EQ(SPV_SUCCESS, spvOpcodeTableGet(&opcodeTable, env));
|
||||
spv_opcode_desc entry;
|
||||
ASSERT_EQ(SPV_SUCCESS, spvOpcodeTableValueLookup(env, opcodeTable,
|
||||
GetParam().opcode, &entry));
|
||||
EXPECT_EQ(
|
||||
ElementsIn(GetParam().capabilities),
|
||||
ElementsIn(CapabilitySet(entry->numCapabilities, entry->capabilities)));
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
TableRowTest, OpcodeTableCapabilitiesTest,
|
||||
// Spot-check a few opcodes.
|
||||
::testing::Values(
|
||||
ExpectedOpCodeCapabilities{
|
||||
SpvOpImageQuerySize,
|
||||
CapabilitySet{SpvCapabilityKernel, SpvCapabilityImageQuery}},
|
||||
ExpectedOpCodeCapabilities{
|
||||
SpvOpImageQuerySizeLod,
|
||||
CapabilitySet{SpvCapabilityKernel, SpvCapabilityImageQuery}},
|
||||
ExpectedOpCodeCapabilities{
|
||||
SpvOpImageQueryLevels,
|
||||
CapabilitySet{SpvCapabilityKernel, SpvCapabilityImageQuery}},
|
||||
ExpectedOpCodeCapabilities{
|
||||
SpvOpImageQuerySamples,
|
||||
CapabilitySet{SpvCapabilityKernel, SpvCapabilityImageQuery}},
|
||||
ExpectedOpCodeCapabilities{SpvOpImageSparseSampleImplicitLod,
|
||||
CapabilitySet{SpvCapabilitySparseResidency}},
|
||||
ExpectedOpCodeCapabilities{SpvOpCopyMemorySized,
|
||||
CapabilitySet{SpvCapabilityAddresses}},
|
||||
ExpectedOpCodeCapabilities{SpvOpArrayLength,
|
||||
CapabilitySet{SpvCapabilityShader}},
|
||||
ExpectedOpCodeCapabilities{SpvOpFunction, CapabilitySet()},
|
||||
ExpectedOpCodeCapabilities{SpvOpConvertFToS, CapabilitySet()},
|
||||
ExpectedOpCodeCapabilities{SpvOpEmitStreamVertex,
|
||||
CapabilitySet{SpvCapabilityGeometryStreams}},
|
||||
ExpectedOpCodeCapabilities{SpvOpTypeNamedBarrier,
|
||||
CapabilitySet{SpvCapabilityNamedBarrier}},
|
||||
ExpectedOpCodeCapabilities{
|
||||
SpvOpGetKernelMaxNumSubgroups,
|
||||
CapabilitySet{SpvCapabilitySubgroupDispatch}}));
|
||||
|
||||
} // namespace
|
||||
} // namespace spvtools
|
||||
30
3rdparty/spirv-tools/test/opcode_split_test.cpp
vendored
30
3rdparty/spirv-tools/test/opcode_split_test.cpp
vendored
@@ -1,30 +0,0 @@
|
||||
// Copyright (c) 2015-2016 The Khronos Group Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "test/unit_spirv.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace {
|
||||
|
||||
TEST(OpcodeSplit, Default) {
|
||||
uint32_t word = spvOpcodeMake(42, (SpvOp)23);
|
||||
uint16_t wordCount = 0;
|
||||
uint16_t opcode;
|
||||
spvOpcodeSplit(word, &wordCount, &opcode);
|
||||
ASSERT_EQ(42, wordCount);
|
||||
ASSERT_EQ(23, opcode);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace spvtools
|
||||
@@ -1,39 +0,0 @@
|
||||
// Copyright (c) 2015-2016 The Khronos Group Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "test/unit_spirv.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace {
|
||||
|
||||
using GetTargetOpcodeTableGetTest = ::testing::TestWithParam<spv_target_env>;
|
||||
using ::testing::ValuesIn;
|
||||
|
||||
TEST_P(GetTargetOpcodeTableGetTest, SanityCheck) {
|
||||
spv_opcode_table table;
|
||||
ASSERT_EQ(SPV_SUCCESS, spvOpcodeTableGet(&table, GetParam()));
|
||||
ASSERT_NE(0u, table->count);
|
||||
ASSERT_NE(nullptr, table->entries);
|
||||
}
|
||||
|
||||
TEST_P(GetTargetOpcodeTableGetTest, InvalidPointerTable) {
|
||||
ASSERT_EQ(SPV_ERROR_INVALID_POINTER, spvOpcodeTableGet(nullptr, GetParam()));
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(OpcodeTableGet, GetTargetOpcodeTableGetTest,
|
||||
ValuesIn(spvtest::AllTargetEnvironments()));
|
||||
|
||||
} // namespace
|
||||
} // namespace spvtools
|
||||
@@ -1,43 +0,0 @@
|
||||
Operand class,Example instruction,Notes,example unit test,negative-enum coverage location
|
||||
" OperandNone,",UNUSED,not in grammar,,not enum
|
||||
" OperandId,",many,ID,too many to count,not enum
|
||||
" OperandOptionalId,","Source, Variable",OPTIONAL_ID,OpSourceAcceptsOptionalFileId,not enum
|
||||
" OperandOptionalImage,",ImageFetch,,ImageOperandsTest,"TEST_F(ImageOperandsTest, WrongOperand)"
|
||||
" OperandVariableIds,",ExtInst,,,not enum
|
||||
" OperandOptionalLiteral,",ExecutionMode,,AnyExecutionMode,not enum
|
||||
" OperandOptionalLiteralString,",Source,,OpSourceAcceptsOptionalSourceText,not enum
|
||||
" OperandVariableLiterals,",Decorate,,OpDecorateSimpleTest,not enum
|
||||
" OperandVariableIdLiteral,",GroupMemberDecorate,,GroupMemberDecorate*,not enum
|
||||
" OperandVariableLiteralId,",Switch,,Switch*,not enum
|
||||
" OperandLiteralNumber,","Source, Switch, ...",,Switch*,not enum
|
||||
" OperandLiteralString,",SourceContinued,,OpSourceContinued,not enum
|
||||
" OperandSource,",Source,,OpSource,not enum
|
||||
" OperandExecutionModel,",EntryPoint,,OpEntryPointTest,"TEST_F(OpEntryPointTest, WrongModel)"
|
||||
" OperandAddressing,",OpMemoryModel,,OpMemoryModelTest,"TEST_F(OpMemoryModelTest, WrongModel)"
|
||||
" OperandMemory,",OpMemoryModel,,OpMemoryModelTest,"TEST_F(OpMemoryModelTest, WrongModel)"
|
||||
" OperandExecutionMode,",OpExecutionMode,,OpExecutionModeTest,"TEST_F(OpExecutionModeTest, WrongMode)"
|
||||
" OperandStorage,","TypePointer, TypeForwardPointer, Variable",,StorageClassTest,"TEST_F(OpTypeForwardPointerTest, WrongClass)"
|
||||
" OperandDimensionality,",TypeImage,,DimTest/AnyDim,"TEST_F(DimTest, WrongDim)"
|
||||
" OperandSamplerAddressingMode,",ConstantSampler,,SamplerAddressingModeTest,"TEST_F(SamplerAddressingModeTest, WrongMode)"
|
||||
" OperandSamplerFilterMode,",ConstantSampler,,AnySamplerFilterMode,"TEST_F(SamplerFilterModeTest, WrongMode)"
|
||||
" OperandSamplerImageFormat,",TypeImage,SAMPLER_IMAGE_FORMAT,ImageFormatTest,"TEST_F(ImageFormatTest, WrongFormat)"
|
||||
" OperandImageChannelOrder,",UNUSED,returned as result value only,,
|
||||
" OperandImageChannelDataType,",UNUSED,returned as result value only,,
|
||||
" OperandImageOperands,",UNUSED,used to make a spec section,,see OperandOptionalImage
|
||||
" OperandFPFastMath,",OpDecorate,,CombinedFPFastMathMask,"TEST_F(OpDecorateEnumTest, WrongFPFastMathMode)"
|
||||
" OperandFPRoundingMode,",OpDecorate,,,"TEST_F(OpDecorateEnumTest, WrongFPRoundingMode)"
|
||||
" OperandLinkageType,",OpDecorate,,OpDecorateLinkageTest,"TEST_F(OpDecorateLinkageTest, WrongType)"
|
||||
" OperandAccessQualifier,",OpTypePipe,,AnyAccessQualifier,"TEST_F(OpTypePipeTest, WrongAccessQualifier)"
|
||||
" OperandFuncParamAttr,",OpDecorate,,TextToBinaryDecorateFuncParamAttr,"TEST_F(OpDecorateEnumTest, WrongFuncParamAttr)"
|
||||
" OperandDecoration,",OpDecorate,,AnyAccessQualifier,"TEST_F(OpTypePipeTest, WrongAccessQualifier)"
|
||||
" OperandBuiltIn,",OpDecorate,,TextToBinaryDecorateBultIn,"TEST_F(OpDecorateEnumTest, WrongBuiltIn)"
|
||||
" OperandSelect,",SelectionMerge,,TextToBinarySelectionMerge,"TEST_F(OpSelectionMergeTest, WrongSelectionControl)"
|
||||
" OperandLoop,",LoopMerge,,CombinedLoopControlMask,"TEST_F(OpLoopMergeTest, WrongLoopControl)"
|
||||
" OperandFunction,",Function,,AnySingleFunctionControlMask,"TEST_F(OpFunctionControlTest, WrongFunctionControl)"
|
||||
" OperandMemorySemantics,",OpMemoryBarrier,"it's an ID, not in grammar",OpMemoryBarrier*,not enum
|
||||
" OperandMemoryAccess,",UNUSED,"should be on opstore, but hacked in opcode.cpp",,not enum
|
||||
" OperandScope,",MemoryBarrier,"it's an ID, not in grammar",OpMemoryBarrier*,not enum
|
||||
" OperandGroupOperation,",GroupIAdd,,GroupOperationTest,"TEST_F(GroupOperationTest, WrongGroupOperation)"
|
||||
" OperandKernelEnqueueFlags,",OpEnqueueKernel,"it's an ID, not in grammar",should not have one,not enum
|
||||
" OperandKernelProfilingInfo,",OpCaptureEventProfilingInfo,"it's an ID, not in grammar",should not have one,not enum
|
||||
" OperandCapability,",Capability,,OpCapabilityTest,"TEST_F(TextToBinaryCapability, BadInvalidCapability)"
|
||||
|
@@ -1,748 +0,0 @@
|
||||
// Copyright (c) 2015-2016 The Khronos Group Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Test capability dependencies for enums.
|
||||
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "source/enum_set.h"
|
||||
#include "test/unit_spirv.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace {
|
||||
|
||||
using spvtest::ElementsIn;
|
||||
using ::testing::Combine;
|
||||
using ::testing::Eq;
|
||||
using ::testing::TestWithParam;
|
||||
using ::testing::Values;
|
||||
using ::testing::ValuesIn;
|
||||
|
||||
// A test case for mapping an enum to a capability mask.
|
||||
struct EnumCapabilityCase {
|
||||
spv_operand_type_t type;
|
||||
uint32_t value;
|
||||
CapabilitySet expected_capabilities;
|
||||
};
|
||||
|
||||
// Test fixture for testing EnumCapabilityCases.
|
||||
using EnumCapabilityTest =
|
||||
TestWithParam<std::tuple<spv_target_env, EnumCapabilityCase>>;
|
||||
|
||||
TEST_P(EnumCapabilityTest, Sample) {
|
||||
const auto env = std::get<0>(GetParam());
|
||||
const auto context = spvContextCreate(env);
|
||||
const AssemblyGrammar grammar(context);
|
||||
spv_operand_desc entry;
|
||||
|
||||
ASSERT_EQ(SPV_SUCCESS,
|
||||
grammar.lookupOperand(std::get<1>(GetParam()).type,
|
||||
std::get<1>(GetParam()).value, &entry));
|
||||
const auto cap_set = grammar.filterCapsAgainstTargetEnv(
|
||||
entry->capabilities, entry->numCapabilities);
|
||||
|
||||
EXPECT_THAT(ElementsIn(cap_set),
|
||||
Eq(ElementsIn(std::get<1>(GetParam()).expected_capabilities)))
|
||||
<< " capability value " << std::get<1>(GetParam()).value;
|
||||
spvContextDestroy(context);
|
||||
}
|
||||
|
||||
#define CASE0(TYPE, VALUE) \
|
||||
{ \
|
||||
SPV_OPERAND_TYPE_##TYPE, uint32_t(Spv##VALUE), {} \
|
||||
}
|
||||
#define CASE1(TYPE, VALUE, CAP) \
|
||||
{ \
|
||||
SPV_OPERAND_TYPE_##TYPE, uint32_t(Spv##VALUE), CapabilitySet { \
|
||||
SpvCapability##CAP \
|
||||
} \
|
||||
}
|
||||
#define CASE2(TYPE, VALUE, CAP1, CAP2) \
|
||||
{ \
|
||||
SPV_OPERAND_TYPE_##TYPE, uint32_t(Spv##VALUE), CapabilitySet { \
|
||||
SpvCapability##CAP1, SpvCapability##CAP2 \
|
||||
} \
|
||||
}
|
||||
#define CASE3(TYPE, VALUE, CAP1, CAP2, CAP3) \
|
||||
{ \
|
||||
SPV_OPERAND_TYPE_##TYPE, uint32_t(Spv##VALUE), CapabilitySet { \
|
||||
SpvCapability##CAP1, SpvCapability##CAP2, SpvCapability##CAP3 \
|
||||
} \
|
||||
}
|
||||
#define CASE5(TYPE, VALUE, CAP1, CAP2, CAP3, CAP4, CAP5) \
|
||||
{ \
|
||||
SPV_OPERAND_TYPE_##TYPE, uint32_t(Spv##VALUE), CapabilitySet { \
|
||||
SpvCapability##CAP1, SpvCapability##CAP2, SpvCapability##CAP3, \
|
||||
SpvCapability##CAP4, SpvCapability##CAP5 \
|
||||
} \
|
||||
}
|
||||
|
||||
// See SPIR-V Section 3.3 Execution Model
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
ExecutionModel, EnumCapabilityTest,
|
||||
Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1),
|
||||
ValuesIn(std::vector<EnumCapabilityCase>{
|
||||
CASE1(EXECUTION_MODEL, ExecutionModelVertex, Shader),
|
||||
CASE1(EXECUTION_MODEL, ExecutionModelTessellationControl,
|
||||
Tessellation),
|
||||
CASE1(EXECUTION_MODEL, ExecutionModelTessellationEvaluation,
|
||||
Tessellation),
|
||||
CASE1(EXECUTION_MODEL, ExecutionModelGeometry, Geometry),
|
||||
CASE1(EXECUTION_MODEL, ExecutionModelFragment, Shader),
|
||||
CASE1(EXECUTION_MODEL, ExecutionModelGLCompute, Shader),
|
||||
CASE1(EXECUTION_MODEL, ExecutionModelKernel, Kernel),
|
||||
})));
|
||||
|
||||
// See SPIR-V Section 3.4 Addressing Model
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
AddressingModel, EnumCapabilityTest,
|
||||
Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1),
|
||||
ValuesIn(std::vector<EnumCapabilityCase>{
|
||||
CASE0(ADDRESSING_MODEL, AddressingModelLogical),
|
||||
CASE1(ADDRESSING_MODEL, AddressingModelPhysical32, Addresses),
|
||||
CASE1(ADDRESSING_MODEL, AddressingModelPhysical64, Addresses),
|
||||
})));
|
||||
|
||||
// See SPIR-V Section 3.5 Memory Model
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
MemoryModel, EnumCapabilityTest,
|
||||
Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1),
|
||||
ValuesIn(std::vector<EnumCapabilityCase>{
|
||||
CASE1(MEMORY_MODEL, MemoryModelSimple, Shader),
|
||||
CASE1(MEMORY_MODEL, MemoryModelGLSL450, Shader),
|
||||
CASE1(MEMORY_MODEL, MemoryModelOpenCL, Kernel),
|
||||
})));
|
||||
|
||||
// See SPIR-V Section 3.6 Execution Mode
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
ExecutionMode, EnumCapabilityTest,
|
||||
Combine(
|
||||
Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1),
|
||||
ValuesIn(std::vector<EnumCapabilityCase>{
|
||||
CASE1(EXECUTION_MODE, ExecutionModeInvocations, Geometry),
|
||||
CASE1(EXECUTION_MODE, ExecutionModeSpacingEqual, Tessellation),
|
||||
CASE1(EXECUTION_MODE, ExecutionModeSpacingFractionalEven,
|
||||
Tessellation),
|
||||
CASE1(EXECUTION_MODE, ExecutionModeSpacingFractionalOdd,
|
||||
Tessellation),
|
||||
CASE1(EXECUTION_MODE, ExecutionModeVertexOrderCw, Tessellation),
|
||||
CASE1(EXECUTION_MODE, ExecutionModeVertexOrderCcw, Tessellation),
|
||||
CASE1(EXECUTION_MODE, ExecutionModePixelCenterInteger, Shader),
|
||||
CASE1(EXECUTION_MODE, ExecutionModeOriginUpperLeft, Shader),
|
||||
CASE1(EXECUTION_MODE, ExecutionModeOriginLowerLeft, Shader),
|
||||
CASE1(EXECUTION_MODE, ExecutionModeEarlyFragmentTests, Shader),
|
||||
CASE1(EXECUTION_MODE, ExecutionModePointMode, Tessellation),
|
||||
CASE1(EXECUTION_MODE, ExecutionModeXfb, TransformFeedback),
|
||||
CASE1(EXECUTION_MODE, ExecutionModeDepthReplacing, Shader),
|
||||
CASE1(EXECUTION_MODE, ExecutionModeDepthGreater, Shader),
|
||||
CASE1(EXECUTION_MODE, ExecutionModeDepthLess, Shader),
|
||||
CASE1(EXECUTION_MODE, ExecutionModeDepthUnchanged, Shader),
|
||||
CASE0(EXECUTION_MODE, ExecutionModeLocalSize),
|
||||
CASE1(EXECUTION_MODE, ExecutionModeLocalSizeHint, Kernel),
|
||||
CASE1(EXECUTION_MODE, ExecutionModeInputPoints, Geometry),
|
||||
CASE1(EXECUTION_MODE, ExecutionModeInputLines, Geometry),
|
||||
CASE1(EXECUTION_MODE, ExecutionModeInputLinesAdjacency, Geometry),
|
||||
CASE2(EXECUTION_MODE, ExecutionModeTriangles, Geometry,
|
||||
Tessellation),
|
||||
CASE1(EXECUTION_MODE, ExecutionModeInputTrianglesAdjacency,
|
||||
Geometry),
|
||||
CASE1(EXECUTION_MODE, ExecutionModeQuads, Tessellation),
|
||||
CASE1(EXECUTION_MODE, ExecutionModeIsolines, Tessellation),
|
||||
CASE3(EXECUTION_MODE, ExecutionModeOutputVertices, Geometry,
|
||||
Tessellation, MeshShadingNV),
|
||||
CASE2(EXECUTION_MODE, ExecutionModeOutputPoints, Geometry,
|
||||
MeshShadingNV),
|
||||
CASE1(EXECUTION_MODE, ExecutionModeOutputLineStrip, Geometry),
|
||||
CASE1(EXECUTION_MODE, ExecutionModeOutputTriangleStrip, Geometry),
|
||||
CASE1(EXECUTION_MODE, ExecutionModeVecTypeHint, Kernel),
|
||||
CASE1(EXECUTION_MODE, ExecutionModeContractionOff, Kernel),
|
||||
})));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
ExecutionModeV11, EnumCapabilityTest,
|
||||
Combine(Values(SPV_ENV_UNIVERSAL_1_1),
|
||||
ValuesIn(std::vector<EnumCapabilityCase>{
|
||||
CASE1(EXECUTION_MODE, ExecutionModeInitializer, Kernel),
|
||||
CASE1(EXECUTION_MODE, ExecutionModeFinalizer, Kernel),
|
||||
CASE1(EXECUTION_MODE, ExecutionModeSubgroupSize,
|
||||
SubgroupDispatch),
|
||||
CASE1(EXECUTION_MODE, ExecutionModeSubgroupsPerWorkgroup,
|
||||
SubgroupDispatch)})));
|
||||
|
||||
// See SPIR-V Section 3.7 Storage Class
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
StorageClass, EnumCapabilityTest,
|
||||
Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1),
|
||||
ValuesIn(std::vector<EnumCapabilityCase>{
|
||||
CASE0(STORAGE_CLASS, StorageClassUniformConstant),
|
||||
CASE1(STORAGE_CLASS, StorageClassUniform, Shader),
|
||||
CASE1(STORAGE_CLASS, StorageClassOutput, Shader),
|
||||
CASE0(STORAGE_CLASS, StorageClassWorkgroup),
|
||||
CASE0(STORAGE_CLASS, StorageClassCrossWorkgroup),
|
||||
CASE1(STORAGE_CLASS, StorageClassPrivate, Shader),
|
||||
CASE0(STORAGE_CLASS, StorageClassFunction),
|
||||
CASE1(STORAGE_CLASS, StorageClassGeneric,
|
||||
GenericPointer), // Bug 14287
|
||||
CASE1(STORAGE_CLASS, StorageClassPushConstant, Shader),
|
||||
CASE1(STORAGE_CLASS, StorageClassAtomicCounter, AtomicStorage),
|
||||
CASE0(STORAGE_CLASS, StorageClassImage),
|
||||
})));
|
||||
|
||||
// See SPIR-V Section 3.8 Dim
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
Dim, EnumCapabilityTest,
|
||||
Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1),
|
||||
ValuesIn(std::vector<EnumCapabilityCase>{
|
||||
CASE2(DIMENSIONALITY, Dim1D, Sampled1D, Image1D),
|
||||
CASE3(DIMENSIONALITY, Dim2D, Kernel, Shader, ImageMSArray),
|
||||
CASE0(DIMENSIONALITY, Dim3D),
|
||||
CASE2(DIMENSIONALITY, DimCube, Shader, ImageCubeArray),
|
||||
CASE2(DIMENSIONALITY, DimRect, SampledRect, ImageRect),
|
||||
CASE2(DIMENSIONALITY, DimBuffer, SampledBuffer, ImageBuffer),
|
||||
CASE1(DIMENSIONALITY, DimSubpassData, InputAttachment),
|
||||
})));
|
||||
|
||||
// See SPIR-V Section 3.9 Sampler Addressing Mode
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
SamplerAddressingMode, EnumCapabilityTest,
|
||||
Combine(
|
||||
Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1),
|
||||
ValuesIn(std::vector<EnumCapabilityCase>{
|
||||
CASE1(SAMPLER_ADDRESSING_MODE, SamplerAddressingModeNone, Kernel),
|
||||
CASE1(SAMPLER_ADDRESSING_MODE, SamplerAddressingModeClampToEdge,
|
||||
Kernel),
|
||||
CASE1(SAMPLER_ADDRESSING_MODE, SamplerAddressingModeClamp, Kernel),
|
||||
CASE1(SAMPLER_ADDRESSING_MODE, SamplerAddressingModeRepeat, Kernel),
|
||||
CASE1(SAMPLER_ADDRESSING_MODE, SamplerAddressingModeRepeatMirrored,
|
||||
Kernel),
|
||||
})));
|
||||
|
||||
// See SPIR-V Section 3.10 Sampler Filter Mode
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
SamplerFilterMode, EnumCapabilityTest,
|
||||
Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1),
|
||||
ValuesIn(std::vector<EnumCapabilityCase>{
|
||||
CASE1(SAMPLER_FILTER_MODE, SamplerFilterModeNearest, Kernel),
|
||||
CASE1(SAMPLER_FILTER_MODE, SamplerFilterModeLinear, Kernel),
|
||||
})));
|
||||
|
||||
// See SPIR-V Section 3.11 Image Format
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
ImageFormat, EnumCapabilityTest,
|
||||
Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1),
|
||||
ValuesIn(std::vector<EnumCapabilityCase>{
|
||||
// clang-format off
|
||||
CASE0(SAMPLER_IMAGE_FORMAT, ImageFormatUnknown),
|
||||
CASE1(SAMPLER_IMAGE_FORMAT, ImageFormatRgba32f, Shader),
|
||||
CASE1(SAMPLER_IMAGE_FORMAT, ImageFormatRgba16f, Shader),
|
||||
CASE1(SAMPLER_IMAGE_FORMAT, ImageFormatR32f, Shader),
|
||||
CASE1(SAMPLER_IMAGE_FORMAT, ImageFormatRgba8, Shader),
|
||||
CASE1(SAMPLER_IMAGE_FORMAT, ImageFormatRgba8Snorm, Shader),
|
||||
CASE1(SAMPLER_IMAGE_FORMAT, ImageFormatRg32f, StorageImageExtendedFormats),
|
||||
CASE1(SAMPLER_IMAGE_FORMAT, ImageFormatRg16f, StorageImageExtendedFormats),
|
||||
CASE1(SAMPLER_IMAGE_FORMAT, ImageFormatR11fG11fB10f, StorageImageExtendedFormats),
|
||||
CASE1(SAMPLER_IMAGE_FORMAT, ImageFormatR16f, StorageImageExtendedFormats),
|
||||
CASE1(SAMPLER_IMAGE_FORMAT, ImageFormatRgba16, StorageImageExtendedFormats),
|
||||
CASE1(SAMPLER_IMAGE_FORMAT, ImageFormatRgb10A2, StorageImageExtendedFormats),
|
||||
CASE1(SAMPLER_IMAGE_FORMAT, ImageFormatRg16, StorageImageExtendedFormats),
|
||||
CASE1(SAMPLER_IMAGE_FORMAT, ImageFormatRg8, StorageImageExtendedFormats),
|
||||
CASE1(SAMPLER_IMAGE_FORMAT, ImageFormatR16, StorageImageExtendedFormats),
|
||||
CASE1(SAMPLER_IMAGE_FORMAT, ImageFormatR8, StorageImageExtendedFormats),
|
||||
CASE1(SAMPLER_IMAGE_FORMAT, ImageFormatRgba16Snorm, StorageImageExtendedFormats),
|
||||
CASE1(SAMPLER_IMAGE_FORMAT, ImageFormatRg16Snorm, StorageImageExtendedFormats),
|
||||
CASE1(SAMPLER_IMAGE_FORMAT, ImageFormatRg8Snorm, StorageImageExtendedFormats),
|
||||
CASE1(SAMPLER_IMAGE_FORMAT, ImageFormatR16Snorm, StorageImageExtendedFormats),
|
||||
CASE1(SAMPLER_IMAGE_FORMAT, ImageFormatR8Snorm, StorageImageExtendedFormats),
|
||||
CASE1(SAMPLER_IMAGE_FORMAT, ImageFormatRgba32i, Shader),
|
||||
CASE1(SAMPLER_IMAGE_FORMAT, ImageFormatRgba16i, Shader),
|
||||
CASE1(SAMPLER_IMAGE_FORMAT, ImageFormatRgba8i, Shader),
|
||||
CASE1(SAMPLER_IMAGE_FORMAT, ImageFormatR32i, Shader),
|
||||
CASE1(SAMPLER_IMAGE_FORMAT, ImageFormatRg32i, StorageImageExtendedFormats),
|
||||
CASE1(SAMPLER_IMAGE_FORMAT, ImageFormatRg16i, StorageImageExtendedFormats),
|
||||
CASE1(SAMPLER_IMAGE_FORMAT, ImageFormatRg8i, StorageImageExtendedFormats),
|
||||
CASE1(SAMPLER_IMAGE_FORMAT, ImageFormatR16i, StorageImageExtendedFormats),
|
||||
CASE1(SAMPLER_IMAGE_FORMAT, ImageFormatR8i, StorageImageExtendedFormats),
|
||||
CASE1(SAMPLER_IMAGE_FORMAT, ImageFormatRgba32ui, Shader),
|
||||
CASE1(SAMPLER_IMAGE_FORMAT, ImageFormatRgba16ui, Shader),
|
||||
CASE1(SAMPLER_IMAGE_FORMAT, ImageFormatRgba8ui, Shader),
|
||||
CASE1(SAMPLER_IMAGE_FORMAT, ImageFormatRgba8ui, Shader),
|
||||
CASE1(SAMPLER_IMAGE_FORMAT, ImageFormatRgb10a2ui, StorageImageExtendedFormats),
|
||||
CASE1(SAMPLER_IMAGE_FORMAT, ImageFormatRg32ui, StorageImageExtendedFormats),
|
||||
CASE1(SAMPLER_IMAGE_FORMAT, ImageFormatRg16ui, StorageImageExtendedFormats),
|
||||
CASE1(SAMPLER_IMAGE_FORMAT, ImageFormatRg8ui, StorageImageExtendedFormats),
|
||||
CASE1(SAMPLER_IMAGE_FORMAT, ImageFormatR16ui, StorageImageExtendedFormats),
|
||||
CASE1(SAMPLER_IMAGE_FORMAT, ImageFormatR8ui, StorageImageExtendedFormats),
|
||||
// clang-format on
|
||||
})));
|
||||
|
||||
// See SPIR-V Section 3.12 Image Channel Order
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
ImageChannelOrder, EnumCapabilityTest,
|
||||
Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1),
|
||||
ValuesIn(std::vector<EnumCapabilityCase>{
|
||||
CASE1(IMAGE_CHANNEL_ORDER, ImageChannelOrderR, Kernel),
|
||||
CASE1(IMAGE_CHANNEL_ORDER, ImageChannelOrderA, Kernel),
|
||||
CASE1(IMAGE_CHANNEL_ORDER, ImageChannelOrderRG, Kernel),
|
||||
CASE1(IMAGE_CHANNEL_ORDER, ImageChannelOrderRA, Kernel),
|
||||
CASE1(IMAGE_CHANNEL_ORDER, ImageChannelOrderRGB, Kernel),
|
||||
CASE1(IMAGE_CHANNEL_ORDER, ImageChannelOrderRGBA, Kernel),
|
||||
CASE1(IMAGE_CHANNEL_ORDER, ImageChannelOrderBGRA, Kernel),
|
||||
CASE1(IMAGE_CHANNEL_ORDER, ImageChannelOrderARGB, Kernel),
|
||||
CASE1(IMAGE_CHANNEL_ORDER, ImageChannelOrderIntensity, Kernel),
|
||||
CASE1(IMAGE_CHANNEL_ORDER, ImageChannelOrderLuminance, Kernel),
|
||||
CASE1(IMAGE_CHANNEL_ORDER, ImageChannelOrderRx, Kernel),
|
||||
CASE1(IMAGE_CHANNEL_ORDER, ImageChannelOrderRGx, Kernel),
|
||||
CASE1(IMAGE_CHANNEL_ORDER, ImageChannelOrderRGBx, Kernel),
|
||||
CASE1(IMAGE_CHANNEL_ORDER, ImageChannelOrderDepth, Kernel),
|
||||
CASE1(IMAGE_CHANNEL_ORDER, ImageChannelOrderDepthStencil,
|
||||
Kernel),
|
||||
CASE1(IMAGE_CHANNEL_ORDER, ImageChannelOrdersRGB, Kernel),
|
||||
CASE1(IMAGE_CHANNEL_ORDER, ImageChannelOrdersRGBx, Kernel),
|
||||
CASE1(IMAGE_CHANNEL_ORDER, ImageChannelOrdersRGBA, Kernel),
|
||||
CASE1(IMAGE_CHANNEL_ORDER, ImageChannelOrdersBGRA, Kernel),
|
||||
CASE1(IMAGE_CHANNEL_ORDER, ImageChannelOrderABGR, Kernel),
|
||||
})));
|
||||
|
||||
// See SPIR-V Section 3.13 Image Channel Data Type
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
ImageChannelDataType, EnumCapabilityTest,
|
||||
Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1),
|
||||
ValuesIn(std::vector<EnumCapabilityCase>{
|
||||
// clang-format off
|
||||
CASE1(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataTypeSnormInt8, Kernel),
|
||||
CASE1(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataTypeSnormInt16, Kernel),
|
||||
CASE1(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataTypeUnormInt8, Kernel),
|
||||
CASE1(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataTypeUnormInt16, Kernel),
|
||||
CASE1(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataTypeUnormShort565, Kernel),
|
||||
CASE1(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataTypeUnormShort555, Kernel),
|
||||
CASE1(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataTypeUnormInt101010, Kernel),
|
||||
CASE1(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataTypeSignedInt8, Kernel),
|
||||
CASE1(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataTypeSignedInt16, Kernel),
|
||||
CASE1(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataTypeSignedInt32, Kernel),
|
||||
CASE1(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataTypeUnsignedInt8, Kernel),
|
||||
CASE1(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataTypeUnsignedInt16, Kernel),
|
||||
CASE1(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataTypeUnsignedInt32, Kernel),
|
||||
CASE1(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataTypeHalfFloat, Kernel),
|
||||
CASE1(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataTypeFloat, Kernel),
|
||||
CASE1(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataTypeUnormInt24, Kernel),
|
||||
CASE1(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataTypeUnormInt101010_2, Kernel),
|
||||
// clang-format on
|
||||
})));
|
||||
|
||||
// See SPIR-V Section 3.14 Image Operands
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
ImageOperands, EnumCapabilityTest,
|
||||
Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1),
|
||||
ValuesIn(std::vector<EnumCapabilityCase>{
|
||||
// clang-format off
|
||||
CASE0(OPTIONAL_IMAGE, ImageOperandsMaskNone),
|
||||
CASE1(OPTIONAL_IMAGE, ImageOperandsBiasMask, Shader),
|
||||
CASE0(OPTIONAL_IMAGE, ImageOperandsLodMask),
|
||||
CASE0(OPTIONAL_IMAGE, ImageOperandsGradMask),
|
||||
CASE0(OPTIONAL_IMAGE, ImageOperandsConstOffsetMask),
|
||||
CASE1(OPTIONAL_IMAGE, ImageOperandsOffsetMask, ImageGatherExtended),
|
||||
CASE1(OPTIONAL_IMAGE, ImageOperandsConstOffsetsMask, ImageGatherExtended),
|
||||
CASE0(OPTIONAL_IMAGE, ImageOperandsSampleMask),
|
||||
CASE1(OPTIONAL_IMAGE, ImageOperandsMinLodMask, MinLod),
|
||||
// clang-format on
|
||||
})));
|
||||
|
||||
// See SPIR-V Section 3.15 FP Fast Math Mode
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
FPFastMathMode, EnumCapabilityTest,
|
||||
Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1),
|
||||
ValuesIn(std::vector<EnumCapabilityCase>{
|
||||
CASE0(FP_FAST_MATH_MODE, FPFastMathModeMaskNone),
|
||||
CASE1(FP_FAST_MATH_MODE, FPFastMathModeNotNaNMask, Kernel),
|
||||
CASE1(FP_FAST_MATH_MODE, FPFastMathModeNotInfMask, Kernel),
|
||||
CASE1(FP_FAST_MATH_MODE, FPFastMathModeNSZMask, Kernel),
|
||||
CASE1(FP_FAST_MATH_MODE, FPFastMathModeAllowRecipMask, Kernel),
|
||||
CASE1(FP_FAST_MATH_MODE, FPFastMathModeFastMask, Kernel),
|
||||
})));
|
||||
|
||||
// See SPIR-V Section 3.17 Linkage Type
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
LinkageType, EnumCapabilityTest,
|
||||
Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1),
|
||||
ValuesIn(std::vector<EnumCapabilityCase>{
|
||||
CASE1(LINKAGE_TYPE, LinkageTypeExport, Linkage),
|
||||
CASE1(LINKAGE_TYPE, LinkageTypeImport, Linkage),
|
||||
})));
|
||||
|
||||
// See SPIR-V Section 3.18 Access Qualifier
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
AccessQualifier, EnumCapabilityTest,
|
||||
Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1),
|
||||
ValuesIn(std::vector<EnumCapabilityCase>{
|
||||
CASE1(ACCESS_QUALIFIER, AccessQualifierReadOnly, Kernel),
|
||||
CASE1(ACCESS_QUALIFIER, AccessQualifierWriteOnly, Kernel),
|
||||
CASE1(ACCESS_QUALIFIER, AccessQualifierReadWrite, Kernel),
|
||||
})));
|
||||
|
||||
// See SPIR-V Section 3.19 Function Parameter Attribute
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
FunctionParameterAttribute, EnumCapabilityTest,
|
||||
Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1),
|
||||
ValuesIn(std::vector<EnumCapabilityCase>{
|
||||
// clang-format off
|
||||
CASE1(FUNCTION_PARAMETER_ATTRIBUTE, FunctionParameterAttributeZext, Kernel),
|
||||
CASE1(FUNCTION_PARAMETER_ATTRIBUTE, FunctionParameterAttributeSext, Kernel),
|
||||
CASE1(FUNCTION_PARAMETER_ATTRIBUTE, FunctionParameterAttributeByVal, Kernel),
|
||||
CASE1(FUNCTION_PARAMETER_ATTRIBUTE, FunctionParameterAttributeSret, Kernel),
|
||||
CASE1(FUNCTION_PARAMETER_ATTRIBUTE, FunctionParameterAttributeNoAlias, Kernel),
|
||||
CASE1(FUNCTION_PARAMETER_ATTRIBUTE, FunctionParameterAttributeNoCapture, Kernel),
|
||||
CASE1(FUNCTION_PARAMETER_ATTRIBUTE, FunctionParameterAttributeNoWrite, Kernel),
|
||||
CASE1(FUNCTION_PARAMETER_ATTRIBUTE, FunctionParameterAttributeNoReadWrite, Kernel),
|
||||
// clang-format on
|
||||
})));
|
||||
|
||||
// See SPIR-V Section 3.20 Decoration
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
Decoration, EnumCapabilityTest,
|
||||
Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1),
|
||||
ValuesIn(std::vector<EnumCapabilityCase>{
|
||||
CASE1(DECORATION, DecorationRelaxedPrecision, Shader),
|
||||
// DecorationSpecId handled below.
|
||||
CASE1(DECORATION, DecorationBlock, Shader),
|
||||
CASE1(DECORATION, DecorationBufferBlock, Shader),
|
||||
CASE1(DECORATION, DecorationRowMajor, Matrix),
|
||||
CASE1(DECORATION, DecorationColMajor, Matrix),
|
||||
CASE1(DECORATION, DecorationArrayStride, Shader),
|
||||
CASE1(DECORATION, DecorationMatrixStride, Matrix), // Bug 15234
|
||||
CASE1(DECORATION, DecorationGLSLShared, Shader),
|
||||
CASE1(DECORATION, DecorationGLSLPacked, Shader),
|
||||
CASE1(DECORATION, DecorationCPacked, Kernel),
|
||||
CASE0(DECORATION, DecorationBuiltIn), // Bug 15248
|
||||
// Value 12 placeholder
|
||||
CASE1(DECORATION, DecorationNoPerspective, Shader),
|
||||
CASE1(DECORATION, DecorationFlat, Shader),
|
||||
CASE1(DECORATION, DecorationPatch, Tessellation),
|
||||
CASE1(DECORATION, DecorationCentroid, Shader),
|
||||
CASE1(DECORATION, DecorationSample,
|
||||
SampleRateShading), // Bug 15234
|
||||
CASE1(DECORATION, DecorationInvariant, Shader),
|
||||
CASE0(DECORATION, DecorationRestrict),
|
||||
CASE0(DECORATION, DecorationAliased),
|
||||
CASE0(DECORATION, DecorationVolatile),
|
||||
CASE1(DECORATION, DecorationConstant, Kernel),
|
||||
CASE0(DECORATION, DecorationCoherent),
|
||||
CASE0(DECORATION, DecorationNonWritable),
|
||||
CASE0(DECORATION, DecorationNonReadable),
|
||||
CASE1(DECORATION, DecorationUniform, Shader),
|
||||
// Value 27 is an intentional gap in the spec numbering.
|
||||
CASE1(DECORATION, DecorationSaturatedConversion, Kernel),
|
||||
CASE1(DECORATION, DecorationStream, GeometryStreams),
|
||||
CASE1(DECORATION, DecorationLocation, Shader),
|
||||
CASE1(DECORATION, DecorationComponent, Shader),
|
||||
CASE1(DECORATION, DecorationIndex, Shader),
|
||||
CASE1(DECORATION, DecorationBinding, Shader),
|
||||
CASE1(DECORATION, DecorationDescriptorSet, Shader),
|
||||
CASE1(DECORATION, DecorationOffset, Shader), // Bug 15268
|
||||
CASE1(DECORATION, DecorationXfbBuffer, TransformFeedback),
|
||||
CASE1(DECORATION, DecorationXfbStride, TransformFeedback),
|
||||
CASE1(DECORATION, DecorationFuncParamAttr, Kernel),
|
||||
CASE1(DECORATION, DecorationFPFastMathMode, Kernel),
|
||||
CASE1(DECORATION, DecorationLinkageAttributes, Linkage),
|
||||
CASE1(DECORATION, DecorationNoContraction, Shader),
|
||||
CASE1(DECORATION, DecorationInputAttachmentIndex,
|
||||
InputAttachment),
|
||||
CASE1(DECORATION, DecorationAlignment, Kernel),
|
||||
})));
|
||||
|
||||
#if 0
|
||||
// SpecId has different requirements in v1.0 and v1.1:
|
||||
INSTANTIATE_TEST_SUITE_P(DecorationSpecIdV10, EnumCapabilityTest,
|
||||
Combine(Values(SPV_ENV_UNIVERSAL_1_0),
|
||||
ValuesIn(std::vector<EnumCapabilityCase>{CASE1(
|
||||
DECORATION, DecorationSpecId, Shader)})));
|
||||
#endif
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
DecorationV11, EnumCapabilityTest,
|
||||
Combine(Values(SPV_ENV_UNIVERSAL_1_1),
|
||||
ValuesIn(std::vector<EnumCapabilityCase>{
|
||||
CASE2(DECORATION, DecorationSpecId, Shader, Kernel),
|
||||
CASE1(DECORATION, DecorationMaxByteOffset, Addresses)})));
|
||||
|
||||
// See SPIR-V Section 3.21 BuiltIn
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
BuiltIn, EnumCapabilityTest,
|
||||
Combine(
|
||||
Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1),
|
||||
ValuesIn(std::vector<EnumCapabilityCase>{
|
||||
// clang-format off
|
||||
CASE1(BUILT_IN, BuiltInPosition, Shader),
|
||||
CASE1(BUILT_IN, BuiltInPointSize, Shader),
|
||||
// 2 is an intentional gap in the spec numbering.
|
||||
CASE1(BUILT_IN, BuiltInClipDistance, ClipDistance), // Bug 1407, 15234
|
||||
CASE1(BUILT_IN, BuiltInCullDistance, CullDistance), // Bug 1407, 15234
|
||||
CASE1(BUILT_IN, BuiltInVertexId, Shader),
|
||||
CASE1(BUILT_IN, BuiltInInstanceId, Shader),
|
||||
CASE3(BUILT_IN, BuiltInPrimitiveId, Geometry, Tessellation,
|
||||
RayTracingNV),
|
||||
CASE2(BUILT_IN, BuiltInInvocationId, Geometry, Tessellation),
|
||||
CASE2(BUILT_IN, BuiltInLayer, Geometry, ShaderViewportIndexLayerEXT),
|
||||
CASE2(BUILT_IN, BuiltInViewportIndex, MultiViewport, ShaderViewportIndexLayerEXT), // Bug 15234
|
||||
CASE1(BUILT_IN, BuiltInTessLevelOuter, Tessellation),
|
||||
CASE1(BUILT_IN, BuiltInTessLevelInner, Tessellation),
|
||||
CASE1(BUILT_IN, BuiltInTessCoord, Tessellation),
|
||||
CASE1(BUILT_IN, BuiltInPatchVertices, Tessellation),
|
||||
CASE1(BUILT_IN, BuiltInFragCoord, Shader),
|
||||
CASE1(BUILT_IN, BuiltInPointCoord, Shader),
|
||||
CASE1(BUILT_IN, BuiltInFrontFacing, Shader),
|
||||
CASE1(BUILT_IN, BuiltInSampleId, SampleRateShading), // Bug 15234
|
||||
CASE1(BUILT_IN, BuiltInSamplePosition, SampleRateShading), // Bug 15234
|
||||
CASE1(BUILT_IN, BuiltInSampleMask, Shader), // Bug 15234, Issue 182
|
||||
// Value 21 intentionally missing
|
||||
CASE1(BUILT_IN, BuiltInFragDepth, Shader),
|
||||
CASE1(BUILT_IN, BuiltInHelperInvocation, Shader),
|
||||
CASE0(BUILT_IN, BuiltInNumWorkgroups),
|
||||
CASE0(BUILT_IN, BuiltInWorkgroupSize),
|
||||
CASE0(BUILT_IN, BuiltInWorkgroupId),
|
||||
CASE0(BUILT_IN, BuiltInLocalInvocationId),
|
||||
CASE0(BUILT_IN, BuiltInGlobalInvocationId),
|
||||
CASE0(BUILT_IN, BuiltInLocalInvocationIndex),
|
||||
CASE1(BUILT_IN, BuiltInWorkDim, Kernel),
|
||||
CASE1(BUILT_IN, BuiltInGlobalSize, Kernel),
|
||||
CASE1(BUILT_IN, BuiltInEnqueuedWorkgroupSize, Kernel),
|
||||
CASE1(BUILT_IN, BuiltInGlobalOffset, Kernel),
|
||||
CASE1(BUILT_IN, BuiltInGlobalLinearId, Kernel),
|
||||
// Value 35 intentionally missing
|
||||
CASE2(BUILT_IN, BuiltInSubgroupSize, Kernel, SubgroupBallotKHR),
|
||||
CASE1(BUILT_IN, BuiltInSubgroupMaxSize, Kernel),
|
||||
CASE1(BUILT_IN, BuiltInNumSubgroups, Kernel),
|
||||
CASE1(BUILT_IN, BuiltInNumEnqueuedSubgroups, Kernel),
|
||||
CASE1(BUILT_IN, BuiltInSubgroupId, Kernel),
|
||||
CASE2(BUILT_IN, BuiltInSubgroupLocalInvocationId, Kernel, SubgroupBallotKHR),
|
||||
CASE1(BUILT_IN, BuiltInVertexIndex, Shader),
|
||||
CASE1(BUILT_IN, BuiltInInstanceIndex, Shader),
|
||||
// clang-format on
|
||||
})));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
BuiltInV1_5, EnumCapabilityTest,
|
||||
Combine(
|
||||
Values(SPV_ENV_UNIVERSAL_1_5),
|
||||
ValuesIn(std::vector<EnumCapabilityCase>{
|
||||
// SPIR-V 1.5 adds new capabilities to enable these two builtins.
|
||||
CASE3(BUILT_IN, BuiltInLayer, Geometry, ShaderLayer,
|
||||
ShaderViewportIndexLayerEXT),
|
||||
CASE3(BUILT_IN, BuiltInViewportIndex, MultiViewport,
|
||||
ShaderViewportIndex, ShaderViewportIndexLayerEXT),
|
||||
})));
|
||||
|
||||
// See SPIR-V Section 3.22 Selection Control
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
SelectionControl, EnumCapabilityTest,
|
||||
Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1),
|
||||
ValuesIn(std::vector<EnumCapabilityCase>{
|
||||
CASE0(SELECTION_CONTROL, SelectionControlMaskNone),
|
||||
CASE0(SELECTION_CONTROL, SelectionControlFlattenMask),
|
||||
CASE0(SELECTION_CONTROL, SelectionControlDontFlattenMask),
|
||||
})));
|
||||
|
||||
// See SPIR-V Section 3.23 Loop Control
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
LoopControl, EnumCapabilityTest,
|
||||
Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1),
|
||||
ValuesIn(std::vector<EnumCapabilityCase>{
|
||||
CASE0(LOOP_CONTROL, LoopControlMaskNone),
|
||||
CASE0(LOOP_CONTROL, LoopControlUnrollMask),
|
||||
CASE0(LOOP_CONTROL, LoopControlDontUnrollMask),
|
||||
})));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
LoopControlV11, EnumCapabilityTest,
|
||||
Combine(Values(SPV_ENV_UNIVERSAL_1_1),
|
||||
ValuesIn(std::vector<EnumCapabilityCase>{
|
||||
CASE0(LOOP_CONTROL, LoopControlDependencyInfiniteMask),
|
||||
CASE0(LOOP_CONTROL, LoopControlDependencyLengthMask),
|
||||
})));
|
||||
|
||||
// See SPIR-V Section 3.24 Function Control
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
FunctionControl, EnumCapabilityTest,
|
||||
Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1),
|
||||
ValuesIn(std::vector<EnumCapabilityCase>{
|
||||
CASE0(FUNCTION_CONTROL, FunctionControlMaskNone),
|
||||
CASE0(FUNCTION_CONTROL, FunctionControlInlineMask),
|
||||
CASE0(FUNCTION_CONTROL, FunctionControlDontInlineMask),
|
||||
CASE0(FUNCTION_CONTROL, FunctionControlPureMask),
|
||||
CASE0(FUNCTION_CONTROL, FunctionControlConstMask),
|
||||
})));
|
||||
|
||||
// See SPIR-V Section 3.25 Memory Semantics <id>
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
MemorySemantics, EnumCapabilityTest,
|
||||
Combine(
|
||||
Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1),
|
||||
ValuesIn(std::vector<EnumCapabilityCase>{
|
||||
CASE0(MEMORY_SEMANTICS_ID, MemorySemanticsMaskNone),
|
||||
CASE0(MEMORY_SEMANTICS_ID, MemorySemanticsAcquireMask),
|
||||
CASE0(MEMORY_SEMANTICS_ID, MemorySemanticsReleaseMask),
|
||||
CASE0(MEMORY_SEMANTICS_ID, MemorySemanticsAcquireReleaseMask),
|
||||
CASE0(MEMORY_SEMANTICS_ID,
|
||||
MemorySemanticsSequentiallyConsistentMask),
|
||||
CASE1(MEMORY_SEMANTICS_ID, MemorySemanticsUniformMemoryMask,
|
||||
Shader),
|
||||
CASE0(MEMORY_SEMANTICS_ID, MemorySemanticsSubgroupMemoryMask),
|
||||
CASE0(MEMORY_SEMANTICS_ID, MemorySemanticsWorkgroupMemoryMask),
|
||||
CASE0(MEMORY_SEMANTICS_ID, MemorySemanticsCrossWorkgroupMemoryMask),
|
||||
CASE1(MEMORY_SEMANTICS_ID, MemorySemanticsAtomicCounterMemoryMask,
|
||||
AtomicStorage), // Bug 15234
|
||||
CASE0(MEMORY_SEMANTICS_ID, MemorySemanticsImageMemoryMask),
|
||||
})));
|
||||
|
||||
// See SPIR-V Section 3.26 Memory Access
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
MemoryAccess, EnumCapabilityTest,
|
||||
Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1),
|
||||
ValuesIn(std::vector<EnumCapabilityCase>{
|
||||
CASE0(OPTIONAL_MEMORY_ACCESS, MemoryAccessMaskNone),
|
||||
CASE0(OPTIONAL_MEMORY_ACCESS, MemoryAccessVolatileMask),
|
||||
CASE0(OPTIONAL_MEMORY_ACCESS, MemoryAccessAlignedMask),
|
||||
CASE0(OPTIONAL_MEMORY_ACCESS, MemoryAccessNontemporalMask),
|
||||
})));
|
||||
|
||||
// See SPIR-V Section 3.27 Scope <id>
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
Scope, EnumCapabilityTest,
|
||||
Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
|
||||
SPV_ENV_UNIVERSAL_1_2, SPV_ENV_UNIVERSAL_1_3),
|
||||
ValuesIn(std::vector<EnumCapabilityCase>{
|
||||
CASE0(SCOPE_ID, ScopeCrossDevice),
|
||||
CASE0(SCOPE_ID, ScopeDevice),
|
||||
CASE0(SCOPE_ID, ScopeWorkgroup),
|
||||
CASE0(SCOPE_ID, ScopeSubgroup),
|
||||
CASE0(SCOPE_ID, ScopeInvocation),
|
||||
CASE1(SCOPE_ID, ScopeQueueFamilyKHR, VulkanMemoryModelKHR),
|
||||
})));
|
||||
|
||||
// See SPIR-V Section 3.28 Group Operation
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
GroupOperation, EnumCapabilityTest,
|
||||
Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1),
|
||||
ValuesIn(std::vector<EnumCapabilityCase>{
|
||||
CASE3(GROUP_OPERATION, GroupOperationReduce, Kernel,
|
||||
GroupNonUniformArithmetic, GroupNonUniformBallot),
|
||||
CASE3(GROUP_OPERATION, GroupOperationInclusiveScan, Kernel,
|
||||
GroupNonUniformArithmetic, GroupNonUniformBallot),
|
||||
CASE3(GROUP_OPERATION, GroupOperationExclusiveScan, Kernel,
|
||||
GroupNonUniformArithmetic, GroupNonUniformBallot),
|
||||
})));
|
||||
|
||||
// See SPIR-V Section 3.29 Kernel Enqueue Flags
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
KernelEnqueueFlags, EnumCapabilityTest,
|
||||
Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1),
|
||||
ValuesIn(std::vector<EnumCapabilityCase>{
|
||||
CASE1(KERNEL_ENQ_FLAGS, KernelEnqueueFlagsNoWait, Kernel),
|
||||
CASE1(KERNEL_ENQ_FLAGS, KernelEnqueueFlagsWaitKernel, Kernel),
|
||||
CASE1(KERNEL_ENQ_FLAGS, KernelEnqueueFlagsWaitWorkGroup,
|
||||
Kernel),
|
||||
})));
|
||||
|
||||
// See SPIR-V Section 3.30 Kernel Profiling Info
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
KernelProfilingInfo, EnumCapabilityTest,
|
||||
Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1),
|
||||
ValuesIn(std::vector<EnumCapabilityCase>{
|
||||
CASE0(KERNEL_PROFILING_INFO, KernelProfilingInfoMaskNone),
|
||||
CASE1(KERNEL_PROFILING_INFO, KernelProfilingInfoCmdExecTimeMask,
|
||||
Kernel),
|
||||
})));
|
||||
|
||||
// See SPIR-V Section 3.31 Capability
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
CapabilityDependsOn, EnumCapabilityTest,
|
||||
Combine(
|
||||
Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1),
|
||||
ValuesIn(std::vector<EnumCapabilityCase>{
|
||||
// clang-format off
|
||||
CASE0(CAPABILITY, CapabilityMatrix),
|
||||
CASE1(CAPABILITY, CapabilityShader, Matrix),
|
||||
CASE1(CAPABILITY, CapabilityGeometry, Shader),
|
||||
CASE1(CAPABILITY, CapabilityTessellation, Shader),
|
||||
CASE0(CAPABILITY, CapabilityAddresses),
|
||||
CASE0(CAPABILITY, CapabilityLinkage),
|
||||
CASE0(CAPABILITY, CapabilityKernel),
|
||||
CASE1(CAPABILITY, CapabilityVector16, Kernel),
|
||||
CASE1(CAPABILITY, CapabilityFloat16Buffer, Kernel),
|
||||
CASE0(CAPABILITY, CapabilityFloat16), // Bug 15234
|
||||
CASE0(CAPABILITY, CapabilityFloat64),
|
||||
CASE0(CAPABILITY, CapabilityInt64),
|
||||
CASE1(CAPABILITY, CapabilityInt64Atomics, Int64),
|
||||
CASE1(CAPABILITY, CapabilityImageBasic, Kernel),
|
||||
CASE1(CAPABILITY, CapabilityImageReadWrite, ImageBasic),
|
||||
CASE1(CAPABILITY, CapabilityImageMipmap, ImageBasic),
|
||||
// Value 16 intentionally missing.
|
||||
CASE1(CAPABILITY, CapabilityPipes, Kernel),
|
||||
CASE0(CAPABILITY, CapabilityGroups),
|
||||
CASE1(CAPABILITY, CapabilityDeviceEnqueue, Kernel),
|
||||
CASE1(CAPABILITY, CapabilityLiteralSampler, Kernel),
|
||||
CASE1(CAPABILITY, CapabilityAtomicStorage, Shader),
|
||||
CASE0(CAPABILITY, CapabilityInt16),
|
||||
CASE1(CAPABILITY, CapabilityTessellationPointSize, Tessellation),
|
||||
CASE1(CAPABILITY, CapabilityGeometryPointSize, Geometry),
|
||||
CASE1(CAPABILITY, CapabilityImageGatherExtended, Shader),
|
||||
// Value 26 intentionally missing.
|
||||
CASE1(CAPABILITY, CapabilityStorageImageMultisample, Shader),
|
||||
CASE1(CAPABILITY, CapabilityUniformBufferArrayDynamicIndexing, Shader),
|
||||
CASE1(CAPABILITY, CapabilitySampledImageArrayDynamicIndexing, Shader),
|
||||
CASE1(CAPABILITY, CapabilityStorageBufferArrayDynamicIndexing, Shader),
|
||||
CASE1(CAPABILITY, CapabilityStorageImageArrayDynamicIndexing, Shader),
|
||||
CASE1(CAPABILITY, CapabilityClipDistance, Shader),
|
||||
CASE1(CAPABILITY, CapabilityCullDistance, Shader),
|
||||
CASE1(CAPABILITY, CapabilityImageCubeArray, SampledCubeArray),
|
||||
CASE1(CAPABILITY, CapabilitySampleRateShading, Shader),
|
||||
CASE1(CAPABILITY, CapabilityImageRect, SampledRect),
|
||||
CASE1(CAPABILITY, CapabilitySampledRect, Shader),
|
||||
CASE1(CAPABILITY, CapabilityGenericPointer, Addresses),
|
||||
CASE0(CAPABILITY, CapabilityInt8),
|
||||
CASE1(CAPABILITY, CapabilityInputAttachment, Shader),
|
||||
CASE1(CAPABILITY, CapabilitySparseResidency, Shader),
|
||||
CASE1(CAPABILITY, CapabilityMinLod, Shader),
|
||||
CASE1(CAPABILITY, CapabilityImage1D, Sampled1D),
|
||||
CASE1(CAPABILITY, CapabilitySampledCubeArray, Shader),
|
||||
CASE1(CAPABILITY, CapabilityImageBuffer, SampledBuffer),
|
||||
CASE1(CAPABILITY, CapabilityImageMSArray, Shader),
|
||||
CASE1(CAPABILITY, CapabilityStorageImageExtendedFormats, Shader),
|
||||
CASE1(CAPABILITY, CapabilityImageQuery, Shader),
|
||||
CASE1(CAPABILITY, CapabilityDerivativeControl, Shader),
|
||||
CASE1(CAPABILITY, CapabilityInterpolationFunction, Shader),
|
||||
CASE1(CAPABILITY, CapabilityTransformFeedback, Shader),
|
||||
CASE1(CAPABILITY, CapabilityGeometryStreams, Geometry),
|
||||
CASE1(CAPABILITY, CapabilityStorageImageReadWithoutFormat, Shader),
|
||||
CASE1(CAPABILITY, CapabilityStorageImageWriteWithoutFormat, Shader),
|
||||
CASE1(CAPABILITY, CapabilityMultiViewport, Geometry),
|
||||
// clang-format on
|
||||
})));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
CapabilityDependsOnV11, EnumCapabilityTest,
|
||||
Combine(Values(SPV_ENV_UNIVERSAL_1_1),
|
||||
ValuesIn(std::vector<EnumCapabilityCase>{
|
||||
CASE1(CAPABILITY, CapabilitySubgroupDispatch, DeviceEnqueue),
|
||||
CASE1(CAPABILITY, CapabilityNamedBarrier, Kernel),
|
||||
CASE1(CAPABILITY, CapabilityPipeStorage, Pipes),
|
||||
})));
|
||||
|
||||
#undef CASE0
|
||||
#undef CASE1
|
||||
#undef CASE2
|
||||
|
||||
} // namespace
|
||||
} // namespace spvtools
|
||||
270
3rdparty/spirv-tools/test/operand_pattern_test.cpp
vendored
270
3rdparty/spirv-tools/test/operand_pattern_test.cpp
vendored
@@ -1,270 +0,0 @@
|
||||
// Copyright (c) 2015-2016 The Khronos Group Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "source/operand.h"
|
||||
#include "test/unit_spirv.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace {
|
||||
|
||||
using ::testing::Eq;
|
||||
|
||||
TEST(OperandPattern, InitiallyEmpty) {
|
||||
spv_operand_pattern_t empty;
|
||||
EXPECT_THAT(empty, Eq(spv_operand_pattern_t{}));
|
||||
EXPECT_EQ(0u, empty.size());
|
||||
EXPECT_TRUE(empty.empty());
|
||||
}
|
||||
|
||||
TEST(OperandPattern, PushBacksAreOnTheRight) {
|
||||
spv_operand_pattern_t pattern;
|
||||
|
||||
pattern.push_back(SPV_OPERAND_TYPE_ID);
|
||||
EXPECT_THAT(pattern, Eq(spv_operand_pattern_t{SPV_OPERAND_TYPE_ID}));
|
||||
EXPECT_EQ(1u, pattern.size());
|
||||
EXPECT_TRUE(!pattern.empty());
|
||||
EXPECT_EQ(SPV_OPERAND_TYPE_ID, pattern.back());
|
||||
|
||||
pattern.push_back(SPV_OPERAND_TYPE_NONE);
|
||||
EXPECT_THAT(pattern, Eq(spv_operand_pattern_t{SPV_OPERAND_TYPE_ID,
|
||||
SPV_OPERAND_TYPE_NONE}));
|
||||
EXPECT_EQ(2u, pattern.size());
|
||||
EXPECT_TRUE(!pattern.empty());
|
||||
EXPECT_EQ(SPV_OPERAND_TYPE_NONE, pattern.back());
|
||||
}
|
||||
|
||||
TEST(OperandPattern, PopBacksAreOnTheRight) {
|
||||
spv_operand_pattern_t pattern{SPV_OPERAND_TYPE_ID,
|
||||
SPV_OPERAND_TYPE_LITERAL_INTEGER};
|
||||
|
||||
pattern.pop_back();
|
||||
EXPECT_THAT(pattern, Eq(spv_operand_pattern_t{SPV_OPERAND_TYPE_ID}));
|
||||
|
||||
pattern.pop_back();
|
||||
EXPECT_THAT(pattern, Eq(spv_operand_pattern_t{}));
|
||||
}
|
||||
|
||||
// A test case for typed mask expansion
|
||||
struct MaskExpansionCase {
|
||||
spv_operand_type_t type;
|
||||
uint32_t mask;
|
||||
spv_operand_pattern_t initial;
|
||||
spv_operand_pattern_t expected;
|
||||
};
|
||||
|
||||
using MaskExpansionTest = ::testing::TestWithParam<MaskExpansionCase>;
|
||||
|
||||
TEST_P(MaskExpansionTest, Sample) {
|
||||
spv_operand_table operandTable = nullptr;
|
||||
auto env = SPV_ENV_UNIVERSAL_1_0;
|
||||
ASSERT_EQ(SPV_SUCCESS, spvOperandTableGet(&operandTable, env));
|
||||
|
||||
spv_operand_pattern_t pattern(GetParam().initial);
|
||||
spvPushOperandTypesForMask(env, operandTable, GetParam().type,
|
||||
GetParam().mask, &pattern);
|
||||
EXPECT_THAT(pattern, Eq(GetParam().expected));
|
||||
}
|
||||
|
||||
// These macros let us write non-trivial examples without too much text.
|
||||
#define PREFIX0 SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE
|
||||
#define PREFIX1 \
|
||||
SPV_OPERAND_TYPE_STORAGE_CLASS, SPV_OPERAND_TYPE_SAMPLER_FILTER_MODE, \
|
||||
SPV_OPERAND_TYPE_ID
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
OperandPattern, MaskExpansionTest,
|
||||
::testing::ValuesIn(std::vector<MaskExpansionCase>{
|
||||
// No bits means no change.
|
||||
{SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS, 0, {PREFIX0}, {PREFIX0}},
|
||||
// Unknown bits means no change. Use all bits that aren't in the
|
||||
// grammar.
|
||||
// The last mask enum is 0x20
|
||||
{SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS,
|
||||
0xffffffc0,
|
||||
{PREFIX1},
|
||||
{PREFIX1}},
|
||||
// Volatile has no operands.
|
||||
{SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS,
|
||||
SpvMemoryAccessVolatileMask,
|
||||
{PREFIX0},
|
||||
{PREFIX0}},
|
||||
// Aligned has one literal number operand.
|
||||
{SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS,
|
||||
SpvMemoryAccessAlignedMask,
|
||||
{PREFIX1},
|
||||
{PREFIX1, SPV_OPERAND_TYPE_LITERAL_INTEGER}},
|
||||
// Volatile with Aligned still has just one literal number operand.
|
||||
{SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS,
|
||||
SpvMemoryAccessVolatileMask | SpvMemoryAccessAlignedMask,
|
||||
{PREFIX1},
|
||||
{PREFIX1, SPV_OPERAND_TYPE_LITERAL_INTEGER}},
|
||||
}));
|
||||
#undef PREFIX0
|
||||
#undef PREFIX1
|
||||
|
||||
// Returns a vector of all operand types that can be used in a pattern.
|
||||
std::vector<spv_operand_type_t> allOperandTypes() {
|
||||
std::vector<spv_operand_type_t> result;
|
||||
for (int i = 0; i < SPV_OPERAND_TYPE_NUM_OPERAND_TYPES; i++) {
|
||||
result.push_back(spv_operand_type_t(i));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
using MatchableOperandExpansionTest =
|
||||
::testing::TestWithParam<spv_operand_type_t>;
|
||||
|
||||
TEST_P(MatchableOperandExpansionTest, MatchableOperandsDontExpand) {
|
||||
const spv_operand_type_t type = GetParam();
|
||||
if (!spvOperandIsVariable(type)) {
|
||||
spv_operand_pattern_t pattern;
|
||||
const bool did_expand = spvExpandOperandSequenceOnce(type, &pattern);
|
||||
EXPECT_FALSE(did_expand);
|
||||
EXPECT_THAT(pattern, Eq(spv_operand_pattern_t{}));
|
||||
}
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(MatchableOperandExpansion,
|
||||
MatchableOperandExpansionTest,
|
||||
::testing::ValuesIn(allOperandTypes()));
|
||||
|
||||
using VariableOperandExpansionTest =
|
||||
::testing::TestWithParam<spv_operand_type_t>;
|
||||
|
||||
TEST_P(VariableOperandExpansionTest, NonMatchableOperandsExpand) {
|
||||
const spv_operand_type_t type = GetParam();
|
||||
if (spvOperandIsVariable(type)) {
|
||||
spv_operand_pattern_t pattern;
|
||||
const bool did_expand = spvExpandOperandSequenceOnce(type, &pattern);
|
||||
EXPECT_TRUE(did_expand);
|
||||
EXPECT_FALSE(pattern.empty());
|
||||
// For the existing rules, the first expansion of a zero-or-more operand
|
||||
// type yields a matchable operand type. This isn't strictly necessary.
|
||||
EXPECT_FALSE(spvOperandIsVariable(pattern.back()));
|
||||
}
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(NonMatchableOperandExpansion,
|
||||
VariableOperandExpansionTest,
|
||||
::testing::ValuesIn(allOperandTypes()));
|
||||
|
||||
TEST(AlternatePatternFollowingImmediate, Empty) {
|
||||
EXPECT_THAT(spvAlternatePatternFollowingImmediate({}),
|
||||
Eq(spv_operand_pattern_t{SPV_OPERAND_TYPE_OPTIONAL_CIV}));
|
||||
}
|
||||
|
||||
TEST(AlternatePatternFollowingImmediate, SingleElement) {
|
||||
// Spot-check a random selection of types.
|
||||
EXPECT_THAT(spvAlternatePatternFollowingImmediate(
|
||||
{SPV_OPERAND_TYPE_VARIABLE_ID_LITERAL_INTEGER}),
|
||||
Eq(spv_operand_pattern_t{SPV_OPERAND_TYPE_OPTIONAL_CIV}));
|
||||
EXPECT_THAT(
|
||||
spvAlternatePatternFollowingImmediate({SPV_OPERAND_TYPE_CAPABILITY}),
|
||||
Eq(spv_operand_pattern_t{SPV_OPERAND_TYPE_OPTIONAL_CIV}));
|
||||
EXPECT_THAT(
|
||||
spvAlternatePatternFollowingImmediate({SPV_OPERAND_TYPE_LOOP_CONTROL}),
|
||||
Eq(spv_operand_pattern_t{SPV_OPERAND_TYPE_OPTIONAL_CIV}));
|
||||
EXPECT_THAT(spvAlternatePatternFollowingImmediate(
|
||||
{SPV_OPERAND_TYPE_OPTIONAL_LITERAL_INTEGER}),
|
||||
Eq(spv_operand_pattern_t{SPV_OPERAND_TYPE_OPTIONAL_CIV}));
|
||||
EXPECT_THAT(spvAlternatePatternFollowingImmediate({SPV_OPERAND_TYPE_ID}),
|
||||
Eq(spv_operand_pattern_t{SPV_OPERAND_TYPE_OPTIONAL_CIV}));
|
||||
}
|
||||
|
||||
TEST(AlternatePatternFollowingImmediate, SingleResultId) {
|
||||
EXPECT_THAT(
|
||||
spvAlternatePatternFollowingImmediate({SPV_OPERAND_TYPE_RESULT_ID}),
|
||||
Eq(spv_operand_pattern_t{SPV_OPERAND_TYPE_OPTIONAL_CIV,
|
||||
SPV_OPERAND_TYPE_RESULT_ID}));
|
||||
}
|
||||
|
||||
TEST(AlternatePatternFollowingImmediate, MultipleNonResultIds) {
|
||||
EXPECT_THAT(
|
||||
spvAlternatePatternFollowingImmediate(
|
||||
{SPV_OPERAND_TYPE_VARIABLE_ID_LITERAL_INTEGER,
|
||||
SPV_OPERAND_TYPE_CAPABILITY, SPV_OPERAND_TYPE_LOOP_CONTROL,
|
||||
SPV_OPERAND_TYPE_OPTIONAL_LITERAL_INTEGER, SPV_OPERAND_TYPE_ID}),
|
||||
Eq(spv_operand_pattern_t{SPV_OPERAND_TYPE_OPTIONAL_CIV}));
|
||||
}
|
||||
|
||||
TEST(AlternatePatternFollowingImmediate, ResultIdFront) {
|
||||
EXPECT_THAT(spvAlternatePatternFollowingImmediate(
|
||||
{SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}),
|
||||
Eq(spv_operand_pattern_t{SPV_OPERAND_TYPE_OPTIONAL_CIV,
|
||||
SPV_OPERAND_TYPE_RESULT_ID,
|
||||
SPV_OPERAND_TYPE_OPTIONAL_CIV}));
|
||||
EXPECT_THAT(
|
||||
spvAlternatePatternFollowingImmediate({SPV_OPERAND_TYPE_RESULT_ID,
|
||||
SPV_OPERAND_TYPE_FP_ROUNDING_MODE,
|
||||
SPV_OPERAND_TYPE_ID}),
|
||||
Eq(spv_operand_pattern_t{
|
||||
SPV_OPERAND_TYPE_OPTIONAL_CIV, SPV_OPERAND_TYPE_RESULT_ID,
|
||||
SPV_OPERAND_TYPE_OPTIONAL_CIV, SPV_OPERAND_TYPE_OPTIONAL_CIV}));
|
||||
EXPECT_THAT(
|
||||
spvAlternatePatternFollowingImmediate(
|
||||
{SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_DIMENSIONALITY,
|
||||
SPV_OPERAND_TYPE_LINKAGE_TYPE,
|
||||
SPV_OPERAND_TYPE_FUNCTION_PARAMETER_ATTRIBUTE,
|
||||
SPV_OPERAND_TYPE_FP_ROUNDING_MODE, SPV_OPERAND_TYPE_ID,
|
||||
SPV_OPERAND_TYPE_VARIABLE_ID}),
|
||||
Eq(spv_operand_pattern_t{
|
||||
SPV_OPERAND_TYPE_OPTIONAL_CIV, SPV_OPERAND_TYPE_RESULT_ID,
|
||||
SPV_OPERAND_TYPE_OPTIONAL_CIV, SPV_OPERAND_TYPE_OPTIONAL_CIV,
|
||||
SPV_OPERAND_TYPE_OPTIONAL_CIV, SPV_OPERAND_TYPE_OPTIONAL_CIV,
|
||||
SPV_OPERAND_TYPE_OPTIONAL_CIV, SPV_OPERAND_TYPE_OPTIONAL_CIV}));
|
||||
}
|
||||
|
||||
TEST(AlternatePatternFollowingImmediate, ResultIdMiddle) {
|
||||
EXPECT_THAT(spvAlternatePatternFollowingImmediate(
|
||||
{SPV_OPERAND_TYPE_FP_ROUNDING_MODE,
|
||||
SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}),
|
||||
Eq(spv_operand_pattern_t{SPV_OPERAND_TYPE_OPTIONAL_CIV,
|
||||
SPV_OPERAND_TYPE_RESULT_ID,
|
||||
SPV_OPERAND_TYPE_OPTIONAL_CIV}));
|
||||
EXPECT_THAT(
|
||||
spvAlternatePatternFollowingImmediate(
|
||||
{SPV_OPERAND_TYPE_DIMENSIONALITY, SPV_OPERAND_TYPE_LINKAGE_TYPE,
|
||||
SPV_OPERAND_TYPE_FUNCTION_PARAMETER_ATTRIBUTE,
|
||||
SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_FP_ROUNDING_MODE,
|
||||
SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_VARIABLE_ID}),
|
||||
Eq(spv_operand_pattern_t{
|
||||
SPV_OPERAND_TYPE_OPTIONAL_CIV, SPV_OPERAND_TYPE_RESULT_ID,
|
||||
SPV_OPERAND_TYPE_OPTIONAL_CIV, SPV_OPERAND_TYPE_OPTIONAL_CIV,
|
||||
SPV_OPERAND_TYPE_OPTIONAL_CIV}));
|
||||
}
|
||||
|
||||
TEST(AlternatePatternFollowingImmediate, ResultIdBack) {
|
||||
EXPECT_THAT(spvAlternatePatternFollowingImmediate(
|
||||
{SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID}),
|
||||
Eq(spv_operand_pattern_t{SPV_OPERAND_TYPE_OPTIONAL_CIV,
|
||||
SPV_OPERAND_TYPE_RESULT_ID}));
|
||||
EXPECT_THAT(spvAlternatePatternFollowingImmediate(
|
||||
{SPV_OPERAND_TYPE_FP_ROUNDING_MODE, SPV_OPERAND_TYPE_ID,
|
||||
SPV_OPERAND_TYPE_RESULT_ID}),
|
||||
Eq(spv_operand_pattern_t{SPV_OPERAND_TYPE_OPTIONAL_CIV,
|
||||
SPV_OPERAND_TYPE_RESULT_ID}));
|
||||
EXPECT_THAT(
|
||||
spvAlternatePatternFollowingImmediate(
|
||||
{SPV_OPERAND_TYPE_DIMENSIONALITY, SPV_OPERAND_TYPE_LINKAGE_TYPE,
|
||||
SPV_OPERAND_TYPE_FUNCTION_PARAMETER_ATTRIBUTE,
|
||||
SPV_OPERAND_TYPE_FP_ROUNDING_MODE, SPV_OPERAND_TYPE_ID,
|
||||
SPV_OPERAND_TYPE_VARIABLE_ID, SPV_OPERAND_TYPE_RESULT_ID}),
|
||||
Eq(spv_operand_pattern_t{SPV_OPERAND_TYPE_OPTIONAL_CIV,
|
||||
SPV_OPERAND_TYPE_RESULT_ID}));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace spvtools
|
||||
75
3rdparty/spirv-tools/test/operand_test.cpp
vendored
75
3rdparty/spirv-tools/test/operand_test.cpp
vendored
@@ -1,75 +0,0 @@
|
||||
// Copyright (c) 2015-2016 The Khronos Group Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "test/unit_spirv.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace {
|
||||
|
||||
using GetTargetTest = ::testing::TestWithParam<spv_target_env>;
|
||||
using ::testing::ValuesIn;
|
||||
|
||||
TEST_P(GetTargetTest, Default) {
|
||||
spv_operand_table table;
|
||||
ASSERT_EQ(SPV_SUCCESS, spvOperandTableGet(&table, GetParam()));
|
||||
ASSERT_NE(0u, table->count);
|
||||
ASSERT_NE(nullptr, table->types);
|
||||
}
|
||||
|
||||
TEST_P(GetTargetTest, InvalidPointerTable) {
|
||||
ASSERT_EQ(SPV_ERROR_INVALID_POINTER, spvOperandTableGet(nullptr, GetParam()));
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(OperandTableGet, GetTargetTest,
|
||||
ValuesIn(std::vector<spv_target_env>{
|
||||
SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
|
||||
SPV_ENV_VULKAN_1_0}));
|
||||
|
||||
TEST(OperandString, AllAreDefinedExceptVariable) {
|
||||
// None has no string, so don't test it.
|
||||
EXPECT_EQ(0u, SPV_OPERAND_TYPE_NONE);
|
||||
// Start testing at enum with value 1, skipping None.
|
||||
for (int i = 1; i < int(SPV_OPERAND_TYPE_FIRST_VARIABLE_TYPE); i++) {
|
||||
EXPECT_NE(nullptr, spvOperandTypeStr(static_cast<spv_operand_type_t>(i)))
|
||||
<< " Operand type " << i;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(OperandIsConcreteMask, Sample) {
|
||||
// Check a few operand types preceding the concrete mask types.
|
||||
EXPECT_FALSE(spvOperandIsConcreteMask(SPV_OPERAND_TYPE_NONE));
|
||||
EXPECT_FALSE(spvOperandIsConcreteMask(SPV_OPERAND_TYPE_ID));
|
||||
EXPECT_FALSE(spvOperandIsConcreteMask(SPV_OPERAND_TYPE_LITERAL_INTEGER));
|
||||
EXPECT_FALSE(spvOperandIsConcreteMask(SPV_OPERAND_TYPE_CAPABILITY));
|
||||
|
||||
// Check all the concrete mask operand types.
|
||||
EXPECT_TRUE(spvOperandIsConcreteMask(SPV_OPERAND_TYPE_IMAGE));
|
||||
EXPECT_TRUE(spvOperandIsConcreteMask(SPV_OPERAND_TYPE_FP_FAST_MATH_MODE));
|
||||
EXPECT_TRUE(spvOperandIsConcreteMask(SPV_OPERAND_TYPE_SELECTION_CONTROL));
|
||||
EXPECT_TRUE(spvOperandIsConcreteMask(SPV_OPERAND_TYPE_LOOP_CONTROL));
|
||||
EXPECT_TRUE(spvOperandIsConcreteMask(SPV_OPERAND_TYPE_FUNCTION_CONTROL));
|
||||
EXPECT_TRUE(spvOperandIsConcreteMask(SPV_OPERAND_TYPE_MEMORY_ACCESS));
|
||||
|
||||
// Check a few operand types after the concrete mask types, including the
|
||||
// optional forms for Image and MemoryAccess.
|
||||
EXPECT_FALSE(spvOperandIsConcreteMask(SPV_OPERAND_TYPE_OPTIONAL_ID));
|
||||
EXPECT_FALSE(spvOperandIsConcreteMask(SPV_OPERAND_TYPE_OPTIONAL_IMAGE));
|
||||
EXPECT_FALSE(
|
||||
spvOperandIsConcreteMask(SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace spvtools
|
||||
107
3rdparty/spirv-tools/test/opt/CMakeLists.txt
vendored
107
3rdparty/spirv-tools/test/opt/CMakeLists.txt
vendored
@@ -1,107 +0,0 @@
|
||||
# Copyright (c) 2016 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
add_subdirectory(dominator_tree)
|
||||
add_subdirectory(loop_optimizations)
|
||||
|
||||
add_spvtools_unittest(TARGET opt
|
||||
SRCS aggressive_dead_code_elim_test.cpp
|
||||
amd_ext_to_khr.cpp
|
||||
assembly_builder_test.cpp
|
||||
block_merge_test.cpp
|
||||
ccp_test.cpp
|
||||
cfg_cleanup_test.cpp
|
||||
cfg_test.cpp
|
||||
code_sink_test.cpp
|
||||
combine_access_chains_test.cpp
|
||||
compact_ids_test.cpp
|
||||
constants_test.cpp
|
||||
constant_manager_test.cpp
|
||||
convert_relaxed_to_half_test.cpp
|
||||
copy_prop_array_test.cpp
|
||||
dead_branch_elim_test.cpp
|
||||
dead_insert_elim_test.cpp
|
||||
dead_variable_elim_test.cpp
|
||||
decompose_initialized_variables_test.cpp
|
||||
decoration_manager_test.cpp
|
||||
def_use_test.cpp
|
||||
desc_sroa_test.cpp
|
||||
eliminate_dead_const_test.cpp
|
||||
eliminate_dead_functions_test.cpp
|
||||
eliminate_dead_member_test.cpp
|
||||
feature_manager_test.cpp
|
||||
fix_storage_class_test.cpp
|
||||
flatten_decoration_test.cpp
|
||||
fold_spec_const_op_composite_test.cpp
|
||||
fold_test.cpp
|
||||
freeze_spec_const_test.cpp
|
||||
function_test.cpp
|
||||
generate_webgpu_initializers_test.cpp
|
||||
graphics_robust_access_test.cpp
|
||||
if_conversion_test.cpp
|
||||
inline_opaque_test.cpp
|
||||
inline_test.cpp
|
||||
insert_extract_elim_test.cpp
|
||||
inst_bindless_check_test.cpp
|
||||
inst_buff_addr_check_test.cpp
|
||||
instruction_list_test.cpp
|
||||
instruction_test.cpp
|
||||
ir_builder.cpp
|
||||
ir_context_test.cpp
|
||||
ir_loader_test.cpp
|
||||
iterator_test.cpp
|
||||
legalize_vector_shuffle_test.cpp
|
||||
line_debug_info_test.cpp
|
||||
local_access_chain_convert_test.cpp
|
||||
local_redundancy_elimination_test.cpp
|
||||
local_single_block_elim.cpp
|
||||
local_single_store_elim_test.cpp
|
||||
local_ssa_elim_test.cpp
|
||||
module_test.cpp
|
||||
module_utils.h
|
||||
optimizer_test.cpp
|
||||
pass_manager_test.cpp
|
||||
pass_merge_return_test.cpp
|
||||
pass_remove_duplicates_test.cpp
|
||||
pass_utils.cpp
|
||||
private_to_local_test.cpp
|
||||
process_lines_test.cpp
|
||||
propagator_test.cpp
|
||||
reduce_load_size_test.cpp
|
||||
redundancy_elimination_test.cpp
|
||||
register_liveness.cpp
|
||||
relax_float_ops_test.cpp
|
||||
replace_invalid_opc_test.cpp
|
||||
scalar_analysis.cpp
|
||||
scalar_replacement_test.cpp
|
||||
set_spec_const_default_value_test.cpp
|
||||
simplification_test.cpp
|
||||
split_invalid_unreachable_test.cpp
|
||||
strength_reduction_test.cpp
|
||||
strip_atomic_counter_memory_test.cpp
|
||||
strip_debug_info_test.cpp
|
||||
strip_reflect_info_test.cpp
|
||||
struct_cfg_analysis_test.cpp
|
||||
type_manager_test.cpp
|
||||
types_test.cpp
|
||||
unify_const_test.cpp
|
||||
upgrade_memory_model_test.cpp
|
||||
utils_test.cpp pass_utils.cpp
|
||||
value_table_test.cpp
|
||||
vector_dce_test.cpp
|
||||
workaround1209_test.cpp
|
||||
wrap_opkill_test.cpp
|
||||
LIBS SPIRV-Tools-opt
|
||||
PCH_FILE pch_test_opt
|
||||
)
|
||||
File diff suppressed because it is too large
Load Diff
918
3rdparty/spirv-tools/test/opt/amd_ext_to_khr.cpp
vendored
918
3rdparty/spirv-tools/test/opt/amd_ext_to_khr.cpp
vendored
@@ -1,918 +0,0 @@
|
||||
// Copyright (c) 2019 Google LLC.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
|
||||
#include "test/opt/pass_fixture.h"
|
||||
#include "test/opt/pass_utils.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace opt {
|
||||
namespace {
|
||||
|
||||
using AmdExtToKhrTest = PassTest<::testing::Test>;
|
||||
|
||||
using ::testing::HasSubstr;
|
||||
|
||||
std::string GetTest(std::string op_code, std::string new_op_code) {
|
||||
const std::string text = R"(
|
||||
; CHECK: OpCapability Shader
|
||||
; CHECK-NOT: OpExtension "SPV_AMD_shader_ballot"
|
||||
; CHECK: OpFunction
|
||||
; CHECK-NEXT: OpLabel
|
||||
; CHECK-NEXT: [[undef:%\w+]] = OpUndef %uint
|
||||
; CHECK-NEXT: )" + new_op_code +
|
||||
R"( %uint %uint_3 Reduce [[undef]]
|
||||
OpCapability Shader
|
||||
OpCapability Groups
|
||||
OpExtension "SPV_AMD_shader_ballot"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %1 "func"
|
||||
OpExecutionMode %1 OriginUpperLeft
|
||||
%void = OpTypeVoid
|
||||
%3 = OpTypeFunction %void
|
||||
%uint = OpTypeInt 32 0
|
||||
%uint_3 = OpConstant %uint 3
|
||||
%1 = OpFunction %void None %3
|
||||
%6 = OpLabel
|
||||
%7 = OpUndef %uint
|
||||
%8 = )" + op_code +
|
||||
R"( %uint %uint_3 Reduce %7
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
|
||||
)";
|
||||
return text;
|
||||
}
|
||||
|
||||
TEST_F(AmdExtToKhrTest, ReplaceGroupIAddNonUniformAMD) {
|
||||
std::string text =
|
||||
GetTest("OpGroupIAddNonUniformAMD", "OpGroupNonUniformIAdd");
|
||||
SinglePassRunAndMatch<AmdExtensionToKhrPass>(text, true);
|
||||
}
|
||||
TEST_F(AmdExtToKhrTest, ReplaceGroupFAddNonUniformAMD) {
|
||||
std::string text =
|
||||
GetTest("OpGroupFAddNonUniformAMD", "OpGroupNonUniformFAdd");
|
||||
SinglePassRunAndMatch<AmdExtensionToKhrPass>(text, true);
|
||||
}
|
||||
TEST_F(AmdExtToKhrTest, ReplaceGroupUMinNonUniformAMD) {
|
||||
std::string text =
|
||||
GetTest("OpGroupUMinNonUniformAMD", "OpGroupNonUniformUMin");
|
||||
SinglePassRunAndMatch<AmdExtensionToKhrPass>(text, true);
|
||||
}
|
||||
TEST_F(AmdExtToKhrTest, ReplaceGroupSMinNonUniformAMD) {
|
||||
std::string text =
|
||||
GetTest("OpGroupSMinNonUniformAMD", "OpGroupNonUniformSMin");
|
||||
SinglePassRunAndMatch<AmdExtensionToKhrPass>(text, true);
|
||||
}
|
||||
TEST_F(AmdExtToKhrTest, ReplaceGroupFMinNonUniformAMD) {
|
||||
std::string text =
|
||||
GetTest("OpGroupFMinNonUniformAMD", "OpGroupNonUniformFMin");
|
||||
SinglePassRunAndMatch<AmdExtensionToKhrPass>(text, true);
|
||||
}
|
||||
TEST_F(AmdExtToKhrTest, ReplaceGroupUMaxNonUniformAMD) {
|
||||
std::string text =
|
||||
GetTest("OpGroupUMaxNonUniformAMD", "OpGroupNonUniformUMax");
|
||||
SinglePassRunAndMatch<AmdExtensionToKhrPass>(text, true);
|
||||
}
|
||||
TEST_F(AmdExtToKhrTest, ReplaceGroupSMaxNonUniformAMD) {
|
||||
std::string text =
|
||||
GetTest("OpGroupSMaxNonUniformAMD", "OpGroupNonUniformSMax");
|
||||
SinglePassRunAndMatch<AmdExtensionToKhrPass>(text, true);
|
||||
}
|
||||
TEST_F(AmdExtToKhrTest, ReplaceGroupFMaxNonUniformAMD) {
|
||||
std::string text =
|
||||
GetTest("OpGroupFMaxNonUniformAMD", "OpGroupNonUniformFMax");
|
||||
SinglePassRunAndMatch<AmdExtensionToKhrPass>(text, true);
|
||||
}
|
||||
|
||||
TEST_F(AmdExtToKhrTest, ReplaceMbcntAMD) {
|
||||
const std::string text = R"(
|
||||
; CHECK: OpCapability Shader
|
||||
; CHECK-NOT: OpExtension "SPV_AMD_shader_ballot"
|
||||
; CHECK-NOT: OpExtInstImport "SPV_AMD_shader_ballot"
|
||||
; CHECK: OpDecorate [[var:%\w+]] BuiltIn SubgroupLtMask
|
||||
; CHECK: [[var]] = OpVariable %_ptr_Input_v4uint Input
|
||||
; CHECK: OpFunction
|
||||
; CHECK-NEXT: OpLabel
|
||||
; CHECK-NEXT: [[ld:%\w+]] = OpLoad %v4uint [[var]]
|
||||
; CHECK-NEXT: [[shuffle:%\w+]] = OpVectorShuffle %v2uint [[ld]] [[ld]] 0 1
|
||||
; CHECK-NEXT: [[bitcast:%\w+]] = OpBitcast %ulong [[shuffle]]
|
||||
; CHECK-NEXT: [[and:%\w+]] = OpBitwiseAnd %ulong [[bitcast]] %ulong_0
|
||||
; CHECK-NEXT: [[result:%\w+]] = OpBitCount %uint [[and]]
|
||||
OpCapability Shader
|
||||
OpCapability Int64
|
||||
OpExtension "SPV_AMD_shader_ballot"
|
||||
%1 = OpExtInstImport "SPV_AMD_shader_ballot"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %2 "func"
|
||||
OpExecutionMode %2 OriginUpperLeft
|
||||
%void = OpTypeVoid
|
||||
%4 = OpTypeFunction %void
|
||||
%uint = OpTypeInt 32 0
|
||||
%ulong = OpTypeInt 64 0
|
||||
%ulong_0 = OpConstant %ulong 0
|
||||
%2 = OpFunction %void None %4
|
||||
%8 = OpLabel
|
||||
%9 = OpExtInst %uint %1 MbcntAMD %ulong_0
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<AmdExtensionToKhrPass>(text, true);
|
||||
}
|
||||
|
||||
TEST_F(AmdExtToKhrTest, ReplaceSwizzleInvocationsAMD) {
|
||||
const std::string text = R"(
|
||||
; CHECK: OpCapability Shader
|
||||
; CHECK-NOT: OpExtension "SPV_AMD_shader_ballot"
|
||||
; CHECK-NOT: OpExtInstImport "SPV_AMD_shader_ballot"
|
||||
; CHECK: OpDecorate [[var:%\w+]] BuiltIn SubgroupLocalInvocationId
|
||||
; CHECK: [[subgroup:%\w+]] = OpConstant %uint 3
|
||||
; CHECK: [[offset:%\w+]] = OpConstantComposite %v4uint
|
||||
; CHECK: [[var]] = OpVariable %_ptr_Input_uint Input
|
||||
; CHECK: [[uint_max:%\w+]] = OpConstant %uint 4294967295
|
||||
; CHECK: [[ballot_value:%\w+]] = OpConstantComposite %v4uint [[uint_max]] [[uint_max]] [[uint_max]] [[uint_max]]
|
||||
; CHECK: [[null:%\w+]] = OpConstantNull [[type:%\w+]]
|
||||
; CHECK: OpFunction
|
||||
; CHECK-NEXT: OpLabel
|
||||
; CHECK-NEXT: [[data:%\w+]] = OpUndef [[type]]
|
||||
; CHECK-NEXT: [[id:%\w+]] = OpLoad %uint [[var]]
|
||||
; CHECK-NEXT: [[quad_idx:%\w+]] = OpBitwiseAnd %uint [[id]] %uint_3
|
||||
; CHECK-NEXT: [[quad_ldr:%\w+]] = OpBitwiseXor %uint [[id]] [[quad_idx]]
|
||||
; CHECK-NEXT: [[my_offset:%\w+]] = OpVectorExtractDynamic %uint [[offset]] [[quad_idx]]
|
||||
; CHECK-NEXT: [[target_inv:%\w+]] = OpIAdd %uint [[quad_ldr]] [[my_offset]]
|
||||
; CHECK-NEXT: [[is_active:%\w+]] = OpGroupNonUniformBallotBitExtract %bool [[subgroup]] [[ballot_value]] [[target_inv]]
|
||||
; CHECK-NEXT: [[shuffle:%\w+]] = OpGroupNonUniformShuffle [[type]] [[subgroup]] [[data]] [[target_inv]]
|
||||
; CHECK-NEXT: [[result:%\w+]] = OpSelect [[type]] [[is_active]] [[shuffle]] [[null]]
|
||||
OpCapability Shader
|
||||
OpExtension "SPV_AMD_shader_ballot"
|
||||
%ext = OpExtInstImport "SPV_AMD_shader_ballot"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %1 "func"
|
||||
OpExecutionMode %1 OriginUpperLeft
|
||||
%void = OpTypeVoid
|
||||
%3 = OpTypeFunction %void
|
||||
%uint = OpTypeInt 32 0
|
||||
%uint_x = OpConstant %uint 1
|
||||
%uint_y = OpConstant %uint 2
|
||||
%uint_z = OpConstant %uint 3
|
||||
%uint_w = OpConstant %uint 0
|
||||
%v4uint = OpTypeVector %uint 4
|
||||
%offset = OpConstantComposite %v4uint %uint_x %uint_y %uint_z %uint_x
|
||||
%1 = OpFunction %void None %3
|
||||
%6 = OpLabel
|
||||
%data = OpUndef %uint
|
||||
%9 = OpExtInst %uint %ext SwizzleInvocationsAMD %data %offset
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<AmdExtensionToKhrPass>(text, true);
|
||||
}
|
||||
TEST_F(AmdExtToKhrTest, ReplaceSwizzleInvocationsMaskedAMD) {
|
||||
const std::string text = R"(
|
||||
; CHECK: OpCapability Shader
|
||||
; CHECK-NOT: OpExtension "SPV_AMD_shader_ballot"
|
||||
; CHECK-NOT: OpExtInstImport "SPV_AMD_shader_ballot"
|
||||
; CHECK: OpDecorate [[var:%\w+]] BuiltIn SubgroupLocalInvocationId
|
||||
; CHECK: [[x:%\w+]] = OpConstant %uint 19
|
||||
; CHECK: [[y:%\w+]] = OpConstant %uint 12
|
||||
; CHECK: [[z:%\w+]] = OpConstant %uint 16
|
||||
; CHECK: [[var]] = OpVariable %_ptr_Input_uint Input
|
||||
; CHECK: [[mask_extend:%\w+]] = OpConstant %uint 4294967264
|
||||
; CHECK: [[uint_max:%\w+]] = OpConstant %uint 4294967295
|
||||
; CHECK: [[subgroup:%\w+]] = OpConstant %uint 3
|
||||
; CHECK: [[ballot_value:%\w+]] = OpConstantComposite %v4uint [[uint_max]] [[uint_max]] [[uint_max]] [[uint_max]]
|
||||
; CHECK: [[null:%\w+]] = OpConstantNull [[type:%\w+]]
|
||||
; CHECK: OpFunction
|
||||
; CHECK-NEXT: OpLabel
|
||||
; CHECK-NEXT: [[data:%\w+]] = OpUndef [[type]]
|
||||
; CHECK-NEXT: [[id:%\w+]] = OpLoad %uint [[var]]
|
||||
; CHECK-NEXT: [[and_mask:%\w+]] = OpBitwiseOr %uint [[x]] [[mask_extend]]
|
||||
; CHECK-NEXT: [[and:%\w+]] = OpBitwiseAnd %uint [[id]] [[and_mask]]
|
||||
; CHECK-NEXT: [[or:%\w+]] = OpBitwiseOr %uint [[and]] [[y]]
|
||||
; CHECK-NEXT: [[target_inv:%\w+]] = OpBitwiseXor %uint [[or]] [[z]]
|
||||
; CHECK-NEXT: [[is_active:%\w+]] = OpGroupNonUniformBallotBitExtract %bool [[subgroup]] [[ballot_value]] [[target_inv]]
|
||||
; CHECK-NEXT: [[shuffle:%\w+]] = OpGroupNonUniformShuffle [[type]] [[subgroup]] [[data]] [[target_inv]]
|
||||
; CHECK-NEXT: [[result:%\w+]] = OpSelect [[type]] [[is_active]] [[shuffle]] [[null]]
|
||||
OpCapability Shader
|
||||
OpExtension "SPV_AMD_shader_ballot"
|
||||
%ext = OpExtInstImport "SPV_AMD_shader_ballot"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %1 "func"
|
||||
OpExecutionMode %1 OriginUpperLeft
|
||||
%void = OpTypeVoid
|
||||
%3 = OpTypeFunction %void
|
||||
%uint = OpTypeInt 32 0
|
||||
%uint_x = OpConstant %uint 19
|
||||
%uint_y = OpConstant %uint 12
|
||||
%uint_z = OpConstant %uint 16
|
||||
%v3uint = OpTypeVector %uint 3
|
||||
%mask = OpConstantComposite %v3uint %uint_x %uint_y %uint_z
|
||||
%1 = OpFunction %void None %3
|
||||
%6 = OpLabel
|
||||
%data = OpUndef %uint
|
||||
%9 = OpExtInst %uint %ext SwizzleInvocationsMaskedAMD %data %mask
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<AmdExtensionToKhrPass>(text, true);
|
||||
}
|
||||
|
||||
TEST_F(AmdExtToKhrTest, ReplaceWriteInvocationAMD) {
|
||||
const std::string text = R"(
|
||||
; CHECK: OpCapability Shader
|
||||
; CHECK-NOT: OpExtension "SPV_AMD_shader_ballot"
|
||||
; CHECK-NOT: OpExtInstImport "SPV_AMD_shader_ballot"
|
||||
; CHECK: OpDecorate [[var:%\w+]] BuiltIn SubgroupLocalInvocationId
|
||||
; CHECK: [[var]] = OpVariable %_ptr_Input_uint Input
|
||||
; CHECK: OpFunction
|
||||
; CHECK-NEXT: OpLabel
|
||||
; CHECK-NEXT: [[input_val:%\w+]] = OpUndef %uint
|
||||
; CHECK-NEXT: [[write_val:%\w+]] = OpUndef %uint
|
||||
; CHECK-NEXT: [[ld:%\w+]] = OpLoad %uint [[var]]
|
||||
; CHECK-NEXT: [[cmp:%\w+]] = OpIEqual %bool [[ld]] %uint_3
|
||||
; CHECK-NEXT: [[result:%\w+]] = OpSelect %uint [[cmp]] [[write_val]] [[input_val]]
|
||||
OpCapability Shader
|
||||
OpExtension "SPV_AMD_shader_ballot"
|
||||
%ext = OpExtInstImport "SPV_AMD_shader_ballot"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %1 "func"
|
||||
OpExecutionMode %1 OriginUpperLeft
|
||||
%void = OpTypeVoid
|
||||
%3 = OpTypeFunction %void
|
||||
%uint = OpTypeInt 32 0
|
||||
%uint_3 = OpConstant %uint 3
|
||||
%1 = OpFunction %void None %3
|
||||
%6 = OpLabel
|
||||
%7 = OpUndef %uint
|
||||
%8 = OpUndef %uint
|
||||
%9 = OpExtInst %uint %ext WriteInvocationAMD %7 %8 %uint_3
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<AmdExtensionToKhrPass>(text, true);
|
||||
}
|
||||
|
||||
TEST_F(AmdExtToKhrTest, ReplaceFMin3AMD) {
|
||||
const std::string text = R"(
|
||||
; CHECK: OpCapability Shader
|
||||
; CHECK-NOT: OpExtension "SPV_AMD_shader_trinary_minmax"
|
||||
; CHECK-NOT: OpExtInstImport "SPV_AMD_shader_trinary_minmax"
|
||||
; CHECK: [[ext:%\w+]] = OpExtInstImport "GLSL.std.450"
|
||||
; CHECK: [[type:%\w+]] = OpTypeFloat 32
|
||||
; CHECK: OpFunction
|
||||
; CHECK-NEXT: OpLabel
|
||||
; CHECK-NEXT: [[x:%\w+]] = OpUndef [[type]]
|
||||
; CHECK-NEXT: [[y:%\w+]] = OpUndef [[type]]
|
||||
; CHECK-NEXT: [[z:%\w+]] = OpUndef [[type]]
|
||||
; CHECK-NEXT: [[temp:%\w+]] = OpExtInst [[type]] [[ext]] FMin [[x]] [[y]]
|
||||
; CHECK-NEXT: [[result:%\w+]] = OpExtInst [[type]] [[ext]] FMin [[temp]] [[z]]
|
||||
OpCapability Shader
|
||||
OpExtension "SPV_AMD_shader_trinary_minmax"
|
||||
%ext = OpExtInstImport "SPV_AMD_shader_trinary_minmax"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %1 "func"
|
||||
OpExecutionMode %1 OriginUpperLeft
|
||||
%void = OpTypeVoid
|
||||
%3 = OpTypeFunction %void
|
||||
%uint = OpTypeInt 32 0
|
||||
%float = OpTypeFloat 32
|
||||
%uint_3 = OpConstant %uint 3
|
||||
%1 = OpFunction %void None %3
|
||||
%6 = OpLabel
|
||||
%7 = OpUndef %float
|
||||
%8 = OpUndef %float
|
||||
%9 = OpUndef %float
|
||||
%10 = OpExtInst %float %ext FMin3AMD %7 %8 %9
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<AmdExtensionToKhrPass>(text, true);
|
||||
}
|
||||
|
||||
TEST_F(AmdExtToKhrTest, ReplaceSMin3AMD) {
|
||||
const std::string text = R"(
|
||||
; CHECK: OpCapability Shader
|
||||
; CHECK-NOT: OpExtension "SPV_AMD_shader_trinary_minmax"
|
||||
; CHECK-NOT: OpExtInstImport "SPV_AMD_shader_trinary_minmax"
|
||||
; CHECK: [[ext:%\w+]] = OpExtInstImport "GLSL.std.450"
|
||||
; CHECK: [[type:%\w+]] = OpTypeInt 32 1
|
||||
; CHECK: OpFunction
|
||||
; CHECK-NEXT: OpLabel
|
||||
; CHECK-NEXT: [[x:%\w+]] = OpUndef [[type]]
|
||||
; CHECK-NEXT: [[y:%\w+]] = OpUndef [[type]]
|
||||
; CHECK-NEXT: [[z:%\w+]] = OpUndef [[type]]
|
||||
; CHECK-NEXT: [[temp:%\w+]] = OpExtInst [[type]] [[ext]] SMin [[x]] [[y]]
|
||||
; CHECK-NEXT: [[result:%\w+]] = OpExtInst [[type]] [[ext]] SMin [[temp]] [[z]]
|
||||
OpCapability Shader
|
||||
OpExtension "SPV_AMD_shader_trinary_minmax"
|
||||
%ext = OpExtInstImport "SPV_AMD_shader_trinary_minmax"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %1 "func"
|
||||
OpExecutionMode %1 OriginUpperLeft
|
||||
%void = OpTypeVoid
|
||||
%3 = OpTypeFunction %void
|
||||
%uint = OpTypeInt 32 0
|
||||
%int = OpTypeInt 32 1
|
||||
%float = OpTypeFloat 32
|
||||
%uint_3 = OpConstant %uint 3
|
||||
%1 = OpFunction %void None %3
|
||||
%6 = OpLabel
|
||||
%7 = OpUndef %int
|
||||
%8 = OpUndef %int
|
||||
%9 = OpUndef %int
|
||||
%10 = OpExtInst %int %ext SMin3AMD %7 %8 %9
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<AmdExtensionToKhrPass>(text, true);
|
||||
}
|
||||
|
||||
TEST_F(AmdExtToKhrTest, ReplaceUMin3AMD) {
|
||||
const std::string text = R"(
|
||||
; CHECK: OpCapability Shader
|
||||
; CHECK-NOT: OpExtension "SPV_AMD_shader_trinary_minmax"
|
||||
; CHECK-NOT: OpExtInstImport "SPV_AMD_shader_trinary_minmax"
|
||||
; CHECK: [[ext:%\w+]] = OpExtInstImport "GLSL.std.450"
|
||||
; CHECK: [[type:%\w+]] = OpTypeInt 32 0
|
||||
; CHECK: OpFunction
|
||||
; CHECK-NEXT: OpLabel
|
||||
; CHECK-NEXT: [[x:%\w+]] = OpUndef [[type]]
|
||||
; CHECK-NEXT: [[y:%\w+]] = OpUndef [[type]]
|
||||
; CHECK-NEXT: [[z:%\w+]] = OpUndef [[type]]
|
||||
; CHECK-NEXT: [[temp:%\w+]] = OpExtInst [[type]] [[ext]] UMin [[x]] [[y]]
|
||||
; CHECK-NEXT: [[result:%\w+]] = OpExtInst [[type]] [[ext]] UMin [[temp]] [[z]]
|
||||
OpCapability Shader
|
||||
OpExtension "SPV_AMD_shader_trinary_minmax"
|
||||
%ext = OpExtInstImport "SPV_AMD_shader_trinary_minmax"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %1 "func"
|
||||
OpExecutionMode %1 OriginUpperLeft
|
||||
%void = OpTypeVoid
|
||||
%3 = OpTypeFunction %void
|
||||
%uint = OpTypeInt 32 0
|
||||
%int = OpTypeInt 32 1
|
||||
%float = OpTypeFloat 32
|
||||
%uint_3 = OpConstant %uint 3
|
||||
%1 = OpFunction %void None %3
|
||||
%6 = OpLabel
|
||||
%7 = OpUndef %uint
|
||||
%8 = OpUndef %uint
|
||||
%9 = OpUndef %uint
|
||||
%10 = OpExtInst %uint %ext UMin3AMD %7 %8 %9
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<AmdExtensionToKhrPass>(text, true);
|
||||
}
|
||||
|
||||
TEST_F(AmdExtToKhrTest, ReplaceFMax3AMD) {
|
||||
const std::string text = R"(
|
||||
; CHECK: OpCapability Shader
|
||||
; CHECK-NOT: OpExtension "SPV_AMD_shader_trinary_minmax"
|
||||
; CHECK-NOT: OpExtInstImport "SPV_AMD_shader_trinary_minmax"
|
||||
; CHECK: [[ext:%\w+]] = OpExtInstImport "GLSL.std.450"
|
||||
; CHECK: [[type:%\w+]] = OpTypeFloat 32
|
||||
; CHECK: OpFunction
|
||||
; CHECK-NEXT: OpLabel
|
||||
; CHECK-NEXT: [[x:%\w+]] = OpUndef [[type]]
|
||||
; CHECK-NEXT: [[y:%\w+]] = OpUndef [[type]]
|
||||
; CHECK-NEXT: [[z:%\w+]] = OpUndef [[type]]
|
||||
; CHECK-NEXT: [[temp:%\w+]] = OpExtInst [[type]] [[ext]] FMax [[x]] [[y]]
|
||||
; CHECK-NEXT: [[result:%\w+]] = OpExtInst [[type]] [[ext]] FMax [[temp]] [[z]]
|
||||
OpCapability Shader
|
||||
OpExtension "SPV_AMD_shader_trinary_minmax"
|
||||
%ext = OpExtInstImport "SPV_AMD_shader_trinary_minmax"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %1 "func"
|
||||
OpExecutionMode %1 OriginUpperLeft
|
||||
%void = OpTypeVoid
|
||||
%3 = OpTypeFunction %void
|
||||
%uint = OpTypeInt 32 0
|
||||
%float = OpTypeFloat 32
|
||||
%uint_3 = OpConstant %uint 3
|
||||
%1 = OpFunction %void None %3
|
||||
%6 = OpLabel
|
||||
%7 = OpUndef %float
|
||||
%8 = OpUndef %float
|
||||
%9 = OpUndef %float
|
||||
%10 = OpExtInst %float %ext FMax3AMD %7 %8 %9
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<AmdExtensionToKhrPass>(text, true);
|
||||
}
|
||||
|
||||
TEST_F(AmdExtToKhrTest, ReplaceSMax3AMD) {
|
||||
const std::string text = R"(
|
||||
; CHECK: OpCapability Shader
|
||||
; CHECK-NOT: OpExtension "SPV_AMD_shader_trinary_minmax"
|
||||
; CHECK-NOT: OpExtInstImport "SPV_AMD_shader_trinary_minmax"
|
||||
; CHECK: [[ext:%\w+]] = OpExtInstImport "GLSL.std.450"
|
||||
; CHECK: [[type:%\w+]] = OpTypeInt 32 1
|
||||
; CHECK: OpFunction
|
||||
; CHECK-NEXT: OpLabel
|
||||
; CHECK-NEXT: [[x:%\w+]] = OpUndef [[type]]
|
||||
; CHECK-NEXT: [[y:%\w+]] = OpUndef [[type]]
|
||||
; CHECK-NEXT: [[z:%\w+]] = OpUndef [[type]]
|
||||
; CHECK-NEXT: [[temp:%\w+]] = OpExtInst [[type]] [[ext]] SMax [[x]] [[y]]
|
||||
; CHECK-NEXT: [[result:%\w+]] = OpExtInst [[type]] [[ext]] SMax [[temp]] [[z]]
|
||||
OpCapability Shader
|
||||
OpExtension "SPV_AMD_shader_trinary_minmax"
|
||||
%ext = OpExtInstImport "SPV_AMD_shader_trinary_minmax"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %1 "func"
|
||||
OpExecutionMode %1 OriginUpperLeft
|
||||
%void = OpTypeVoid
|
||||
%3 = OpTypeFunction %void
|
||||
%uint = OpTypeInt 32 0
|
||||
%int = OpTypeInt 32 1
|
||||
%float = OpTypeFloat 32
|
||||
%uint_3 = OpConstant %uint 3
|
||||
%1 = OpFunction %void None %3
|
||||
%6 = OpLabel
|
||||
%7 = OpUndef %int
|
||||
%8 = OpUndef %int
|
||||
%9 = OpUndef %int
|
||||
%10 = OpExtInst %int %ext SMax3AMD %7 %8 %9
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<AmdExtensionToKhrPass>(text, true);
|
||||
}
|
||||
|
||||
TEST_F(AmdExtToKhrTest, ReplaceUMax3AMD) {
|
||||
const std::string text = R"(
|
||||
; CHECK: OpCapability Shader
|
||||
; CHECK-NOT: OpExtension "SPV_AMD_shader_trinary_minmax"
|
||||
; CHECK-NOT: OpExtInstImport "SPV_AMD_shader_trinary_minmax"
|
||||
; CHECK: [[ext:%\w+]] = OpExtInstImport "GLSL.std.450"
|
||||
; CHECK: [[type:%\w+]] = OpTypeInt 32 0
|
||||
; CHECK: OpFunction
|
||||
; CHECK-NEXT: OpLabel
|
||||
; CHECK-NEXT: [[x:%\w+]] = OpUndef [[type]]
|
||||
; CHECK-NEXT: [[y:%\w+]] = OpUndef [[type]]
|
||||
; CHECK-NEXT: [[z:%\w+]] = OpUndef [[type]]
|
||||
; CHECK-NEXT: [[temp:%\w+]] = OpExtInst [[type]] [[ext]] UMax [[x]] [[y]]
|
||||
; CHECK-NEXT: [[result:%\w+]] = OpExtInst [[type]] [[ext]] UMax [[temp]] [[z]]
|
||||
OpCapability Shader
|
||||
OpExtension "SPV_AMD_shader_trinary_minmax"
|
||||
%ext = OpExtInstImport "SPV_AMD_shader_trinary_minmax"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %1 "func"
|
||||
OpExecutionMode %1 OriginUpperLeft
|
||||
%void = OpTypeVoid
|
||||
%3 = OpTypeFunction %void
|
||||
%uint = OpTypeInt 32 0
|
||||
%int = OpTypeInt 32 1
|
||||
%float = OpTypeFloat 32
|
||||
%uint_3 = OpConstant %uint 3
|
||||
%1 = OpFunction %void None %3
|
||||
%6 = OpLabel
|
||||
%7 = OpUndef %uint
|
||||
%8 = OpUndef %uint
|
||||
%9 = OpUndef %uint
|
||||
%10 = OpExtInst %uint %ext UMax3AMD %7 %8 %9
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<AmdExtensionToKhrPass>(text, true);
|
||||
}
|
||||
|
||||
TEST_F(AmdExtToKhrTest, ReplaceVecUMax3AMD) {
|
||||
const std::string text = R"(
|
||||
; CHECK: OpCapability Shader
|
||||
; CHECK-NOT: OpExtension "SPV_AMD_shader_trinary_minmax"
|
||||
; CHECK-NOT: OpExtInstImport "SPV_AMD_shader_trinary_minmax"
|
||||
; CHECK: [[ext:%\w+]] = OpExtInstImport "GLSL.std.450"
|
||||
; CHECK: [[type:%\w+]] = OpTypeVector
|
||||
; CHECK: OpFunction
|
||||
; CHECK-NEXT: OpLabel
|
||||
; CHECK-NEXT: [[x:%\w+]] = OpUndef [[type]]
|
||||
; CHECK-NEXT: [[y:%\w+]] = OpUndef [[type]]
|
||||
; CHECK-NEXT: [[z:%\w+]] = OpUndef [[type]]
|
||||
; CHECK-NEXT: [[temp:%\w+]] = OpExtInst [[type]] [[ext]] UMax [[x]] [[y]]
|
||||
; CHECK-NEXT: [[result:%\w+]] = OpExtInst [[type]] [[ext]] UMax [[temp]] [[z]]
|
||||
OpCapability Shader
|
||||
OpExtension "SPV_AMD_shader_trinary_minmax"
|
||||
%ext = OpExtInstImport "SPV_AMD_shader_trinary_minmax"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %1 "func"
|
||||
OpExecutionMode %1 OriginUpperLeft
|
||||
%void = OpTypeVoid
|
||||
%3 = OpTypeFunction %void
|
||||
%uint = OpTypeInt 32 0
|
||||
%vec = OpTypeVector %uint 4
|
||||
%int = OpTypeInt 32 1
|
||||
%float = OpTypeFloat 32
|
||||
%uint_3 = OpConstant %uint 3
|
||||
%1 = OpFunction %void None %3
|
||||
%6 = OpLabel
|
||||
%7 = OpUndef %vec
|
||||
%8 = OpUndef %vec
|
||||
%9 = OpUndef %vec
|
||||
%10 = OpExtInst %vec %ext UMax3AMD %7 %8 %9
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<AmdExtensionToKhrPass>(text, true);
|
||||
}
|
||||
|
||||
TEST_F(AmdExtToKhrTest, ReplaceFMid3AMD) {
|
||||
const std::string text = R"(
|
||||
; CHECK: OpCapability Shader
|
||||
; CHECK-NOT: OpExtension "SPV_AMD_shader_trinary_minmax"
|
||||
; CHECK-NOT: OpExtInstImport "SPV_AMD_shader_trinary_minmax"
|
||||
; CHECK: [[ext:%\w+]] = OpExtInstImport "GLSL.std.450"
|
||||
; CHECK: [[type:%\w+]] = OpTypeFloat 32
|
||||
; CHECK: OpFunction
|
||||
; CHECK-NEXT: OpLabel
|
||||
; CHECK-NEXT: [[x:%\w+]] = OpUndef [[type]]
|
||||
; CHECK-NEXT: [[y:%\w+]] = OpUndef [[type]]
|
||||
; CHECK-NEXT: [[z:%\w+]] = OpUndef [[type]]
|
||||
; CHECK-NEXT: [[min:%\w+]] = OpExtInst [[type]] [[ext]] FMin [[y]] [[z]]
|
||||
; CHECK-NEXT: [[max:%\w+]] = OpExtInst [[type]] [[ext]] FMax [[y]] [[z]]
|
||||
; CHECK-NEXT: [[result:%\w+]] = OpExtInst [[type]] [[ext]] FClamp [[x]] [[min]] [[max]]
|
||||
OpCapability Shader
|
||||
OpExtension "SPV_AMD_shader_trinary_minmax"
|
||||
%ext = OpExtInstImport "SPV_AMD_shader_trinary_minmax"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %1 "func"
|
||||
OpExecutionMode %1 OriginUpperLeft
|
||||
%void = OpTypeVoid
|
||||
%3 = OpTypeFunction %void
|
||||
%uint = OpTypeInt 32 0
|
||||
%float = OpTypeFloat 32
|
||||
%uint_3 = OpConstant %uint 3
|
||||
%1 = OpFunction %void None %3
|
||||
%6 = OpLabel
|
||||
%7 = OpUndef %float
|
||||
%8 = OpUndef %float
|
||||
%9 = OpUndef %float
|
||||
%10 = OpExtInst %float %ext FMid3AMD %7 %8 %9
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<AmdExtensionToKhrPass>(text, true);
|
||||
}
|
||||
|
||||
TEST_F(AmdExtToKhrTest, ReplaceSMid3AMD) {
|
||||
const std::string text = R"(
|
||||
; CHECK: OpCapability Shader
|
||||
; CHECK-NOT: OpExtension "SPV_AMD_shader_trinary_minmax"
|
||||
; CHECK-NOT: OpExtInstImport "SPV_AMD_shader_trinary_minmax"
|
||||
; CHECK: [[ext:%\w+]] = OpExtInstImport "GLSL.std.450"
|
||||
; CHECK: [[type:%\w+]] = OpTypeInt 32 1
|
||||
; CHECK: OpFunction
|
||||
; CHECK-NEXT: OpLabel
|
||||
; CHECK-NEXT: [[x:%\w+]] = OpUndef [[type]]
|
||||
; CHECK-NEXT: [[y:%\w+]] = OpUndef [[type]]
|
||||
; CHECK-NEXT: [[z:%\w+]] = OpUndef [[type]]
|
||||
; CHECK-NEXT: [[min:%\w+]] = OpExtInst [[type]] [[ext]] SMin [[y]] [[z]]
|
||||
; CHECK-NEXT: [[max:%\w+]] = OpExtInst [[type]] [[ext]] SMax [[y]] [[z]]
|
||||
; CHECK-NEXT: [[result:%\w+]] = OpExtInst [[type]] [[ext]] SClamp [[x]] [[min]] [[max]]
|
||||
OpCapability Shader
|
||||
OpExtension "SPV_AMD_shader_trinary_minmax"
|
||||
%ext = OpExtInstImport "SPV_AMD_shader_trinary_minmax"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %1 "func"
|
||||
OpExecutionMode %1 OriginUpperLeft
|
||||
%void = OpTypeVoid
|
||||
%3 = OpTypeFunction %void
|
||||
%uint = OpTypeInt 32 0
|
||||
%int = OpTypeInt 32 1
|
||||
%float = OpTypeFloat 32
|
||||
%uint_3 = OpConstant %uint 3
|
||||
%1 = OpFunction %void None %3
|
||||
%6 = OpLabel
|
||||
%7 = OpUndef %int
|
||||
%8 = OpUndef %int
|
||||
%9 = OpUndef %int
|
||||
%10 = OpExtInst %int %ext SMid3AMD %7 %8 %9
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<AmdExtensionToKhrPass>(text, true);
|
||||
}
|
||||
|
||||
TEST_F(AmdExtToKhrTest, ReplaceUMid3AMD) {
|
||||
const std::string text = R"(
|
||||
; CHECK: OpCapability Shader
|
||||
; CHECK-NOT: OpExtension "SPV_AMD_shader_trinary_minmax"
|
||||
; CHECK-NOT: OpExtInstImport "SPV_AMD_shader_trinary_minmax"
|
||||
; CHECK: [[ext:%\w+]] = OpExtInstImport "GLSL.std.450"
|
||||
; CHECK: [[type:%\w+]] = OpTypeInt 32 0
|
||||
; CHECK: OpFunction
|
||||
; CHECK-NEXT: OpLabel
|
||||
; CHECK-NEXT: [[x:%\w+]] = OpUndef [[type]]
|
||||
; CHECK-NEXT: [[y:%\w+]] = OpUndef [[type]]
|
||||
; CHECK-NEXT: [[z:%\w+]] = OpUndef [[type]]
|
||||
; CHECK-NEXT: [[min:%\w+]] = OpExtInst [[type]] [[ext]] UMin [[y]] [[z]]
|
||||
; CHECK-NEXT: [[max:%\w+]] = OpExtInst [[type]] [[ext]] UMax [[y]] [[z]]
|
||||
; CHECK-NEXT: [[result:%\w+]] = OpExtInst [[type]] [[ext]] UClamp [[x]] [[min]] [[max]]
|
||||
OpCapability Shader
|
||||
OpExtension "SPV_AMD_shader_trinary_minmax"
|
||||
%ext = OpExtInstImport "SPV_AMD_shader_trinary_minmax"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %1 "func"
|
||||
OpExecutionMode %1 OriginUpperLeft
|
||||
%void = OpTypeVoid
|
||||
%3 = OpTypeFunction %void
|
||||
%uint = OpTypeInt 32 0
|
||||
%int = OpTypeInt 32 1
|
||||
%float = OpTypeFloat 32
|
||||
%uint_3 = OpConstant %uint 3
|
||||
%1 = OpFunction %void None %3
|
||||
%6 = OpLabel
|
||||
%7 = OpUndef %uint
|
||||
%8 = OpUndef %uint
|
||||
%9 = OpUndef %uint
|
||||
%10 = OpExtInst %uint %ext UMid3AMD %7 %8 %9
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<AmdExtensionToKhrPass>(text, true);
|
||||
}
|
||||
|
||||
TEST_F(AmdExtToKhrTest, ReplaceVecUMid3AMD) {
|
||||
const std::string text = R"(
|
||||
; CHECK: OpCapability Shader
|
||||
; CHECK-NOT: OpExtension "SPV_AMD_shader_trinary_minmax"
|
||||
; CHECK-NOT: OpExtInstImport "SPV_AMD_shader_trinary_minmax"
|
||||
; CHECK: [[ext:%\w+]] = OpExtInstImport "GLSL.std.450"
|
||||
; CHECK: [[type:%\w+]] = OpTypeVector
|
||||
; CHECK: OpFunction
|
||||
; CHECK-NEXT: OpLabel
|
||||
; CHECK-NEXT: [[x:%\w+]] = OpUndef [[type]]
|
||||
; CHECK-NEXT: [[y:%\w+]] = OpUndef [[type]]
|
||||
; CHECK-NEXT: [[z:%\w+]] = OpUndef [[type]]
|
||||
; CHECK-NEXT: [[min:%\w+]] = OpExtInst [[type]] [[ext]] UMin [[y]] [[z]]
|
||||
; CHECK-NEXT: [[max:%\w+]] = OpExtInst [[type]] [[ext]] UMax [[y]] [[z]]
|
||||
; CHECK-NEXT: [[result:%\w+]] = OpExtInst [[type]] [[ext]] UClamp [[x]] [[min]] [[max]]
|
||||
OpCapability Shader
|
||||
OpExtension "SPV_AMD_shader_trinary_minmax"
|
||||
%ext = OpExtInstImport "SPV_AMD_shader_trinary_minmax"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %1 "func"
|
||||
OpExecutionMode %1 OriginUpperLeft
|
||||
%void = OpTypeVoid
|
||||
%3 = OpTypeFunction %void
|
||||
%uint = OpTypeInt 32 0
|
||||
%vec = OpTypeVector %uint 3
|
||||
%int = OpTypeInt 32 1
|
||||
%float = OpTypeFloat 32
|
||||
%uint_3 = OpConstant %uint 3
|
||||
%1 = OpFunction %void None %3
|
||||
%6 = OpLabel
|
||||
%7 = OpUndef %vec
|
||||
%8 = OpUndef %vec
|
||||
%9 = OpUndef %vec
|
||||
%10 = OpExtInst %vec %ext UMid3AMD %7 %8 %9
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<AmdExtensionToKhrPass>(text, true);
|
||||
}
|
||||
|
||||
TEST_F(AmdExtToKhrTest, ReplaceCubeFaceCoordAMD) {
|
||||
// Sorry for the Check test. The code sequence is so long, I do not think
|
||||
// that a match test would be anymore legible. This tests the replacement of
|
||||
// the CubeFaceCoordAMD instruction.
|
||||
const std::string before = R"(
|
||||
OpCapability Shader
|
||||
OpExtension "SPV_KHR_storage_buffer_storage_class"
|
||||
OpExtension "SPV_AMD_gcn_shader"
|
||||
%1 = OpExtInstImport "SPV_AMD_gcn_shader"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint GLCompute %2 "main"
|
||||
OpExecutionMode %2 LocalSize 1 1 1
|
||||
%void = OpTypeVoid
|
||||
%4 = OpTypeFunction %void
|
||||
%float = OpTypeFloat 32
|
||||
%v2float = OpTypeVector %float 2
|
||||
%v3float = OpTypeVector %float 3
|
||||
%2 = OpFunction %void None %4
|
||||
%8 = OpLabel
|
||||
%9 = OpUndef %v3float
|
||||
%10 = OpExtInst %v2float %1 CubeFaceCoordAMD %9
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const std::string after = R"(OpCapability Shader
|
||||
OpExtension "SPV_KHR_storage_buffer_storage_class"
|
||||
%12 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint GLCompute %2 "main"
|
||||
OpExecutionMode %2 LocalSize 1 1 1
|
||||
%void = OpTypeVoid
|
||||
%4 = OpTypeFunction %void
|
||||
%float = OpTypeFloat 32
|
||||
%v2float = OpTypeVector %float 2
|
||||
%v3float = OpTypeVector %float 3
|
||||
%bool = OpTypeBool
|
||||
%float_0 = OpConstant %float 0
|
||||
%float_2 = OpConstant %float 2
|
||||
%float_0_5 = OpConstant %float 0.5
|
||||
%16 = OpConstantComposite %v2float %float_0_5 %float_0_5
|
||||
%2 = OpFunction %void None %4
|
||||
%8 = OpLabel
|
||||
%9 = OpUndef %v3float
|
||||
%17 = OpCompositeExtract %float %9 0
|
||||
%18 = OpCompositeExtract %float %9 1
|
||||
%19 = OpCompositeExtract %float %9 2
|
||||
%20 = OpFNegate %float %17
|
||||
%21 = OpFNegate %float %18
|
||||
%22 = OpFNegate %float %19
|
||||
%23 = OpExtInst %float %12 FAbs %17
|
||||
%24 = OpExtInst %float %12 FAbs %18
|
||||
%25 = OpExtInst %float %12 FAbs %19
|
||||
%26 = OpFOrdLessThan %bool %19 %float_0
|
||||
%27 = OpFOrdLessThan %bool %18 %float_0
|
||||
%28 = OpFOrdLessThan %bool %17 %float_0
|
||||
%29 = OpExtInst %float %12 FMax %23 %24
|
||||
%30 = OpExtInst %float %12 FMax %25 %29
|
||||
%31 = OpFMul %float %float_2 %30
|
||||
%32 = OpFOrdGreaterThanEqual %bool %25 %29
|
||||
%33 = OpLogicalNot %bool %32
|
||||
%34 = OpFOrdGreaterThanEqual %bool %24 %23
|
||||
%35 = OpLogicalAnd %bool %33 %34
|
||||
%36 = OpSelect %float %26 %20 %17
|
||||
%37 = OpSelect %float %28 %19 %22
|
||||
%38 = OpSelect %float %35 %17 %37
|
||||
%39 = OpSelect %float %32 %36 %38
|
||||
%40 = OpSelect %float %27 %22 %19
|
||||
%41 = OpSelect %float %35 %40 %21
|
||||
%42 = OpCompositeConstruct %v2float %39 %41
|
||||
%43 = OpCompositeConstruct %v2float %31 %31
|
||||
%44 = OpFDiv %v2float %42 %43
|
||||
%10 = OpFAdd %v2float %44 %16
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndCheck<AmdExtensionToKhrPass>(before, after, true);
|
||||
}
|
||||
|
||||
TEST_F(AmdExtToKhrTest, ReplaceCubeFaceIndexAMD) {
|
||||
// Sorry for the Check test. The code sequence is so long, I do not think
|
||||
// that a match test would be anymore legible. This tests the replacement of
|
||||
// the CubeFaceIndexAMD instruction.
|
||||
const std::string before = R"(OpCapability Shader
|
||||
OpExtension "SPV_KHR_storage_buffer_storage_class"
|
||||
OpExtension "SPV_AMD_gcn_shader"
|
||||
%1 = OpExtInstImport "SPV_AMD_gcn_shader"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint GLCompute %2 "main"
|
||||
OpExecutionMode %2 LocalSize 1 1 1
|
||||
%void = OpTypeVoid
|
||||
%4 = OpTypeFunction %void
|
||||
%float = OpTypeFloat 32
|
||||
%v3float = OpTypeVector %float 3
|
||||
%2 = OpFunction %void None %4
|
||||
%7 = OpLabel
|
||||
%8 = OpUndef %v3float
|
||||
%9 = OpExtInst %float %1 CubeFaceIndexAMD %8
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const std::string after = R"(OpCapability Shader
|
||||
OpExtension "SPV_KHR_storage_buffer_storage_class"
|
||||
%11 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint GLCompute %2 "main"
|
||||
OpExecutionMode %2 LocalSize 1 1 1
|
||||
%void = OpTypeVoid
|
||||
%4 = OpTypeFunction %void
|
||||
%float = OpTypeFloat 32
|
||||
%v3float = OpTypeVector %float 3
|
||||
%bool = OpTypeBool
|
||||
%float_0 = OpConstant %float 0
|
||||
%float_1 = OpConstant %float 1
|
||||
%float_2 = OpConstant %float 2
|
||||
%float_3 = OpConstant %float 3
|
||||
%float_4 = OpConstant %float 4
|
||||
%float_5 = OpConstant %float 5
|
||||
%2 = OpFunction %void None %4
|
||||
%7 = OpLabel
|
||||
%8 = OpUndef %v3float
|
||||
%18 = OpCompositeExtract %float %8 0
|
||||
%19 = OpCompositeExtract %float %8 1
|
||||
%20 = OpCompositeExtract %float %8 2
|
||||
%21 = OpExtInst %float %11 FAbs %18
|
||||
%22 = OpExtInst %float %11 FAbs %19
|
||||
%23 = OpExtInst %float %11 FAbs %20
|
||||
%24 = OpFOrdLessThan %bool %20 %float_0
|
||||
%25 = OpFOrdLessThan %bool %19 %float_0
|
||||
%26 = OpFOrdLessThan %bool %18 %float_0
|
||||
%27 = OpExtInst %float %11 FMax %21 %22
|
||||
%28 = OpFOrdGreaterThanEqual %bool %23 %27
|
||||
%29 = OpFOrdGreaterThanEqual %bool %22 %21
|
||||
%30 = OpSelect %float %24 %float_5 %float_4
|
||||
%31 = OpSelect %float %25 %float_3 %float_2
|
||||
%32 = OpSelect %float %26 %float_1 %float_0
|
||||
%33 = OpSelect %float %29 %31 %32
|
||||
%9 = OpSelect %float %28 %30 %33
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndCheck<AmdExtensionToKhrPass>(before, after, true);
|
||||
}
|
||||
|
||||
TEST_F(AmdExtToKhrTest, SetVersion) {
|
||||
const std::string text = R"(
|
||||
OpCapability Shader
|
||||
OpCapability Int64
|
||||
OpExtension "SPV_AMD_shader_ballot"
|
||||
%1 = OpExtInstImport "SPV_AMD_shader_ballot"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %2 "func"
|
||||
OpExecutionMode %2 OriginUpperLeft
|
||||
%void = OpTypeVoid
|
||||
%4 = OpTypeFunction %void
|
||||
%uint = OpTypeInt 32 0
|
||||
%ulong = OpTypeInt 64 0
|
||||
%ulong_0 = OpConstant %ulong 0
|
||||
%2 = OpFunction %void None %4
|
||||
%8 = OpLabel
|
||||
%9 = OpExtInst %uint %1 MbcntAMD %ulong_0
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
// Set the version to 1.1 and make sure it is upgraded to 1.3.
|
||||
SetTargetEnv(SPV_ENV_UNIVERSAL_1_1);
|
||||
SetDisassembleOptions(0);
|
||||
auto result = SinglePassRunAndDisassemble<AmdExtensionToKhrPass>(
|
||||
text, /* skip_nop = */ true, /* skip_validation = */ false);
|
||||
|
||||
EXPECT_EQ(Pass::Status::SuccessWithChange, std::get<1>(result));
|
||||
const std::string& output = std::get<0>(result);
|
||||
EXPECT_THAT(output, HasSubstr("Version: 1.3"));
|
||||
}
|
||||
|
||||
TEST_F(AmdExtToKhrTest, SetVersion1) {
|
||||
const std::string text = R"(
|
||||
OpCapability Shader
|
||||
OpCapability Int64
|
||||
OpExtension "SPV_AMD_shader_ballot"
|
||||
%1 = OpExtInstImport "SPV_AMD_shader_ballot"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %2 "func"
|
||||
OpExecutionMode %2 OriginUpperLeft
|
||||
%void = OpTypeVoid
|
||||
%4 = OpTypeFunction %void
|
||||
%uint = OpTypeInt 32 0
|
||||
%ulong = OpTypeInt 64 0
|
||||
%ulong_0 = OpConstant %ulong 0
|
||||
%2 = OpFunction %void None %4
|
||||
%8 = OpLabel
|
||||
%9 = OpExtInst %uint %1 MbcntAMD %ulong_0
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
// Set the version to 1.4 and make sure it is stays the same.
|
||||
SetTargetEnv(SPV_ENV_UNIVERSAL_1_4);
|
||||
SetDisassembleOptions(0);
|
||||
auto result = SinglePassRunAndDisassemble<AmdExtensionToKhrPass>(
|
||||
text, /* skip_nop = */ true, /* skip_validation = */ false);
|
||||
|
||||
EXPECT_EQ(Pass::Status::SuccessWithChange, std::get<1>(result));
|
||||
const std::string& output = std::get<0>(result);
|
||||
EXPECT_THAT(output, HasSubstr("Version: 1.4"));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace opt
|
||||
} // namespace spvtools
|
||||
266
3rdparty/spirv-tools/test/opt/assembly_builder.h
vendored
266
3rdparty/spirv-tools/test/opt/assembly_builder.h
vendored
@@ -1,266 +0,0 @@
|
||||
// Copyright (c) 2016 Google Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef TEST_OPT_ASSEMBLY_BUILDER_H_
|
||||
#define TEST_OPT_ASSEMBLY_BUILDER_H_
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
namespace spvtools {
|
||||
namespace opt {
|
||||
|
||||
// A simple SPIR-V assembly code builder for test uses. It builds an SPIR-V
|
||||
// assembly module from vectors of assembly strings. It allows users to add
|
||||
// instructions to the main function and the type-constants-globals section
|
||||
// directly. It relies on OpName instructions and friendly-name disassembling
|
||||
// to keep the ID names unchanged after assembling.
|
||||
//
|
||||
// An assembly module is divided into several sections, matching with the
|
||||
// SPIR-V Logical Layout:
|
||||
// Global Preamble:
|
||||
// OpCapability instructions;
|
||||
// OpExtension instructions and OpExtInstImport instructions;
|
||||
// OpMemoryModel instruction;
|
||||
// OpEntryPoint and OpExecutionMode instruction;
|
||||
// OpString, OpSourceExtension, OpSource and OpSourceContinued instructions.
|
||||
// Names:
|
||||
// OpName instructions.
|
||||
// Annotations:
|
||||
// OpDecorate, OpMemberDecorate, OpGroupDecorate, OpGroupMemberDecorate and
|
||||
// OpDecorationGroup.
|
||||
// Types, Constants and Global variables:
|
||||
// Types, constants and global variables declaration instructions.
|
||||
// Main Function:
|
||||
// Main function instructions.
|
||||
// Main Function Postamble:
|
||||
// The return and function end instructions.
|
||||
//
|
||||
// The assembly code is built by concatenating all the strings in the above
|
||||
// sections.
|
||||
//
|
||||
// Users define the contents in section <Type, Constants and Global Variables>
|
||||
// and <Main Function>. The <Names> section is to hold the names for IDs to
|
||||
// keep them unchanged before and after assembling. All defined IDs to be added
|
||||
// to this code builder will be assigned with a global name through OpName
|
||||
// instruction. The name is extracted from the definition instruction.
|
||||
// E.g. adding instruction: %var_a = OpConstant %int 2, will also add an
|
||||
// instruction: OpName %var_a, "var_a".
|
||||
//
|
||||
// Note that the name must not be used on more than one defined IDs and
|
||||
// friendly-name disassembling must be enabled so that OpName instructions will
|
||||
// be respected.
|
||||
class AssemblyBuilder {
|
||||
// The base ID value for spec constants.
|
||||
static const uint32_t SPEC_ID_BASE = 200;
|
||||
|
||||
public:
|
||||
// Initalize a minimal SPIR-V assembly code as the template. The minimal
|
||||
// module contains an empty main function and some predefined names for the
|
||||
// main function.
|
||||
AssemblyBuilder()
|
||||
: spec_id_counter_(SPEC_ID_BASE),
|
||||
global_preamble_({
|
||||
// clang-format off
|
||||
"OpCapability Shader",
|
||||
"OpCapability Float64",
|
||||
"%1 = OpExtInstImport \"GLSL.std.450\"",
|
||||
"OpMemoryModel Logical GLSL450",
|
||||
"OpEntryPoint Vertex %main \"main\"",
|
||||
// clang-format on
|
||||
}),
|
||||
names_(),
|
||||
annotations_(),
|
||||
types_consts_globals_(),
|
||||
main_func_(),
|
||||
main_func_postamble_({
|
||||
"OpReturn",
|
||||
"OpFunctionEnd",
|
||||
}) {
|
||||
AppendTypesConstantsGlobals({
|
||||
"%void = OpTypeVoid",
|
||||
"%main_func_type = OpTypeFunction %void",
|
||||
});
|
||||
AppendInMain({
|
||||
"%main = OpFunction %void None %main_func_type",
|
||||
"%main_func_entry_block = OpLabel",
|
||||
});
|
||||
}
|
||||
|
||||
// Appends OpName instructions to this builder. Instrcution strings that do
|
||||
// not start with 'OpName ' will be skipped. Returns the references of this
|
||||
// assembly builder.
|
||||
AssemblyBuilder& AppendNames(const std::vector<std::string>& vec_asm_code) {
|
||||
for (auto& inst_str : vec_asm_code) {
|
||||
if (inst_str.find("OpName ") == 0) {
|
||||
names_.push_back(inst_str);
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Appends instructions to the types-constants-globals section and returns
|
||||
// the reference of this assembly builder. IDs defined in the given code will
|
||||
// be added to the Names section and then be registered with OpName
|
||||
// instruction. Corresponding decoration instruction will be added for spec
|
||||
// constants defined with opcode: 'OpSpecConstant'.
|
||||
AssemblyBuilder& AppendTypesConstantsGlobals(
|
||||
const std::vector<std::string>& vec_asm_code) {
|
||||
AddNamesForResultIDsIn(vec_asm_code);
|
||||
// Check spec constants defined with OpSpecConstant.
|
||||
for (auto& inst_str : vec_asm_code) {
|
||||
if (inst_str.find("= OpSpecConstant ") != std::string::npos ||
|
||||
inst_str.find("= OpSpecConstantTrue ") != std::string::npos ||
|
||||
inst_str.find("= OpSpecConstantFalse ") != std::string::npos) {
|
||||
AddSpecIDFor(GetResultIDName(inst_str));
|
||||
}
|
||||
}
|
||||
types_consts_globals_.insert(types_consts_globals_.end(),
|
||||
vec_asm_code.begin(), vec_asm_code.end());
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Appends instructions to the main function block, which is already labelled
|
||||
// with "main_func_entry_block". Returns the reference of this assembly
|
||||
// builder. IDs defined in the given code will be added to the Names section
|
||||
// and then be registered with OpName instruction.
|
||||
AssemblyBuilder& AppendInMain(const std::vector<std::string>& vec_asm_code) {
|
||||
AddNamesForResultIDsIn(vec_asm_code);
|
||||
main_func_.insert(main_func_.end(), vec_asm_code.begin(),
|
||||
vec_asm_code.end());
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Appends annotation instructions to the annotation section, and returns the
|
||||
// reference of this assembly builder.
|
||||
AssemblyBuilder& AppendAnnotations(
|
||||
const std::vector<std::string>& vec_annotations) {
|
||||
annotations_.insert(annotations_.end(), vec_annotations.begin(),
|
||||
vec_annotations.end());
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Pre-pends string to the preamble of the module. Useful for EFFCEE checks.
|
||||
AssemblyBuilder& PrependPreamble(const std::vector<std::string>& preamble) {
|
||||
preamble_.insert(preamble_.end(), preamble.begin(), preamble.end());
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Get the SPIR-V assembly code as string.
|
||||
std::string GetCode() const {
|
||||
std::ostringstream ss;
|
||||
for (const auto& line : preamble_) {
|
||||
ss << line << std::endl;
|
||||
}
|
||||
for (const auto& line : global_preamble_) {
|
||||
ss << line << std::endl;
|
||||
}
|
||||
for (const auto& line : names_) {
|
||||
ss << line << std::endl;
|
||||
}
|
||||
for (const auto& line : annotations_) {
|
||||
ss << line << std::endl;
|
||||
}
|
||||
for (const auto& line : types_consts_globals_) {
|
||||
ss << line << std::endl;
|
||||
}
|
||||
for (const auto& line : main_func_) {
|
||||
ss << line << std::endl;
|
||||
}
|
||||
for (const auto& line : main_func_postamble_) {
|
||||
ss << line << std::endl;
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
private:
|
||||
// Adds a given name to the Name section with OpName. If the given name has
|
||||
// been added before, does nothing.
|
||||
void AddOpNameIfNotExist(const std::string& id_name) {
|
||||
if (!used_names_.count(id_name)) {
|
||||
std::stringstream opname_inst;
|
||||
opname_inst << "OpName "
|
||||
<< "%" << id_name << " \"" << id_name << "\"";
|
||||
names_.emplace_back(opname_inst.str());
|
||||
used_names_.insert(id_name);
|
||||
}
|
||||
}
|
||||
|
||||
// Adds the names in a vector of assembly code strings to the Names section.
|
||||
// If a '=' sign is found in an instruction, this instruction will be treated
|
||||
// as an ID defining instruction. The ID name used in the instruction will be
|
||||
// extracted and added to the Names section.
|
||||
void AddNamesForResultIDsIn(const std::vector<std::string>& vec_asm_code) {
|
||||
for (const auto& line : vec_asm_code) {
|
||||
std::string name = GetResultIDName(line);
|
||||
if (!name.empty()) {
|
||||
AddOpNameIfNotExist(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Adds an OpDecorate SpecId instruction for the given ID name.
|
||||
void AddSpecIDFor(const std::string& id_name) {
|
||||
std::stringstream decorate_inst;
|
||||
decorate_inst << "OpDecorate "
|
||||
<< "%" << id_name << " SpecId " << spec_id_counter_;
|
||||
spec_id_counter_ += 1;
|
||||
annotations_.emplace_back(decorate_inst.str());
|
||||
}
|
||||
|
||||
// Extracts the ID name from a SPIR-V assembly instruction string. If the
|
||||
// instruction is an ID-defining instruction (has result ID), returns the
|
||||
// name of the result ID in string. If the instruction does not have result
|
||||
// ID, returns an empty string.
|
||||
std::string GetResultIDName(const std::string inst_str) {
|
||||
std::string name;
|
||||
if (inst_str.find('=') != std::string::npos) {
|
||||
size_t assign_sign = inst_str.find('=');
|
||||
name = inst_str.substr(0, assign_sign);
|
||||
name.erase(remove_if(name.begin(), name.end(),
|
||||
[](char c) { return c == ' ' || c == '%'; }),
|
||||
name.end());
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
uint32_t spec_id_counter_;
|
||||
// User-defined preamble.
|
||||
std::vector<std::string> preamble_;
|
||||
// The vector that contains common preambles shared across all test SPIR-V
|
||||
// code.
|
||||
std::vector<std::string> global_preamble_;
|
||||
// The vector that contains OpName instructions.
|
||||
std::vector<std::string> names_;
|
||||
// The vector that contains annotation instructions.
|
||||
std::vector<std::string> annotations_;
|
||||
// The vector that contains the code to declare types, constants and global
|
||||
// variables (aka. the Types-Constants-Globals section).
|
||||
std::vector<std::string> types_consts_globals_;
|
||||
// The vector that contains the code in main function's entry block.
|
||||
std::vector<std::string> main_func_;
|
||||
// The vector that contains the postamble of main function body.
|
||||
std::vector<std::string> main_func_postamble_;
|
||||
// All of the defined variable names.
|
||||
std::unordered_set<std::string> used_names_;
|
||||
};
|
||||
|
||||
} // namespace opt
|
||||
} // namespace spvtools
|
||||
|
||||
#endif // TEST_OPT_ASSEMBLY_BUILDER_H_
|
||||
@@ -1,283 +0,0 @@
|
||||
// Copyright (c) 2016 Google Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "test/opt/assembly_builder.h"
|
||||
|
||||
#include "test/opt/pass_fixture.h"
|
||||
#include "test/opt/pass_utils.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace opt {
|
||||
namespace {
|
||||
|
||||
using AssemblyBuilderTest = PassTest<::testing::Test>;
|
||||
|
||||
TEST_F(AssemblyBuilderTest, MinimalShader) {
|
||||
AssemblyBuilder builder;
|
||||
std::vector<const char*> expected = {
|
||||
// clang-format off
|
||||
"OpCapability Shader",
|
||||
"OpCapability Float64",
|
||||
"%1 = OpExtInstImport \"GLSL.std.450\"",
|
||||
"OpMemoryModel Logical GLSL450",
|
||||
"OpEntryPoint Vertex %main \"main\"",
|
||||
"OpName %void \"void\"",
|
||||
"OpName %main_func_type \"main_func_type\"",
|
||||
"OpName %main \"main\"",
|
||||
"OpName %main_func_entry_block \"main_func_entry_block\"",
|
||||
"%void = OpTypeVoid",
|
||||
"%main_func_type = OpTypeFunction %void",
|
||||
"%main = OpFunction %void None %main_func_type",
|
||||
"%main_func_entry_block = OpLabel",
|
||||
"OpReturn",
|
||||
"OpFunctionEnd",
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
SinglePassRunAndCheck<NullPass>(builder.GetCode(), JoinAllInsts(expected),
|
||||
/* skip_nop = */ false);
|
||||
}
|
||||
|
||||
TEST_F(AssemblyBuilderTest, ShaderWithConstants) {
|
||||
AssemblyBuilder builder;
|
||||
builder
|
||||
.AppendTypesConstantsGlobals({
|
||||
// clang-format off
|
||||
"%bool = OpTypeBool",
|
||||
"%_PF_bool = OpTypePointer Function %bool",
|
||||
"%bt = OpConstantTrue %bool",
|
||||
"%bf = OpConstantFalse %bool",
|
||||
"%int = OpTypeInt 32 1",
|
||||
"%_PF_int = OpTypePointer Function %int",
|
||||
"%si = OpConstant %int 1",
|
||||
"%uint = OpTypeInt 32 0",
|
||||
"%_PF_uint = OpTypePointer Function %uint",
|
||||
"%ui = OpConstant %uint 2",
|
||||
"%float = OpTypeFloat 32",
|
||||
"%_PF_float = OpTypePointer Function %float",
|
||||
"%f = OpConstant %float 3.1415",
|
||||
"%double = OpTypeFloat 64",
|
||||
"%_PF_double = OpTypePointer Function %double",
|
||||
"%d = OpConstant %double 3.14159265358979",
|
||||
// clang-format on
|
||||
})
|
||||
.AppendInMain({
|
||||
// clang-format off
|
||||
"%btv = OpVariable %_PF_bool Function",
|
||||
"%bfv = OpVariable %_PF_bool Function",
|
||||
"%iv = OpVariable %_PF_int Function",
|
||||
"%uv = OpVariable %_PF_uint Function",
|
||||
"%fv = OpVariable %_PF_float Function",
|
||||
"%dv = OpVariable %_PF_double Function",
|
||||
"OpStore %btv %bt",
|
||||
"OpStore %bfv %bf",
|
||||
"OpStore %iv %si",
|
||||
"OpStore %uv %ui",
|
||||
"OpStore %fv %f",
|
||||
"OpStore %dv %d",
|
||||
// clang-format on
|
||||
});
|
||||
|
||||
std::vector<const char*> expected = {
|
||||
// clang-format off
|
||||
"OpCapability Shader",
|
||||
"OpCapability Float64",
|
||||
"%1 = OpExtInstImport \"GLSL.std.450\"",
|
||||
"OpMemoryModel Logical GLSL450",
|
||||
"OpEntryPoint Vertex %main \"main\"",
|
||||
"OpName %void \"void\"",
|
||||
"OpName %main_func_type \"main_func_type\"",
|
||||
"OpName %main \"main\"",
|
||||
"OpName %main_func_entry_block \"main_func_entry_block\"",
|
||||
"OpName %bool \"bool\"",
|
||||
"OpName %_PF_bool \"_PF_bool\"",
|
||||
"OpName %bt \"bt\"",
|
||||
"OpName %bf \"bf\"",
|
||||
"OpName %int \"int\"",
|
||||
"OpName %_PF_int \"_PF_int\"",
|
||||
"OpName %si \"si\"",
|
||||
"OpName %uint \"uint\"",
|
||||
"OpName %_PF_uint \"_PF_uint\"",
|
||||
"OpName %ui \"ui\"",
|
||||
"OpName %float \"float\"",
|
||||
"OpName %_PF_float \"_PF_float\"",
|
||||
"OpName %f \"f\"",
|
||||
"OpName %double \"double\"",
|
||||
"OpName %_PF_double \"_PF_double\"",
|
||||
"OpName %d \"d\"",
|
||||
"OpName %btv \"btv\"",
|
||||
"OpName %bfv \"bfv\"",
|
||||
"OpName %iv \"iv\"",
|
||||
"OpName %uv \"uv\"",
|
||||
"OpName %fv \"fv\"",
|
||||
"OpName %dv \"dv\"",
|
||||
"%void = OpTypeVoid",
|
||||
"%main_func_type = OpTypeFunction %void",
|
||||
"%bool = OpTypeBool",
|
||||
"%_PF_bool = OpTypePointer Function %bool",
|
||||
"%bt = OpConstantTrue %bool",
|
||||
"%bf = OpConstantFalse %bool",
|
||||
"%int = OpTypeInt 32 1",
|
||||
"%_PF_int = OpTypePointer Function %int",
|
||||
"%si = OpConstant %int 1",
|
||||
"%uint = OpTypeInt 32 0",
|
||||
"%_PF_uint = OpTypePointer Function %uint",
|
||||
"%ui = OpConstant %uint 2",
|
||||
"%float = OpTypeFloat 32",
|
||||
"%_PF_float = OpTypePointer Function %float",
|
||||
"%f = OpConstant %float 3.1415",
|
||||
"%double = OpTypeFloat 64",
|
||||
"%_PF_double = OpTypePointer Function %double",
|
||||
"%d = OpConstant %double 3.14159265358979",
|
||||
"%main = OpFunction %void None %main_func_type",
|
||||
"%main_func_entry_block = OpLabel",
|
||||
"%btv = OpVariable %_PF_bool Function",
|
||||
"%bfv = OpVariable %_PF_bool Function",
|
||||
"%iv = OpVariable %_PF_int Function",
|
||||
"%uv = OpVariable %_PF_uint Function",
|
||||
"%fv = OpVariable %_PF_float Function",
|
||||
"%dv = OpVariable %_PF_double Function",
|
||||
"OpStore %btv %bt",
|
||||
"OpStore %bfv %bf",
|
||||
"OpStore %iv %si",
|
||||
"OpStore %uv %ui",
|
||||
"OpStore %fv %f",
|
||||
"OpStore %dv %d",
|
||||
"OpReturn",
|
||||
"OpFunctionEnd",
|
||||
// clang-format on
|
||||
};
|
||||
SinglePassRunAndCheck<NullPass>(builder.GetCode(), JoinAllInsts(expected),
|
||||
/* skip_nop = */ false);
|
||||
}
|
||||
|
||||
TEST_F(AssemblyBuilderTest, SpecConstants) {
|
||||
AssemblyBuilder builder;
|
||||
builder.AppendTypesConstantsGlobals({
|
||||
"%bool = OpTypeBool",
|
||||
"%uint = OpTypeInt 32 0",
|
||||
"%int = OpTypeInt 32 1",
|
||||
"%float = OpTypeFloat 32",
|
||||
"%double = OpTypeFloat 64",
|
||||
"%v2int = OpTypeVector %int 2",
|
||||
|
||||
"%spec_true = OpSpecConstantTrue %bool",
|
||||
"%spec_false = OpSpecConstantFalse %bool",
|
||||
"%spec_uint = OpSpecConstant %uint 1",
|
||||
"%spec_int = OpSpecConstant %int 1",
|
||||
"%spec_float = OpSpecConstant %float 1.25",
|
||||
"%spec_double = OpSpecConstant %double 1.2345678",
|
||||
|
||||
// Spec constants defined below should not have SpecID.
|
||||
"%spec_add_op = OpSpecConstantOp %int IAdd %spec_int %spec_int",
|
||||
"%spec_vec = OpSpecConstantComposite %v2int %spec_int %spec_int",
|
||||
"%spec_vec_x = OpSpecConstantOp %int CompositeExtract %spec_vec 0",
|
||||
});
|
||||
std::vector<const char*> expected = {
|
||||
// clang-format off
|
||||
"OpCapability Shader",
|
||||
"OpCapability Float64",
|
||||
"%1 = OpExtInstImport \"GLSL.std.450\"",
|
||||
"OpMemoryModel Logical GLSL450",
|
||||
"OpEntryPoint Vertex %main \"main\"",
|
||||
"OpName %void \"void\"",
|
||||
"OpName %main_func_type \"main_func_type\"",
|
||||
"OpName %main \"main\"",
|
||||
"OpName %main_func_entry_block \"main_func_entry_block\"",
|
||||
"OpName %bool \"bool\"",
|
||||
"OpName %uint \"uint\"",
|
||||
"OpName %int \"int\"",
|
||||
"OpName %float \"float\"",
|
||||
"OpName %double \"double\"",
|
||||
"OpName %v2int \"v2int\"",
|
||||
"OpName %spec_true \"spec_true\"",
|
||||
"OpName %spec_false \"spec_false\"",
|
||||
"OpName %spec_uint \"spec_uint\"",
|
||||
"OpName %spec_int \"spec_int\"",
|
||||
"OpName %spec_float \"spec_float\"",
|
||||
"OpName %spec_double \"spec_double\"",
|
||||
"OpName %spec_add_op \"spec_add_op\"",
|
||||
"OpName %spec_vec \"spec_vec\"",
|
||||
"OpName %spec_vec_x \"spec_vec_x\"",
|
||||
"OpDecorate %spec_true SpecId 200",
|
||||
"OpDecorate %spec_false SpecId 201",
|
||||
"OpDecorate %spec_uint SpecId 202",
|
||||
"OpDecorate %spec_int SpecId 203",
|
||||
"OpDecorate %spec_float SpecId 204",
|
||||
"OpDecorate %spec_double SpecId 205",
|
||||
"%void = OpTypeVoid",
|
||||
"%main_func_type = OpTypeFunction %void",
|
||||
"%bool = OpTypeBool",
|
||||
"%uint = OpTypeInt 32 0",
|
||||
"%int = OpTypeInt 32 1",
|
||||
"%float = OpTypeFloat 32",
|
||||
"%double = OpTypeFloat 64",
|
||||
"%v2int = OpTypeVector %int 2",
|
||||
"%spec_true = OpSpecConstantTrue %bool",
|
||||
"%spec_false = OpSpecConstantFalse %bool",
|
||||
"%spec_uint = OpSpecConstant %uint 1",
|
||||
"%spec_int = OpSpecConstant %int 1",
|
||||
"%spec_float = OpSpecConstant %float 1.25",
|
||||
"%spec_double = OpSpecConstant %double 1.2345678",
|
||||
"%spec_add_op = OpSpecConstantOp %int IAdd %spec_int %spec_int",
|
||||
"%spec_vec = OpSpecConstantComposite %v2int %spec_int %spec_int",
|
||||
"%spec_vec_x = OpSpecConstantOp %int CompositeExtract %spec_vec 0",
|
||||
"%main = OpFunction %void None %main_func_type",
|
||||
"%main_func_entry_block = OpLabel",
|
||||
"OpReturn",
|
||||
"OpFunctionEnd",
|
||||
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
SinglePassRunAndCheck<NullPass>(builder.GetCode(), JoinAllInsts(expected),
|
||||
/* skip_nop = */ false);
|
||||
}
|
||||
|
||||
TEST_F(AssemblyBuilderTest, AppendNames) {
|
||||
AssemblyBuilder builder;
|
||||
builder.AppendNames({
|
||||
"OpName %void \"another_name_for_void\"",
|
||||
"I am an invalid OpName instruction and should not be added",
|
||||
"OpName %main \"another name for main\"",
|
||||
});
|
||||
std::vector<const char*> expected = {
|
||||
// clang-format off
|
||||
"OpCapability Shader",
|
||||
"OpCapability Float64",
|
||||
"%1 = OpExtInstImport \"GLSL.std.450\"",
|
||||
"OpMemoryModel Logical GLSL450",
|
||||
"OpEntryPoint Vertex %main \"main\"",
|
||||
"OpName %void \"void\"",
|
||||
"OpName %main_func_type \"main_func_type\"",
|
||||
"OpName %main \"main\"",
|
||||
"OpName %main_func_entry_block \"main_func_entry_block\"",
|
||||
"OpName %void \"another_name_for_void\"",
|
||||
"OpName %main \"another name for main\"",
|
||||
"%void = OpTypeVoid",
|
||||
"%main_func_type = OpTypeFunction %void",
|
||||
"%main = OpFunction %void None %main_func_type",
|
||||
"%main_func_entry_block = OpLabel",
|
||||
"OpReturn",
|
||||
"OpFunctionEnd",
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
SinglePassRunAndCheck<NullPass>(builder.GetCode(), JoinAllInsts(expected),
|
||||
/* skip_nop = */ false);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace opt
|
||||
} // namespace spvtools
|
||||
976
3rdparty/spirv-tools/test/opt/block_merge_test.cpp
vendored
976
3rdparty/spirv-tools/test/opt/block_merge_test.cpp
vendored
@@ -1,976 +0,0 @@
|
||||
// Copyright (c) 2017 Valve Corporation
|
||||
// Copyright (c) 2017 LunarG Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "test/opt/pass_fixture.h"
|
||||
#include "test/opt/pass_utils.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace opt {
|
||||
namespace {
|
||||
|
||||
using BlockMergeTest = PassTest<::testing::Test>;
|
||||
|
||||
TEST_F(BlockMergeTest, Simple) {
|
||||
// Note: SPIR-V hand edited to insert block boundary
|
||||
// between two statements in main.
|
||||
//
|
||||
// #version 140
|
||||
//
|
||||
// in vec4 BaseColor;
|
||||
//
|
||||
// void main()
|
||||
// {
|
||||
// vec4 v = BaseColor;
|
||||
// gl_FragColor = v;
|
||||
// }
|
||||
|
||||
const std::string predefs =
|
||||
R"(OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %main "main" %BaseColor %gl_FragColor
|
||||
OpExecutionMode %main OriginUpperLeft
|
||||
OpSource GLSL 140
|
||||
OpName %main "main"
|
||||
OpName %v "v"
|
||||
OpName %BaseColor "BaseColor"
|
||||
OpName %gl_FragColor "gl_FragColor"
|
||||
%void = OpTypeVoid
|
||||
%7 = OpTypeFunction %void
|
||||
%float = OpTypeFloat 32
|
||||
%v4float = OpTypeVector %float 4
|
||||
%_ptr_Function_v4float = OpTypePointer Function %v4float
|
||||
%_ptr_Input_v4float = OpTypePointer Input %v4float
|
||||
%BaseColor = OpVariable %_ptr_Input_v4float Input
|
||||
%_ptr_Output_v4float = OpTypePointer Output %v4float
|
||||
%gl_FragColor = OpVariable %_ptr_Output_v4float Output
|
||||
)";
|
||||
|
||||
const std::string before =
|
||||
R"(%main = OpFunction %void None %7
|
||||
%13 = OpLabel
|
||||
%v = OpVariable %_ptr_Function_v4float Function
|
||||
%14 = OpLoad %v4float %BaseColor
|
||||
OpStore %v %14
|
||||
OpBranch %15
|
||||
%15 = OpLabel
|
||||
%16 = OpLoad %v4float %v
|
||||
OpStore %gl_FragColor %16
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const std::string after =
|
||||
R"(%main = OpFunction %void None %7
|
||||
%13 = OpLabel
|
||||
%v = OpVariable %_ptr_Function_v4float Function
|
||||
%14 = OpLoad %v4float %BaseColor
|
||||
OpStore %v %14
|
||||
%16 = OpLoad %v4float %v
|
||||
OpStore %gl_FragColor %16
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndCheck<BlockMergePass>(predefs + before, predefs + after, true,
|
||||
true);
|
||||
}
|
||||
|
||||
TEST_F(BlockMergeTest, EmptyBlock) {
|
||||
// Note: SPIR-V hand edited to insert empty block
|
||||
// after two statements in main.
|
||||
//
|
||||
// #version 140
|
||||
//
|
||||
// in vec4 BaseColor;
|
||||
//
|
||||
// void main()
|
||||
// {
|
||||
// vec4 v = BaseColor;
|
||||
// gl_FragColor = v;
|
||||
// }
|
||||
|
||||
const std::string predefs =
|
||||
R"(OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %main "main" %BaseColor %gl_FragColor
|
||||
OpExecutionMode %main OriginUpperLeft
|
||||
OpSource GLSL 140
|
||||
OpName %main "main"
|
||||
OpName %v "v"
|
||||
OpName %BaseColor "BaseColor"
|
||||
OpName %gl_FragColor "gl_FragColor"
|
||||
%void = OpTypeVoid
|
||||
%7 = OpTypeFunction %void
|
||||
%float = OpTypeFloat 32
|
||||
%v4float = OpTypeVector %float 4
|
||||
%_ptr_Function_v4float = OpTypePointer Function %v4float
|
||||
%_ptr_Input_v4float = OpTypePointer Input %v4float
|
||||
%BaseColor = OpVariable %_ptr_Input_v4float Input
|
||||
%_ptr_Output_v4float = OpTypePointer Output %v4float
|
||||
%gl_FragColor = OpVariable %_ptr_Output_v4float Output
|
||||
)";
|
||||
|
||||
const std::string before =
|
||||
R"(%main = OpFunction %void None %7
|
||||
%13 = OpLabel
|
||||
%v = OpVariable %_ptr_Function_v4float Function
|
||||
%14 = OpLoad %v4float %BaseColor
|
||||
OpStore %v %14
|
||||
OpBranch %15
|
||||
%15 = OpLabel
|
||||
%16 = OpLoad %v4float %v
|
||||
OpStore %gl_FragColor %16
|
||||
OpBranch %17
|
||||
%17 = OpLabel
|
||||
OpBranch %18
|
||||
%18 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const std::string after =
|
||||
R"(%main = OpFunction %void None %7
|
||||
%13 = OpLabel
|
||||
%v = OpVariable %_ptr_Function_v4float Function
|
||||
%14 = OpLoad %v4float %BaseColor
|
||||
OpStore %v %14
|
||||
%16 = OpLoad %v4float %v
|
||||
OpStore %gl_FragColor %16
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndCheck<BlockMergePass>(predefs + before, predefs + after, true,
|
||||
true);
|
||||
}
|
||||
|
||||
TEST_F(BlockMergeTest, NestedInControlFlow) {
|
||||
// Note: SPIR-V hand edited to insert block boundary
|
||||
// between OpFMul and OpStore in then-part.
|
||||
//
|
||||
// #version 140
|
||||
// in vec4 BaseColor;
|
||||
//
|
||||
// layout(std140) uniform U_t
|
||||
// {
|
||||
// bool g_B ;
|
||||
// } ;
|
||||
//
|
||||
// void main()
|
||||
// {
|
||||
// vec4 v = BaseColor;
|
||||
// if (g_B)
|
||||
// vec4 v = v * 0.25;
|
||||
// gl_FragColor = v;
|
||||
// }
|
||||
|
||||
const std::string predefs =
|
||||
R"(OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %main "main" %BaseColor %gl_FragColor
|
||||
OpExecutionMode %main OriginUpperLeft
|
||||
OpSource GLSL 140
|
||||
OpName %main "main"
|
||||
OpName %v "v"
|
||||
OpName %BaseColor "BaseColor"
|
||||
OpName %U_t "U_t"
|
||||
OpMemberName %U_t 0 "g_B"
|
||||
OpName %_ ""
|
||||
OpName %v_0 "v"
|
||||
OpName %gl_FragColor "gl_FragColor"
|
||||
OpMemberDecorate %U_t 0 Offset 0
|
||||
OpDecorate %U_t Block
|
||||
OpDecorate %_ DescriptorSet 0
|
||||
%void = OpTypeVoid
|
||||
%10 = OpTypeFunction %void
|
||||
%float = OpTypeFloat 32
|
||||
%v4float = OpTypeVector %float 4
|
||||
%_ptr_Function_v4float = OpTypePointer Function %v4float
|
||||
%_ptr_Input_v4float = OpTypePointer Input %v4float
|
||||
%BaseColor = OpVariable %_ptr_Input_v4float Input
|
||||
%uint = OpTypeInt 32 0
|
||||
%U_t = OpTypeStruct %uint
|
||||
%_ptr_Uniform_U_t = OpTypePointer Uniform %U_t
|
||||
%_ = OpVariable %_ptr_Uniform_U_t Uniform
|
||||
%int = OpTypeInt 32 1
|
||||
%int_0 = OpConstant %int 0
|
||||
%_ptr_Uniform_uint = OpTypePointer Uniform %uint
|
||||
%bool = OpTypeBool
|
||||
%uint_0 = OpConstant %uint 0
|
||||
%float_0_25 = OpConstant %float 0.25
|
||||
%_ptr_Output_v4float = OpTypePointer Output %v4float
|
||||
%gl_FragColor = OpVariable %_ptr_Output_v4float Output
|
||||
)";
|
||||
|
||||
const std::string before =
|
||||
R"(%main = OpFunction %void None %10
|
||||
%24 = OpLabel
|
||||
%v = OpVariable %_ptr_Function_v4float Function
|
||||
%v_0 = OpVariable %_ptr_Function_v4float Function
|
||||
%25 = OpLoad %v4float %BaseColor
|
||||
OpStore %v %25
|
||||
%26 = OpAccessChain %_ptr_Uniform_uint %_ %int_0
|
||||
%27 = OpLoad %uint %26
|
||||
%28 = OpINotEqual %bool %27 %uint_0
|
||||
OpSelectionMerge %29 None
|
||||
OpBranchConditional %28 %30 %29
|
||||
%30 = OpLabel
|
||||
%31 = OpLoad %v4float %v
|
||||
%32 = OpVectorTimesScalar %v4float %31 %float_0_25
|
||||
OpBranch %33
|
||||
%33 = OpLabel
|
||||
OpStore %v_0 %32
|
||||
OpBranch %29
|
||||
%29 = OpLabel
|
||||
%34 = OpLoad %v4float %v
|
||||
OpStore %gl_FragColor %34
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const std::string after =
|
||||
R"(%main = OpFunction %void None %10
|
||||
%24 = OpLabel
|
||||
%v = OpVariable %_ptr_Function_v4float Function
|
||||
%v_0 = OpVariable %_ptr_Function_v4float Function
|
||||
%25 = OpLoad %v4float %BaseColor
|
||||
OpStore %v %25
|
||||
%26 = OpAccessChain %_ptr_Uniform_uint %_ %int_0
|
||||
%27 = OpLoad %uint %26
|
||||
%28 = OpINotEqual %bool %27 %uint_0
|
||||
OpSelectionMerge %29 None
|
||||
OpBranchConditional %28 %30 %29
|
||||
%30 = OpLabel
|
||||
%31 = OpLoad %v4float %v
|
||||
%32 = OpVectorTimesScalar %v4float %31 %float_0_25
|
||||
OpStore %v_0 %32
|
||||
OpBranch %29
|
||||
%29 = OpLabel
|
||||
%34 = OpLoad %v4float %v
|
||||
OpStore %gl_FragColor %34
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndCheck<BlockMergePass>(predefs + before, predefs + after, true,
|
||||
true);
|
||||
}
|
||||
|
||||
TEST_F(BlockMergeTest, PhiInSuccessorOfMergedBlock) {
|
||||
const std::string text = R"(
|
||||
; CHECK: OpSelectionMerge [[merge:%\w+]] None
|
||||
; CHECK-NEXT: OpBranchConditional {{%\w+}} [[then:%\w+]] [[else:%\w+]]
|
||||
; CHECK: [[then]] = OpLabel
|
||||
; CHECK-NEXT: OpBranch [[merge]]
|
||||
; CHECK: [[else]] = OpLabel
|
||||
; CHECK-NEXT: OpBranch [[merge]]
|
||||
; CHECK: [[merge]] = OpLabel
|
||||
; CHECK-NEXT: OpPhi {{%\w+}} %true [[then]] %false [[else]]
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %func "func"
|
||||
OpExecutionMode %func OriginUpperLeft
|
||||
%void = OpTypeVoid
|
||||
%bool = OpTypeBool
|
||||
%true = OpConstantTrue %bool
|
||||
%false = OpConstantFalse %bool
|
||||
%functy = OpTypeFunction %void
|
||||
%func = OpFunction %void None %functy
|
||||
%entry = OpLabel
|
||||
OpSelectionMerge %merge None
|
||||
OpBranchConditional %true %then %else
|
||||
%then = OpLabel
|
||||
OpBranch %then_next
|
||||
%then_next = OpLabel
|
||||
OpBranch %merge
|
||||
%else = OpLabel
|
||||
OpBranch %merge
|
||||
%merge = OpLabel
|
||||
%phi = OpPhi %bool %true %then_next %false %else
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<BlockMergePass>(text, true);
|
||||
}
|
||||
|
||||
TEST_F(BlockMergeTest, UpdateMergeInstruction) {
|
||||
const std::string text = R"(
|
||||
; CHECK: OpSelectionMerge [[merge:%\w+]] None
|
||||
; CHECK-NEXT: OpBranchConditional {{%\w+}} [[then:%\w+]] [[else:%\w+]]
|
||||
; CHECK: [[then]] = OpLabel
|
||||
; CHECK-NEXT: OpBranch [[merge]]
|
||||
; CHECK: [[else]] = OpLabel
|
||||
; CHECK-NEXT: OpBranch [[merge]]
|
||||
; CHECK: [[merge]] = OpLabel
|
||||
; CHECK-NEXT: OpReturn
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %func "func"
|
||||
OpExecutionMode %func OriginUpperLeft
|
||||
%void = OpTypeVoid
|
||||
%bool = OpTypeBool
|
||||
%true = OpConstantTrue %bool
|
||||
%false = OpConstantFalse %bool
|
||||
%functy = OpTypeFunction %void
|
||||
%func = OpFunction %void None %functy
|
||||
%entry = OpLabel
|
||||
OpSelectionMerge %real_merge None
|
||||
OpBranchConditional %true %then %else
|
||||
%then = OpLabel
|
||||
OpBranch %merge
|
||||
%else = OpLabel
|
||||
OpBranch %merge
|
||||
%merge = OpLabel
|
||||
OpBranch %real_merge
|
||||
%real_merge = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<BlockMergePass>(text, true);
|
||||
}
|
||||
|
||||
TEST_F(BlockMergeTest, TwoMergeBlocksCannotBeMerged) {
|
||||
const std::string text = R"(
|
||||
; CHECK: OpSelectionMerge [[outer_merge:%\w+]] None
|
||||
; CHECK: OpSelectionMerge [[inner_merge:%\w+]] None
|
||||
; CHECK: [[inner_merge]] = OpLabel
|
||||
; CHECK-NEXT: OpBranch [[outer_merge]]
|
||||
; CHECK: [[outer_merge]] = OpLabel
|
||||
; CHECK-NEXT: OpReturn
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %func "func"
|
||||
OpExecutionMode %func OriginUpperLeft
|
||||
%void = OpTypeVoid
|
||||
%bool = OpTypeBool
|
||||
%true = OpConstantTrue %bool
|
||||
%false = OpConstantFalse %bool
|
||||
%functy = OpTypeFunction %void
|
||||
%func = OpFunction %void None %functy
|
||||
%entry = OpLabel
|
||||
OpSelectionMerge %outer_merge None
|
||||
OpBranchConditional %true %then %else
|
||||
%then = OpLabel
|
||||
OpBranch %inner_header
|
||||
%else = OpLabel
|
||||
OpBranch %inner_header
|
||||
%inner_header = OpLabel
|
||||
OpSelectionMerge %inner_merge None
|
||||
OpBranchConditional %true %inner_then %inner_else
|
||||
%inner_then = OpLabel
|
||||
OpBranch %inner_merge
|
||||
%inner_else = OpLabel
|
||||
OpBranch %inner_merge
|
||||
%inner_merge = OpLabel
|
||||
OpBranch %outer_merge
|
||||
%outer_merge = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<BlockMergePass>(text, true);
|
||||
}
|
||||
|
||||
TEST_F(BlockMergeTest, MergeContinue) {
|
||||
const std::string text = R"(
|
||||
; CHECK: OpBranch [[header:%\w+]]
|
||||
; CHECK: [[header]] = OpLabel
|
||||
; CHECK-NEXT: OpLogicalAnd
|
||||
; CHECK-NEXT: OpLoopMerge {{%\w+}} [[header]] None
|
||||
; CHECK-NEXT: OpBranch [[header]]
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %func "func"
|
||||
OpExecutionMode %func OriginUpperLeft
|
||||
%void = OpTypeVoid
|
||||
%bool = OpTypeBool
|
||||
%true = OpConstantTrue %bool
|
||||
%false = OpConstantFalse %bool
|
||||
%functy = OpTypeFunction %void
|
||||
%func = OpFunction %void None %functy
|
||||
%entry = OpLabel
|
||||
OpBranch %header
|
||||
%header = OpLabel
|
||||
OpLoopMerge %merge %continue None
|
||||
OpBranch %continue
|
||||
%continue = OpLabel
|
||||
%op = OpLogicalAnd %bool %true %false
|
||||
OpBranch %header
|
||||
%merge = OpLabel
|
||||
OpUnreachable
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<BlockMergePass>(text, true);
|
||||
}
|
||||
|
||||
TEST_F(BlockMergeTest, TwoHeadersCannotBeMerged) {
|
||||
const std::string text = R"(
|
||||
; CHECK: OpBranch [[loop_header:%\w+]]
|
||||
; CHECK: [[loop_header]] = OpLabel
|
||||
; CHECK-NEXT: OpLoopMerge
|
||||
; CHECK-NEXT: OpBranch [[if_header:%\w+]]
|
||||
; CHECK: [[if_header]] = OpLabel
|
||||
; CHECK-NEXT: OpSelectionMerge
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %func "func"
|
||||
OpExecutionMode %func OriginUpperLeft
|
||||
%void = OpTypeVoid
|
||||
%bool = OpTypeBool
|
||||
%true = OpConstantTrue %bool
|
||||
%false = OpConstantFalse %bool
|
||||
%functy = OpTypeFunction %void
|
||||
%func = OpFunction %void None %functy
|
||||
%entry = OpLabel
|
||||
OpBranch %header
|
||||
%header = OpLabel
|
||||
OpLoopMerge %merge %continue None
|
||||
OpBranch %inner_header
|
||||
%inner_header = OpLabel
|
||||
OpSelectionMerge %if_merge None
|
||||
OpBranchConditional %true %then %if_merge
|
||||
%then = OpLabel
|
||||
OpBranch %continue
|
||||
%if_merge = OpLabel
|
||||
OpBranch %continue
|
||||
%continue = OpLabel
|
||||
OpBranchConditional %false %merge %header
|
||||
%merge = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<BlockMergePass>(text, true);
|
||||
}
|
||||
|
||||
TEST_F(BlockMergeTest, CannotMergeContinue) {
|
||||
const std::string text = R"(
|
||||
; CHECK: OpBranch [[loop_header:%\w+]]
|
||||
; CHECK: [[loop_header]] = OpLabel
|
||||
; CHECK-NEXT: OpLoopMerge {{%\w+}} [[continue:%\w+]]
|
||||
; CHECK-NEXT: OpBranchConditional {{%\w+}} [[if_header:%\w+]]
|
||||
; CHECK: [[if_header]] = OpLabel
|
||||
; CHECK-NEXT: OpSelectionMerge
|
||||
; CHECK: [[continue]] = OpLabel
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %func "func"
|
||||
OpExecutionMode %func OriginUpperLeft
|
||||
%void = OpTypeVoid
|
||||
%bool = OpTypeBool
|
||||
%true = OpConstantTrue %bool
|
||||
%false = OpConstantFalse %bool
|
||||
%functy = OpTypeFunction %void
|
||||
%func = OpFunction %void None %functy
|
||||
%entry = OpLabel
|
||||
OpBranch %header
|
||||
%header = OpLabel
|
||||
OpLoopMerge %merge %continue None
|
||||
OpBranchConditional %true %inner_header %merge
|
||||
%inner_header = OpLabel
|
||||
OpSelectionMerge %if_merge None
|
||||
OpBranchConditional %true %then %if_merge
|
||||
%then = OpLabel
|
||||
OpBranch %continue
|
||||
%if_merge = OpLabel
|
||||
OpBranch %continue
|
||||
%continue = OpLabel
|
||||
OpBranchConditional %false %merge %header
|
||||
%merge = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<BlockMergePass>(text, true);
|
||||
}
|
||||
|
||||
TEST_F(BlockMergeTest, RemoveStructuredDeclaration) {
|
||||
// Note: SPIR-V hand edited remove dead branch and add block
|
||||
// before continue block
|
||||
//
|
||||
// #version 140
|
||||
// in vec4 BaseColor;
|
||||
//
|
||||
// void main()
|
||||
// {
|
||||
// while (true) {
|
||||
// break;
|
||||
// }
|
||||
// gl_FragColor = BaseColor;
|
||||
// }
|
||||
|
||||
const std::string assembly =
|
||||
R"(
|
||||
; CHECK: OpLabel
|
||||
; CHECK: [[header:%\w+]] = OpLabel
|
||||
; CHECK-NOT: OpLoopMerge
|
||||
; CHECK: OpReturn
|
||||
; CHECK: [[continue:%\w+]] = OpLabel
|
||||
; CHECK-NEXT: OpBranch [[block:%\w+]]
|
||||
; CHECK: [[block]] = OpLabel
|
||||
; CHECK-NEXT: OpBranch [[header]]
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %main "main" %gl_FragColor %BaseColor
|
||||
OpExecutionMode %main OriginUpperLeft
|
||||
OpSource GLSL 140
|
||||
OpName %main "main"
|
||||
OpName %gl_FragColor "gl_FragColor"
|
||||
OpName %BaseColor "BaseColor"
|
||||
%void = OpTypeVoid
|
||||
%6 = OpTypeFunction %void
|
||||
%bool = OpTypeBool
|
||||
%true = OpConstantTrue %bool
|
||||
%float = OpTypeFloat 32
|
||||
%v4float = OpTypeVector %float 4
|
||||
%_ptr_Output_v4float = OpTypePointer Output %v4float
|
||||
%gl_FragColor = OpVariable %_ptr_Output_v4float Output
|
||||
%_ptr_Input_v4float = OpTypePointer Input %v4float
|
||||
%BaseColor = OpVariable %_ptr_Input_v4float Input
|
||||
%main = OpFunction %void None %6
|
||||
%13 = OpLabel
|
||||
OpBranch %14
|
||||
%14 = OpLabel
|
||||
OpLoopMerge %15 %16 None
|
||||
OpBranch %17
|
||||
%17 = OpLabel
|
||||
OpBranch %15
|
||||
%18 = OpLabel
|
||||
OpBranch %16
|
||||
%16 = OpLabel
|
||||
OpBranch %14
|
||||
%15 = OpLabel
|
||||
%19 = OpLoad %v4float %BaseColor
|
||||
OpStore %gl_FragColor %19
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<BlockMergePass>(assembly, true);
|
||||
}
|
||||
|
||||
TEST_F(BlockMergeTest, DontMergeKill) {
|
||||
const std::string text = R"(
|
||||
; CHECK: OpLoopMerge [[merge:%\w+]] [[cont:%\w+]] None
|
||||
; CHECK-NEXT: OpBranch [[ret:%\w+]]
|
||||
; CHECK: [[ret:%\w+]] = OpLabel
|
||||
; CHECK-NEXT: OpKill
|
||||
; CHECK-DAG: [[cont]] = OpLabel
|
||||
; CHECK-DAG: [[merge]] = OpLabel
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %func "func"
|
||||
OpExecutionMode %func OriginUpperLeft
|
||||
%void = OpTypeVoid
|
||||
%bool = OpTypeBool
|
||||
%functy = OpTypeFunction %void
|
||||
%func = OpFunction %void None %functy
|
||||
%1 = OpLabel
|
||||
OpBranch %2
|
||||
%2 = OpLabel
|
||||
OpLoopMerge %3 %4 None
|
||||
OpBranch %5
|
||||
%5 = OpLabel
|
||||
OpKill
|
||||
%4 = OpLabel
|
||||
OpBranch %2
|
||||
%3 = OpLabel
|
||||
OpUnreachable
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<BlockMergePass>(text, true);
|
||||
}
|
||||
|
||||
TEST_F(BlockMergeTest, DontMergeUnreachable) {
|
||||
const std::string text = R"(
|
||||
; CHECK: OpLoopMerge [[merge:%\w+]] [[cont:%\w+]] None
|
||||
; CHECK-NEXT: OpBranch [[ret:%\w+]]
|
||||
; CHECK: [[ret:%\w+]] = OpLabel
|
||||
; CHECK-NEXT: OpUnreachable
|
||||
; CHECK-DAG: [[cont]] = OpLabel
|
||||
; CHECK-DAG: [[merge]] = OpLabel
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %func "func"
|
||||
OpExecutionMode %func OriginUpperLeft
|
||||
%void = OpTypeVoid
|
||||
%bool = OpTypeBool
|
||||
%functy = OpTypeFunction %void
|
||||
%func = OpFunction %void None %functy
|
||||
%1 = OpLabel
|
||||
OpBranch %2
|
||||
%2 = OpLabel
|
||||
OpLoopMerge %3 %4 None
|
||||
OpBranch %5
|
||||
%5 = OpLabel
|
||||
OpUnreachable
|
||||
%4 = OpLabel
|
||||
OpBranch %2
|
||||
%3 = OpLabel
|
||||
OpUnreachable
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<BlockMergePass>(text, false);
|
||||
}
|
||||
|
||||
TEST_F(BlockMergeTest, DontMergeReturn) {
|
||||
const std::string text = R"(
|
||||
; CHECK: OpLoopMerge [[merge:%\w+]] [[cont:%\w+]] None
|
||||
; CHECK-NEXT: OpBranch [[ret:%\w+]]
|
||||
; CHECK: [[ret:%\w+]] = OpLabel
|
||||
; CHECK-NEXT: OpReturn
|
||||
; CHECK-DAG: [[cont]] = OpLabel
|
||||
; CHECK-DAG: [[merge]] = OpLabel
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %func "func"
|
||||
OpExecutionMode %func OriginUpperLeft
|
||||
%void = OpTypeVoid
|
||||
%bool = OpTypeBool
|
||||
%functy = OpTypeFunction %void
|
||||
%func = OpFunction %void None %functy
|
||||
%1 = OpLabel
|
||||
OpBranch %2
|
||||
%2 = OpLabel
|
||||
OpLoopMerge %3 %4 None
|
||||
OpBranch %5
|
||||
%5 = OpLabel
|
||||
OpReturn
|
||||
%4 = OpLabel
|
||||
OpBranch %2
|
||||
%3 = OpLabel
|
||||
OpUnreachable
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<BlockMergePass>(text, true);
|
||||
}
|
||||
|
||||
TEST_F(BlockMergeTest, DontMergeSwitch) {
|
||||
const std::string text = R"(
|
||||
; CHECK: OpLoopMerge [[merge:%\w+]] [[cont:%\w+]] None
|
||||
; CHECK-NEXT: OpBranch [[ret:%\w+]]
|
||||
; CHECK: [[ret:%\w+]] = OpLabel
|
||||
; CHECK-NEXT: OpSwitch
|
||||
; CHECK-DAG: [[cont]] = OpLabel
|
||||
; CHECK-DAG: [[merge]] = OpLabel
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %func "func"
|
||||
OpExecutionMode %func OriginUpperLeft
|
||||
%void = OpTypeVoid
|
||||
%bool = OpTypeBool
|
||||
%int = OpTypeInt 32 1
|
||||
%int_0 = OpConstant %int 0
|
||||
%functy = OpTypeFunction %void
|
||||
%func = OpFunction %void None %functy
|
||||
%1 = OpLabel
|
||||
OpBranch %2
|
||||
%2 = OpLabel
|
||||
OpLoopMerge %3 %4 None
|
||||
OpBranch %5
|
||||
%5 = OpLabel
|
||||
OpSwitch %int_0 %6
|
||||
%6 = OpLabel
|
||||
OpReturn
|
||||
%4 = OpLabel
|
||||
OpBranch %2
|
||||
%3 = OpLabel
|
||||
OpUnreachable
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<BlockMergePass>(text, true);
|
||||
}
|
||||
|
||||
TEST_F(BlockMergeTest, DontMergeReturnValue) {
|
||||
const std::string text = R"(
|
||||
; CHECK: OpLoopMerge [[merge:%\w+]] [[cont:%\w+]] None
|
||||
; CHECK-NEXT: OpBranch [[ret:%\w+]]
|
||||
; CHECK: [[ret:%\w+]] = OpLabel
|
||||
; CHECK-NEXT: OpReturn
|
||||
; CHECK-DAG: [[cont]] = OpLabel
|
||||
; CHECK-DAG: [[merge]] = OpLabel
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %func "func"
|
||||
OpExecutionMode %func OriginUpperLeft
|
||||
%void = OpTypeVoid
|
||||
%bool = OpTypeBool
|
||||
%functy = OpTypeFunction %void
|
||||
%otherfuncty = OpTypeFunction %bool
|
||||
%true = OpConstantTrue %bool
|
||||
%func = OpFunction %void None %functy
|
||||
%1 = OpLabel
|
||||
%2 = OpFunctionCall %bool %3
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
%3 = OpFunction %bool None %otherfuncty
|
||||
%4 = OpLabel
|
||||
OpBranch %5
|
||||
%5 = OpLabel
|
||||
OpLoopMerge %6 %7 None
|
||||
OpBranch %8
|
||||
%8 = OpLabel
|
||||
OpReturnValue %true
|
||||
%7 = OpLabel
|
||||
OpBranch %5
|
||||
%6 = OpLabel
|
||||
OpUnreachable
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<BlockMergePass>(text, true);
|
||||
}
|
||||
|
||||
TEST_F(BlockMergeTest, MergeHeaders) {
|
||||
// Merge two headers when the second is the merge block of the first.
|
||||
const std::string text = R"(
|
||||
; CHECK: OpFunction
|
||||
; CHECK-NEXT: OpLabel
|
||||
; CHECK-NEXT: OpBranch [[header:%\w+]]
|
||||
; CHECK-NEXT: [[header]] = OpLabel
|
||||
; CHECK-NEXT: OpSelectionMerge [[merge:%\w+]]
|
||||
; CHECK: [[merge]] = OpLabel
|
||||
; CHEKC: OpReturn
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %func "func"
|
||||
OpExecutionMode %func OriginUpperLeft
|
||||
%void = OpTypeVoid
|
||||
%bool = OpTypeBool
|
||||
%functy = OpTypeFunction %void
|
||||
%otherfuncty = OpTypeFunction %bool
|
||||
%true = OpConstantTrue %bool
|
||||
%func = OpFunction %void None %functy
|
||||
%1 = OpLabel
|
||||
OpBranch %5
|
||||
%5 = OpLabel
|
||||
OpLoopMerge %8 %7 None
|
||||
OpBranch %8
|
||||
%7 = OpLabel
|
||||
OpBranch %5
|
||||
%8 = OpLabel
|
||||
OpSelectionMerge %m None
|
||||
OpBranchConditional %true %a %m
|
||||
%a = OpLabel
|
||||
OpBranch %m
|
||||
%m = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<BlockMergePass>(text, true);
|
||||
}
|
||||
|
||||
TEST_F(BlockMergeTest, OpPhiInSuccessor) {
|
||||
// Checks that when merging blocks A and B, the OpPhi at the start of B is
|
||||
// removed and uses of its definition are replaced appropriately.
|
||||
const std::string prefix =
|
||||
R"(OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %main "main"
|
||||
OpExecutionMode %main OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %main "main"
|
||||
OpName %x "x"
|
||||
OpName %y "y"
|
||||
%void = OpTypeVoid
|
||||
%6 = OpTypeFunction %void
|
||||
%int = OpTypeInt 32 1
|
||||
%_ptr_Function_int = OpTypePointer Function %int
|
||||
%int_1 = OpConstant %int 1
|
||||
%main = OpFunction %void None %6
|
||||
%10 = OpLabel
|
||||
%x = OpVariable %_ptr_Function_int Function
|
||||
%y = OpVariable %_ptr_Function_int Function
|
||||
OpStore %x %int_1
|
||||
%11 = OpLoad %int %x
|
||||
)";
|
||||
|
||||
const std::string suffix_before =
|
||||
R"(OpBranch %12
|
||||
%12 = OpLabel
|
||||
%13 = OpPhi %int %11 %10
|
||||
OpStore %y %13
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const std::string suffix_after =
|
||||
R"(OpStore %y %11
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
SinglePassRunAndCheck<BlockMergePass>(prefix + suffix_before,
|
||||
prefix + suffix_after, true, true);
|
||||
}
|
||||
|
||||
TEST_F(BlockMergeTest, MultipleOpPhisInSuccessor) {
|
||||
// Checks that when merging blocks A and B, the OpPhis at the start of B are
|
||||
// removed and uses of their definitions are replaced appropriately.
|
||||
const std::string prefix =
|
||||
R"(OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %main "main"
|
||||
OpExecutionMode %main OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %main "main"
|
||||
OpName %S "S"
|
||||
OpMemberName %S 0 "x"
|
||||
OpMemberName %S 1 "f"
|
||||
OpName %s "s"
|
||||
OpName %g "g"
|
||||
OpName %y "y"
|
||||
OpName %t "t"
|
||||
OpName %z "z"
|
||||
%void = OpTypeVoid
|
||||
%10 = OpTypeFunction %void
|
||||
%int = OpTypeInt 32 1
|
||||
%float = OpTypeFloat 32
|
||||
%S = OpTypeStruct %int %float
|
||||
%_ptr_Function_S = OpTypePointer Function %S
|
||||
%int_1 = OpConstant %int 1
|
||||
%float_2 = OpConstant %float 2
|
||||
%16 = OpConstantComposite %S %int_1 %float_2
|
||||
%_ptr_Function_float = OpTypePointer Function %float
|
||||
%_ptr_Function_int = OpTypePointer Function %int
|
||||
%int_3 = OpConstant %int 3
|
||||
%int_0 = OpConstant %int 0
|
||||
%main = OpFunction %void None %10
|
||||
%21 = OpLabel
|
||||
%s = OpVariable %_ptr_Function_S Function
|
||||
%g = OpVariable %_ptr_Function_float Function
|
||||
%y = OpVariable %_ptr_Function_int Function
|
||||
%t = OpVariable %_ptr_Function_S Function
|
||||
%z = OpVariable %_ptr_Function_float Function
|
||||
OpStore %s %16
|
||||
OpStore %g %float_2
|
||||
OpStore %y %int_3
|
||||
%22 = OpLoad %S %s
|
||||
OpStore %t %22
|
||||
%23 = OpAccessChain %_ptr_Function_float %s %int_1
|
||||
%24 = OpLoad %float %23
|
||||
%25 = OpLoad %float %g
|
||||
)";
|
||||
|
||||
const std::string suffix_before =
|
||||
R"(OpBranch %26
|
||||
%26 = OpLabel
|
||||
%27 = OpPhi %float %24 %21
|
||||
%28 = OpPhi %float %25 %21
|
||||
%29 = OpFAdd %float %27 %28
|
||||
%30 = OpAccessChain %_ptr_Function_int %s %int_0
|
||||
%31 = OpLoad %int %30
|
||||
OpBranch %32
|
||||
%32 = OpLabel
|
||||
%33 = OpPhi %float %29 %26
|
||||
%34 = OpPhi %int %31 %26
|
||||
%35 = OpConvertSToF %float %34
|
||||
OpBranch %36
|
||||
%36 = OpLabel
|
||||
%37 = OpPhi %float %35 %32
|
||||
%38 = OpFSub %float %33 %37
|
||||
%39 = OpLoad %int %y
|
||||
OpBranch %40
|
||||
%40 = OpLabel
|
||||
%41 = OpPhi %float %38 %36
|
||||
%42 = OpPhi %int %39 %36
|
||||
%43 = OpConvertSToF %float %42
|
||||
%44 = OpFAdd %float %41 %43
|
||||
OpStore %z %44
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const std::string suffix_after =
|
||||
R"(%29 = OpFAdd %float %24 %25
|
||||
%30 = OpAccessChain %_ptr_Function_int %s %int_0
|
||||
%31 = OpLoad %int %30
|
||||
%35 = OpConvertSToF %float %31
|
||||
%38 = OpFSub %float %29 %35
|
||||
%39 = OpLoad %int %y
|
||||
%43 = OpConvertSToF %float %39
|
||||
%44 = OpFAdd %float %38 %43
|
||||
OpStore %z %44
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
SinglePassRunAndCheck<BlockMergePass>(prefix + suffix_before,
|
||||
prefix + suffix_after, true, true);
|
||||
}
|
||||
|
||||
TEST_F(BlockMergeTest, UnreachableLoop) {
|
||||
const std::string spirv = R"(OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %main "main"
|
||||
OpExecutionMode %main OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpName %main "main"
|
||||
%void = OpTypeVoid
|
||||
%4 = OpTypeFunction %void
|
||||
%int = OpTypeInt 32 1
|
||||
%_ptr_Function_int = OpTypePointer Function %int
|
||||
%bool = OpTypeBool
|
||||
%false = OpConstantFalse %bool
|
||||
%main = OpFunction %void None %4
|
||||
%9 = OpLabel
|
||||
OpBranch %10
|
||||
%11 = OpLabel
|
||||
OpLoopMerge %12 %13 None
|
||||
OpBranchConditional %false %13 %14
|
||||
%13 = OpLabel
|
||||
OpSelectionMerge %15 None
|
||||
OpBranchConditional %false %16 %17
|
||||
%16 = OpLabel
|
||||
OpBranch %15
|
||||
%17 = OpLabel
|
||||
OpBranch %15
|
||||
%15 = OpLabel
|
||||
OpBranch %11
|
||||
%14 = OpLabel
|
||||
OpReturn
|
||||
%12 = OpLabel
|
||||
OpBranch %10
|
||||
%10 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndCheck<BlockMergePass>(spirv, spirv, true, true);
|
||||
}
|
||||
|
||||
// TODO(greg-lunarg): Add tests to verify handling of these cases:
|
||||
//
|
||||
// More complex control flow
|
||||
// Others?
|
||||
|
||||
} // namespace
|
||||
} // namespace opt
|
||||
} // namespace spvtools
|
||||
930
3rdparty/spirv-tools/test/opt/ccp_test.cpp
vendored
930
3rdparty/spirv-tools/test/opt/ccp_test.cpp
vendored
@@ -1,930 +0,0 @@
|
||||
// Copyright (c) 2017 Google Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "source/opt/ccp_pass.h"
|
||||
#include "test/opt/pass_fixture.h"
|
||||
#include "test/opt/pass_utils.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace opt {
|
||||
namespace {
|
||||
|
||||
using CCPTest = PassTest<::testing::Test>;
|
||||
|
||||
TEST_F(CCPTest, PropagateThroughPhis) {
|
||||
const std::string spv_asm = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %main "main" %x %outparm
|
||||
OpExecutionMode %main OriginUpperLeft
|
||||
OpSource GLSL 450
|
||||
OpName %main "main"
|
||||
OpName %x "x"
|
||||
OpName %outparm "outparm"
|
||||
OpDecorate %x Flat
|
||||
OpDecorate %x Location 0
|
||||
OpDecorate %outparm Location 0
|
||||
%void = OpTypeVoid
|
||||
%3 = OpTypeFunction %void
|
||||
%int = OpTypeInt 32 1
|
||||
%bool = OpTypeBool
|
||||
%_ptr_Function_int = OpTypePointer Function %int
|
||||
%int_4 = OpConstant %int 4
|
||||
%int_3 = OpConstant %int 3
|
||||
%int_1 = OpConstant %int 1
|
||||
%_ptr_Input_int = OpTypePointer Input %int
|
||||
%x = OpVariable %_ptr_Input_int Input
|
||||
%_ptr_Output_int = OpTypePointer Output %int
|
||||
%outparm = OpVariable %_ptr_Output_int Output
|
||||
%main = OpFunction %void None %3
|
||||
%4 = OpLabel
|
||||
%5 = OpLoad %int %x
|
||||
%9 = OpIAdd %int %int_1 %int_3
|
||||
%6 = OpSGreaterThan %bool %5 %int_3
|
||||
OpSelectionMerge %25 None
|
||||
OpBranchConditional %6 %22 %23
|
||||
%22 = OpLabel
|
||||
|
||||
; CHECK: OpCopyObject %int %int_4
|
||||
%7 = OpCopyObject %int %9
|
||||
|
||||
OpBranch %25
|
||||
%23 = OpLabel
|
||||
%8 = OpCopyObject %int %int_4
|
||||
OpBranch %25
|
||||
%25 = OpLabel
|
||||
|
||||
; %int_4 should have propagated to both OpPhi operands.
|
||||
; CHECK: OpPhi %int %int_4 {{%\d+}} %int_4 {{%\d+}}
|
||||
%35 = OpPhi %int %7 %22 %8 %23
|
||||
|
||||
; This function always returns 4. DCE should get rid of everything else.
|
||||
; CHECK OpStore %outparm %int_4
|
||||
OpStore %outparm %35
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<CCPPass>(spv_asm, true);
|
||||
}
|
||||
|
||||
TEST_F(CCPTest, SimplifyConditionals) {
|
||||
const std::string spv_asm = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %main "main" %outparm
|
||||
OpExecutionMode %main OriginUpperLeft
|
||||
OpSource GLSL 450
|
||||
OpName %main "main"
|
||||
OpName %outparm "outparm"
|
||||
OpDecorate %outparm Location 0
|
||||
%void = OpTypeVoid
|
||||
%3 = OpTypeFunction %void
|
||||
%int = OpTypeInt 32 1
|
||||
%bool = OpTypeBool
|
||||
%_ptr_Function_int = OpTypePointer Function %int
|
||||
%int_4 = OpConstant %int 4
|
||||
%int_3 = OpConstant %int 3
|
||||
%int_1 = OpConstant %int 1
|
||||
%_ptr_Output_int = OpTypePointer Output %int
|
||||
%outparm = OpVariable %_ptr_Output_int Output
|
||||
%main = OpFunction %void None %3
|
||||
%4 = OpLabel
|
||||
%9 = OpIAdd %int %int_4 %int_3
|
||||
%6 = OpSGreaterThan %bool %9 %int_3
|
||||
OpSelectionMerge %25 None
|
||||
; CHECK: OpBranchConditional %true [[bb_taken:%\d+]] [[bb_not_taken:%\d+]]
|
||||
OpBranchConditional %6 %22 %23
|
||||
; CHECK: [[bb_taken]] = OpLabel
|
||||
%22 = OpLabel
|
||||
; CHECK: OpCopyObject %int %int_7
|
||||
%7 = OpCopyObject %int %9
|
||||
OpBranch %25
|
||||
; CHECK: [[bb_not_taken]] = OpLabel
|
||||
%23 = OpLabel
|
||||
; CHECK: [[id_not_evaluated:%\d+]] = OpCopyObject %int %int_4
|
||||
%8 = OpCopyObject %int %int_4
|
||||
OpBranch %25
|
||||
%25 = OpLabel
|
||||
|
||||
; %int_7 should have propagated to the first OpPhi operand. But the else branch
|
||||
; is not executable (conditional is always true), so no values should be
|
||||
; propagated there and the value of the OpPhi should always be %int_7.
|
||||
; CHECK: OpPhi %int %int_7 [[bb_taken]] [[id_not_evaluated]] [[bb_not_taken]]
|
||||
%35 = OpPhi %int %7 %22 %8 %23
|
||||
|
||||
; Only the true path of the conditional is ever executed. The output of this
|
||||
; function is always %int_7.
|
||||
; CHECK: OpStore %outparm %int_7
|
||||
OpStore %outparm %35
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<CCPPass>(spv_asm, true);
|
||||
}
|
||||
|
||||
TEST_F(CCPTest, SimplifySwitches) {
|
||||
const std::string spv_asm = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %main "main" %outparm
|
||||
OpExecutionMode %main OriginUpperLeft
|
||||
OpSource GLSL 450
|
||||
OpName %main "main"
|
||||
OpName %outparm "outparm"
|
||||
OpDecorate %outparm Location 0
|
||||
%void = OpTypeVoid
|
||||
%6 = OpTypeFunction %void
|
||||
%int = OpTypeInt 32 1
|
||||
%_ptr_Function_int = OpTypePointer Function %int
|
||||
%int_23 = OpConstant %int 23
|
||||
%int_42 = OpConstant %int 42
|
||||
%int_14 = OpConstant %int 14
|
||||
%int_15 = OpConstant %int 15
|
||||
%int_4 = OpConstant %int 4
|
||||
%_ptr_Output_int = OpTypePointer Output %int
|
||||
%outparm = OpVariable %_ptr_Output_int Output
|
||||
%main = OpFunction %void None %6
|
||||
%15 = OpLabel
|
||||
OpSelectionMerge %17 None
|
||||
OpSwitch %int_23 %17 10 %18 13 %19 23 %20
|
||||
%18 = OpLabel
|
||||
OpBranch %17
|
||||
%19 = OpLabel
|
||||
OpBranch %17
|
||||
%20 = OpLabel
|
||||
OpBranch %17
|
||||
%17 = OpLabel
|
||||
%24 = OpPhi %int %int_23 %15 %int_42 %18 %int_14 %19 %int_15 %20
|
||||
|
||||
; The switch will always jump to label %20, which carries the value %int_15.
|
||||
; CHECK: OpIAdd %int %int_15 %int_4
|
||||
%22 = OpIAdd %int %24 %int_4
|
||||
|
||||
; Consequently, the return value will always be %int_19.
|
||||
; CHECK: OpStore %outparm %int_19
|
||||
OpStore %outparm %22
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<CCPPass>(spv_asm, true);
|
||||
}
|
||||
|
||||
TEST_F(CCPTest, SimplifySwitchesDefaultBranch) {
|
||||
const std::string spv_asm = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %main "main" %outparm
|
||||
OpExecutionMode %main OriginUpperLeft
|
||||
OpSource GLSL 450
|
||||
OpName %main "main"
|
||||
OpName %outparm "outparm"
|
||||
OpDecorate %outparm Location 0
|
||||
%void = OpTypeVoid
|
||||
%6 = OpTypeFunction %void
|
||||
%int = OpTypeInt 32 1
|
||||
%_ptr_Function_int = OpTypePointer Function %int
|
||||
%int_42 = OpConstant %int 42
|
||||
%int_4 = OpConstant %int 4
|
||||
%int_1 = OpConstant %int 1
|
||||
%_ptr_Output_int = OpTypePointer Output %int
|
||||
%outparm = OpVariable %_ptr_Output_int Output
|
||||
%main = OpFunction %void None %6
|
||||
%13 = OpLabel
|
||||
%15 = OpIAdd %int %int_42 %int_4
|
||||
OpSelectionMerge %16 None
|
||||
|
||||
; CHECK: OpSwitch %int_46 {{%\d+}} 10 {{%\d+}}
|
||||
OpSwitch %15 %17 10 %18
|
||||
%18 = OpLabel
|
||||
OpBranch %16
|
||||
%17 = OpLabel
|
||||
OpBranch %16
|
||||
%16 = OpLabel
|
||||
%22 = OpPhi %int %int_42 %18 %int_1 %17
|
||||
|
||||
; The switch will always jump to the default label %17. This carries the value
|
||||
; %int_1.
|
||||
; CHECK: OpIAdd %int %int_1 %int_4
|
||||
%20 = OpIAdd %int %22 %int_4
|
||||
|
||||
; Resulting in a return value of %int_5.
|
||||
; CHECK: OpStore %outparm %int_5
|
||||
OpStore %outparm %20
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<CCPPass>(spv_asm, true);
|
||||
}
|
||||
|
||||
TEST_F(CCPTest, SimplifyIntVector) {
|
||||
const std::string spv_asm = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %main "main" %OutColor
|
||||
OpExecutionMode %main OriginUpperLeft
|
||||
OpSource GLSL 450
|
||||
OpName %main "main"
|
||||
OpName %v "v"
|
||||
OpName %OutColor "OutColor"
|
||||
OpDecorate %OutColor Location 0
|
||||
%void = OpTypeVoid
|
||||
%3 = OpTypeFunction %void
|
||||
%int = OpTypeInt 32 1
|
||||
%v4int = OpTypeVector %int 4
|
||||
%_ptr_Function_v4int = OpTypePointer Function %v4int
|
||||
%int_1 = OpConstant %int 1
|
||||
%int_2 = OpConstant %int 2
|
||||
%int_3 = OpConstant %int 3
|
||||
%int_4 = OpConstant %int 4
|
||||
%14 = OpConstantComposite %v4int %int_1 %int_2 %int_3 %int_4
|
||||
%uint = OpTypeInt 32 0
|
||||
%uint_0 = OpConstant %uint 0
|
||||
%_ptr_Function_int = OpTypePointer Function %int
|
||||
%_ptr_Output_v4int = OpTypePointer Output %v4int
|
||||
%OutColor = OpVariable %_ptr_Output_v4int Output
|
||||
%main = OpFunction %void None %3
|
||||
%5 = OpLabel
|
||||
%v = OpVariable %_ptr_Function_v4int Function
|
||||
OpStore %v %14
|
||||
%18 = OpAccessChain %_ptr_Function_int %v %uint_0
|
||||
%19 = OpLoad %int %18
|
||||
|
||||
; The constant folder does not see through access chains. To get this, the
|
||||
; vector would have to be scalarized.
|
||||
; CHECK: [[result_id:%\d+]] = OpIAdd %int {{%\d+}} %int_1
|
||||
%20 = OpIAdd %int %19 %int_1
|
||||
%21 = OpAccessChain %_ptr_Function_int %v %uint_0
|
||||
|
||||
; CHECK: OpStore {{%\d+}} [[result_id]]
|
||||
OpStore %21 %20
|
||||
%24 = OpLoad %v4int %v
|
||||
OpStore %OutColor %24
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<CCPPass>(spv_asm, true);
|
||||
}
|
||||
|
||||
TEST_F(CCPTest, BadSimplifyFloatVector) {
|
||||
const std::string spv_asm = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %main "main" %OutColor
|
||||
OpExecutionMode %main OriginUpperLeft
|
||||
OpSource GLSL 450
|
||||
OpName %main "main"
|
||||
OpName %v "v"
|
||||
OpName %OutColor "OutColor"
|
||||
OpDecorate %OutColor Location 0
|
||||
%void = OpTypeVoid
|
||||
%3 = OpTypeFunction %void
|
||||
%float = OpTypeFloat 32
|
||||
%v4float = OpTypeVector %float 4
|
||||
%_ptr_Function_v4float = OpTypePointer Function %v4float
|
||||
%float_1 = OpConstant %float 1
|
||||
%float_2 = OpConstant %float 2
|
||||
%float_3 = OpConstant %float 3
|
||||
%float_4 = OpConstant %float 4
|
||||
%14 = OpConstantComposite %v4float %float_1 %float_2 %float_3 %float_4
|
||||
%uint = OpTypeInt 32 0
|
||||
%uint_0 = OpConstant %uint 0
|
||||
%_ptr_Function_float = OpTypePointer Function %float
|
||||
%_ptr_Output_v4float = OpTypePointer Output %v4float
|
||||
%OutColor = OpVariable %_ptr_Output_v4float Output
|
||||
%main = OpFunction %void None %3
|
||||
%5 = OpLabel
|
||||
%v = OpVariable %_ptr_Function_v4float Function
|
||||
OpStore %v %14
|
||||
%18 = OpAccessChain %_ptr_Function_float %v %uint_0
|
||||
%19 = OpLoad %float %18
|
||||
|
||||
; NOTE: This test should start failing once floating point folding is
|
||||
; implemented (https://github.com/KhronosGroup/SPIRV-Tools/issues/943).
|
||||
; This should be checking that we are adding %float_1 + %float_1.
|
||||
; CHECK: [[result_id:%\d+]] = OpFAdd %float {{%\d+}} %float_1
|
||||
%20 = OpFAdd %float %19 %float_1
|
||||
%21 = OpAccessChain %_ptr_Function_float %v %uint_0
|
||||
|
||||
; This should be checkint that we are storing %float_2 instead of result_it.
|
||||
; CHECK: OpStore {{%\d+}} [[result_id]]
|
||||
OpStore %21 %20
|
||||
%24 = OpLoad %v4float %v
|
||||
OpStore %OutColor %24
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<CCPPass>(spv_asm, true);
|
||||
}
|
||||
|
||||
TEST_F(CCPTest, NoLoadStorePropagation) {
|
||||
const std::string spv_asm = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %main "main" %outparm
|
||||
OpExecutionMode %main OriginUpperLeft
|
||||
OpSource GLSL 450
|
||||
OpName %main "main"
|
||||
OpName %x "x"
|
||||
OpName %outparm "outparm"
|
||||
OpDecorate %outparm Location 0
|
||||
%void = OpTypeVoid
|
||||
%3 = OpTypeFunction %void
|
||||
%int = OpTypeInt 32 1
|
||||
%_ptr_Function_int = OpTypePointer Function %int
|
||||
%int_23 = OpConstant %int 23
|
||||
%_ptr_Output_int = OpTypePointer Output %int
|
||||
%outparm = OpVariable %_ptr_Output_int Output
|
||||
%main = OpFunction %void None %3
|
||||
%5 = OpLabel
|
||||
%x = OpVariable %_ptr_Function_int Function
|
||||
OpStore %x %int_23
|
||||
|
||||
; int_23 should not propagate into this load.
|
||||
; CHECK: [[load_id:%\d+]] = OpLoad %int %x
|
||||
%12 = OpLoad %int %x
|
||||
|
||||
; Nor into this copy operation.
|
||||
; CHECK: [[copy_id:%\d+]] = OpCopyObject %int [[load_id]]
|
||||
%13 = OpCopyObject %int %12
|
||||
|
||||
; Likewise here.
|
||||
; CHECK: OpStore %outparm [[copy_id]]
|
||||
OpStore %outparm %13
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<CCPPass>(spv_asm, true);
|
||||
}
|
||||
|
||||
TEST_F(CCPTest, HandleAbortInstructions) {
|
||||
const std::string spv_asm = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %main "main"
|
||||
OpExecutionMode %main OriginUpperLeft
|
||||
OpSource HLSL 500
|
||||
OpName %main "main"
|
||||
%void = OpTypeVoid
|
||||
%3 = OpTypeFunction %void
|
||||
%int = OpTypeInt 32 1
|
||||
%bool = OpTypeBool
|
||||
; CHECK: %true = OpConstantTrue %bool
|
||||
%int_3 = OpConstant %int 3
|
||||
%int_1 = OpConstant %int 1
|
||||
%main = OpFunction %void None %3
|
||||
%4 = OpLabel
|
||||
%9 = OpIAdd %int %int_3 %int_1
|
||||
%6 = OpSGreaterThan %bool %9 %int_3
|
||||
OpSelectionMerge %23 None
|
||||
; CHECK: OpBranchConditional %true {{%\d+}} {{%\d+}}
|
||||
OpBranchConditional %6 %22 %23
|
||||
%22 = OpLabel
|
||||
OpKill
|
||||
%23 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<CCPPass>(spv_asm, true);
|
||||
}
|
||||
|
||||
TEST_F(CCPTest, SSAWebCycles) {
|
||||
// Test reduced from https://github.com/KhronosGroup/SPIRV-Tools/issues/1159
|
||||
// When there is a cycle in the SSA def-use web, the propagator was getting
|
||||
// into an infinite loop. SSA edges for Phi instructions should not be
|
||||
// added to the edges to simulate.
|
||||
const std::string spv_asm = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %main "main"
|
||||
OpExecutionMode %main OriginUpperLeft
|
||||
OpSource GLSL 450
|
||||
OpName %main "main"
|
||||
%void = OpTypeVoid
|
||||
%3 = OpTypeFunction %void
|
||||
%int = OpTypeInt 32 1
|
||||
%_ptr_Function_int = OpTypePointer Function %int
|
||||
%int_0 = OpConstant %int 0
|
||||
%int_4 = OpConstant %int 4
|
||||
%bool = OpTypeBool
|
||||
%int_1 = OpConstant %int 1
|
||||
%_ptr_Output_int = OpTypePointer Output %int
|
||||
%main = OpFunction %void None %3
|
||||
%5 = OpLabel
|
||||
OpBranch %11
|
||||
%11 = OpLabel
|
||||
%29 = OpPhi %int %int_0 %5 %22 %14
|
||||
%30 = OpPhi %int %int_0 %5 %25 %14
|
||||
OpLoopMerge %13 %14 None
|
||||
OpBranch %15
|
||||
%15 = OpLabel
|
||||
%19 = OpSLessThan %bool %30 %int_4
|
||||
; CHECK: OpBranchConditional %true {{%\d+}} {{%\d+}}
|
||||
OpBranchConditional %19 %12 %13
|
||||
%12 = OpLabel
|
||||
; CHECK: OpIAdd %int %int_0 %int_0
|
||||
%22 = OpIAdd %int %29 %30
|
||||
OpBranch %14
|
||||
%14 = OpLabel
|
||||
; CHECK: OpPhi %int %int_0 {{%\d+}}
|
||||
%25 = OpPhi %int %30 %12
|
||||
OpBranch %11
|
||||
%13 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
|
||||
SinglePassRunAndMatch<CCPPass>(spv_asm, true);
|
||||
}
|
||||
|
||||
TEST_F(CCPTest, LoopInductionVariables) {
|
||||
// Test reduced from https://github.com/KhronosGroup/SPIRV-Tools/issues/1143
|
||||
// We are failing to properly consider the induction variable for this loop
|
||||
// as Varying.
|
||||
const std::string spv_asm = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %main "main"
|
||||
OpExecutionMode %main OriginUpperLeft
|
||||
OpSource GLSL 430
|
||||
OpName %main "main"
|
||||
%void = OpTypeVoid
|
||||
%5 = OpTypeFunction %void
|
||||
%int = OpTypeInt 32 1
|
||||
%_ptr_Function_int = OpTypePointer Function %int
|
||||
%int_0 = OpConstant %int 0
|
||||
%int_10 = OpConstant %int 10
|
||||
%bool = OpTypeBool
|
||||
%int_1 = OpConstant %int 1
|
||||
%main = OpFunction %void None %5
|
||||
%12 = OpLabel
|
||||
OpBranch %13
|
||||
%13 = OpLabel
|
||||
|
||||
; This Phi should not have all constant arguments:
|
||||
; CHECK: [[phi_id:%\d+]] = OpPhi %int %int_0 {{%\d+}} {{%\d+}} {{%\d+}}
|
||||
%22 = OpPhi %int %int_0 %12 %21 %15
|
||||
OpLoopMerge %14 %15 None
|
||||
OpBranch %16
|
||||
%16 = OpLabel
|
||||
|
||||
; The Phi should never be considered to have the value %int_0.
|
||||
; CHECK: [[branch_selector:%\d+]] = OpSLessThan %bool [[phi_id]] %int_10
|
||||
%18 = OpSLessThan %bool %22 %int_10
|
||||
|
||||
; This conditional was wrongly converted into an always-true jump due to the
|
||||
; bad meet evaluation of %22.
|
||||
; CHECK: OpBranchConditional [[branch_selector]] {{%\d+}} {{%\d+}}
|
||||
OpBranchConditional %18 %19 %14
|
||||
%19 = OpLabel
|
||||
OpBranch %15
|
||||
%15 = OpLabel
|
||||
; CHECK: OpIAdd %int [[phi_id]] %int_1
|
||||
%21 = OpIAdd %int %22 %int_1
|
||||
OpBranch %13
|
||||
%14 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<CCPPass>(spv_asm, true);
|
||||
}
|
||||
|
||||
TEST_F(CCPTest, HandleCompositeWithUndef) {
|
||||
// Check to make sure that CCP does not crash when given a "constant" struct
|
||||
// with an undef. If at a later time CCP is enhanced to optimize this case,
|
||||
// it is not wrong.
|
||||
const std::string spv_asm = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %main "main"
|
||||
OpExecutionMode %main OriginUpperLeft
|
||||
OpSource HLSL 500
|
||||
OpName %main "main"
|
||||
%void = OpTypeVoid
|
||||
%4 = OpTypeFunction %void
|
||||
%int = OpTypeInt 32 1
|
||||
%bool = OpTypeBool
|
||||
%_struct_7 = OpTypeStruct %int %int
|
||||
%int_1 = OpConstant %int 1
|
||||
%9 = OpUndef %int
|
||||
%10 = OpConstantComposite %_struct_7 %int_1 %9
|
||||
%main = OpFunction %void None %4
|
||||
%11 = OpLabel
|
||||
%12 = OpCompositeExtract %int %10 0
|
||||
%13 = OpCopyObject %int %12
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
auto res = SinglePassRunToBinary<CCPPass>(spv_asm, true);
|
||||
EXPECT_EQ(std::get<1>(res), Pass::Status::SuccessWithoutChange);
|
||||
}
|
||||
|
||||
TEST_F(CCPTest, SkipSpecConstantInstrucitons) {
|
||||
const std::string spv_asm = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %main "main"
|
||||
OpExecutionMode %main OriginUpperLeft
|
||||
OpSource HLSL 500
|
||||
OpName %main "main"
|
||||
%void = OpTypeVoid
|
||||
%4 = OpTypeFunction %void
|
||||
%bool = OpTypeBool
|
||||
%10 = OpSpecConstantFalse %bool
|
||||
%main = OpFunction %void None %4
|
||||
%11 = OpLabel
|
||||
OpBranchConditional %10 %L1 %L2
|
||||
%L1 = OpLabel
|
||||
OpReturn
|
||||
%L2 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
auto res = SinglePassRunToBinary<CCPPass>(spv_asm, true);
|
||||
EXPECT_EQ(std::get<1>(res), Pass::Status::SuccessWithoutChange);
|
||||
}
|
||||
|
||||
TEST_F(CCPTest, UpdateSubsequentPhisToVarying) {
|
||||
const std::string text = R"(
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %func "func" %in
|
||||
OpExecutionMode %func OriginUpperLeft
|
||||
%void = OpTypeVoid
|
||||
%bool = OpTypeBool
|
||||
%int = OpTypeInt 32 1
|
||||
%false = OpConstantFalse %bool
|
||||
%int0 = OpConstant %int 0
|
||||
%int1 = OpConstant %int 1
|
||||
%int6 = OpConstant %int 6
|
||||
%int_ptr_Input = OpTypePointer Input %int
|
||||
%in = OpVariable %int_ptr_Input Input
|
||||
%undef = OpUndef %int
|
||||
%functy = OpTypeFunction %void
|
||||
%func = OpFunction %void None %functy
|
||||
%1 = OpLabel
|
||||
OpBranch %2
|
||||
%2 = OpLabel
|
||||
%outer_phi = OpPhi %int %int0 %1 %outer_add %15
|
||||
%cond1 = OpSLessThanEqual %bool %outer_phi %int6
|
||||
OpLoopMerge %3 %15 None
|
||||
OpBranchConditional %cond1 %4 %3
|
||||
%4 = OpLabel
|
||||
%ld = OpLoad %int %in
|
||||
%cond2 = OpSGreaterThanEqual %bool %int1 %ld
|
||||
OpSelectionMerge %10 None
|
||||
OpBranchConditional %cond2 %8 %9
|
||||
%8 = OpLabel
|
||||
OpBranch %10
|
||||
%9 = OpLabel
|
||||
OpBranch %10
|
||||
%10 = OpLabel
|
||||
%extra_phi = OpPhi %int %outer_phi %8 %outer_phi %9
|
||||
OpBranch %11
|
||||
%11 = OpLabel
|
||||
%inner_phi = OpPhi %int %int0 %10 %inner_add %13
|
||||
%cond3 = OpSLessThanEqual %bool %inner_phi %int6
|
||||
OpLoopMerge %14 %13 None
|
||||
OpBranchConditional %cond3 %12 %14
|
||||
%12 = OpLabel
|
||||
OpBranch %13
|
||||
%13 = OpLabel
|
||||
%inner_add = OpIAdd %int %inner_phi %int1
|
||||
OpBranch %11
|
||||
%14 = OpLabel
|
||||
OpBranch %15
|
||||
%15 = OpLabel
|
||||
%outer_add = OpIAdd %int %extra_phi %int1
|
||||
OpBranch %2
|
||||
%3 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
auto res = SinglePassRunToBinary<CCPPass>(text, true);
|
||||
EXPECT_EQ(std::get<1>(res), Pass::Status::SuccessWithoutChange);
|
||||
}
|
||||
|
||||
TEST_F(CCPTest, UndefInPhi) {
|
||||
const std::string text = R"(
|
||||
; CHECK: [[uint1:%\w+]] = OpConstant {{%\w+}} 1
|
||||
; CHECK: [[phi:%\w+]] = OpPhi
|
||||
; CHECK: OpIAdd {{%\w+}} [[phi]] [[uint1]]
|
||||
OpCapability Kernel
|
||||
OpCapability Linkage
|
||||
OpMemoryModel Logical OpenCL
|
||||
OpDecorate %1 LinkageAttributes "func" Export
|
||||
%void = OpTypeVoid
|
||||
%bool = OpTypeBool
|
||||
%uint = OpTypeInt 32 0
|
||||
%uint_0 = OpConstant %uint 0
|
||||
%uint_1 = OpConstant %uint 1
|
||||
%7 = OpUndef %uint
|
||||
%8 = OpTypeFunction %void %bool
|
||||
%1 = OpFunction %void None %8
|
||||
%9 = OpFunctionParameter %bool
|
||||
%10 = OpLabel
|
||||
OpBranchConditional %9 %11 %12
|
||||
%11 = OpLabel
|
||||
OpBranch %13
|
||||
%12 = OpLabel
|
||||
OpBranch %14
|
||||
%14 = OpLabel
|
||||
OpBranchConditional %9 %13 %15
|
||||
%15 = OpLabel
|
||||
OpBranch %13
|
||||
%13 = OpLabel
|
||||
%16 = OpPhi %uint %uint_0 %11 %7 %14 %uint_1 %15
|
||||
%17 = OpIAdd %uint %16 %uint_1
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<CCPPass>(text, true);
|
||||
}
|
||||
|
||||
// Just test to make sure the constant fold rules are being used. Will rely on
|
||||
// the folding test for specific testing of specific rules.
|
||||
TEST_F(CCPTest, UseConstantFoldingRules) {
|
||||
const std::string text = R"(
|
||||
; CHECK: [[float1:%\w+]] = OpConstant {{%\w+}} 1
|
||||
; CHECK: OpReturnValue [[float1]]
|
||||
OpCapability Shader
|
||||
OpCapability Linkage
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpDecorate %1 LinkageAttributes "func" Export
|
||||
%void = OpTypeVoid
|
||||
%bool = OpTypeBool
|
||||
%float = OpTypeFloat 32
|
||||
%float_0 = OpConstant %float 0
|
||||
%float_1 = OpConstant %float 1
|
||||
%8 = OpTypeFunction %float
|
||||
%1 = OpFunction %float None %8
|
||||
%10 = OpLabel
|
||||
%17 = OpFAdd %float %float_0 %float_1
|
||||
OpReturnValue %17
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<CCPPass>(text, true);
|
||||
}
|
||||
|
||||
// Test for #1300. Previously value for %5 would not settle during simulation.
|
||||
TEST_F(CCPTest, SettlePhiLatticeValue) {
|
||||
const std::string text = R"(
|
||||
OpCapability Kernel
|
||||
OpCapability Linkage
|
||||
OpMemoryModel Logical OpenCL
|
||||
OpDecorate %func LinkageAttributes "func" Export
|
||||
%void = OpTypeVoid
|
||||
%bool = OpTypeBool
|
||||
%true = OpConstantTrue %bool
|
||||
%false = OpConstantFalse %bool
|
||||
%functy = OpTypeFunction %void
|
||||
%func = OpFunction %void None %functy
|
||||
%1 = OpLabel
|
||||
OpBranchConditional %true %2 %3
|
||||
%3 = OpLabel
|
||||
OpBranch %2
|
||||
%2 = OpLabel
|
||||
%5 = OpPhi %bool %true %1 %false %3
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
|
||||
SinglePassRunToBinary<CCPPass>(text, true);
|
||||
}
|
||||
|
||||
TEST_F(CCPTest, NullBranchCondition) {
|
||||
const std::string text = R"(
|
||||
; CHECK: [[int1:%\w+]] = OpConstant {{%\w+}} 1
|
||||
; CHECK: [[int2:%\w+]] = OpConstant {{%\w+}} 2
|
||||
; CHECK: OpIAdd {{%\w+}} [[int1]] [[int2]]
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %func "func"
|
||||
OpExecutionMode %func OriginUpperLeft
|
||||
%void = OpTypeVoid
|
||||
%bool = OpTypeBool
|
||||
%int = OpTypeInt 32 1
|
||||
%null = OpConstantNull %bool
|
||||
%int_1 = OpConstant %int 1
|
||||
%int_2 = OpConstant %int 2
|
||||
%functy = OpTypeFunction %void
|
||||
%func = OpFunction %void None %functy
|
||||
%1 = OpLabel
|
||||
OpSelectionMerge %2 None
|
||||
OpBranchConditional %null %2 %3
|
||||
%3 = OpLabel
|
||||
OpBranch %2
|
||||
%2 = OpLabel
|
||||
%phi = OpPhi %int %int_1 %1 %int_2 %3
|
||||
%add = OpIAdd %int %int_1 %phi
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<CCPPass>(text, true);
|
||||
}
|
||||
|
||||
TEST_F(CCPTest, UndefBranchCondition) {
|
||||
const std::string text = R"(
|
||||
; CHECK: [[int1:%\w+]] = OpConstant {{%\w+}} 1
|
||||
; CHECK: [[phi:%\w+]] = OpPhi
|
||||
; CHECK: OpIAdd {{%\w+}} [[int1]] [[phi]]
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %func "func"
|
||||
OpExecutionMode %func OriginUpperLeft
|
||||
%void = OpTypeVoid
|
||||
%bool = OpTypeBool
|
||||
%int = OpTypeInt 32 1
|
||||
%undef = OpUndef %bool
|
||||
%int_1 = OpConstant %int 1
|
||||
%int_2 = OpConstant %int 2
|
||||
%functy = OpTypeFunction %void
|
||||
%func = OpFunction %void None %functy
|
||||
%1 = OpLabel
|
||||
OpSelectionMerge %2 None
|
||||
OpBranchConditional %undef %2 %3
|
||||
%3 = OpLabel
|
||||
OpBranch %2
|
||||
%2 = OpLabel
|
||||
%phi = OpPhi %int %int_1 %1 %int_2 %3
|
||||
%add = OpIAdd %int %int_1 %phi
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<CCPPass>(text, true);
|
||||
}
|
||||
|
||||
TEST_F(CCPTest, NullSwitchCondition) {
|
||||
const std::string text = R"(
|
||||
; CHECK: [[int1:%\w+]] = OpConstant {{%\w+}} 1
|
||||
; CHECK: [[int2:%\w+]] = OpConstant {{%\w+}} 2
|
||||
; CHECK: OpIAdd {{%\w+}} [[int1]] [[int2]]
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %func "func"
|
||||
OpExecutionMode %func OriginUpperLeft
|
||||
%void = OpTypeVoid
|
||||
%int = OpTypeInt 32 1
|
||||
%null = OpConstantNull %int
|
||||
%int_1 = OpConstant %int 1
|
||||
%int_2 = OpConstant %int 2
|
||||
%functy = OpTypeFunction %void
|
||||
%func = OpFunction %void None %functy
|
||||
%1 = OpLabel
|
||||
OpSelectionMerge %2 None
|
||||
OpSwitch %null %2 0 %3
|
||||
%3 = OpLabel
|
||||
OpBranch %2
|
||||
%2 = OpLabel
|
||||
%phi = OpPhi %int %int_1 %1 %int_2 %3
|
||||
%add = OpIAdd %int %int_1 %phi
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<CCPPass>(text, true);
|
||||
}
|
||||
|
||||
TEST_F(CCPTest, UndefSwitchCondition) {
|
||||
const std::string text = R"(
|
||||
; CHECK: [[int1:%\w+]] = OpConstant {{%\w+}} 1
|
||||
; CHECK: [[phi:%\w+]] = OpPhi
|
||||
; CHECK: OpIAdd {{%\w+}} [[int1]] [[phi]]
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %func "func"
|
||||
OpExecutionMode %func OriginUpperLeft
|
||||
%void = OpTypeVoid
|
||||
%int = OpTypeInt 32 1
|
||||
%undef = OpUndef %int
|
||||
%int_1 = OpConstant %int 1
|
||||
%int_2 = OpConstant %int 2
|
||||
%functy = OpTypeFunction %void
|
||||
%func = OpFunction %void None %functy
|
||||
%1 = OpLabel
|
||||
OpSelectionMerge %2 None
|
||||
OpSwitch %undef %2 0 %3
|
||||
%3 = OpLabel
|
||||
OpBranch %2
|
||||
%2 = OpLabel
|
||||
%phi = OpPhi %int %int_1 %1 %int_2 %3
|
||||
%add = OpIAdd %int %int_1 %phi
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<CCPPass>(text, true);
|
||||
}
|
||||
|
||||
// Test for #1361.
|
||||
TEST_F(CCPTest, CompositeConstructOfGlobalValue) {
|
||||
const std::string text = R"(
|
||||
; CHECK: [[phi:%\w+]] = OpPhi
|
||||
; CHECK-NEXT: OpCompositeExtract {{%\w+}} [[phi]] 0
|
||||
OpCapability Shader
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %func "func" %in
|
||||
OpExecutionMode %func OriginUpperLeft
|
||||
%void = OpTypeVoid
|
||||
%int = OpTypeInt 32 1
|
||||
%bool = OpTypeBool
|
||||
%functy = OpTypeFunction %void
|
||||
%ptr_int_Input = OpTypePointer Input %int
|
||||
%in = OpVariable %ptr_int_Input Input
|
||||
%struct = OpTypeStruct %ptr_int_Input %ptr_int_Input
|
||||
%struct_null = OpConstantNull %struct
|
||||
%func = OpFunction %void None %functy
|
||||
%1 = OpLabel
|
||||
OpBranch %2
|
||||
%2 = OpLabel
|
||||
%phi = OpPhi %struct %struct_null %1 %5 %4
|
||||
%extract = OpCompositeExtract %ptr_int_Input %phi 0
|
||||
OpLoopMerge %3 %4 None
|
||||
OpBranch %4
|
||||
%4 = OpLabel
|
||||
%5 = OpCompositeConstruct %struct %in %in
|
||||
OpBranch %2
|
||||
%3 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<CCPPass>(text, true);
|
||||
}
|
||||
|
||||
TEST_F(CCPTest, FoldWithDecoration) {
|
||||
const std::string text = R"(
|
||||
; CHECK: OpCapability
|
||||
; CHECK-NOT: OpDecorate
|
||||
; CHECK: OpFunctionEnd
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %2 "main"
|
||||
OpExecutionMode %2 OriginUpperLeft
|
||||
OpSource ESSL 310
|
||||
OpDecorate %3 RelaxedPrecision
|
||||
%void = OpTypeVoid
|
||||
%5 = OpTypeFunction %void
|
||||
%float = OpTypeFloat 32
|
||||
%v3float = OpTypeVector %float 3
|
||||
%float_0 = OpConstant %float 0
|
||||
%v4float = OpTypeVector %float 4
|
||||
%10 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
|
||||
%2 = OpFunction %void None %5
|
||||
%11 = OpLabel
|
||||
%3 = OpVectorShuffle %v3float %10 %10 0 1 2
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndMatch<CCPPass>(text, true);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace opt
|
||||
} // namespace spvtools
|
||||
456
3rdparty/spirv-tools/test/opt/cfg_cleanup_test.cpp
vendored
456
3rdparty/spirv-tools/test/opt/cfg_cleanup_test.cpp
vendored
@@ -1,456 +0,0 @@
|
||||
// Copyright (c) 2017 Google Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "test/opt/pass_fixture.h"
|
||||
#include "test/opt/pass_utils.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace opt {
|
||||
namespace {
|
||||
|
||||
using CFGCleanupTest = PassTest<::testing::Test>;
|
||||
|
||||
TEST_F(CFGCleanupTest, RemoveUnreachableBlocks) {
|
||||
const std::string declarations = R"(OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %main "main" %inf %outf4
|
||||
OpExecutionMode %main OriginUpperLeft
|
||||
OpSource GLSL 450
|
||||
OpName %main "main"
|
||||
OpName %inf "inf"
|
||||
OpName %outf4 "outf4"
|
||||
OpDecorate %inf Location 0
|
||||
OpDecorate %outf4 Location 0
|
||||
%void = OpTypeVoid
|
||||
%6 = OpTypeFunction %void
|
||||
%float = OpTypeFloat 32
|
||||
%_ptr_Input_float = OpTypePointer Input %float
|
||||
%inf = OpVariable %_ptr_Input_float Input
|
||||
%float_2 = OpConstant %float 2
|
||||
%bool = OpTypeBool
|
||||
%v4float = OpTypeVector %float 4
|
||||
%_ptr_Output_v4float = OpTypePointer Output %v4float
|
||||
%outf4 = OpVariable %_ptr_Output_v4float Output
|
||||
%float_n0_5 = OpConstant %float -0.5
|
||||
)";
|
||||
|
||||
const std::string body_before = R"(%main = OpFunction %void None %6
|
||||
%14 = OpLabel
|
||||
OpBranch %18
|
||||
%19 = OpLabel
|
||||
%20 = OpLoad %float %inf
|
||||
%21 = OpCompositeConstruct %v4float %20 %20 %20 %20
|
||||
OpStore %outf4 %21
|
||||
OpBranch %17
|
||||
%18 = OpLabel
|
||||
%22 = OpLoad %float %inf
|
||||
%23 = OpFAdd %float %22 %float_n0_5
|
||||
%24 = OpCompositeConstruct %v4float %23 %23 %23 %23
|
||||
OpStore %outf4 %24
|
||||
OpBranch %17
|
||||
%17 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const std::string body_after = R"(%main = OpFunction %void None %6
|
||||
%14 = OpLabel
|
||||
OpBranch %15
|
||||
%15 = OpLabel
|
||||
%20 = OpLoad %float %inf
|
||||
%21 = OpFAdd %float %20 %float_n0_5
|
||||
%22 = OpCompositeConstruct %v4float %21 %21 %21 %21
|
||||
OpStore %outf4 %22
|
||||
OpBranch %19
|
||||
%19 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndCheck<CFGCleanupPass>(declarations + body_before,
|
||||
declarations + body_after, true, true);
|
||||
}
|
||||
|
||||
TEST_F(CFGCleanupTest, RemoveDecorations) {
|
||||
const std::string before = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %main "main"
|
||||
OpExecutionMode %main OriginUpperLeft
|
||||
OpName %main "main"
|
||||
OpName %x "x"
|
||||
OpName %dead "dead"
|
||||
OpDecorate %x RelaxedPrecision
|
||||
OpDecorate %dead RelaxedPrecision
|
||||
%void = OpTypeVoid
|
||||
%6 = OpTypeFunction %void
|
||||
%float = OpTypeFloat 32
|
||||
%_ptr_Function_float = OpTypePointer Function %float
|
||||
%float_2 = OpConstant %float 2
|
||||
%float_4 = OpConstant %float 4
|
||||
|
||||
%main = OpFunction %void None %6
|
||||
%14 = OpLabel
|
||||
%x = OpVariable %_ptr_Function_float Function
|
||||
OpBranch %18
|
||||
%19 = OpLabel
|
||||
%dead = OpVariable %_ptr_Function_float Function
|
||||
OpStore %dead %float_2
|
||||
OpBranch %17
|
||||
%18 = OpLabel
|
||||
OpStore %x %float_4
|
||||
OpBranch %17
|
||||
%17 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const std::string after = R"(OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %main "main"
|
||||
OpExecutionMode %main OriginUpperLeft
|
||||
OpName %main "main"
|
||||
OpName %x "x"
|
||||
OpDecorate %x RelaxedPrecision
|
||||
%void = OpTypeVoid
|
||||
%6 = OpTypeFunction %void
|
||||
%float = OpTypeFloat 32
|
||||
%_ptr_Function_float = OpTypePointer Function %float
|
||||
%float_2 = OpConstant %float 2
|
||||
%float_4 = OpConstant %float 4
|
||||
%main = OpFunction %void None %6
|
||||
%11 = OpLabel
|
||||
%x = OpVariable %_ptr_Function_float Function
|
||||
OpBranch %12
|
||||
%12 = OpLabel
|
||||
OpStore %x %float_4
|
||||
OpBranch %14
|
||||
%14 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndCheck<CFGCleanupPass>(before, after, true, true);
|
||||
}
|
||||
|
||||
TEST_F(CFGCleanupTest, UpdatePhis) {
|
||||
const std::string before = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %main "main" %y %outparm
|
||||
OpExecutionMode %main OriginUpperLeft
|
||||
OpName %main "main"
|
||||
OpName %y "y"
|
||||
OpName %outparm "outparm"
|
||||
OpDecorate %y Flat
|
||||
OpDecorate %y Location 0
|
||||
OpDecorate %outparm Location 0
|
||||
%void = OpTypeVoid
|
||||
%3 = OpTypeFunction %void
|
||||
%int = OpTypeInt 32 1
|
||||
%_ptr_Function_int = OpTypePointer Function %int
|
||||
%_ptr_Input_int = OpTypePointer Input %int
|
||||
%y = OpVariable %_ptr_Input_int Input
|
||||
%int_10 = OpConstant %int 10
|
||||
%bool = OpTypeBool
|
||||
%int_42 = OpConstant %int 42
|
||||
%int_23 = OpConstant %int 23
|
||||
%int_5 = OpConstant %int 5
|
||||
%_ptr_Output_int = OpTypePointer Output %int
|
||||
%outparm = OpVariable %_ptr_Output_int Output
|
||||
%main = OpFunction %void None %3
|
||||
%5 = OpLabel
|
||||
%11 = OpLoad %int %y
|
||||
OpBranch %21
|
||||
%16 = OpLabel
|
||||
%20 = OpIAdd %int %11 %int_42
|
||||
OpBranch %17
|
||||
%21 = OpLabel
|
||||
%24 = OpISub %int %11 %int_23
|
||||
OpBranch %17
|
||||
%17 = OpLabel
|
||||
%31 = OpPhi %int %20 %16 %24 %21
|
||||
%27 = OpIAdd %int %31 %int_5
|
||||
OpStore %outparm %27
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
const std::string after = R"(OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %main "main" %y %outparm
|
||||
OpExecutionMode %main OriginUpperLeft
|
||||
OpName %main "main"
|
||||
OpName %y "y"
|
||||
OpName %outparm "outparm"
|
||||
OpDecorate %y Flat
|
||||
OpDecorate %y Location 0
|
||||
OpDecorate %outparm Location 0
|
||||
%void = OpTypeVoid
|
||||
%6 = OpTypeFunction %void
|
||||
%int = OpTypeInt 32 1
|
||||
%_ptr_Function_int = OpTypePointer Function %int
|
||||
%_ptr_Input_int = OpTypePointer Input %int
|
||||
%y = OpVariable %_ptr_Input_int Input
|
||||
%int_10 = OpConstant %int 10
|
||||
%bool = OpTypeBool
|
||||
%int_42 = OpConstant %int 42
|
||||
%int_23 = OpConstant %int 23
|
||||
%int_5 = OpConstant %int 5
|
||||
%_ptr_Output_int = OpTypePointer Output %int
|
||||
%outparm = OpVariable %_ptr_Output_int Output
|
||||
%main = OpFunction %void None %6
|
||||
%16 = OpLabel
|
||||
%17 = OpLoad %int %y
|
||||
OpBranch %18
|
||||
%18 = OpLabel
|
||||
%22 = OpISub %int %17 %int_23
|
||||
OpBranch %21
|
||||
%21 = OpLabel
|
||||
%23 = OpPhi %int %22 %18
|
||||
%24 = OpIAdd %int %23 %int_5
|
||||
OpStore %outparm %24
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndCheck<CFGCleanupPass>(before, after, true, true);
|
||||
}
|
||||
|
||||
TEST_F(CFGCleanupTest, RemoveNamedLabels) {
|
||||
const std::string before = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Vertex %main "main"
|
||||
OpSource GLSL 430
|
||||
OpName %main "main"
|
||||
OpName %dead "dead"
|
||||
%void = OpTypeVoid
|
||||
%5 = OpTypeFunction %void
|
||||
%main = OpFunction %void None %5
|
||||
%6 = OpLabel
|
||||
OpReturn
|
||||
%dead = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd)";
|
||||
|
||||
const std::string after = R"(OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Vertex %main "main"
|
||||
OpSource GLSL 430
|
||||
OpName %main "main"
|
||||
%void = OpTypeVoid
|
||||
%5 = OpTypeFunction %void
|
||||
%main = OpFunction %void None %5
|
||||
%6 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndCheck<CFGCleanupPass>(before, after, true, true);
|
||||
}
|
||||
|
||||
TEST_F(CFGCleanupTest, RemovePhiArgsFromFarBlocks) {
|
||||
const std::string before = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %main "main" %y %outparm
|
||||
OpExecutionMode %main OriginUpperLeft
|
||||
OpName %main "main"
|
||||
OpName %y "y"
|
||||
OpName %outparm "outparm"
|
||||
OpDecorate %y Flat
|
||||
OpDecorate %y Location 0
|
||||
OpDecorate %outparm Location 0
|
||||
%void = OpTypeVoid
|
||||
%3 = OpTypeFunction %void
|
||||
%int = OpTypeInt 32 1
|
||||
%_ptr_Function_int = OpTypePointer Function %int
|
||||
%_ptr_Input_int = OpTypePointer Input %int
|
||||
%y = OpVariable %_ptr_Input_int Input
|
||||
%int_42 = OpConstant %int 42
|
||||
%_ptr_Output_int = OpTypePointer Output %int
|
||||
%outparm = OpVariable %_ptr_Output_int Output
|
||||
%int_14 = OpConstant %int 14
|
||||
%int_15 = OpConstant %int 15
|
||||
%int_5 = OpConstant %int 5
|
||||
%main = OpFunction %void None %3
|
||||
%5 = OpLabel
|
||||
OpBranch %40
|
||||
%41 = OpLabel
|
||||
%11 = OpLoad %int %y
|
||||
OpBranch %40
|
||||
%40 = OpLabel
|
||||
%12 = OpLoad %int %y
|
||||
OpSelectionMerge %16 None
|
||||
OpSwitch %12 %16 10 %13 13 %14 18 %15
|
||||
%13 = OpLabel
|
||||
OpBranch %16
|
||||
%14 = OpLabel
|
||||
OpStore %outparm %int_14
|
||||
OpBranch %16
|
||||
%15 = OpLabel
|
||||
OpStore %outparm %int_15
|
||||
OpBranch %16
|
||||
%16 = OpLabel
|
||||
%30 = OpPhi %int %11 %40 %int_42 %13 %11 %14 %11 %15
|
||||
%28 = OpIAdd %int %30 %int_5
|
||||
OpStore %outparm %28
|
||||
OpReturn
|
||||
OpFunctionEnd)";
|
||||
|
||||
const std::string after = R"(OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %main "main" %y %outparm
|
||||
OpExecutionMode %main OriginUpperLeft
|
||||
OpName %main "main"
|
||||
OpName %y "y"
|
||||
OpName %outparm "outparm"
|
||||
OpDecorate %y Flat
|
||||
OpDecorate %y Location 0
|
||||
OpDecorate %outparm Location 0
|
||||
%void = OpTypeVoid
|
||||
%6 = OpTypeFunction %void
|
||||
%int = OpTypeInt 32 1
|
||||
%_ptr_Function_int = OpTypePointer Function %int
|
||||
%_ptr_Input_int = OpTypePointer Input %int
|
||||
%y = OpVariable %_ptr_Input_int Input
|
||||
%int_42 = OpConstant %int 42
|
||||
%_ptr_Output_int = OpTypePointer Output %int
|
||||
%outparm = OpVariable %_ptr_Output_int Output
|
||||
%int_14 = OpConstant %int 14
|
||||
%int_15 = OpConstant %int 15
|
||||
%int_5 = OpConstant %int 5
|
||||
%26 = OpUndef %int
|
||||
%main = OpFunction %void None %6
|
||||
%15 = OpLabel
|
||||
OpBranch %16
|
||||
%16 = OpLabel
|
||||
%19 = OpLoad %int %y
|
||||
OpSelectionMerge %20 None
|
||||
OpSwitch %19 %20 10 %21 13 %22 18 %23
|
||||
%21 = OpLabel
|
||||
OpBranch %20
|
||||
%22 = OpLabel
|
||||
OpStore %outparm %int_14
|
||||
OpBranch %20
|
||||
%23 = OpLabel
|
||||
OpStore %outparm %int_15
|
||||
OpBranch %20
|
||||
%20 = OpLabel
|
||||
%24 = OpPhi %int %26 %16 %int_42 %21 %26 %22 %26 %23
|
||||
%25 = OpIAdd %int %24 %int_5
|
||||
OpStore %outparm %25
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndCheck<CFGCleanupPass>(before, after, true, true);
|
||||
}
|
||||
|
||||
TEST_F(CFGCleanupTest, RemovePhiConstantArgs) {
|
||||
const std::string before = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %main "main" %y %outparm
|
||||
OpExecutionMode %main OriginUpperLeft
|
||||
OpName %main "main"
|
||||
OpName %y "y"
|
||||
OpName %outparm "outparm"
|
||||
OpDecorate %y Flat
|
||||
OpDecorate %y Location 0
|
||||
OpDecorate %outparm Location 0
|
||||
%void = OpTypeVoid
|
||||
%3 = OpTypeFunction %void
|
||||
%int = OpTypeInt 32 1
|
||||
%_ptr_Input_int = OpTypePointer Input %int
|
||||
%y = OpVariable %_ptr_Input_int Input
|
||||
%int_10 = OpConstant %int 10
|
||||
%bool = OpTypeBool
|
||||
%_ptr_Function_int = OpTypePointer Function %int
|
||||
%int_23 = OpConstant %int 23
|
||||
%int_5 = OpConstant %int 5
|
||||
%_ptr_Output_int = OpTypePointer Output %int
|
||||
%outparm = OpVariable %_ptr_Output_int Output
|
||||
%24 = OpUndef %int
|
||||
%main = OpFunction %void None %3
|
||||
%5 = OpLabel
|
||||
OpBranch %14
|
||||
%40 = OpLabel
|
||||
%9 = OpLoad %int %y
|
||||
%12 = OpSGreaterThan %bool %9 %int_10
|
||||
OpSelectionMerge %14 None
|
||||
OpBranchConditional %12 %13 %14
|
||||
%13 = OpLabel
|
||||
OpBranch %14
|
||||
%14 = OpLabel
|
||||
%25 = OpPhi %int %24 %5 %int_23 %13
|
||||
%20 = OpIAdd %int %25 %int_5
|
||||
OpStore %outparm %20
|
||||
OpReturn
|
||||
OpFunctionEnd)";
|
||||
|
||||
const std::string after = R"(OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %main "main" %y %outparm
|
||||
OpExecutionMode %main OriginUpperLeft
|
||||
OpName %main "main"
|
||||
OpName %y "y"
|
||||
OpName %outparm "outparm"
|
||||
OpDecorate %y Flat
|
||||
OpDecorate %y Location 0
|
||||
OpDecorate %outparm Location 0
|
||||
%void = OpTypeVoid
|
||||
%6 = OpTypeFunction %void
|
||||
%int = OpTypeInt 32 1
|
||||
%_ptr_Input_int = OpTypePointer Input %int
|
||||
%y = OpVariable %_ptr_Input_int Input
|
||||
%int_10 = OpConstant %int 10
|
||||
%bool = OpTypeBool
|
||||
%_ptr_Function_int = OpTypePointer Function %int
|
||||
%int_23 = OpConstant %int 23
|
||||
%int_5 = OpConstant %int 5
|
||||
%_ptr_Output_int = OpTypePointer Output %int
|
||||
%outparm = OpVariable %_ptr_Output_int Output
|
||||
%15 = OpUndef %int
|
||||
%main = OpFunction %void None %6
|
||||
%16 = OpLabel
|
||||
OpBranch %17
|
||||
%17 = OpLabel
|
||||
%22 = OpPhi %int %15 %16
|
||||
%23 = OpIAdd %int %22 %int_5
|
||||
OpStore %outparm %23
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
SinglePassRunAndCheck<CFGCleanupPass>(before, after, true, true);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace opt
|
||||
} // namespace spvtools
|
||||
205
3rdparty/spirv-tools/test/opt/cfg_test.cpp
vendored
205
3rdparty/spirv-tools/test/opt/cfg_test.cpp
vendored
@@ -1,205 +0,0 @@
|
||||
// Copyright (c) 2019 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "source/opt/ir_context.h"
|
||||
#include "test/opt/pass_fixture.h"
|
||||
#include "test/opt/pass_utils.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace opt {
|
||||
namespace {
|
||||
|
||||
using ::testing::ContainerEq;
|
||||
|
||||
using CFGTest = PassTest<::testing::Test>;
|
||||
|
||||
TEST_F(CFGTest, ForEachBlockInPostOrderIf) {
|
||||
const std::string test = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Vertex %main "main"
|
||||
OpName %main "main"
|
||||
%bool = OpTypeBool
|
||||
%true = OpConstantTrue %bool
|
||||
%void = OpTypeVoid
|
||||
%4 = OpTypeFunction %void
|
||||
%uint = OpTypeInt 32 0
|
||||
%5 = OpConstant %uint 5
|
||||
%main = OpFunction %void None %4
|
||||
%8 = OpLabel
|
||||
OpSelectionMerge %10 None
|
||||
OpBranchConditional %true %9 %10
|
||||
%9 = OpLabel
|
||||
OpBranch %10
|
||||
%10 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
std::unique_ptr<IRContext> context =
|
||||
BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, test,
|
||||
SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
|
||||
ASSERT_NE(nullptr, context);
|
||||
|
||||
CFG* cfg = context->cfg();
|
||||
Module* module = context->module();
|
||||
Function* function = &*module->begin();
|
||||
std::vector<uint32_t> order;
|
||||
cfg->ForEachBlockInPostOrder(&*function->begin(), [&order](BasicBlock* bb) {
|
||||
order.push_back(bb->id());
|
||||
});
|
||||
|
||||
std::vector<uint32_t> expected_result = {10, 9, 8};
|
||||
EXPECT_THAT(order, ContainerEq(expected_result));
|
||||
}
|
||||
|
||||
TEST_F(CFGTest, ForEachBlockInPostOrderLoop) {
|
||||
const std::string test = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Vertex %main "main"
|
||||
OpName %main "main"
|
||||
%bool = OpTypeBool
|
||||
%true = OpConstantTrue %bool
|
||||
%void = OpTypeVoid
|
||||
%4 = OpTypeFunction %void
|
||||
%uint = OpTypeInt 32 0
|
||||
%5 = OpConstant %uint 5
|
||||
%main = OpFunction %void None %4
|
||||
%8 = OpLabel
|
||||
OpBranch %9
|
||||
%9 = OpLabel
|
||||
OpLoopMerge %11 %10 None
|
||||
OpBranchConditional %true %11 %10
|
||||
%10 = OpLabel
|
||||
OpBranch %9
|
||||
%11 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
std::unique_ptr<IRContext> context =
|
||||
BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, test,
|
||||
SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
|
||||
ASSERT_NE(nullptr, context);
|
||||
|
||||
CFG* cfg = context->cfg();
|
||||
Module* module = context->module();
|
||||
Function* function = &*module->begin();
|
||||
std::vector<uint32_t> order;
|
||||
cfg->ForEachBlockInPostOrder(&*function->begin(), [&order](BasicBlock* bb) {
|
||||
order.push_back(bb->id());
|
||||
});
|
||||
|
||||
std::vector<uint32_t> expected_result1 = {10, 11, 9, 8};
|
||||
std::vector<uint32_t> expected_result2 = {11, 10, 9, 8};
|
||||
EXPECT_THAT(order, AnyOf(ContainerEq(expected_result1),
|
||||
ContainerEq(expected_result2)));
|
||||
}
|
||||
|
||||
TEST_F(CFGTest, ForEachBlockInReversePostOrderIf) {
|
||||
const std::string test = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Vertex %main "main"
|
||||
OpName %main "main"
|
||||
%bool = OpTypeBool
|
||||
%true = OpConstantTrue %bool
|
||||
%void = OpTypeVoid
|
||||
%4 = OpTypeFunction %void
|
||||
%uint = OpTypeInt 32 0
|
||||
%5 = OpConstant %uint 5
|
||||
%main = OpFunction %void None %4
|
||||
%8 = OpLabel
|
||||
OpSelectionMerge %10 None
|
||||
OpBranchConditional %true %9 %10
|
||||
%9 = OpLabel
|
||||
OpBranch %10
|
||||
%10 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
std::unique_ptr<IRContext> context =
|
||||
BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, test,
|
||||
SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
|
||||
ASSERT_NE(nullptr, context);
|
||||
|
||||
CFG* cfg = context->cfg();
|
||||
Module* module = context->module();
|
||||
Function* function = &*module->begin();
|
||||
std::vector<uint32_t> order;
|
||||
cfg->ForEachBlockInReversePostOrder(
|
||||
&*function->begin(),
|
||||
[&order](BasicBlock* bb) { order.push_back(bb->id()); });
|
||||
|
||||
std::vector<uint32_t> expected_result = {8, 9, 10};
|
||||
EXPECT_THAT(order, ContainerEq(expected_result));
|
||||
}
|
||||
|
||||
TEST_F(CFGTest, ForEachBlockInReversePostOrderLoop) {
|
||||
const std::string test = R"(
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Vertex %main "main"
|
||||
OpName %main "main"
|
||||
%bool = OpTypeBool
|
||||
%true = OpConstantTrue %bool
|
||||
%void = OpTypeVoid
|
||||
%4 = OpTypeFunction %void
|
||||
%uint = OpTypeInt 32 0
|
||||
%5 = OpConstant %uint 5
|
||||
%main = OpFunction %void None %4
|
||||
%8 = OpLabel
|
||||
OpBranch %9
|
||||
%9 = OpLabel
|
||||
OpLoopMerge %11 %10 None
|
||||
OpBranchConditional %true %11 %10
|
||||
%10 = OpLabel
|
||||
OpBranch %9
|
||||
%11 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
|
||||
std::unique_ptr<IRContext> context =
|
||||
BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, test,
|
||||
SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
|
||||
ASSERT_NE(nullptr, context);
|
||||
|
||||
CFG* cfg = context->cfg();
|
||||
Module* module = context->module();
|
||||
Function* function = &*module->begin();
|
||||
std::vector<uint32_t> order;
|
||||
cfg->ForEachBlockInReversePostOrder(
|
||||
&*function->begin(),
|
||||
[&order](BasicBlock* bb) { order.push_back(bb->id()); });
|
||||
|
||||
std::vector<uint32_t> expected_result1 = {8, 9, 10, 11};
|
||||
std::vector<uint32_t> expected_result2 = {8, 9, 11, 10};
|
||||
EXPECT_THAT(order, AnyOf(ContainerEq(expected_result1),
|
||||
ContainerEq(expected_result2)));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace opt
|
||||
} // namespace spvtools
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user