mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2024-10-20 12:00:05 +00:00
67f4838659
The fact manager maintains an equivalence relation on data descriptors that tracks when one data descriptor could be used in place of another. An algorithm to compute the closure of such facts allows deducing new synonym facts from existing facts. E.g., for two 2D vectors u and v it is known that u.x is synonymous with v.x and u.y is synonymous with v.y, it can be deduced that u and v are synonymous. The closure computation algorithm is very expensive if we get large equivalence relations. This change addresses this in three ways: - The size of equivalence relations is reduced by limiting the extent to which the components of a composite are recursively noted as being equivalent, so that when we have large synonymous arrays we do not record all array elements as being pairwise equivalent. - When computing the closure of facts, equivalence classes above a certain size are simply skipped (which can lead to missed facts) - The closure computation is performed less frequently - it is invoked explicitly before fuzzer passes that will benefit from data synonym facts. A new transformation is used to control its invocation, so that fuzzing and replaying do not get out of sync. The change also tidies up the order in which some getters are declared in FuzzerContext.
1060 lines
40 KiB
C++
1060 lines
40 KiB
C++
// 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 <limits>
|
|
|
|
#include "source/fuzz/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, opt::IRContext* context,
|
|
std::vector<uint32_t>&& 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->AddFact(fact, context);
|
|
}
|
|
|
|
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<int32_t>::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<int64_t>::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<uint64_t>::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;
|
|
|
|
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(context.get(),
|
|
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, context.get(), {1},
|
|
MakeUniformBufferElementDescriptor(0, 0, {2, 3})));
|
|
|
|
// 200[1][2][3] == int(1)
|
|
ASSERT_TRUE(
|
|
AddFactHelper(&fact_manager, context.get(), {1},
|
|
MakeUniformBufferElementDescriptor(0, 1, {1, 2, 3})));
|
|
|
|
// 300[1][0][2][3] == int(1)
|
|
ASSERT_TRUE(
|
|
AddFactHelper(&fact_manager, context.get(), {1},
|
|
MakeUniformBufferElementDescriptor(0, 2, {1, 0, 2, 3})));
|
|
|
|
// 400[2][3] = int32_min
|
|
ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), {buffer_int32_min[0]},
|
|
MakeUniformBufferElementDescriptor(0, 3, {2, 3})));
|
|
|
|
// 500[1][2][3] = int32_min
|
|
ASSERT_TRUE(
|
|
AddFactHelper(&fact_manager, context.get(), {buffer_int32_min[0]},
|
|
MakeUniformBufferElementDescriptor(0, 4, {1, 2, 3})));
|
|
|
|
// 600[1][2][3] = int64_max
|
|
ASSERT_TRUE(AddFactHelper(
|
|
&fact_manager, context.get(), {buffer_int64_max[0], buffer_int64_max[1]},
|
|
MakeUniformBufferElementDescriptor(0, 5, {1, 2, 3})));
|
|
|
|
// 700[1][1] = int64_max
|
|
ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(),
|
|
{buffer_int64_max[0], buffer_int64_max[1]},
|
|
MakeUniformBufferElementDescriptor(0, 6, {1, 1})));
|
|
|
|
// 800[2][3] = uint(1)
|
|
ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), {1},
|
|
MakeUniformBufferElementDescriptor(1, 0, {2, 3})));
|
|
|
|
// 900[1][2][3] = uint(1)
|
|
ASSERT_TRUE(
|
|
AddFactHelper(&fact_manager, context.get(), {1},
|
|
MakeUniformBufferElementDescriptor(1, 1, {1, 2, 3})));
|
|
|
|
// 1000[1][0][2][3] = uint(1)
|
|
ASSERT_TRUE(
|
|
AddFactHelper(&fact_manager, context.get(), {1},
|
|
MakeUniformBufferElementDescriptor(1, 2, {1, 0, 2, 3})));
|
|
|
|
// 1100[0] = uint64(1)
|
|
ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(),
|
|
{buffer_uint64_1[0], buffer_uint64_1[1]},
|
|
MakeUniformBufferElementDescriptor(1, 3, {0})));
|
|
|
|
// 1200[0][0] = uint64_max
|
|
ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(),
|
|
{buffer_uint64_max[0], buffer_uint64_max[1]},
|
|
MakeUniformBufferElementDescriptor(1, 4, {0, 0})));
|
|
|
|
// 1300[1][0] = uint64_max
|
|
ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(),
|
|
{buffer_uint64_max[0], buffer_uint64_max[1]},
|
|
MakeUniformBufferElementDescriptor(1, 5, {1, 0})));
|
|
|
|
// 1400[6] = float(10.0)
|
|
ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), {buffer_float_10[0]},
|
|
MakeUniformBufferElementDescriptor(1, 6, {6})));
|
|
|
|
// 1500[7] = float(10.0)
|
|
ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), {buffer_float_10[0]},
|
|
MakeUniformBufferElementDescriptor(2, 0, {7})));
|
|
|
|
// 1600[9][9] = float(10.0)
|
|
ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), {buffer_float_10[0]},
|
|
MakeUniformBufferElementDescriptor(2, 1, {9, 9})));
|
|
|
|
// 1700[9][9][1] = double(10.0)
|
|
ASSERT_TRUE(AddFactHelper(
|
|
&fact_manager, context.get(), {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, context.get(), {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, context.get(), {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<opt::Instruction>(
|
|
context.get(), SpvOpConstant, type_int32_id, 50, operands));
|
|
operands = {{SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_int32_min[0]}}};
|
|
context->module()->AddGlobalValue(MakeUnique<opt::Instruction>(
|
|
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<opt::Instruction>(
|
|
context.get(), SpvOpConstant, type_int64_id, 52, operands));
|
|
operands = {{SPV_OPERAND_TYPE_LITERAL_INTEGER, {1}}};
|
|
context->module()->AddGlobalValue(MakeUnique<opt::Instruction>(
|
|
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<opt::Instruction>(
|
|
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<opt::Instruction>(
|
|
context.get(), SpvOpConstant, type_uint64_id, 55, operands));
|
|
operands = {{SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_float_10[0]}}};
|
|
context->module()->AddGlobalValue(MakeUnique<opt::Instruction>(
|
|
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<opt::Instruction>(
|
|
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<opt::Instruction>(
|
|
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<opt::Instruction>(
|
|
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(context.get(),
|
|
type_int32_id)
|
|
.size());
|
|
// Constant int64_max is available.
|
|
ASSERT_EQ(1, fact_manager
|
|
.GetConstantsAvailableFromUniformsForType(context.get(),
|
|
type_int64_id)
|
|
.size());
|
|
// Constant 1u is available.
|
|
ASSERT_EQ(1, fact_manager
|
|
.GetConstantsAvailableFromUniformsForType(context.get(),
|
|
type_uint32_id)
|
|
.size());
|
|
// Constants 1u and uint64_max are available.
|
|
ASSERT_EQ(2, fact_manager
|
|
.GetConstantsAvailableFromUniformsForType(context.get(),
|
|
type_uint64_id)
|
|
.size());
|
|
// Constant 10.0 is available.
|
|
ASSERT_EQ(1, fact_manager
|
|
.GetConstantsAvailableFromUniformsForType(context.get(),
|
|
type_float_id)
|
|
.size());
|
|
// Constants 10.0 and 20.0 are available.
|
|
ASSERT_EQ(2, fact_manager
|
|
.GetConstantsAvailableFromUniformsForType(context.get(),
|
|
type_double_id)
|
|
.size());
|
|
|
|
ASSERT_EQ(std::numeric_limits<int64_t>::max(),
|
|
context->get_constant_mgr()
|
|
->FindDeclaredConstant(
|
|
fact_manager.GetConstantsAvailableFromUniformsForType(
|
|
context.get(), type_int64_id)[0])
|
|
->AsIntConstant()
|
|
->GetS64());
|
|
ASSERT_EQ(1, context->get_constant_mgr()
|
|
->FindDeclaredConstant(
|
|
fact_manager.GetConstantsAvailableFromUniformsForType(
|
|
context.get(), type_uint32_id)[0])
|
|
->AsIntConstant()
|
|
->GetU32());
|
|
ASSERT_EQ(10.0f,
|
|
context->get_constant_mgr()
|
|
->FindDeclaredConstant(
|
|
fact_manager.GetConstantsAvailableFromUniformsForType(
|
|
context.get(), type_float_id)[0])
|
|
->AsFloatConstant()
|
|
->GetFloat());
|
|
const std::vector<uint32_t>& double_constant_ids =
|
|
fact_manager.GetConstantsAvailableFromUniformsForType(context.get(),
|
|
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<protobufs::UniformBufferElementDescriptor>
|
|
descriptors_for_double_10 = fact_manager.GetUniformDescriptorsForConstant(
|
|
context.get(), 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<protobufs::UniformBufferElementDescriptor>
|
|
descriptors_for_double_20 = fact_manager.GetUniformDescriptorsForConstant(
|
|
context.get(), 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(
|
|
context.get(), MakeUniformBufferElementDescriptor(2, 3, {9, 9, 2}));
|
|
ASSERT_TRUE(constant_1_id);
|
|
|
|
auto constant_2_id = fact_manager.GetConstantFromUniformDescriptor(
|
|
context.get(), 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;
|
|
|
|
auto uniform_buffer_element_descriptor =
|
|
MakeUniformBufferElementDescriptor(0, 0, {0});
|
|
|
|
// (0, 0, [0]) = int(1)
|
|
ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), {1},
|
|
uniform_buffer_element_descriptor));
|
|
auto constants =
|
|
fact_manager.GetConstantsAvailableFromUniformsForType(context.get(), 6);
|
|
ASSERT_EQ(1, constants.size());
|
|
ASSERT_TRUE(constants[0] == 9 || constants[0] == 20);
|
|
|
|
auto constant = fact_manager.GetConstantFromUniformDescriptor(
|
|
context.get(), 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(
|
|
context.get(), 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;
|
|
auto uniform_buffer_element_descriptor_f =
|
|
MakeUniformBufferElementDescriptor(0, 0, {0});
|
|
|
|
auto uniform_buffer_element_descriptor_d =
|
|
MakeUniformBufferElementDescriptor(0, 0, {1});
|
|
|
|
if (std::numeric_limits<float>::has_infinity) {
|
|
// f == +inf
|
|
float positive_infinity_float = std::numeric_limits<float>::infinity();
|
|
uint32_t words[1];
|
|
memcpy(words, &positive_infinity_float, sizeof(float));
|
|
ASSERT_FALSE(AddFactHelper(&fact_manager, context.get(), {words[0]},
|
|
uniform_buffer_element_descriptor_f));
|
|
// f == -inf
|
|
float negative_infinity_float = std::numeric_limits<float>::infinity();
|
|
memcpy(words, &negative_infinity_float, sizeof(float));
|
|
ASSERT_FALSE(AddFactHelper(&fact_manager, context.get(), {words[0]},
|
|
uniform_buffer_element_descriptor_f));
|
|
}
|
|
|
|
if (std::numeric_limits<float>::has_quiet_NaN) {
|
|
// f == NaN
|
|
float quiet_nan_float = std::numeric_limits<float>::quiet_NaN();
|
|
uint32_t words[1];
|
|
memcpy(words, &quiet_nan_float, sizeof(float));
|
|
ASSERT_FALSE(AddFactHelper(&fact_manager, context.get(), {words[0]},
|
|
uniform_buffer_element_descriptor_f));
|
|
}
|
|
|
|
if (std::numeric_limits<double>::has_infinity) {
|
|
// d == +inf
|
|
double positive_infinity_double = std::numeric_limits<double>::infinity();
|
|
uint32_t words[2];
|
|
memcpy(words, &positive_infinity_double, sizeof(double));
|
|
ASSERT_FALSE(AddFactHelper(&fact_manager, context.get(),
|
|
{words[0], words[1]},
|
|
uniform_buffer_element_descriptor_d));
|
|
// d == -inf
|
|
double negative_infinity_double = -std::numeric_limits<double>::infinity();
|
|
memcpy(words, &negative_infinity_double, sizeof(double));
|
|
ASSERT_FALSE(AddFactHelper(&fact_manager, context.get(),
|
|
{words[0], words[1]},
|
|
uniform_buffer_element_descriptor_d));
|
|
}
|
|
|
|
if (std::numeric_limits<double>::has_quiet_NaN) {
|
|
// d == NaN
|
|
double quiet_nan_double = std::numeric_limits<double>::quiet_NaN();
|
|
uint32_t words[2];
|
|
memcpy(words, &quiet_nan_double, sizeof(double));
|
|
ASSERT_FALSE(AddFactHelper(&fact_manager, context.get(),
|
|
{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;
|
|
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, context.get(), {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;
|
|
|
|
fact_manager.AddFactDataSynonym(MakeDataDescriptor(10, {}),
|
|
MakeDataDescriptor(11, {2}), context.get());
|
|
|
|
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, 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;
|
|
|
|
fact_manager.AddFactDataSynonym(MakeDataDescriptor(15, {}),
|
|
MakeDataDescriptor(7, {}), context.get());
|
|
fact_manager.AddFactDataSynonym(MakeDataDescriptor(16, {}),
|
|
MakeDataDescriptor(14, {}), context.get());
|
|
fact_manager.AddFactIdEquation(14, SpvOpLogicalNot, {7}, context.get());
|
|
fact_manager.AddFactIdEquation(17, SpvOpLogicalNot, {16}, context.get());
|
|
|
|
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;
|
|
|
|
fact_manager.AddFactIdEquation(14, SpvOpSNegate, {7}, context.get());
|
|
fact_manager.AddFactIdEquation(15, SpvOpSNegate, {14}, context.get());
|
|
|
|
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;
|
|
|
|
fact_manager.AddFactIdEquation(14, SpvOpIAdd, {15, 16}, context.get());
|
|
fact_manager.AddFactDataSynonym(MakeDataDescriptor(17, {}),
|
|
MakeDataDescriptor(15, {}), context.get());
|
|
fact_manager.AddFactDataSynonym(MakeDataDescriptor(18, {}),
|
|
MakeDataDescriptor(16, {}), context.get());
|
|
fact_manager.AddFactIdEquation(19, SpvOpISub, {14, 18}, context.get());
|
|
fact_manager.AddFactIdEquation(20, SpvOpISub, {14, 17}, context.get());
|
|
fact_manager.AddFactDataSynonym(MakeDataDescriptor(21, {}),
|
|
MakeDataDescriptor(14, {}), context.get());
|
|
fact_manager.AddFactIdEquation(22, SpvOpISub, {16, 21}, context.get());
|
|
fact_manager.AddFactDataSynonym(MakeDataDescriptor(23, {}),
|
|
MakeDataDescriptor(22, {}), context.get());
|
|
fact_manager.AddFactIdEquation(24, SpvOpSNegate, {23}, context.get());
|
|
|
|
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;
|
|
|
|
fact_manager.AddFactIdEquation(14, SpvOpISub, {15, 16}, context.get());
|
|
fact_manager.AddFactIdEquation(17, SpvOpIAdd, {14, 16}, context.get());
|
|
|
|
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(17, {}),
|
|
MakeDataDescriptor(15, {})));
|
|
|
|
fact_manager.AddFactIdEquation(18, SpvOpIAdd, {16, 14}, context.get());
|
|
|
|
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}, context.get());
|
|
fact_manager.AddFactIdEquation(20, SpvOpSNegate, {19}, context.get());
|
|
|
|
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(20, {}),
|
|
MakeDataDescriptor(16, {})));
|
|
|
|
fact_manager.AddFactIdEquation(21, SpvOpISub, {14, 19}, context.get());
|
|
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(21, {}),
|
|
MakeDataDescriptor(15, {})));
|
|
|
|
fact_manager.AddFactIdEquation(22, SpvOpISub, {14, 18}, context.get());
|
|
fact_manager.AddFactIdEquation(23, SpvOpSNegate, {22}, context.get());
|
|
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(23, {}),
|
|
MakeDataDescriptor(16, {})));
|
|
}
|
|
|
|
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;
|
|
|
|
fact_manager.AddFactIdEquation(14, SpvOpISub, {15, 16}, context.get());
|
|
fact_manager.AddFactDataSynonym(MakeDataDescriptor(114, {}),
|
|
MakeDataDescriptor(14, {}), context.get());
|
|
fact_manager.AddFactIdEquation(17, SpvOpIAdd, {114, 16}, context.get());
|
|
|
|
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(17, {}),
|
|
MakeDataDescriptor(15, {})));
|
|
|
|
fact_manager.AddFactIdEquation(18, SpvOpIAdd, {16, 114}, context.get());
|
|
|
|
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}, context.get());
|
|
fact_manager.AddFactDataSynonym(MakeDataDescriptor(119, {}),
|
|
MakeDataDescriptor(19, {}), context.get());
|
|
fact_manager.AddFactIdEquation(20, SpvOpSNegate, {119}, context.get());
|
|
|
|
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(20, {}),
|
|
MakeDataDescriptor(16, {})));
|
|
|
|
fact_manager.AddFactIdEquation(21, SpvOpISub, {14, 19}, context.get());
|
|
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(21, {}),
|
|
MakeDataDescriptor(15, {})));
|
|
|
|
fact_manager.AddFactIdEquation(22, SpvOpISub, {14, 18}, context.get());
|
|
fact_manager.AddFactDataSynonym(MakeDataDescriptor(22, {}),
|
|
MakeDataDescriptor(220, {}), context.get());
|
|
fact_manager.AddFactIdEquation(23, SpvOpSNegate, {220}, context.get());
|
|
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(23, {}),
|
|
MakeDataDescriptor(16, {})));
|
|
}
|
|
|
|
} // namespace
|
|
} // namespace fuzz
|
|
} // namespace spvtools
|