From d91afd8de27a064f938a196fdea2ace234971faa Mon Sep 17 00:00:00 2001 From: Vasyl Teliman Date: Fri, 2 Oct 2020 10:51:54 +0300 Subject: [PATCH] spirv-fuzz: Refactor fact manager tests (#3879) Fixes #3698. --- test/fuzz/CMakeLists.txt | 5 +- .../constant_uniform_facts_test.cpp | 784 ++++++++ ...ata_synonym_and_id_equation_facts_test.cpp | 644 +++++++ .../fact_manager/dead_block_facts_test.cpp | 69 + .../irrelevant_value_facts_test.cpp | 170 ++ test/fuzz/fact_manager_test.cpp | 1595 ----------------- 6 files changed, 1671 insertions(+), 1596 deletions(-) create mode 100644 test/fuzz/fact_manager/constant_uniform_facts_test.cpp create mode 100644 test/fuzz/fact_manager/data_synonym_and_id_equation_facts_test.cpp create mode 100644 test/fuzz/fact_manager/dead_block_facts_test.cpp create mode 100644 test/fuzz/fact_manager/irrelevant_value_facts_test.cpp delete mode 100644 test/fuzz/fact_manager_test.cpp diff --git a/test/fuzz/CMakeLists.txt b/test/fuzz/CMakeLists.txt index 89ffa590c..7d085066b 100644 --- a/test/fuzz/CMakeLists.txt +++ b/test/fuzz/CMakeLists.txt @@ -21,7 +21,10 @@ if (${SPIRV_BUILD_FUZZER}) comparator_deep_blocks_first_test.cpp data_synonym_transformation_test.cpp equivalence_relation_test.cpp - fact_manager_test.cpp + fact_manager/constant_uniform_facts_test.cpp + fact_manager/data_synonym_and_id_equation_facts_test.cpp + fact_manager/dead_block_facts_test.cpp + fact_manager/irrelevant_value_facts_test.cpp fuzz_test_util.cpp fuzzer_pass_add_opphi_synonyms_test.cpp fuzzer_pass_construct_composites_test.cpp diff --git a/test/fuzz/fact_manager/constant_uniform_facts_test.cpp b/test/fuzz/fact_manager/constant_uniform_facts_test.cpp new file mode 100644 index 000000000..a6a49be17 --- /dev/null +++ b/test/fuzz/fact_manager/constant_uniform_facts_test.cpp @@ -0,0 +1,784 @@ +// 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 + +#include "source/fuzz/fact_manager/fact_manager.h" +#include "source/fuzz/uniform_buffer_element_descriptor.h" +#include "test/fuzz/fuzz_test_util.h" + +namespace spvtools { +namespace fuzz { +namespace { + +using opt::analysis::BoolConstant; +using opt::analysis::FloatConstant; +using opt::analysis::IntConstant; +using opt::analysis::ScalarConstant; + +using opt::analysis::Bool; +using opt::analysis::Float; +using opt::analysis::Integer; +using opt::analysis::Type; + +bool AddFactHelper( + FactManager* fact_manager, const std::vector& words, + const protobufs::UniformBufferElementDescriptor& descriptor) { + protobufs::FactConstantUniform constant_uniform_fact; + for (auto word : words) { + 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->MaybeAddFact(fact); +} + +TEST(ConstantUniformFactsTest, ConstantsAvailableViaUniforms) { + std::string shader = R"( + OpCapability Shader + OpCapability Int64 + OpCapability Float64 + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource GLSL 450 + OpName %4 "main" + OpDecorate %100 DescriptorSet 0 + OpDecorate %100 Binding 0 + OpDecorate %200 DescriptorSet 0 + OpDecorate %200 Binding 1 + OpDecorate %300 DescriptorSet 0 + OpDecorate %300 Binding 2 + OpDecorate %400 DescriptorSet 0 + OpDecorate %400 Binding 3 + OpDecorate %500 DescriptorSet 0 + OpDecorate %500 Binding 4 + OpDecorate %600 DescriptorSet 0 + OpDecorate %600 Binding 5 + OpDecorate %700 DescriptorSet 0 + OpDecorate %700 Binding 6 + OpDecorate %800 DescriptorSet 1 + OpDecorate %800 Binding 0 + OpDecorate %900 DescriptorSet 1 + OpDecorate %900 Binding 1 + OpDecorate %1000 DescriptorSet 1 + OpDecorate %1000 Binding 2 + OpDecorate %1100 DescriptorSet 1 + OpDecorate %1100 Binding 3 + OpDecorate %1200 DescriptorSet 1 + OpDecorate %1200 Binding 4 + OpDecorate %1300 DescriptorSet 1 + OpDecorate %1300 Binding 5 + OpDecorate %1400 DescriptorSet 1 + OpDecorate %1400 Binding 6 + OpDecorate %1500 DescriptorSet 2 + OpDecorate %1500 Binding 0 + OpDecorate %1600 DescriptorSet 2 + OpDecorate %1600 Binding 1 + OpDecorate %1700 DescriptorSet 2 + OpDecorate %1700 Binding 2 + OpDecorate %1800 DescriptorSet 2 + OpDecorate %1800 Binding 3 + OpDecorate %1900 DescriptorSet 2 + OpDecorate %1900 Binding 4 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %10 = OpTypeInt 32 0 + %11 = OpTypeInt 32 1 + %12 = OpTypeInt 64 0 + %13 = OpTypeInt 64 1 + %15 = OpTypeFloat 32 + %16 = OpTypeFloat 64 + %17 = OpConstant %11 5 + %18 = OpConstant %11 20 + %19 = OpTypeVector %10 4 + %20 = OpConstant %11 6 + %21 = OpTypeVector %12 4 + %22 = OpConstant %11 10 + %23 = OpTypeVector %11 4 + + %102 = OpTypeStruct %10 %10 %23 + %101 = OpTypePointer Uniform %102 + %100 = OpVariable %101 Uniform + + %203 = OpTypeArray %23 %17 + %202 = OpTypeArray %203 %18 + %201 = OpTypePointer Uniform %202 + %200 = OpVariable %201 Uniform + + %305 = OpTypeStruct %16 %16 %16 %11 %16 + %304 = OpTypeStruct %16 %16 %305 + %303 = OpTypeStruct %304 + %302 = OpTypeStruct %10 %303 + %301 = OpTypePointer Uniform %302 + %300 = OpVariable %301 Uniform + + %400 = OpVariable %101 Uniform + + %500 = OpVariable %201 Uniform + + %604 = OpTypeArray %13 %20 + %603 = OpTypeArray %604 %20 + %602 = OpTypeArray %603 %20 + %601 = OpTypePointer Uniform %602 + %600 = OpVariable %601 Uniform + + %703 = OpTypeArray %13 %20 + %702 = OpTypeArray %703 %20 + %701 = OpTypePointer Uniform %702 + %700 = OpVariable %701 Uniform + + %802 = OpTypeStruct %702 %602 %19 %202 %302 + %801 = OpTypePointer Uniform %802 + %800 = OpVariable %801 Uniform + + %902 = OpTypeStruct %702 %802 %19 %202 %302 + %901 = OpTypePointer Uniform %902 + %900 = OpVariable %901 Uniform + + %1003 = OpTypeStruct %802 + %1002 = OpTypeArray %1003 %20 + %1001 = OpTypePointer Uniform %1002 + %1000 = OpVariable %1001 Uniform + + %1101 = OpTypePointer Uniform %21 + %1100 = OpVariable %1101 Uniform + + %1202 = OpTypeArray %21 %20 + %1201 = OpTypePointer Uniform %1202 + %1200 = OpVariable %1201 Uniform + + %1302 = OpTypeArray %21 %20 + %1301 = OpTypePointer Uniform %1302 + %1300 = OpVariable %1301 Uniform + + %1402 = OpTypeArray %15 %22 + %1401 = OpTypePointer Uniform %1402 + %1400 = OpVariable %1401 Uniform + + %1501 = OpTypePointer Uniform %1402 + %1500 = OpVariable %1501 Uniform + + %1602 = OpTypeArray %1402 %22 + %1601 = OpTypePointer Uniform %1602 + %1600 = OpVariable %1601 Uniform + + %1704 = OpTypeStruct %16 %16 %16 + %1703 = OpTypeArray %1704 %22 + %1702 = OpTypeArray %1703 %22 + %1701 = OpTypePointer Uniform %1702 + %1700 = OpVariable %1701 Uniform + + %1800 = OpVariable %1701 Uniform + + %1906 = OpTypeStruct %16 + %1905 = OpTypeStruct %1906 + %1904 = OpTypeStruct %1905 + %1903 = OpTypeStruct %1904 + %1902 = OpTypeStruct %1903 + %1901 = OpTypePointer Uniform %1902 + %1900 = OpVariable %1901 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())); + + uint32_t buffer_int32_min[1]; + uint32_t buffer_int64_1[2]; + uint32_t buffer_int64_max[2]; + uint32_t buffer_uint64_1[2]; + uint32_t buffer_uint64_max[2]; + uint32_t buffer_float_10[1]; + uint32_t buffer_double_10[2]; + uint32_t buffer_double_20[2]; + + { + int32_t temp = std::numeric_limits::min(); + std::memcpy(&buffer_int32_min, &temp, sizeof(temp)); + } + + { + int64_t temp = 1; + std::memcpy(&buffer_int64_1, &temp, sizeof(temp)); + } + + { + int64_t temp = std::numeric_limits::max(); + std::memcpy(&buffer_int64_max, &temp, sizeof(temp)); + } + + { + uint64_t temp = 1; + std::memcpy(&buffer_uint64_1, &temp, sizeof(temp)); + } + + { + uint64_t temp = std::numeric_limits::max(); + std::memcpy(&buffer_uint64_max, &temp, sizeof(temp)); + } + + { + float temp = 10.0f; + std::memcpy(&buffer_float_10, &temp, sizeof(float)); + } + + { + double temp = 10.0; + std::memcpy(&buffer_double_10, &temp, sizeof(temp)); + } + + { + double temp = 20.0; + std::memcpy(&buffer_double_20, &temp, sizeof(temp)); + } + + FactManager fact_manager(context.get()); + + uint32_t type_int32_id = 11; + uint32_t type_int64_id = 13; + uint32_t type_uint32_id = 10; + uint32_t type_uint64_id = 12; + uint32_t type_float_id = 15; + uint32_t type_double_id = 16; + + // Initially there should be no facts about uniforms. + ASSERT_TRUE( + fact_manager.GetConstantsAvailableFromUniformsForType(type_uint32_id) + .empty()); + + // In the comments that follow we write v[...][...] to refer to uniform + // variable v indexed with some given indices, when in practice v is + // identified via a (descriptor set, binding) pair. + + // 100[2][3] == int(1) + ASSERT_TRUE(AddFactHelper(&fact_manager, {1}, + MakeUniformBufferElementDescriptor(0, 0, {2, 3}))); + + // 200[1][2][3] == int(1) + ASSERT_TRUE(AddFactHelper( + &fact_manager, {1}, MakeUniformBufferElementDescriptor(0, 1, {1, 2, 3}))); + + // 300[1][0][2][3] == int(1) + ASSERT_TRUE( + AddFactHelper(&fact_manager, {1}, + MakeUniformBufferElementDescriptor(0, 2, {1, 0, 2, 3}))); + + // 400[2][3] = int32_min + ASSERT_TRUE(AddFactHelper(&fact_manager, {buffer_int32_min[0]}, + MakeUniformBufferElementDescriptor(0, 3, {2, 3}))); + + // 500[1][2][3] = int32_min + ASSERT_TRUE( + AddFactHelper(&fact_manager, {buffer_int32_min[0]}, + MakeUniformBufferElementDescriptor(0, 4, {1, 2, 3}))); + + // 600[1][2][3] = int64_max + ASSERT_TRUE( + AddFactHelper(&fact_manager, {buffer_int64_max[0], buffer_int64_max[1]}, + MakeUniformBufferElementDescriptor(0, 5, {1, 2, 3}))); + + // 700[1][1] = int64_max + ASSERT_TRUE(AddFactHelper(&fact_manager, + {buffer_int64_max[0], buffer_int64_max[1]}, + MakeUniformBufferElementDescriptor(0, 6, {1, 1}))); + + // 800[2][3] = uint(1) + ASSERT_TRUE(AddFactHelper(&fact_manager, {1}, + MakeUniformBufferElementDescriptor(1, 0, {2, 3}))); + + // 900[1][2][3] = uint(1) + ASSERT_TRUE(AddFactHelper( + &fact_manager, {1}, MakeUniformBufferElementDescriptor(1, 1, {1, 2, 3}))); + + // 1000[1][0][2][3] = uint(1) + ASSERT_TRUE( + AddFactHelper(&fact_manager, {1}, + MakeUniformBufferElementDescriptor(1, 2, {1, 0, 2, 3}))); + + // 1100[0] = uint64(1) + ASSERT_TRUE(AddFactHelper(&fact_manager, + {buffer_uint64_1[0], buffer_uint64_1[1]}, + MakeUniformBufferElementDescriptor(1, 3, {0}))); + + // 1200[0][0] = uint64_max + ASSERT_TRUE(AddFactHelper(&fact_manager, + {buffer_uint64_max[0], buffer_uint64_max[1]}, + MakeUniformBufferElementDescriptor(1, 4, {0, 0}))); + + // 1300[1][0] = uint64_max + ASSERT_TRUE(AddFactHelper(&fact_manager, + {buffer_uint64_max[0], buffer_uint64_max[1]}, + MakeUniformBufferElementDescriptor(1, 5, {1, 0}))); + + // 1400[6] = float(10.0) + ASSERT_TRUE(AddFactHelper(&fact_manager, {buffer_float_10[0]}, + MakeUniformBufferElementDescriptor(1, 6, {6}))); + + // 1500[7] = float(10.0) + ASSERT_TRUE(AddFactHelper(&fact_manager, {buffer_float_10[0]}, + MakeUniformBufferElementDescriptor(2, 0, {7}))); + + // 1600[9][9] = float(10.0) + ASSERT_TRUE(AddFactHelper(&fact_manager, {buffer_float_10[0]}, + MakeUniformBufferElementDescriptor(2, 1, {9, 9}))); + + // 1700[9][9][1] = double(10.0) + ASSERT_TRUE( + AddFactHelper(&fact_manager, {buffer_double_10[0], buffer_double_10[1]}, + MakeUniformBufferElementDescriptor(2, 2, {9, 9, 1}))); + + // 1800[9][9][2] = double(10.0) + ASSERT_TRUE( + AddFactHelper(&fact_manager, {buffer_double_10[0], buffer_double_10[1]}, + MakeUniformBufferElementDescriptor(2, 3, {9, 9, 2}))); + + // 1900[0][0][0][0][0] = double(20.0) + ASSERT_TRUE( + AddFactHelper(&fact_manager, {buffer_double_20[0], buffer_double_20[1]}, + MakeUniformBufferElementDescriptor(2, 4, {0, 0, 0, 0, 0}))); + + opt::Instruction::OperandList operands = { + {SPV_OPERAND_TYPE_LITERAL_INTEGER, {1}}}; + context->module()->AddGlobalValue(MakeUnique( + context.get(), SpvOpConstant, type_int32_id, 50, operands)); + operands = {{SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_int32_min[0]}}}; + context->module()->AddGlobalValue(MakeUnique( + context.get(), SpvOpConstant, type_int32_id, 51, operands)); + operands = {{SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_int64_max[0]}}, + {SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_int64_max[1]}}}; + context->module()->AddGlobalValue(MakeUnique( + context.get(), SpvOpConstant, type_int64_id, 52, operands)); + operands = {{SPV_OPERAND_TYPE_LITERAL_INTEGER, {1}}}; + context->module()->AddGlobalValue(MakeUnique( + context.get(), SpvOpConstant, type_uint32_id, 53, operands)); + operands = {{SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_uint64_1[0]}}, + {SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_uint64_1[1]}}}; + context->module()->AddGlobalValue(MakeUnique( + context.get(), SpvOpConstant, type_uint64_id, 54, operands)); + operands = {{SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_uint64_max[0]}}, + {SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_uint64_max[1]}}}; + context->module()->AddGlobalValue(MakeUnique( + context.get(), SpvOpConstant, type_uint64_id, 55, operands)); + operands = {{SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_float_10[0]}}}; + context->module()->AddGlobalValue(MakeUnique( + context.get(), SpvOpConstant, type_float_id, 56, operands)); + operands = {{SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_double_10[0]}}, + {SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_double_10[1]}}}; + context->module()->AddGlobalValue(MakeUnique( + context.get(), SpvOpConstant, type_double_id, 57, operands)); + operands = {{SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_double_20[0]}}, + {SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_double_20[1]}}}; + context->module()->AddGlobalValue(MakeUnique( + context.get(), SpvOpConstant, type_double_id, 58, operands)); + + // A duplicate of the constant with id 59. + operands = {{SPV_OPERAND_TYPE_LITERAL_INTEGER, {1}}}; + context->module()->AddGlobalValue(MakeUnique( + context.get(), SpvOpConstant, type_int32_id, 59, operands)); + + context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone); + + // Constants 1 and int32_min are available. + ASSERT_EQ(2, + fact_manager.GetConstantsAvailableFromUniformsForType(type_int32_id) + .size()); + // Constant int64_max is available. + ASSERT_EQ(1, + fact_manager.GetConstantsAvailableFromUniformsForType(type_int64_id) + .size()); + // Constant 1u is available. + ASSERT_EQ( + 1, fact_manager.GetConstantsAvailableFromUniformsForType(type_uint32_id) + .size()); + // Constants 1u and uint64_max are available. + ASSERT_EQ( + 2, fact_manager.GetConstantsAvailableFromUniformsForType(type_uint64_id) + .size()); + // Constant 10.0 is available. + ASSERT_EQ(1, + fact_manager.GetConstantsAvailableFromUniformsForType(type_float_id) + .size()); + // Constants 10.0 and 20.0 are available. + ASSERT_EQ( + 2, fact_manager.GetConstantsAvailableFromUniformsForType(type_double_id) + .size()); + + ASSERT_EQ(std::numeric_limits::max(), + context->get_constant_mgr() + ->FindDeclaredConstant( + fact_manager.GetConstantsAvailableFromUniformsForType( + type_int64_id)[0]) + ->AsIntConstant() + ->GetS64()); + ASSERT_EQ(1, context->get_constant_mgr() + ->FindDeclaredConstant( + fact_manager.GetConstantsAvailableFromUniformsForType( + type_uint32_id)[0]) + ->AsIntConstant() + ->GetU32()); + ASSERT_EQ(10.0f, + context->get_constant_mgr() + ->FindDeclaredConstant( + fact_manager.GetConstantsAvailableFromUniformsForType( + type_float_id)[0]) + ->AsFloatConstant() + ->GetFloat()); + const std::vector& double_constant_ids = + fact_manager.GetConstantsAvailableFromUniformsForType(type_double_id); + ASSERT_EQ(10.0, context->get_constant_mgr() + ->FindDeclaredConstant(double_constant_ids[0]) + ->AsFloatConstant() + ->GetDouble()); + ASSERT_EQ(20.0, context->get_constant_mgr() + ->FindDeclaredConstant(double_constant_ids[1]) + ->AsFloatConstant() + ->GetDouble()); + + const std::vector + descriptors_for_double_10 = + fact_manager.GetUniformDescriptorsForConstant(double_constant_ids[0]); + ASSERT_EQ(2, descriptors_for_double_10.size()); + { + auto temp = MakeUniformBufferElementDescriptor(2, 2, {9, 9, 1}); + ASSERT_TRUE(UniformBufferElementDescriptorEquals()( + &temp, &descriptors_for_double_10[0])); + } + { + auto temp = MakeUniformBufferElementDescriptor(2, 3, {9, 9, 2}); + ASSERT_TRUE(UniformBufferElementDescriptorEquals()( + &temp, &descriptors_for_double_10[1])); + } + const std::vector + descriptors_for_double_20 = + fact_manager.GetUniformDescriptorsForConstant(double_constant_ids[1]); + ASSERT_EQ(1, descriptors_for_double_20.size()); + { + auto temp = MakeUniformBufferElementDescriptor(2, 4, {0, 0, 0, 0, 0}); + ASSERT_TRUE(UniformBufferElementDescriptorEquals()( + &temp, &descriptors_for_double_20[0])); + } + + auto constant_1_id = fact_manager.GetConstantFromUniformDescriptor( + MakeUniformBufferElementDescriptor(2, 3, {9, 9, 2})); + ASSERT_TRUE(constant_1_id); + + auto constant_2_id = fact_manager.GetConstantFromUniformDescriptor( + MakeUniformBufferElementDescriptor(2, 4, {0, 0, 0, 0, 0})); + ASSERT_TRUE(constant_2_id); + + ASSERT_EQ(double_constant_ids[0], constant_1_id); + + ASSERT_EQ(double_constant_ids[1], constant_2_id); +} + +TEST(ConstantUniformFactsTest, TwoConstantsWithSameValue) { + 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 "buf" + OpMemberName %10 0 "a" + OpName %12 "" + OpDecorate %8 RelaxedPrecision + OpMemberDecorate %10 0 RelaxedPrecision + OpMemberDecorate %10 0 Offset 0 + OpDecorate %10 Block + OpDecorate %12 DescriptorSet 0 + OpDecorate %12 Binding 0 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 1 + %20 = OpConstant %6 1 + %10 = OpTypeStruct %6 + %11 = OpTypePointer Uniform %10 + %12 = OpVariable %11 Uniform + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + OpStore %8 %9 + 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(context.get()); + + auto uniform_buffer_element_descriptor = + MakeUniformBufferElementDescriptor(0, 0, {0}); + + // (0, 0, [0]) = int(1) + ASSERT_TRUE( + AddFactHelper(&fact_manager, {1}, uniform_buffer_element_descriptor)); + auto constants = fact_manager.GetConstantsAvailableFromUniformsForType(6); + ASSERT_EQ(1, constants.size()); + ASSERT_TRUE(constants[0] == 9 || constants[0] == 20); + + auto constant = fact_manager.GetConstantFromUniformDescriptor( + uniform_buffer_element_descriptor); + ASSERT_TRUE(constant == 9 || constant == 20); + + // Because the constants with ids 9 and 20 are equal, we should get the same + // single uniform buffer element descriptor when we look up the descriptors + // for either one of them. + for (auto constant_id : {9u, 20u}) { + auto descriptors = + fact_manager.GetUniformDescriptorsForConstant(constant_id); + ASSERT_EQ(1, descriptors.size()); + ASSERT_TRUE(UniformBufferElementDescriptorEquals()( + &uniform_buffer_element_descriptor, &descriptors[0])); + } +} + +TEST(ConstantUniformFactsTest, NonFiniteFactsAreNotValid) { + std::string shader = R"( + OpCapability Shader + OpCapability Float64 + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %7 "buf" + OpMemberName %7 0 "f" + OpMemberName %7 1 "d" + OpName %9 "" + OpMemberDecorate %7 0 Offset 0 + OpMemberDecorate %7 1 Offset 8 + OpDecorate %7 Block + OpDecorate %9 DescriptorSet 0 + OpDecorate %9 Binding 0 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %10 = OpTypeFloat 64 + %7 = OpTypeStruct %6 %10 + %8 = OpTypePointer Uniform %7 + %9 = OpVariable %8 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(context.get()); + auto uniform_buffer_element_descriptor_f = + MakeUniformBufferElementDescriptor(0, 0, {0}); + + auto uniform_buffer_element_descriptor_d = + MakeUniformBufferElementDescriptor(0, 0, {1}); + + if (std::numeric_limits::has_infinity) { + // f == +inf + float positive_infinity_float = std::numeric_limits::infinity(); + uint32_t words[1]; + memcpy(words, &positive_infinity_float, sizeof(float)); + ASSERT_FALSE(AddFactHelper(&fact_manager, {words[0]}, + uniform_buffer_element_descriptor_f)); + // f == -inf + float negative_infinity_float = std::numeric_limits::infinity(); + memcpy(words, &negative_infinity_float, sizeof(float)); + ASSERT_FALSE(AddFactHelper(&fact_manager, {words[0]}, + uniform_buffer_element_descriptor_f)); + } + + if (std::numeric_limits::has_quiet_NaN) { + // f == NaN + float quiet_nan_float = std::numeric_limits::quiet_NaN(); + uint32_t words[1]; + memcpy(words, &quiet_nan_float, sizeof(float)); + ASSERT_FALSE(AddFactHelper(&fact_manager, {words[0]}, + uniform_buffer_element_descriptor_f)); + } + + if (std::numeric_limits::has_infinity) { + // d == +inf + double positive_infinity_double = std::numeric_limits::infinity(); + uint32_t words[2]; + memcpy(words, &positive_infinity_double, sizeof(double)); + ASSERT_FALSE(AddFactHelper(&fact_manager, {words[0], words[1]}, + uniform_buffer_element_descriptor_d)); + // d == -inf + double negative_infinity_double = -std::numeric_limits::infinity(); + memcpy(words, &negative_infinity_double, sizeof(double)); + ASSERT_FALSE(AddFactHelper(&fact_manager, {words[0], words[1]}, + uniform_buffer_element_descriptor_d)); + } + + if (std::numeric_limits::has_quiet_NaN) { + // d == NaN + double quiet_nan_double = std::numeric_limits::quiet_NaN(); + uint32_t words[2]; + memcpy(words, &quiet_nan_double, sizeof(double)); + ASSERT_FALSE(AddFactHelper(&fact_manager, {words[0], words[1]}, + uniform_buffer_element_descriptor_d)); + } +} + +TEST(ConstantUniformFactsTest, AmbiguousFact) { + // This test came from the following GLSL: + // + // #version 310 es + // + // precision highp float; + // + // layout(set = 0, binding = 0) uniform buf { + // float f; + // }; + // + // layout(set = 0, binding = 0) uniform buf2 { + // float g; + // }; + // + // void main() { + // + // } + + 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 "buf" + OpMemberName %7 0 "f" + OpName %9 "" + OpName %10 "buf2" + OpMemberName %10 0 "g" + OpName %12 "" + OpMemberDecorate %7 0 Offset 0 + OpDecorate %7 Block + OpDecorate %9 DescriptorSet 0 + OpDecorate %9 Binding 0 + OpMemberDecorate %10 0 Offset 0 + OpDecorate %10 Block + OpDecorate %12 DescriptorSet 0 + OpDecorate %12 Binding 0 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %7 = OpTypeStruct %6 + %8 = OpTypePointer Uniform %7 + %9 = OpVariable %8 Uniform + %10 = OpTypeStruct %6 + %11 = OpTypePointer Uniform %10 + %12 = OpVariable %11 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(context.get()); + auto uniform_buffer_element_descriptor = + MakeUniformBufferElementDescriptor(0, 0, {0}); + + // The fact cannot be added because it is ambiguous: there are two uniforms + // with descriptor set 0 and binding 0. + ASSERT_FALSE( + AddFactHelper(&fact_manager, {1}, uniform_buffer_element_descriptor)); +} + +TEST(ConstantUniformFactsTest, CheckingFactsDoesNotAddConstants) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 320 + OpMemberDecorate %9 0 Offset 0 + OpDecorate %9 Block + OpDecorate %11 DescriptorSet 0 + OpDecorate %11 Binding 0 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpTypeStruct %6 + %10 = OpTypePointer Uniform %9 + %11 = OpVariable %10 Uniform + %12 = OpConstant %6 0 + %13 = OpTypePointer Uniform %6 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %14 = OpAccessChain %13 %11 %12 + %15 = OpLoad %6 %14 + OpStore %8 %15 + 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(context.get()); + + // 8[0] == int(1) + ASSERT_TRUE(AddFactHelper(&fact_manager, {1}, + MakeUniformBufferElementDescriptor(0, 0, {0}))); + + // Although 8[0] has the value 1, we do not have the constant 1 in the module. + // We thus should not find any constants available from uniforms for int type. + // Furthermore, the act of looking for appropriate constants should not change + // which constants are known to the constant manager. + auto int_type = context->get_type_mgr()->GetType(6)->AsInteger(); + opt::analysis::IntConstant constant_one(int_type, {1}); + ASSERT_FALSE(context->get_constant_mgr()->FindConstant(&constant_one)); + auto available_constants = + fact_manager.GetConstantsAvailableFromUniformsForType(6); + ASSERT_EQ(0, available_constants.size()); + ASSERT_TRUE(IsEqual(env, shader, context.get())); + ASSERT_FALSE(context->get_constant_mgr()->FindConstant(&constant_one)); +} + +} // namespace +} // namespace fuzz +} // namespace spvtools diff --git a/test/fuzz/fact_manager/data_synonym_and_id_equation_facts_test.cpp b/test/fuzz/fact_manager/data_synonym_and_id_equation_facts_test.cpp new file mode 100644 index 000000000..069268b4f --- /dev/null +++ b/test/fuzz/fact_manager/data_synonym_and_id_equation_facts_test.cpp @@ -0,0 +1,644 @@ +// 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/fact_manager/fact_manager.h" +#include "source/fuzz/transformation_merge_blocks.h" +#include "test/fuzz/fuzz_test_util.h" + +namespace spvtools { +namespace fuzz { +namespace { + +TEST(DataSynonymAndIdEquationFactsTest, RecursiveAdditionOfFacts) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %12 "main" + OpExecutionMode %12 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %7 = OpTypeVector %6 4 + %8 = OpTypeMatrix %7 4 + %9 = OpConstant %6 0 + %10 = OpConstantComposite %7 %9 %9 %9 %9 + %11 = OpConstantComposite %8 %10 %10 %10 %10 + %12 = OpFunction %2 None %3 + %13 = 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(context.get()); + + fact_manager.AddFactDataSynonym(MakeDataDescriptor(10, {}), + MakeDataDescriptor(11, {2})); + + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(10, {}), + MakeDataDescriptor(11, {2}))); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(10, {0}), + MakeDataDescriptor(11, {2, 0}))); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(10, {1}), + MakeDataDescriptor(11, {2, 1}))); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(10, {2}), + MakeDataDescriptor(11, {2, 2}))); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(10, {3}), + MakeDataDescriptor(11, {2, 3}))); +} + +TEST(DataSynonymAndIdEquationFactsTest, CorollaryConversionFacts) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %12 "main" + OpExecutionMode %12 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypeInt 32 0 + %8 = OpTypeVector %6 2 + %9 = OpTypeVector %7 2 + %10 = OpTypeFloat 32 + %11 = OpTypeVector %10 2 + %15 = OpConstant %6 24 ; synonym of %16 + %16 = OpConstant %6 24 + %17 = OpConstant %7 24 ; synonym of %18 + %18 = OpConstant %7 24 + %19 = OpConstantComposite %8 %15 %15 ; synonym of %20 + %20 = OpConstantComposite %8 %16 %16 + %21 = OpConstantComposite %9 %17 %17 ; synonym of %22 + %22 = OpConstantComposite %9 %18 %18 + %23 = OpConstantComposite %8 %15 %15 ; not a synonym of %19 + %12 = OpFunction %2 None %3 + %13 = OpLabel + %24 = OpConvertSToF %10 %15 ; synonym of %25 + %25 = OpConvertSToF %10 %16 + %26 = OpConvertUToF %10 %17 ; not a synonym of %27 (different opcode) + %27 = OpConvertSToF %10 %18 + %28 = OpConvertUToF %11 %19 ; synonym of %29 + %29 = OpConvertUToF %11 %20 + %30 = OpConvertSToF %11 %21 ; not a synonym of %31 (different opcode) + %31 = OpConvertUToF %11 %22 + %32 = OpConvertUToF %11 %23 ; not a synonym of %28 (operand is not synonymous) + 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(context.get()); + + // Add equation facts + fact_manager.AddFactIdEquation(24, SpvOpConvertSToF, {15}); + fact_manager.AddFactIdEquation(25, SpvOpConvertSToF, {16}); + fact_manager.AddFactIdEquation(26, SpvOpConvertUToF, {17}); + fact_manager.AddFactIdEquation(27, SpvOpConvertSToF, {18}); + fact_manager.AddFactIdEquation(28, SpvOpConvertUToF, {19}); + fact_manager.AddFactIdEquation(29, SpvOpConvertUToF, {20}); + fact_manager.AddFactIdEquation(30, SpvOpConvertSToF, {21}); + fact_manager.AddFactIdEquation(31, SpvOpConvertUToF, {22}); + fact_manager.AddFactIdEquation(32, SpvOpConvertUToF, {23}); + + fact_manager.AddFactDataSynonym(MakeDataDescriptor(15, {}), + MakeDataDescriptor(16, {})); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(24, {}), + MakeDataDescriptor(25, {}))); + + fact_manager.AddFactDataSynonym(MakeDataDescriptor(17, {}), + MakeDataDescriptor(18, {})); + ASSERT_FALSE(fact_manager.IsSynonymous(MakeDataDescriptor(26, {}), + MakeDataDescriptor(27, {}))); + + fact_manager.AddFactDataSynonym(MakeDataDescriptor(19, {}), + MakeDataDescriptor(20, {})); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(28, {}), + MakeDataDescriptor(29, {}))); + + fact_manager.AddFactDataSynonym(MakeDataDescriptor(21, {}), + MakeDataDescriptor(22, {})); + ASSERT_FALSE(fact_manager.IsSynonymous(MakeDataDescriptor(30, {}), + MakeDataDescriptor(31, {}))); + + ASSERT_FALSE(fact_manager.IsSynonymous(MakeDataDescriptor(32, {}), + MakeDataDescriptor(28, {}))); + fact_manager.AddFactDataSynonym(MakeDataDescriptor(23, {}), + MakeDataDescriptor(19, {})); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(32, {}), + MakeDataDescriptor(28, {}))); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(32, {}), + MakeDataDescriptor(29, {}))); +} + +TEST(DataSynonymAndIdEquationFactsTest, HandlesCorollariesWithInvalidIds) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %12 "main" + OpExecutionMode %12 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %8 = OpTypeInt 32 1 + %9 = OpConstant %8 3 + %12 = OpFunction %2 None %3 + %13 = OpLabel + %14 = OpConvertSToF %6 %9 + OpBranch %16 + %16 = OpLabel + %17 = OpPhi %6 %14 %13 + %15 = OpConvertSToF %6 %9 + %18 = OpConvertSToF %6 %9 + 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())); + + spvtools::ValidatorOptions validator_options; + TransformationContext transformation_context( + MakeUnique(context.get()), validator_options); + + // Add required facts. + transformation_context.GetFactManager()->AddFactIdEquation( + 14, SpvOpConvertSToF, {9}); + transformation_context.GetFactManager()->AddFactDataSynonym( + MakeDataDescriptor(14, {}), MakeDataDescriptor(17, {})); + + // Apply TransformationMergeBlocks which will remove %17 from the module. + TransformationMergeBlocks transformation(16); + ASSERT_TRUE( + transformation.IsApplicable(context.get(), transformation_context)); + transformation.Apply(context.get(), &transformation_context); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_EQ(context->get_def_use_mgr()->GetDef(17), nullptr); + + // Add another equation. + transformation_context.GetFactManager()->AddFactIdEquation( + 15, SpvOpConvertSToF, {9}); + + // Check that two ids are synonymous even though one of them doesn't exist in + // the module (%17). + ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( + MakeDataDescriptor(15, {}), MakeDataDescriptor(17, {}))); + ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( + MakeDataDescriptor(15, {}), MakeDataDescriptor(14, {}))); + + // Remove some instructions from the module. At this point, the equivalence + // class of %14 has no valid members. + ASSERT_TRUE(context->KillDef(14)); + ASSERT_TRUE(context->KillDef(15)); + + transformation_context.GetFactManager()->AddFactIdEquation( + 18, SpvOpConvertSToF, {9}); + + // We don't create synonyms if at least one of the equivalence classes has no + // valid members. + ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous( + MakeDataDescriptor(14, {}), MakeDataDescriptor(18, {}))); +} + +TEST(DataSynonymAndIdEquationFactsTest, LogicalNotEquationFacts) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %12 "main" + OpExecutionMode %12 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeBool + %7 = OpConstantTrue %6 + %12 = OpFunction %2 None %3 + %13 = OpLabel + %14 = OpLogicalNot %6 %7 + %15 = OpCopyObject %6 %7 + %16 = OpCopyObject %6 %14 + %17 = OpLogicalNot %6 %16 + 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(context.get()); + + fact_manager.AddFactDataSynonym(MakeDataDescriptor(15, {}), + MakeDataDescriptor(7, {})); + fact_manager.AddFactDataSynonym(MakeDataDescriptor(16, {}), + MakeDataDescriptor(14, {})); + fact_manager.AddFactIdEquation(14, SpvOpLogicalNot, {7}); + fact_manager.AddFactIdEquation(17, SpvOpLogicalNot, {16}); + + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(15, {}), + MakeDataDescriptor(7, {}))); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(17, {}), + MakeDataDescriptor(7, {}))); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(15, {}), + MakeDataDescriptor(17, {}))); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(16, {}), + MakeDataDescriptor(14, {}))); +} + +TEST(DataSynonymAndIdEquationFactsTest, SignedNegateEquationFacts) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %12 "main" + OpExecutionMode %12 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpConstant %6 24 + %12 = OpFunction %2 None %3 + %13 = OpLabel + %14 = OpSNegate %6 %7 + %15 = OpSNegate %6 %14 + 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(context.get()); + + fact_manager.AddFactIdEquation(14, SpvOpSNegate, {7}); + fact_manager.AddFactIdEquation(15, SpvOpSNegate, {14}); + + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(7, {}), + MakeDataDescriptor(15, {}))); +} + +TEST(DataSynonymAndIdEquationFactsTest, AddSubNegateFacts1) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %12 "main" + OpExecutionMode %12 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %15 = OpConstant %6 24 + %16 = OpConstant %6 37 + %12 = OpFunction %2 None %3 + %13 = OpLabel + %14 = OpIAdd %6 %15 %16 + %17 = OpCopyObject %6 %15 + %18 = OpCopyObject %6 %16 + %19 = OpISub %6 %14 %18 ; ==> synonymous(%19, %15) + %20 = OpISub %6 %14 %17 ; ==> synonymous(%20, %16) + %21 = OpCopyObject %6 %14 + %22 = OpISub %6 %16 %21 + %23 = OpCopyObject %6 %22 + %24 = OpSNegate %6 %23 ; ==> synonymous(%24, %15) + 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(context.get()); + + fact_manager.AddFactIdEquation(14, SpvOpIAdd, {15, 16}); + fact_manager.AddFactDataSynonym(MakeDataDescriptor(17, {}), + MakeDataDescriptor(15, {})); + fact_manager.AddFactDataSynonym(MakeDataDescriptor(18, {}), + MakeDataDescriptor(16, {})); + fact_manager.AddFactIdEquation(19, SpvOpISub, {14, 18}); + fact_manager.AddFactIdEquation(20, SpvOpISub, {14, 17}); + fact_manager.AddFactDataSynonym(MakeDataDescriptor(21, {}), + MakeDataDescriptor(14, {})); + fact_manager.AddFactIdEquation(22, SpvOpISub, {16, 21}); + fact_manager.AddFactDataSynonym(MakeDataDescriptor(23, {}), + MakeDataDescriptor(22, {})); + fact_manager.AddFactIdEquation(24, SpvOpSNegate, {23}); + + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(19, {}), + MakeDataDescriptor(15, {}))); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(20, {}), + MakeDataDescriptor(16, {}))); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(24, {}), + MakeDataDescriptor(15, {}))); +} + +TEST(DataSynonymAndIdEquationFactsTest, AddSubNegateFacts2) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %12 "main" + OpExecutionMode %12 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %15 = OpConstant %6 24 + %16 = OpConstant %6 37 + %12 = OpFunction %2 None %3 + %13 = OpLabel + %14 = OpISub %6 %15 %16 + %17 = OpIAdd %6 %14 %16 ; ==> synonymous(%17, %15) + %18 = OpIAdd %6 %16 %14 ; ==> synonymous(%17, %18, %15) + %19 = OpISub %6 %14 %15 + %20 = OpSNegate %6 %19 ; ==> synonymous(%20, %16) + %21 = OpISub %6 %14 %19 ; ==> synonymous(%21, %15) + %22 = OpISub %6 %14 %18 + %23 = OpSNegate %6 %22 ; ==> synonymous(%23, %16) + 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(context.get()); + + fact_manager.AddFactIdEquation(14, SpvOpISub, {15, 16}); + fact_manager.AddFactIdEquation(17, SpvOpIAdd, {14, 16}); + + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(17, {}), + MakeDataDescriptor(15, {}))); + + fact_manager.AddFactIdEquation(18, SpvOpIAdd, {16, 14}); + + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(18, {}), + MakeDataDescriptor(15, {}))); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(17, {}), + MakeDataDescriptor(18, {}))); + + fact_manager.AddFactIdEquation(19, SpvOpISub, {14, 15}); + fact_manager.AddFactIdEquation(20, SpvOpSNegate, {19}); + + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(20, {}), + MakeDataDescriptor(16, {}))); + + fact_manager.AddFactIdEquation(21, SpvOpISub, {14, 19}); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(21, {}), + MakeDataDescriptor(15, {}))); + + fact_manager.AddFactIdEquation(22, SpvOpISub, {14, 18}); + fact_manager.AddFactIdEquation(23, SpvOpSNegate, {22}); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(23, {}), + MakeDataDescriptor(16, {}))); +} + +TEST(DataSynonymAndIdEquationFactsTest, ConversionEquations) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %12 "main" + OpExecutionMode %12 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %4 = OpTypeInt 32 1 + %5 = OpTypeInt 32 0 + %6 = OpTypeFloat 32 + %14 = OpTypeVector %4 2 + %15 = OpTypeVector %5 2 + %24 = OpTypeVector %6 2 + %16 = OpConstant %4 32 ; synonym of %17 + %17 = OpConstant %4 32 + %18 = OpConstant %5 32 ; synonym of %19 + %19 = OpConstant %5 32 + %20 = OpConstantComposite %14 %16 %16 ; synonym of %21 + %21 = OpConstantComposite %14 %17 %17 + %22 = OpConstantComposite %15 %18 %18 ; synonym of %23 + %23 = OpConstantComposite %15 %19 %19 + %12 = OpFunction %2 None %3 + %13 = OpLabel + %25 = OpConvertUToF %6 %16 ; synonym of %26 + %26 = OpConvertUToF %6 %17 + %27 = OpConvertSToF %24 %20 ; not a synonym of %28 (wrong opcode) + %28 = OpConvertUToF %24 %21 + %29 = OpConvertSToF %6 %18 ; not a synonym of %30 (wrong opcode) + %30 = OpConvertUToF %6 %19 + %31 = OpConvertSToF %24 %22 ; synonym of %32 + %32 = OpConvertSToF %24 %23 + %33 = OpConvertUToF %6 %17 ; synonym of %26 + %34 = OpConvertSToF %24 %23 ; synonym of %32 + 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(context.get()); + + fact_manager.AddFactDataSynonym(MakeDataDescriptor(16, {}), + MakeDataDescriptor(17, {})); + fact_manager.AddFactDataSynonym(MakeDataDescriptor(18, {}), + MakeDataDescriptor(19, {})); + fact_manager.AddFactDataSynonym(MakeDataDescriptor(20, {}), + MakeDataDescriptor(21, {})); + fact_manager.AddFactDataSynonym(MakeDataDescriptor(22, {}), + MakeDataDescriptor(23, {})); + + fact_manager.AddFactIdEquation(25, SpvOpConvertUToF, {16}); + fact_manager.AddFactIdEquation(26, SpvOpConvertUToF, {17}); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(25, {}), + MakeDataDescriptor(26, {}))); + + fact_manager.AddFactIdEquation(27, SpvOpConvertSToF, {20}); + fact_manager.AddFactIdEquation(28, SpvOpConvertUToF, {21}); + ASSERT_FALSE(fact_manager.IsSynonymous(MakeDataDescriptor(27, {}), + MakeDataDescriptor(28, {}))); + + fact_manager.AddFactIdEquation(29, SpvOpConvertSToF, {18}); + fact_manager.AddFactIdEquation(30, SpvOpConvertUToF, {19}); + ASSERT_FALSE(fact_manager.IsSynonymous(MakeDataDescriptor(29, {}), + MakeDataDescriptor(30, {}))); + + fact_manager.AddFactIdEquation(31, SpvOpConvertSToF, {22}); + fact_manager.AddFactIdEquation(32, SpvOpConvertSToF, {23}); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(31, {}), + MakeDataDescriptor(32, {}))); + + fact_manager.AddFactIdEquation(33, SpvOpConvertUToF, {17}); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(33, {}), + MakeDataDescriptor(26, {}))); + + fact_manager.AddFactIdEquation(34, SpvOpConvertSToF, {23}); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(32, {}), + MakeDataDescriptor(34, {}))); +} + +TEST(DataSynonymAndIdEquationFactsTest, BitcastEquationFacts) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %12 "main" + OpExecutionMode %12 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %4 = OpTypeInt 32 1 + %5 = OpTypeInt 32 0 + %8 = OpTypeFloat 32 + %9 = OpTypeVector %4 2 + %10 = OpTypeVector %5 2 + %11 = OpTypeVector %8 2 + %6 = OpConstant %4 23 + %7 = OpConstant %5 23 + %19 = OpConstant %8 23 + %20 = OpConstantComposite %9 %6 %6 + %21 = OpConstantComposite %10 %7 %7 + %22 = OpConstantComposite %11 %19 %19 + %12 = OpFunction %2 None %3 + %13 = OpLabel + %30 = OpBitcast %8 %6 + %31 = OpBitcast %5 %6 + %32 = OpBitcast %8 %7 + %33 = OpBitcast %4 %7 + %34 = OpBitcast %4 %19 + %35 = OpBitcast %5 %19 + %36 = OpBitcast %10 %20 + %37 = OpBitcast %11 %20 + %38 = OpBitcast %9 %21 + %39 = OpBitcast %11 %21 + %40 = OpBitcast %9 %22 + %41 = OpBitcast %10 %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(context.get()); + + uint32_t lhs_id = 30; + for (uint32_t rhs_id : {6, 6, 7, 7, 19, 19, 20, 20, 21, 21, 22, 22}) { + fact_manager.AddFactIdEquation(lhs_id, SpvOpBitcast, {rhs_id}); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(lhs_id, {}), + MakeDataDescriptor(rhs_id, {}))); + ++lhs_id; + } +} + +TEST(DataSynonymAndIdEquationFactsTest, EquationAndEquivalenceFacts) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %12 "main" + OpExecutionMode %12 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %15 = OpConstant %6 24 + %16 = OpConstant %6 37 + %12 = OpFunction %2 None %3 + %13 = OpLabel + %14 = OpISub %6 %15 %16 + %114 = OpCopyObject %6 %14 + %17 = OpIAdd %6 %114 %16 ; ==> synonymous(%17, %15) + %18 = OpIAdd %6 %16 %114 ; ==> synonymous(%17, %18, %15) + %19 = OpISub %6 %114 %15 + %119 = OpCopyObject %6 %19 + %20 = OpSNegate %6 %119 ; ==> synonymous(%20, %16) + %21 = OpISub %6 %14 %19 ; ==> synonymous(%21, %15) + %22 = OpISub %6 %14 %18 + %220 = OpCopyObject %6 %22 + %23 = OpSNegate %6 %220 ; ==> synonymous(%23, %16) + 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(context.get()); + + fact_manager.AddFactIdEquation(14, SpvOpISub, {15, 16}); + fact_manager.AddFactDataSynonym(MakeDataDescriptor(114, {}), + MakeDataDescriptor(14, {})); + fact_manager.AddFactIdEquation(17, SpvOpIAdd, {114, 16}); + + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(17, {}), + MakeDataDescriptor(15, {}))); + + fact_manager.AddFactIdEquation(18, SpvOpIAdd, {16, 114}); + + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(18, {}), + MakeDataDescriptor(15, {}))); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(17, {}), + MakeDataDescriptor(18, {}))); + + fact_manager.AddFactIdEquation(19, SpvOpISub, {14, 15}); + fact_manager.AddFactDataSynonym(MakeDataDescriptor(119, {}), + MakeDataDescriptor(19, {})); + fact_manager.AddFactIdEquation(20, SpvOpSNegate, {119}); + + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(20, {}), + MakeDataDescriptor(16, {}))); + + fact_manager.AddFactIdEquation(21, SpvOpISub, {14, 19}); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(21, {}), + MakeDataDescriptor(15, {}))); + + fact_manager.AddFactIdEquation(22, SpvOpISub, {14, 18}); + fact_manager.AddFactDataSynonym(MakeDataDescriptor(22, {}), + MakeDataDescriptor(220, {})); + fact_manager.AddFactIdEquation(23, SpvOpSNegate, {220}); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(23, {}), + MakeDataDescriptor(16, {}))); +} + +} // namespace +} // namespace fuzz +} // namespace spvtools diff --git a/test/fuzz/fact_manager/dead_block_facts_test.cpp b/test/fuzz/fact_manager/dead_block_facts_test.cpp new file mode 100644 index 000000000..0799d0076 --- /dev/null +++ b/test/fuzz/fact_manager/dead_block_facts_test.cpp @@ -0,0 +1,69 @@ +// 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/fact_manager/fact_manager.h" +#include "test/fuzz/fuzz_test_util.h" + +namespace spvtools { +namespace fuzz { +namespace { + +TEST(DeadBlockFactsTest, BlockIsDead) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" + OpExecutionMode %2 OriginUpperLeft + OpSource ESSL 310 + %3 = OpTypeVoid + %4 = OpTypeFunction %3 + %5 = OpTypeBool + %6 = OpConstantTrue %5 + %7 = OpTypeInt 32 1 + %8 = OpTypePointer Function %7 + %2 = OpFunction %3 None %4 + %9 = OpLabel + OpSelectionMerge %10 None + OpBranchConditional %6 %11 %12 + %11 = OpLabel + OpBranch %10 + %12 = OpLabel + OpBranch %10 + %10 = OpLabel + OpReturn + OpFunctionEnd +)"; + + const auto env = SPV_ENV_UNIVERSAL_1_5; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager(context.get()); + + ASSERT_FALSE(fact_manager.BlockIsDead(9)); + ASSERT_FALSE(fact_manager.BlockIsDead(11)); + ASSERT_FALSE(fact_manager.BlockIsDead(12)); + + fact_manager.AddFactBlockIsDead(12); + + ASSERT_FALSE(fact_manager.BlockIsDead(9)); + ASSERT_FALSE(fact_manager.BlockIsDead(11)); + ASSERT_TRUE(fact_manager.BlockIsDead(12)); +} + +} // namespace +} // namespace fuzz +} // namespace spvtools diff --git a/test/fuzz/fact_manager/irrelevant_value_facts_test.cpp b/test/fuzz/fact_manager/irrelevant_value_facts_test.cpp new file mode 100644 index 000000000..aae614a55 --- /dev/null +++ b/test/fuzz/fact_manager/irrelevant_value_facts_test.cpp @@ -0,0 +1,170 @@ +// 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/fact_manager/fact_manager.h" +#include "test/fuzz/fuzz_test_util.h" + +namespace spvtools { +namespace fuzz { +namespace { + +TEST(IrrelevantValueFactsTest, IdIsIrrelevant) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 320 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %12 = OpConstant %6 0 + %13 = OpConstant %6 1 + %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(context.get()); + + ASSERT_FALSE(fact_manager.IdIsIrrelevant(12)); + ASSERT_FALSE(fact_manager.IdIsIrrelevant(13)); + + fact_manager.AddFactIdIsIrrelevant(12); + + ASSERT_TRUE(fact_manager.IdIsIrrelevant(12)); + ASSERT_FALSE(fact_manager.IdIsIrrelevant(13)); +} + +TEST(IrrelevantValueFactsTest, GetIrrelevantIds) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 320 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %12 = OpConstant %6 0 + %13 = OpConstant %6 1 + %14 = OpConstant %6 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(context.get()); + + ASSERT_EQ(fact_manager.GetIrrelevantIds(), std::unordered_set({})); + + fact_manager.AddFactIdIsIrrelevant(12); + + ASSERT_EQ(fact_manager.GetIrrelevantIds(), + std::unordered_set({12})); + + fact_manager.AddFactIdIsIrrelevant(13); + + ASSERT_EQ(fact_manager.GetIrrelevantIds(), + std::unordered_set({12, 13})); +} + +TEST(IrrelevantValueFactsTest, IdsFromDeadBlocksAreIrrelevant) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" + OpExecutionMode %2 OriginUpperLeft + OpSource ESSL 310 + %3 = OpTypeVoid + %4 = OpTypeFunction %3 + %5 = OpTypeBool + %6 = OpConstantTrue %5 + %7 = OpTypeInt 32 1 + %8 = OpTypePointer Function %7 + %9 = OpConstant %7 1 + %2 = OpFunction %3 None %4 + %10 = OpLabel + %11 = OpVariable %8 Function + OpSelectionMerge %12 None + OpBranchConditional %6 %13 %14 + %13 = OpLabel + OpBranch %12 + %14 = OpLabel + %15 = OpCopyObject %8 %11 + %16 = OpCopyObject %7 %9 + %17 = OpFunctionCall %3 %18 + OpBranch %12 + %12 = OpLabel + OpReturn + OpFunctionEnd + %18 = OpFunction %3 None %4 + %19 = OpLabel + %20 = OpVariable %8 Function + %21 = OpCopyObject %7 %9 + OpReturn + OpFunctionEnd +)"; + + const auto env = SPV_ENV_UNIVERSAL_1_5; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager(context.get()); + + ASSERT_FALSE(fact_manager.BlockIsDead(14)); + ASSERT_FALSE(fact_manager.BlockIsDead(19)); + + // Initially no id is irrelevant. + ASSERT_FALSE(fact_manager.IdIsIrrelevant(16)); + ASSERT_FALSE(fact_manager.IdIsIrrelevant(17)); + ASSERT_EQ(fact_manager.GetIrrelevantIds(), std::unordered_set({})); + + fact_manager.AddFactBlockIsDead(14); + + // %16 and %17 should now be considered irrelevant. + ASSERT_TRUE(fact_manager.IdIsIrrelevant(16)); + ASSERT_TRUE(fact_manager.IdIsIrrelevant(17)); + ASSERT_EQ(fact_manager.GetIrrelevantIds(), + std::unordered_set({16, 17})); + + // Similarly for %21. + ASSERT_FALSE(fact_manager.IdIsIrrelevant(21)); + + fact_manager.AddFactBlockIsDead(19); + + ASSERT_TRUE(fact_manager.IdIsIrrelevant(21)); + ASSERT_EQ(fact_manager.GetIrrelevantIds(), + std::unordered_set({16, 17, 21})); +} + +} // namespace +} // namespace fuzz +} // namespace spvtools diff --git a/test/fuzz/fact_manager_test.cpp b/test/fuzz/fact_manager_test.cpp deleted file mode 100644 index 8322c7c3e..000000000 --- a/test/fuzz/fact_manager_test.cpp +++ /dev/null @@ -1,1595 +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/fact_manager/fact_manager.h" - -#include - -#include "source/fuzz/transformation_merge_blocks.h" -#include "source/fuzz/uniform_buffer_element_descriptor.h" -#include "test/fuzz/fuzz_test_util.h" - -namespace spvtools { -namespace fuzz { -namespace { - -using opt::analysis::BoolConstant; -using opt::analysis::FloatConstant; -using opt::analysis::IntConstant; -using opt::analysis::ScalarConstant; - -using opt::analysis::Bool; -using opt::analysis::Float; -using opt::analysis::Integer; -using opt::analysis::Type; - -bool AddFactHelper( - FactManager* fact_manager, const std::vector& words, - const protobufs::UniformBufferElementDescriptor& descriptor) { - protobufs::FactConstantUniform constant_uniform_fact; - for (auto word : words) { - 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->MaybeAddFact(fact); -} - -TEST(FactManagerTest, ConstantsAvailableViaUniforms) { - std::string shader = R"( - OpCapability Shader - OpCapability Int64 - OpCapability Float64 - %1 = OpExtInstImport "GLSL.std.450" - OpMemoryModel Logical GLSL450 - OpEntryPoint Fragment %4 "main" - OpExecutionMode %4 OriginUpperLeft - OpSource GLSL 450 - OpName %4 "main" - OpDecorate %100 DescriptorSet 0 - OpDecorate %100 Binding 0 - OpDecorate %200 DescriptorSet 0 - OpDecorate %200 Binding 1 - OpDecorate %300 DescriptorSet 0 - OpDecorate %300 Binding 2 - OpDecorate %400 DescriptorSet 0 - OpDecorate %400 Binding 3 - OpDecorate %500 DescriptorSet 0 - OpDecorate %500 Binding 4 - OpDecorate %600 DescriptorSet 0 - OpDecorate %600 Binding 5 - OpDecorate %700 DescriptorSet 0 - OpDecorate %700 Binding 6 - OpDecorate %800 DescriptorSet 1 - OpDecorate %800 Binding 0 - OpDecorate %900 DescriptorSet 1 - OpDecorate %900 Binding 1 - OpDecorate %1000 DescriptorSet 1 - OpDecorate %1000 Binding 2 - OpDecorate %1100 DescriptorSet 1 - OpDecorate %1100 Binding 3 - OpDecorate %1200 DescriptorSet 1 - OpDecorate %1200 Binding 4 - OpDecorate %1300 DescriptorSet 1 - OpDecorate %1300 Binding 5 - OpDecorate %1400 DescriptorSet 1 - OpDecorate %1400 Binding 6 - OpDecorate %1500 DescriptorSet 2 - OpDecorate %1500 Binding 0 - OpDecorate %1600 DescriptorSet 2 - OpDecorate %1600 Binding 1 - OpDecorate %1700 DescriptorSet 2 - OpDecorate %1700 Binding 2 - OpDecorate %1800 DescriptorSet 2 - OpDecorate %1800 Binding 3 - OpDecorate %1900 DescriptorSet 2 - OpDecorate %1900 Binding 4 - %2 = OpTypeVoid - %3 = OpTypeFunction %2 - %10 = OpTypeInt 32 0 - %11 = OpTypeInt 32 1 - %12 = OpTypeInt 64 0 - %13 = OpTypeInt 64 1 - %15 = OpTypeFloat 32 - %16 = OpTypeFloat 64 - %17 = OpConstant %11 5 - %18 = OpConstant %11 20 - %19 = OpTypeVector %10 4 - %20 = OpConstant %11 6 - %21 = OpTypeVector %12 4 - %22 = OpConstant %11 10 - %23 = OpTypeVector %11 4 - - %102 = OpTypeStruct %10 %10 %23 - %101 = OpTypePointer Uniform %102 - %100 = OpVariable %101 Uniform - - %203 = OpTypeArray %23 %17 - %202 = OpTypeArray %203 %18 - %201 = OpTypePointer Uniform %202 - %200 = OpVariable %201 Uniform - - %305 = OpTypeStruct %16 %16 %16 %11 %16 - %304 = OpTypeStruct %16 %16 %305 - %303 = OpTypeStruct %304 - %302 = OpTypeStruct %10 %303 - %301 = OpTypePointer Uniform %302 - %300 = OpVariable %301 Uniform - - %400 = OpVariable %101 Uniform - - %500 = OpVariable %201 Uniform - - %604 = OpTypeArray %13 %20 - %603 = OpTypeArray %604 %20 - %602 = OpTypeArray %603 %20 - %601 = OpTypePointer Uniform %602 - %600 = OpVariable %601 Uniform - - %703 = OpTypeArray %13 %20 - %702 = OpTypeArray %703 %20 - %701 = OpTypePointer Uniform %702 - %700 = OpVariable %701 Uniform - - %802 = OpTypeStruct %702 %602 %19 %202 %302 - %801 = OpTypePointer Uniform %802 - %800 = OpVariable %801 Uniform - - %902 = OpTypeStruct %702 %802 %19 %202 %302 - %901 = OpTypePointer Uniform %902 - %900 = OpVariable %901 Uniform - - %1003 = OpTypeStruct %802 - %1002 = OpTypeArray %1003 %20 - %1001 = OpTypePointer Uniform %1002 - %1000 = OpVariable %1001 Uniform - - %1101 = OpTypePointer Uniform %21 - %1100 = OpVariable %1101 Uniform - - %1202 = OpTypeArray %21 %20 - %1201 = OpTypePointer Uniform %1202 - %1200 = OpVariable %1201 Uniform - - %1302 = OpTypeArray %21 %20 - %1301 = OpTypePointer Uniform %1302 - %1300 = OpVariable %1301 Uniform - - %1402 = OpTypeArray %15 %22 - %1401 = OpTypePointer Uniform %1402 - %1400 = OpVariable %1401 Uniform - - %1501 = OpTypePointer Uniform %1402 - %1500 = OpVariable %1501 Uniform - - %1602 = OpTypeArray %1402 %22 - %1601 = OpTypePointer Uniform %1602 - %1600 = OpVariable %1601 Uniform - - %1704 = OpTypeStruct %16 %16 %16 - %1703 = OpTypeArray %1704 %22 - %1702 = OpTypeArray %1703 %22 - %1701 = OpTypePointer Uniform %1702 - %1700 = OpVariable %1701 Uniform - - %1800 = OpVariable %1701 Uniform - - %1906 = OpTypeStruct %16 - %1905 = OpTypeStruct %1906 - %1904 = OpTypeStruct %1905 - %1903 = OpTypeStruct %1904 - %1902 = OpTypeStruct %1903 - %1901 = OpTypePointer Uniform %1902 - %1900 = OpVariable %1901 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())); - - uint32_t buffer_int32_min[1]; - uint32_t buffer_int64_1[2]; - uint32_t buffer_int64_max[2]; - uint32_t buffer_uint64_1[2]; - uint32_t buffer_uint64_max[2]; - uint32_t buffer_float_10[1]; - uint32_t buffer_double_10[2]; - uint32_t buffer_double_20[2]; - - { - int32_t temp = std::numeric_limits::min(); - std::memcpy(&buffer_int32_min, &temp, sizeof(temp)); - } - - { - int64_t temp = 1; - std::memcpy(&buffer_int64_1, &temp, sizeof(temp)); - } - - { - int64_t temp = std::numeric_limits::max(); - std::memcpy(&buffer_int64_max, &temp, sizeof(temp)); - } - - { - uint64_t temp = 1; - std::memcpy(&buffer_uint64_1, &temp, sizeof(temp)); - } - - { - uint64_t temp = std::numeric_limits::max(); - std::memcpy(&buffer_uint64_max, &temp, sizeof(temp)); - } - - { - float temp = 10.0f; - std::memcpy(&buffer_float_10, &temp, sizeof(float)); - } - - { - double temp = 10.0; - std::memcpy(&buffer_double_10, &temp, sizeof(temp)); - } - - { - double temp = 20.0; - std::memcpy(&buffer_double_20, &temp, sizeof(temp)); - } - - FactManager fact_manager(context.get()); - - uint32_t type_int32_id = 11; - uint32_t type_int64_id = 13; - uint32_t type_uint32_id = 10; - uint32_t type_uint64_id = 12; - uint32_t type_float_id = 15; - uint32_t type_double_id = 16; - - // Initially there should be no facts about uniforms. - ASSERT_TRUE( - fact_manager.GetConstantsAvailableFromUniformsForType(type_uint32_id) - .empty()); - - // In the comments that follow we write v[...][...] to refer to uniform - // variable v indexed with some given indices, when in practice v is - // identified via a (descriptor set, binding) pair. - - // 100[2][3] == int(1) - ASSERT_TRUE(AddFactHelper(&fact_manager, {1}, - MakeUniformBufferElementDescriptor(0, 0, {2, 3}))); - - // 200[1][2][3] == int(1) - ASSERT_TRUE(AddFactHelper( - &fact_manager, {1}, MakeUniformBufferElementDescriptor(0, 1, {1, 2, 3}))); - - // 300[1][0][2][3] == int(1) - ASSERT_TRUE( - AddFactHelper(&fact_manager, {1}, - MakeUniformBufferElementDescriptor(0, 2, {1, 0, 2, 3}))); - - // 400[2][3] = int32_min - ASSERT_TRUE(AddFactHelper(&fact_manager, {buffer_int32_min[0]}, - MakeUniformBufferElementDescriptor(0, 3, {2, 3}))); - - // 500[1][2][3] = int32_min - ASSERT_TRUE( - AddFactHelper(&fact_manager, {buffer_int32_min[0]}, - MakeUniformBufferElementDescriptor(0, 4, {1, 2, 3}))); - - // 600[1][2][3] = int64_max - ASSERT_TRUE( - AddFactHelper(&fact_manager, {buffer_int64_max[0], buffer_int64_max[1]}, - MakeUniformBufferElementDescriptor(0, 5, {1, 2, 3}))); - - // 700[1][1] = int64_max - ASSERT_TRUE(AddFactHelper(&fact_manager, - {buffer_int64_max[0], buffer_int64_max[1]}, - MakeUniformBufferElementDescriptor(0, 6, {1, 1}))); - - // 800[2][3] = uint(1) - ASSERT_TRUE(AddFactHelper(&fact_manager, {1}, - MakeUniformBufferElementDescriptor(1, 0, {2, 3}))); - - // 900[1][2][3] = uint(1) - ASSERT_TRUE(AddFactHelper( - &fact_manager, {1}, MakeUniformBufferElementDescriptor(1, 1, {1, 2, 3}))); - - // 1000[1][0][2][3] = uint(1) - ASSERT_TRUE( - AddFactHelper(&fact_manager, {1}, - MakeUniformBufferElementDescriptor(1, 2, {1, 0, 2, 3}))); - - // 1100[0] = uint64(1) - ASSERT_TRUE(AddFactHelper(&fact_manager, - {buffer_uint64_1[0], buffer_uint64_1[1]}, - MakeUniformBufferElementDescriptor(1, 3, {0}))); - - // 1200[0][0] = uint64_max - ASSERT_TRUE(AddFactHelper(&fact_manager, - {buffer_uint64_max[0], buffer_uint64_max[1]}, - MakeUniformBufferElementDescriptor(1, 4, {0, 0}))); - - // 1300[1][0] = uint64_max - ASSERT_TRUE(AddFactHelper(&fact_manager, - {buffer_uint64_max[0], buffer_uint64_max[1]}, - MakeUniformBufferElementDescriptor(1, 5, {1, 0}))); - - // 1400[6] = float(10.0) - ASSERT_TRUE(AddFactHelper(&fact_manager, {buffer_float_10[0]}, - MakeUniformBufferElementDescriptor(1, 6, {6}))); - - // 1500[7] = float(10.0) - ASSERT_TRUE(AddFactHelper(&fact_manager, {buffer_float_10[0]}, - MakeUniformBufferElementDescriptor(2, 0, {7}))); - - // 1600[9][9] = float(10.0) - ASSERT_TRUE(AddFactHelper(&fact_manager, {buffer_float_10[0]}, - MakeUniformBufferElementDescriptor(2, 1, {9, 9}))); - - // 1700[9][9][1] = double(10.0) - ASSERT_TRUE( - AddFactHelper(&fact_manager, {buffer_double_10[0], buffer_double_10[1]}, - MakeUniformBufferElementDescriptor(2, 2, {9, 9, 1}))); - - // 1800[9][9][2] = double(10.0) - ASSERT_TRUE( - AddFactHelper(&fact_manager, {buffer_double_10[0], buffer_double_10[1]}, - MakeUniformBufferElementDescriptor(2, 3, {9, 9, 2}))); - - // 1900[0][0][0][0][0] = double(20.0) - ASSERT_TRUE( - AddFactHelper(&fact_manager, {buffer_double_20[0], buffer_double_20[1]}, - MakeUniformBufferElementDescriptor(2, 4, {0, 0, 0, 0, 0}))); - - opt::Instruction::OperandList operands = { - {SPV_OPERAND_TYPE_LITERAL_INTEGER, {1}}}; - context->module()->AddGlobalValue(MakeUnique( - context.get(), SpvOpConstant, type_int32_id, 50, operands)); - operands = {{SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_int32_min[0]}}}; - context->module()->AddGlobalValue(MakeUnique( - context.get(), SpvOpConstant, type_int32_id, 51, operands)); - operands = {{SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_int64_max[0]}}, - {SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_int64_max[1]}}}; - context->module()->AddGlobalValue(MakeUnique( - context.get(), SpvOpConstant, type_int64_id, 52, operands)); - operands = {{SPV_OPERAND_TYPE_LITERAL_INTEGER, {1}}}; - context->module()->AddGlobalValue(MakeUnique( - context.get(), SpvOpConstant, type_uint32_id, 53, operands)); - operands = {{SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_uint64_1[0]}}, - {SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_uint64_1[1]}}}; - context->module()->AddGlobalValue(MakeUnique( - context.get(), SpvOpConstant, type_uint64_id, 54, operands)); - operands = {{SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_uint64_max[0]}}, - {SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_uint64_max[1]}}}; - context->module()->AddGlobalValue(MakeUnique( - context.get(), SpvOpConstant, type_uint64_id, 55, operands)); - operands = {{SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_float_10[0]}}}; - context->module()->AddGlobalValue(MakeUnique( - context.get(), SpvOpConstant, type_float_id, 56, operands)); - operands = {{SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_double_10[0]}}, - {SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_double_10[1]}}}; - context->module()->AddGlobalValue(MakeUnique( - context.get(), SpvOpConstant, type_double_id, 57, operands)); - operands = {{SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_double_20[0]}}, - {SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_double_20[1]}}}; - context->module()->AddGlobalValue(MakeUnique( - context.get(), SpvOpConstant, type_double_id, 58, operands)); - - // A duplicate of the constant with id 59. - operands = {{SPV_OPERAND_TYPE_LITERAL_INTEGER, {1}}}; - context->module()->AddGlobalValue(MakeUnique( - context.get(), SpvOpConstant, type_int32_id, 59, operands)); - - context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone); - - // Constants 1 and int32_min are available. - ASSERT_EQ(2, - fact_manager.GetConstantsAvailableFromUniformsForType(type_int32_id) - .size()); - // Constant int64_max is available. - ASSERT_EQ(1, - fact_manager.GetConstantsAvailableFromUniformsForType(type_int64_id) - .size()); - // Constant 1u is available. - ASSERT_EQ( - 1, fact_manager.GetConstantsAvailableFromUniformsForType(type_uint32_id) - .size()); - // Constants 1u and uint64_max are available. - ASSERT_EQ( - 2, fact_manager.GetConstantsAvailableFromUniformsForType(type_uint64_id) - .size()); - // Constant 10.0 is available. - ASSERT_EQ(1, - fact_manager.GetConstantsAvailableFromUniformsForType(type_float_id) - .size()); - // Constants 10.0 and 20.0 are available. - ASSERT_EQ( - 2, fact_manager.GetConstantsAvailableFromUniformsForType(type_double_id) - .size()); - - ASSERT_EQ(std::numeric_limits::max(), - context->get_constant_mgr() - ->FindDeclaredConstant( - fact_manager.GetConstantsAvailableFromUniformsForType( - type_int64_id)[0]) - ->AsIntConstant() - ->GetS64()); - ASSERT_EQ(1, context->get_constant_mgr() - ->FindDeclaredConstant( - fact_manager.GetConstantsAvailableFromUniformsForType( - type_uint32_id)[0]) - ->AsIntConstant() - ->GetU32()); - ASSERT_EQ(10.0f, - context->get_constant_mgr() - ->FindDeclaredConstant( - fact_manager.GetConstantsAvailableFromUniformsForType( - type_float_id)[0]) - ->AsFloatConstant() - ->GetFloat()); - const std::vector& double_constant_ids = - fact_manager.GetConstantsAvailableFromUniformsForType(type_double_id); - ASSERT_EQ(10.0, context->get_constant_mgr() - ->FindDeclaredConstant(double_constant_ids[0]) - ->AsFloatConstant() - ->GetDouble()); - ASSERT_EQ(20.0, context->get_constant_mgr() - ->FindDeclaredConstant(double_constant_ids[1]) - ->AsFloatConstant() - ->GetDouble()); - - const std::vector - descriptors_for_double_10 = - fact_manager.GetUniformDescriptorsForConstant(double_constant_ids[0]); - ASSERT_EQ(2, descriptors_for_double_10.size()); - { - auto temp = MakeUniformBufferElementDescriptor(2, 2, {9, 9, 1}); - ASSERT_TRUE(UniformBufferElementDescriptorEquals()( - &temp, &descriptors_for_double_10[0])); - } - { - auto temp = MakeUniformBufferElementDescriptor(2, 3, {9, 9, 2}); - ASSERT_TRUE(UniformBufferElementDescriptorEquals()( - &temp, &descriptors_for_double_10[1])); - } - const std::vector - descriptors_for_double_20 = - fact_manager.GetUniformDescriptorsForConstant(double_constant_ids[1]); - ASSERT_EQ(1, descriptors_for_double_20.size()); - { - auto temp = MakeUniformBufferElementDescriptor(2, 4, {0, 0, 0, 0, 0}); - ASSERT_TRUE(UniformBufferElementDescriptorEquals()( - &temp, &descriptors_for_double_20[0])); - } - - auto constant_1_id = fact_manager.GetConstantFromUniformDescriptor( - MakeUniformBufferElementDescriptor(2, 3, {9, 9, 2})); - ASSERT_TRUE(constant_1_id); - - auto constant_2_id = fact_manager.GetConstantFromUniformDescriptor( - MakeUniformBufferElementDescriptor(2, 4, {0, 0, 0, 0, 0})); - ASSERT_TRUE(constant_2_id); - - ASSERT_EQ(double_constant_ids[0], constant_1_id); - - ASSERT_EQ(double_constant_ids[1], constant_2_id); -} - -TEST(FactManagerTest, TwoConstantsWithSameValue) { - 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 "buf" - OpMemberName %10 0 "a" - OpName %12 "" - OpDecorate %8 RelaxedPrecision - OpMemberDecorate %10 0 RelaxedPrecision - OpMemberDecorate %10 0 Offset 0 - OpDecorate %10 Block - OpDecorate %12 DescriptorSet 0 - OpDecorate %12 Binding 0 - %2 = OpTypeVoid - %3 = OpTypeFunction %2 - %6 = OpTypeInt 32 1 - %7 = OpTypePointer Function %6 - %9 = OpConstant %6 1 - %20 = OpConstant %6 1 - %10 = OpTypeStruct %6 - %11 = OpTypePointer Uniform %10 - %12 = OpVariable %11 Uniform - %4 = OpFunction %2 None %3 - %5 = OpLabel - %8 = OpVariable %7 Function - OpStore %8 %9 - 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(context.get()); - - auto uniform_buffer_element_descriptor = - MakeUniformBufferElementDescriptor(0, 0, {0}); - - // (0, 0, [0]) = int(1) - ASSERT_TRUE( - AddFactHelper(&fact_manager, {1}, uniform_buffer_element_descriptor)); - auto constants = fact_manager.GetConstantsAvailableFromUniformsForType(6); - ASSERT_EQ(1, constants.size()); - ASSERT_TRUE(constants[0] == 9 || constants[0] == 20); - - auto constant = fact_manager.GetConstantFromUniformDescriptor( - uniform_buffer_element_descriptor); - ASSERT_TRUE(constant == 9 || constant == 20); - - // Because the constants with ids 9 and 20 are equal, we should get the same - // single uniform buffer element descriptor when we look up the descriptors - // for either one of them. - for (auto constant_id : {9u, 20u}) { - auto descriptors = - fact_manager.GetUniformDescriptorsForConstant(constant_id); - ASSERT_EQ(1, descriptors.size()); - ASSERT_TRUE(UniformBufferElementDescriptorEquals()( - &uniform_buffer_element_descriptor, &descriptors[0])); - } -} - -TEST(FactManagerTest, NonFiniteFactsAreNotValid) { - std::string shader = R"( - OpCapability Shader - OpCapability Float64 - %1 = OpExtInstImport "GLSL.std.450" - OpMemoryModel Logical GLSL450 - OpEntryPoint Fragment %4 "main" - OpExecutionMode %4 OriginUpperLeft - OpSource ESSL 310 - OpName %4 "main" - OpName %7 "buf" - OpMemberName %7 0 "f" - OpMemberName %7 1 "d" - OpName %9 "" - OpMemberDecorate %7 0 Offset 0 - OpMemberDecorate %7 1 Offset 8 - OpDecorate %7 Block - OpDecorate %9 DescriptorSet 0 - OpDecorate %9 Binding 0 - %2 = OpTypeVoid - %3 = OpTypeFunction %2 - %6 = OpTypeFloat 32 - %10 = OpTypeFloat 64 - %7 = OpTypeStruct %6 %10 - %8 = OpTypePointer Uniform %7 - %9 = OpVariable %8 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(context.get()); - auto uniform_buffer_element_descriptor_f = - MakeUniformBufferElementDescriptor(0, 0, {0}); - - auto uniform_buffer_element_descriptor_d = - MakeUniformBufferElementDescriptor(0, 0, {1}); - - if (std::numeric_limits::has_infinity) { - // f == +inf - float positive_infinity_float = std::numeric_limits::infinity(); - uint32_t words[1]; - memcpy(words, &positive_infinity_float, sizeof(float)); - ASSERT_FALSE(AddFactHelper(&fact_manager, {words[0]}, - uniform_buffer_element_descriptor_f)); - // f == -inf - float negative_infinity_float = std::numeric_limits::infinity(); - memcpy(words, &negative_infinity_float, sizeof(float)); - ASSERT_FALSE(AddFactHelper(&fact_manager, {words[0]}, - uniform_buffer_element_descriptor_f)); - } - - if (std::numeric_limits::has_quiet_NaN) { - // f == NaN - float quiet_nan_float = std::numeric_limits::quiet_NaN(); - uint32_t words[1]; - memcpy(words, &quiet_nan_float, sizeof(float)); - ASSERT_FALSE(AddFactHelper(&fact_manager, {words[0]}, - uniform_buffer_element_descriptor_f)); - } - - if (std::numeric_limits::has_infinity) { - // d == +inf - double positive_infinity_double = std::numeric_limits::infinity(); - uint32_t words[2]; - memcpy(words, &positive_infinity_double, sizeof(double)); - ASSERT_FALSE(AddFactHelper(&fact_manager, {words[0], words[1]}, - uniform_buffer_element_descriptor_d)); - // d == -inf - double negative_infinity_double = -std::numeric_limits::infinity(); - memcpy(words, &negative_infinity_double, sizeof(double)); - ASSERT_FALSE(AddFactHelper(&fact_manager, {words[0], words[1]}, - uniform_buffer_element_descriptor_d)); - } - - if (std::numeric_limits::has_quiet_NaN) { - // d == NaN - double quiet_nan_double = std::numeric_limits::quiet_NaN(); - uint32_t words[2]; - memcpy(words, &quiet_nan_double, sizeof(double)); - ASSERT_FALSE(AddFactHelper(&fact_manager, {words[0], words[1]}, - uniform_buffer_element_descriptor_d)); - } -} - -TEST(FactManagerTest, AmbiguousFact) { - // This test came from the following GLSL: - // - // #version 310 es - // - // precision highp float; - // - // layout(set = 0, binding = 0) uniform buf { - // float f; - // }; - // - // layout(set = 0, binding = 0) uniform buf2 { - // float g; - // }; - // - // void main() { - // - // } - - 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 "buf" - OpMemberName %7 0 "f" - OpName %9 "" - OpName %10 "buf2" - OpMemberName %10 0 "g" - OpName %12 "" - OpMemberDecorate %7 0 Offset 0 - OpDecorate %7 Block - OpDecorate %9 DescriptorSet 0 - OpDecorate %9 Binding 0 - OpMemberDecorate %10 0 Offset 0 - OpDecorate %10 Block - OpDecorate %12 DescriptorSet 0 - OpDecorate %12 Binding 0 - %2 = OpTypeVoid - %3 = OpTypeFunction %2 - %6 = OpTypeFloat 32 - %7 = OpTypeStruct %6 - %8 = OpTypePointer Uniform %7 - %9 = OpVariable %8 Uniform - %10 = OpTypeStruct %6 - %11 = OpTypePointer Uniform %10 - %12 = OpVariable %11 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(context.get()); - auto uniform_buffer_element_descriptor = - MakeUniformBufferElementDescriptor(0, 0, {0}); - - // The fact cannot be added because it is ambiguous: there are two uniforms - // with descriptor set 0 and binding 0. - ASSERT_FALSE( - AddFactHelper(&fact_manager, {1}, uniform_buffer_element_descriptor)); -} - -TEST(FactManagerTest, RecursiveAdditionOfFacts) { - std::string shader = R"( - OpCapability Shader - %1 = OpExtInstImport "GLSL.std.450" - OpMemoryModel Logical GLSL450 - OpEntryPoint Fragment %12 "main" - OpExecutionMode %12 OriginUpperLeft - OpSource ESSL 310 - %2 = OpTypeVoid - %3 = OpTypeFunction %2 - %6 = OpTypeFloat 32 - %7 = OpTypeVector %6 4 - %8 = OpTypeMatrix %7 4 - %9 = OpConstant %6 0 - %10 = OpConstantComposite %7 %9 %9 %9 %9 - %11 = OpConstantComposite %8 %10 %10 %10 %10 - %12 = OpFunction %2 None %3 - %13 = 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(context.get()); - - fact_manager.AddFactDataSynonym(MakeDataDescriptor(10, {}), - MakeDataDescriptor(11, {2})); - - ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(10, {}), - MakeDataDescriptor(11, {2}))); - ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(10, {0}), - MakeDataDescriptor(11, {2, 0}))); - ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(10, {1}), - MakeDataDescriptor(11, {2, 1}))); - ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(10, {2}), - MakeDataDescriptor(11, {2, 2}))); - ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(10, {3}), - MakeDataDescriptor(11, {2, 3}))); -} - -TEST(FactManagerTest, CorollaryConversionFacts) { - std::string shader = R"( - OpCapability Shader - %1 = OpExtInstImport "GLSL.std.450" - OpMemoryModel Logical GLSL450 - OpEntryPoint Fragment %12 "main" - OpExecutionMode %12 OriginUpperLeft - OpSource ESSL 310 - %2 = OpTypeVoid - %3 = OpTypeFunction %2 - %6 = OpTypeInt 32 1 - %7 = OpTypeInt 32 0 - %8 = OpTypeVector %6 2 - %9 = OpTypeVector %7 2 - %10 = OpTypeFloat 32 - %11 = OpTypeVector %10 2 - %15 = OpConstant %6 24 ; synonym of %16 - %16 = OpConstant %6 24 - %17 = OpConstant %7 24 ; synonym of %18 - %18 = OpConstant %7 24 - %19 = OpConstantComposite %8 %15 %15 ; synonym of %20 - %20 = OpConstantComposite %8 %16 %16 - %21 = OpConstantComposite %9 %17 %17 ; synonym of %22 - %22 = OpConstantComposite %9 %18 %18 - %23 = OpConstantComposite %8 %15 %15 ; not a synonym of %19 - %12 = OpFunction %2 None %3 - %13 = OpLabel - %24 = OpConvertSToF %10 %15 ; synonym of %25 - %25 = OpConvertSToF %10 %16 - %26 = OpConvertUToF %10 %17 ; not a synonym of %27 (different opcode) - %27 = OpConvertSToF %10 %18 - %28 = OpConvertUToF %11 %19 ; synonym of %29 - %29 = OpConvertUToF %11 %20 - %30 = OpConvertSToF %11 %21 ; not a synonym of %31 (different opcode) - %31 = OpConvertUToF %11 %22 - %32 = OpConvertUToF %11 %23 ; not a synonym of %28 (operand is not synonymous) - 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(context.get()); - - // Add equation facts - fact_manager.AddFactIdEquation(24, SpvOpConvertSToF, {15}); - fact_manager.AddFactIdEquation(25, SpvOpConvertSToF, {16}); - fact_manager.AddFactIdEquation(26, SpvOpConvertUToF, {17}); - fact_manager.AddFactIdEquation(27, SpvOpConvertSToF, {18}); - fact_manager.AddFactIdEquation(28, SpvOpConvertUToF, {19}); - fact_manager.AddFactIdEquation(29, SpvOpConvertUToF, {20}); - fact_manager.AddFactIdEquation(30, SpvOpConvertSToF, {21}); - fact_manager.AddFactIdEquation(31, SpvOpConvertUToF, {22}); - fact_manager.AddFactIdEquation(32, SpvOpConvertUToF, {23}); - - fact_manager.AddFactDataSynonym(MakeDataDescriptor(15, {}), - MakeDataDescriptor(16, {})); - ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(24, {}), - MakeDataDescriptor(25, {}))); - - fact_manager.AddFactDataSynonym(MakeDataDescriptor(17, {}), - MakeDataDescriptor(18, {})); - ASSERT_FALSE(fact_manager.IsSynonymous(MakeDataDescriptor(26, {}), - MakeDataDescriptor(27, {}))); - - fact_manager.AddFactDataSynonym(MakeDataDescriptor(19, {}), - MakeDataDescriptor(20, {})); - ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(28, {}), - MakeDataDescriptor(29, {}))); - - fact_manager.AddFactDataSynonym(MakeDataDescriptor(21, {}), - MakeDataDescriptor(22, {})); - ASSERT_FALSE(fact_manager.IsSynonymous(MakeDataDescriptor(30, {}), - MakeDataDescriptor(31, {}))); - - ASSERT_FALSE(fact_manager.IsSynonymous(MakeDataDescriptor(32, {}), - MakeDataDescriptor(28, {}))); - fact_manager.AddFactDataSynonym(MakeDataDescriptor(23, {}), - MakeDataDescriptor(19, {})); - ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(32, {}), - MakeDataDescriptor(28, {}))); - ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(32, {}), - MakeDataDescriptor(29, {}))); -} - -TEST(FactManagerTest, HandlesCorollariesWithInvalidIds) { - std::string shader = R"( - OpCapability Shader - %1 = OpExtInstImport "GLSL.std.450" - OpMemoryModel Logical GLSL450 - OpEntryPoint Fragment %12 "main" - OpExecutionMode %12 OriginUpperLeft - OpSource ESSL 310 - %2 = OpTypeVoid - %3 = OpTypeFunction %2 - %6 = OpTypeFloat 32 - %8 = OpTypeInt 32 1 - %9 = OpConstant %8 3 - %12 = OpFunction %2 None %3 - %13 = OpLabel - %14 = OpConvertSToF %6 %9 - OpBranch %16 - %16 = OpLabel - %17 = OpPhi %6 %14 %13 - %15 = OpConvertSToF %6 %9 - %18 = OpConvertSToF %6 %9 - 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())); - - spvtools::ValidatorOptions validator_options; - TransformationContext transformation_context( - MakeUnique(context.get()), validator_options); - - // Add required facts. - transformation_context.GetFactManager()->AddFactIdEquation( - 14, SpvOpConvertSToF, {9}); - transformation_context.GetFactManager()->AddFactDataSynonym( - MakeDataDescriptor(14, {}), MakeDataDescriptor(17, {})); - - // Apply TransformationMergeBlocks which will remove %17 from the module. - TransformationMergeBlocks transformation(16); - ASSERT_TRUE( - transformation.IsApplicable(context.get(), transformation_context)); - transformation.Apply(context.get(), &transformation_context); - ASSERT_TRUE(IsValid(env, context.get())); - - ASSERT_EQ(context->get_def_use_mgr()->GetDef(17), nullptr); - - // Add another equation. - transformation_context.GetFactManager()->AddFactIdEquation( - 15, SpvOpConvertSToF, {9}); - - // Check that two ids are synonymous even though one of them doesn't exist in - // the module (%17). - ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( - MakeDataDescriptor(15, {}), MakeDataDescriptor(17, {}))); - ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous( - MakeDataDescriptor(15, {}), MakeDataDescriptor(14, {}))); - - // Remove some instructions from the module. At this point, the equivalence - // class of %14 has no valid members. - ASSERT_TRUE(context->KillDef(14)); - ASSERT_TRUE(context->KillDef(15)); - - transformation_context.GetFactManager()->AddFactIdEquation( - 18, SpvOpConvertSToF, {9}); - - // We don't create synonyms if at least one of the equivalence classes has no - // valid members. - ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous( - MakeDataDescriptor(14, {}), MakeDataDescriptor(18, {}))); -} - -TEST(FactManagerTest, LogicalNotEquationFacts) { - std::string shader = R"( - OpCapability Shader - %1 = OpExtInstImport "GLSL.std.450" - OpMemoryModel Logical GLSL450 - OpEntryPoint Fragment %12 "main" - OpExecutionMode %12 OriginUpperLeft - OpSource ESSL 310 - %2 = OpTypeVoid - %3 = OpTypeFunction %2 - %6 = OpTypeBool - %7 = OpConstantTrue %6 - %12 = OpFunction %2 None %3 - %13 = OpLabel - %14 = OpLogicalNot %6 %7 - %15 = OpCopyObject %6 %7 - %16 = OpCopyObject %6 %14 - %17 = OpLogicalNot %6 %16 - 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(context.get()); - - fact_manager.AddFactDataSynonym(MakeDataDescriptor(15, {}), - MakeDataDescriptor(7, {})); - fact_manager.AddFactDataSynonym(MakeDataDescriptor(16, {}), - MakeDataDescriptor(14, {})); - fact_manager.AddFactIdEquation(14, SpvOpLogicalNot, {7}); - fact_manager.AddFactIdEquation(17, SpvOpLogicalNot, {16}); - - ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(15, {}), - MakeDataDescriptor(7, {}))); - ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(17, {}), - MakeDataDescriptor(7, {}))); - ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(15, {}), - MakeDataDescriptor(17, {}))); - ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(16, {}), - MakeDataDescriptor(14, {}))); -} - -TEST(FactManagerTest, SignedNegateEquationFacts) { - std::string shader = R"( - OpCapability Shader - %1 = OpExtInstImport "GLSL.std.450" - OpMemoryModel Logical GLSL450 - OpEntryPoint Fragment %12 "main" - OpExecutionMode %12 OriginUpperLeft - OpSource ESSL 310 - %2 = OpTypeVoid - %3 = OpTypeFunction %2 - %6 = OpTypeInt 32 1 - %7 = OpConstant %6 24 - %12 = OpFunction %2 None %3 - %13 = OpLabel - %14 = OpSNegate %6 %7 - %15 = OpSNegate %6 %14 - 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(context.get()); - - fact_manager.AddFactIdEquation(14, SpvOpSNegate, {7}); - fact_manager.AddFactIdEquation(15, SpvOpSNegate, {14}); - - ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(7, {}), - MakeDataDescriptor(15, {}))); -} - -TEST(FactManagerTest, AddSubNegateFacts1) { - std::string shader = R"( - OpCapability Shader - %1 = OpExtInstImport "GLSL.std.450" - OpMemoryModel Logical GLSL450 - OpEntryPoint Fragment %12 "main" - OpExecutionMode %12 OriginUpperLeft - OpSource ESSL 310 - %2 = OpTypeVoid - %3 = OpTypeFunction %2 - %6 = OpTypeInt 32 1 - %15 = OpConstant %6 24 - %16 = OpConstant %6 37 - %12 = OpFunction %2 None %3 - %13 = OpLabel - %14 = OpIAdd %6 %15 %16 - %17 = OpCopyObject %6 %15 - %18 = OpCopyObject %6 %16 - %19 = OpISub %6 %14 %18 ; ==> synonymous(%19, %15) - %20 = OpISub %6 %14 %17 ; ==> synonymous(%20, %16) - %21 = OpCopyObject %6 %14 - %22 = OpISub %6 %16 %21 - %23 = OpCopyObject %6 %22 - %24 = OpSNegate %6 %23 ; ==> synonymous(%24, %15) - 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(context.get()); - - fact_manager.AddFactIdEquation(14, SpvOpIAdd, {15, 16}); - fact_manager.AddFactDataSynonym(MakeDataDescriptor(17, {}), - MakeDataDescriptor(15, {})); - fact_manager.AddFactDataSynonym(MakeDataDescriptor(18, {}), - MakeDataDescriptor(16, {})); - fact_manager.AddFactIdEquation(19, SpvOpISub, {14, 18}); - fact_manager.AddFactIdEquation(20, SpvOpISub, {14, 17}); - fact_manager.AddFactDataSynonym(MakeDataDescriptor(21, {}), - MakeDataDescriptor(14, {})); - fact_manager.AddFactIdEquation(22, SpvOpISub, {16, 21}); - fact_manager.AddFactDataSynonym(MakeDataDescriptor(23, {}), - MakeDataDescriptor(22, {})); - fact_manager.AddFactIdEquation(24, SpvOpSNegate, {23}); - - ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(19, {}), - MakeDataDescriptor(15, {}))); - ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(20, {}), - MakeDataDescriptor(16, {}))); - ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(24, {}), - MakeDataDescriptor(15, {}))); -} - -TEST(FactManagerTest, AddSubNegateFacts2) { - std::string shader = R"( - OpCapability Shader - %1 = OpExtInstImport "GLSL.std.450" - OpMemoryModel Logical GLSL450 - OpEntryPoint Fragment %12 "main" - OpExecutionMode %12 OriginUpperLeft - OpSource ESSL 310 - %2 = OpTypeVoid - %3 = OpTypeFunction %2 - %6 = OpTypeInt 32 1 - %15 = OpConstant %6 24 - %16 = OpConstant %6 37 - %12 = OpFunction %2 None %3 - %13 = OpLabel - %14 = OpISub %6 %15 %16 - %17 = OpIAdd %6 %14 %16 ; ==> synonymous(%17, %15) - %18 = OpIAdd %6 %16 %14 ; ==> synonymous(%17, %18, %15) - %19 = OpISub %6 %14 %15 - %20 = OpSNegate %6 %19 ; ==> synonymous(%20, %16) - %21 = OpISub %6 %14 %19 ; ==> synonymous(%21, %15) - %22 = OpISub %6 %14 %18 - %23 = OpSNegate %6 %22 ; ==> synonymous(%23, %16) - 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(context.get()); - - fact_manager.AddFactIdEquation(14, SpvOpISub, {15, 16}); - fact_manager.AddFactIdEquation(17, SpvOpIAdd, {14, 16}); - - ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(17, {}), - MakeDataDescriptor(15, {}))); - - fact_manager.AddFactIdEquation(18, SpvOpIAdd, {16, 14}); - - ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(18, {}), - MakeDataDescriptor(15, {}))); - ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(17, {}), - MakeDataDescriptor(18, {}))); - - fact_manager.AddFactIdEquation(19, SpvOpISub, {14, 15}); - fact_manager.AddFactIdEquation(20, SpvOpSNegate, {19}); - - ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(20, {}), - MakeDataDescriptor(16, {}))); - - fact_manager.AddFactIdEquation(21, SpvOpISub, {14, 19}); - ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(21, {}), - MakeDataDescriptor(15, {}))); - - fact_manager.AddFactIdEquation(22, SpvOpISub, {14, 18}); - fact_manager.AddFactIdEquation(23, SpvOpSNegate, {22}); - ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(23, {}), - MakeDataDescriptor(16, {}))); -} - -TEST(FactManagerTest, ConversionEquations) { - std::string shader = R"( - OpCapability Shader - %1 = OpExtInstImport "GLSL.std.450" - OpMemoryModel Logical GLSL450 - OpEntryPoint Fragment %12 "main" - OpExecutionMode %12 OriginUpperLeft - OpSource ESSL 310 - %2 = OpTypeVoid - %3 = OpTypeFunction %2 - %4 = OpTypeInt 32 1 - %5 = OpTypeInt 32 0 - %6 = OpTypeFloat 32 - %14 = OpTypeVector %4 2 - %15 = OpTypeVector %5 2 - %24 = OpTypeVector %6 2 - %16 = OpConstant %4 32 ; synonym of %17 - %17 = OpConstant %4 32 - %18 = OpConstant %5 32 ; synonym of %19 - %19 = OpConstant %5 32 - %20 = OpConstantComposite %14 %16 %16 ; synonym of %21 - %21 = OpConstantComposite %14 %17 %17 - %22 = OpConstantComposite %15 %18 %18 ; synonym of %23 - %23 = OpConstantComposite %15 %19 %19 - %12 = OpFunction %2 None %3 - %13 = OpLabel - %25 = OpConvertUToF %6 %16 ; synonym of %26 - %26 = OpConvertUToF %6 %17 - %27 = OpConvertSToF %24 %20 ; not a synonym of %28 (wrong opcode) - %28 = OpConvertUToF %24 %21 - %29 = OpConvertSToF %6 %18 ; not a synonym of %30 (wrong opcode) - %30 = OpConvertUToF %6 %19 - %31 = OpConvertSToF %24 %22 ; synonym of %32 - %32 = OpConvertSToF %24 %23 - %33 = OpConvertUToF %6 %17 ; synonym of %26 - %34 = OpConvertSToF %24 %23 ; synonym of %32 - 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(context.get()); - - fact_manager.AddFactDataSynonym(MakeDataDescriptor(16, {}), - MakeDataDescriptor(17, {})); - fact_manager.AddFactDataSynonym(MakeDataDescriptor(18, {}), - MakeDataDescriptor(19, {})); - fact_manager.AddFactDataSynonym(MakeDataDescriptor(20, {}), - MakeDataDescriptor(21, {})); - fact_manager.AddFactDataSynonym(MakeDataDescriptor(22, {}), - MakeDataDescriptor(23, {})); - - fact_manager.AddFactIdEquation(25, SpvOpConvertUToF, {16}); - fact_manager.AddFactIdEquation(26, SpvOpConvertUToF, {17}); - ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(25, {}), - MakeDataDescriptor(26, {}))); - - fact_manager.AddFactIdEquation(27, SpvOpConvertSToF, {20}); - fact_manager.AddFactIdEquation(28, SpvOpConvertUToF, {21}); - ASSERT_FALSE(fact_manager.IsSynonymous(MakeDataDescriptor(27, {}), - MakeDataDescriptor(28, {}))); - - fact_manager.AddFactIdEquation(29, SpvOpConvertSToF, {18}); - fact_manager.AddFactIdEquation(30, SpvOpConvertUToF, {19}); - ASSERT_FALSE(fact_manager.IsSynonymous(MakeDataDescriptor(29, {}), - MakeDataDescriptor(30, {}))); - - fact_manager.AddFactIdEquation(31, SpvOpConvertSToF, {22}); - fact_manager.AddFactIdEquation(32, SpvOpConvertSToF, {23}); - ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(31, {}), - MakeDataDescriptor(32, {}))); - - fact_manager.AddFactIdEquation(33, SpvOpConvertUToF, {17}); - ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(33, {}), - MakeDataDescriptor(26, {}))); - - fact_manager.AddFactIdEquation(34, SpvOpConvertSToF, {23}); - ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(32, {}), - MakeDataDescriptor(34, {}))); -} - -TEST(FactManagerTest, BitcastEquationFacts) { - std::string shader = R"( - OpCapability Shader - %1 = OpExtInstImport "GLSL.std.450" - OpMemoryModel Logical GLSL450 - OpEntryPoint Fragment %12 "main" - OpExecutionMode %12 OriginUpperLeft - OpSource ESSL 310 - %2 = OpTypeVoid - %3 = OpTypeFunction %2 - %4 = OpTypeInt 32 1 - %5 = OpTypeInt 32 0 - %8 = OpTypeFloat 32 - %9 = OpTypeVector %4 2 - %10 = OpTypeVector %5 2 - %11 = OpTypeVector %8 2 - %6 = OpConstant %4 23 - %7 = OpConstant %5 23 - %19 = OpConstant %8 23 - %20 = OpConstantComposite %9 %6 %6 - %21 = OpConstantComposite %10 %7 %7 - %22 = OpConstantComposite %11 %19 %19 - %12 = OpFunction %2 None %3 - %13 = OpLabel - %30 = OpBitcast %8 %6 - %31 = OpBitcast %5 %6 - %32 = OpBitcast %8 %7 - %33 = OpBitcast %4 %7 - %34 = OpBitcast %4 %19 - %35 = OpBitcast %5 %19 - %36 = OpBitcast %10 %20 - %37 = OpBitcast %11 %20 - %38 = OpBitcast %9 %21 - %39 = OpBitcast %11 %21 - %40 = OpBitcast %9 %22 - %41 = OpBitcast %10 %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(context.get()); - - uint32_t lhs_id = 30; - for (uint32_t rhs_id : {6, 6, 7, 7, 19, 19, 20, 20, 21, 21, 22, 22}) { - fact_manager.AddFactIdEquation(lhs_id, SpvOpBitcast, {rhs_id}); - ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(lhs_id, {}), - MakeDataDescriptor(rhs_id, {}))); - ++lhs_id; - } -} - -TEST(FactManagerTest, EquationAndEquivalenceFacts) { - std::string shader = R"( - OpCapability Shader - %1 = OpExtInstImport "GLSL.std.450" - OpMemoryModel Logical GLSL450 - OpEntryPoint Fragment %12 "main" - OpExecutionMode %12 OriginUpperLeft - OpSource ESSL 310 - %2 = OpTypeVoid - %3 = OpTypeFunction %2 - %6 = OpTypeInt 32 1 - %15 = OpConstant %6 24 - %16 = OpConstant %6 37 - %12 = OpFunction %2 None %3 - %13 = OpLabel - %14 = OpISub %6 %15 %16 - %114 = OpCopyObject %6 %14 - %17 = OpIAdd %6 %114 %16 ; ==> synonymous(%17, %15) - %18 = OpIAdd %6 %16 %114 ; ==> synonymous(%17, %18, %15) - %19 = OpISub %6 %114 %15 - %119 = OpCopyObject %6 %19 - %20 = OpSNegate %6 %119 ; ==> synonymous(%20, %16) - %21 = OpISub %6 %14 %19 ; ==> synonymous(%21, %15) - %22 = OpISub %6 %14 %18 - %220 = OpCopyObject %6 %22 - %23 = OpSNegate %6 %220 ; ==> synonymous(%23, %16) - 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(context.get()); - - fact_manager.AddFactIdEquation(14, SpvOpISub, {15, 16}); - fact_manager.AddFactDataSynonym(MakeDataDescriptor(114, {}), - MakeDataDescriptor(14, {})); - fact_manager.AddFactIdEquation(17, SpvOpIAdd, {114, 16}); - - ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(17, {}), - MakeDataDescriptor(15, {}))); - - fact_manager.AddFactIdEquation(18, SpvOpIAdd, {16, 114}); - - ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(18, {}), - MakeDataDescriptor(15, {}))); - ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(17, {}), - MakeDataDescriptor(18, {}))); - - fact_manager.AddFactIdEquation(19, SpvOpISub, {14, 15}); - fact_manager.AddFactDataSynonym(MakeDataDescriptor(119, {}), - MakeDataDescriptor(19, {})); - fact_manager.AddFactIdEquation(20, SpvOpSNegate, {119}); - - ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(20, {}), - MakeDataDescriptor(16, {}))); - - fact_manager.AddFactIdEquation(21, SpvOpISub, {14, 19}); - ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(21, {}), - MakeDataDescriptor(15, {}))); - - fact_manager.AddFactIdEquation(22, SpvOpISub, {14, 18}); - fact_manager.AddFactDataSynonym(MakeDataDescriptor(22, {}), - MakeDataDescriptor(220, {})); - fact_manager.AddFactIdEquation(23, SpvOpSNegate, {220}); - ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(23, {}), - MakeDataDescriptor(16, {}))); -} - -TEST(FactManagerTest, CheckingFactsDoesNotAddConstants) { - std::string shader = R"( - OpCapability Shader - %1 = OpExtInstImport "GLSL.std.450" - OpMemoryModel Logical GLSL450 - OpEntryPoint Fragment %4 "main" - OpExecutionMode %4 OriginUpperLeft - OpSource ESSL 320 - OpMemberDecorate %9 0 Offset 0 - OpDecorate %9 Block - OpDecorate %11 DescriptorSet 0 - OpDecorate %11 Binding 0 - %2 = OpTypeVoid - %3 = OpTypeFunction %2 - %6 = OpTypeInt 32 1 - %7 = OpTypePointer Function %6 - %9 = OpTypeStruct %6 - %10 = OpTypePointer Uniform %9 - %11 = OpVariable %10 Uniform - %12 = OpConstant %6 0 - %13 = OpTypePointer Uniform %6 - %4 = OpFunction %2 None %3 - %5 = OpLabel - %8 = OpVariable %7 Function - %14 = OpAccessChain %13 %11 %12 - %15 = OpLoad %6 %14 - OpStore %8 %15 - 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(context.get()); - - // 8[0] == int(1) - ASSERT_TRUE(AddFactHelper(&fact_manager, {1}, - MakeUniformBufferElementDescriptor(0, 0, {0}))); - - // Although 8[0] has the value 1, we do not have the constant 1 in the module. - // We thus should not find any constants available from uniforms for int type. - // Furthermore, the act of looking for appropriate constants should not change - // which constants are known to the constant manager. - auto int_type = context->get_type_mgr()->GetType(6)->AsInteger(); - opt::analysis::IntConstant constant_one(int_type, {1}); - ASSERT_FALSE(context->get_constant_mgr()->FindConstant(&constant_one)); - auto available_constants = - fact_manager.GetConstantsAvailableFromUniformsForType(6); - ASSERT_EQ(0, available_constants.size()); - ASSERT_TRUE(IsEqual(env, shader, context.get())); - ASSERT_FALSE(context->get_constant_mgr()->FindConstant(&constant_one)); -} - -TEST(FactManagerTest, IdIsIrrelevant) { - std::string shader = R"( - OpCapability Shader - %1 = OpExtInstImport "GLSL.std.450" - OpMemoryModel Logical GLSL450 - OpEntryPoint Fragment %4 "main" - OpExecutionMode %4 OriginUpperLeft - OpSource ESSL 320 - %2 = OpTypeVoid - %3 = OpTypeFunction %2 - %6 = OpTypeInt 32 1 - %12 = OpConstant %6 0 - %13 = OpConstant %6 1 - %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(context.get()); - - ASSERT_FALSE(fact_manager.IdIsIrrelevant(12)); - ASSERT_FALSE(fact_manager.IdIsIrrelevant(13)); - - fact_manager.AddFactIdIsIrrelevant(12); - - ASSERT_TRUE(fact_manager.IdIsIrrelevant(12)); - ASSERT_FALSE(fact_manager.IdIsIrrelevant(13)); -} - -TEST(FactManagerTest, GetIrrelevantIds) { - std::string shader = R"( - OpCapability Shader - %1 = OpExtInstImport "GLSL.std.450" - OpMemoryModel Logical GLSL450 - OpEntryPoint Fragment %4 "main" - OpExecutionMode %4 OriginUpperLeft - OpSource ESSL 320 - %2 = OpTypeVoid - %3 = OpTypeFunction %2 - %6 = OpTypeInt 32 1 - %12 = OpConstant %6 0 - %13 = OpConstant %6 1 - %14 = OpConstant %6 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(context.get()); - - ASSERT_EQ(fact_manager.GetIrrelevantIds(), std::unordered_set({})); - - fact_manager.AddFactIdIsIrrelevant(12); - - ASSERT_EQ(fact_manager.GetIrrelevantIds(), - std::unordered_set({12})); - - fact_manager.AddFactIdIsIrrelevant(13); - - ASSERT_EQ(fact_manager.GetIrrelevantIds(), - std::unordered_set({12, 13})); -} - -TEST(FactManagerTest, BlockIsDead) { - std::string shader = R"( - OpCapability Shader - %1 = OpExtInstImport "GLSL.std.450" - OpMemoryModel Logical GLSL450 - OpEntryPoint Fragment %2 "main" - OpExecutionMode %2 OriginUpperLeft - OpSource ESSL 310 - %3 = OpTypeVoid - %4 = OpTypeFunction %3 - %5 = OpTypeBool - %6 = OpConstantTrue %5 - %7 = OpTypeInt 32 1 - %8 = OpTypePointer Function %7 - %2 = OpFunction %3 None %4 - %9 = OpLabel - OpSelectionMerge %10 None - OpBranchConditional %6 %11 %12 - %11 = OpLabel - OpBranch %10 - %12 = OpLabel - OpBranch %10 - %10 = OpLabel - OpReturn - OpFunctionEnd -)"; - - const auto env = SPV_ENV_UNIVERSAL_1_5; - const auto consumer = nullptr; - const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); - ASSERT_TRUE(IsValid(env, context.get())); - - FactManager fact_manager(context.get()); - - ASSERT_FALSE(fact_manager.BlockIsDead(9)); - ASSERT_FALSE(fact_manager.BlockIsDead(11)); - ASSERT_FALSE(fact_manager.BlockIsDead(12)); - - fact_manager.AddFactBlockIsDead(12); - - ASSERT_FALSE(fact_manager.BlockIsDead(9)); - ASSERT_FALSE(fact_manager.BlockIsDead(11)); - ASSERT_TRUE(fact_manager.BlockIsDead(12)); -} - -TEST(FactManagerTest, IdsFromDeadBlocksAreIrrelevant) { - std::string shader = R"( - OpCapability Shader - %1 = OpExtInstImport "GLSL.std.450" - OpMemoryModel Logical GLSL450 - OpEntryPoint Fragment %2 "main" - OpExecutionMode %2 OriginUpperLeft - OpSource ESSL 310 - %3 = OpTypeVoid - %4 = OpTypeFunction %3 - %5 = OpTypeBool - %6 = OpConstantTrue %5 - %7 = OpTypeInt 32 1 - %8 = OpTypePointer Function %7 - %9 = OpConstant %7 1 - %2 = OpFunction %3 None %4 - %10 = OpLabel - %11 = OpVariable %8 Function - OpSelectionMerge %12 None - OpBranchConditional %6 %13 %14 - %13 = OpLabel - OpBranch %12 - %14 = OpLabel - %15 = OpCopyObject %8 %11 - %16 = OpCopyObject %7 %9 - %17 = OpFunctionCall %3 %18 - OpBranch %12 - %12 = OpLabel - OpReturn - OpFunctionEnd - %18 = OpFunction %3 None %4 - %19 = OpLabel - %20 = OpVariable %8 Function - %21 = OpCopyObject %7 %9 - OpReturn - OpFunctionEnd -)"; - - const auto env = SPV_ENV_UNIVERSAL_1_5; - const auto consumer = nullptr; - const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); - ASSERT_TRUE(IsValid(env, context.get())); - - FactManager fact_manager(context.get()); - - ASSERT_FALSE(fact_manager.BlockIsDead(14)); - ASSERT_FALSE(fact_manager.BlockIsDead(19)); - - // Initially no id is irrelevant. - ASSERT_FALSE(fact_manager.IdIsIrrelevant(16)); - ASSERT_FALSE(fact_manager.IdIsIrrelevant(17)); - ASSERT_EQ(fact_manager.GetIrrelevantIds(), std::unordered_set({})); - - fact_manager.AddFactBlockIsDead(14); - - // %16 and %17 should now be considered irrelevant. - ASSERT_TRUE(fact_manager.IdIsIrrelevant(16)); - ASSERT_TRUE(fact_manager.IdIsIrrelevant(17)); - ASSERT_EQ(fact_manager.GetIrrelevantIds(), - std::unordered_set({16, 17})); - - // Similarly for %21. - ASSERT_FALSE(fact_manager.IdIsIrrelevant(21)); - - fact_manager.AddFactBlockIsDead(19); - - ASSERT_TRUE(fact_manager.IdIsIrrelevant(21)); - ASSERT_EQ(fact_manager.GetIrrelevantIds(), - std::unordered_set({16, 17, 21})); -} -} // namespace -} // namespace fuzz -} // namespace spvtools