SPIRV-Tools/test/fuzz/fuzzer_pass_add_useful_constructs_test.cpp
Alastair Donaldson 51b0d5ce50
Represent uniform facts via descriptor set and binding. (#2681)
* Represent uniform facts via descriptor set and binding.

Previously uniform facts were expressed with resepect to the id of a
uniform variable.  Describing them with respect to a descriptor set
and binding is more convenient from the point of view of expressing
facts about a shader without requiring analysis of its SPIR-V.

* Fix equality testing for uniform buffer element descriptors.

The equality test now checks that the lengths of the index vectors
match.  Added a test that exposes the previous omission.
2019-06-19 20:45:14 +01:00

394 lines
15 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 "source/fuzz/fuzzer_pass_add_useful_constructs.h"
#include "source/fuzz/pseudo_random_generator.h"
#include "source/fuzz/uniform_buffer_element_descriptor.h"
#include "test/fuzz/fuzz_test_util.h"
namespace spvtools {
namespace fuzz {
namespace {
bool AddFactHelper(
FactManager* fact_manager, opt::IRContext* context, uint32_t word,
const protobufs::UniformBufferElementDescriptor& descriptor) {
protobufs::FactConstantUniform constant_uniform_fact;
constant_uniform_fact.add_constant_word(word);
*constant_uniform_fact.mutable_uniform_buffer_element_descriptor() =
descriptor;
protobufs::Fact fact;
*fact.mutable_constant_uniform_fact() = constant_uniform_fact;
return fact_manager->AddFact(fact, context);
}
TEST(FuzzerPassAddUsefulConstructsTest, CheckBasicStuffIsAdded) {
// The SPIR-V came from the following empty GLSL shader:
//
// #version 450
//
// void main()
// {
// }
std::string shader = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %4 "main"
OpExecutionMode %4 OriginUpperLeft
OpSource GLSL 450
OpName %4 "main"
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%4 = OpFunction %2 None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
const auto env = SPV_ENV_UNIVERSAL_1_3;
const auto consumer = nullptr;
const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
ASSERT_TRUE(IsValid(env, context.get()));
FactManager fact_manager;
FuzzerContext fuzzer_context(MakeUnique<PseudoRandomGenerator>(0).get(), 100);
protobufs::TransformationSequence transformation_sequence;
FuzzerPassAddUsefulConstructs pass(context.get(), &fact_manager,
&fuzzer_context, &transformation_sequence);
pass.Apply();
ASSERT_TRUE(IsValid(env, context.get()));
std::string after = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %4 "main"
OpExecutionMode %4 OriginUpperLeft
OpSource GLSL 450
OpName %4 "main"
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%100 = OpTypeBool
%101 = OpTypeInt 32 1
%102 = OpTypeInt 32 0
%103 = OpTypeFloat 32
%104 = OpConstantTrue %100
%105 = OpConstantFalse %100
%106 = OpConstant %101 0
%107 = OpConstant %101 1
%108 = OpConstant %102 0
%109 = OpConstant %102 1
%110 = OpConstant %103 0
%111 = OpConstant %103 1
%4 = OpFunction %2 None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
ASSERT_TRUE(IsEqual(env, after, context.get()));
}
TEST(FuzzerPassAddUsefulConstructsTest,
CheckTypesIndicesAndConstantsAddedForUniformFacts) {
// The SPIR-V came from the following GLSL shader:
//
// #version 450
//
// struct S {
// int x;
// float y;
// int z;
// int w;
// };
//
// uniform buf {
// S s;
// uint w[10];
// };
//
// void main() {
// }
std::string shader = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %4 "main"
OpExecutionMode %4 OriginUpperLeft
OpSource GLSL 450
OpName %4 "main"
OpName %8 "S"
OpMemberName %8 0 "x"
OpMemberName %8 1 "y"
OpMemberName %8 2 "z"
OpMemberName %8 3 "w"
OpName %12 "buf"
OpMemberName %12 0 "s"
OpMemberName %12 1 "w"
OpName %14 ""
OpMemberDecorate %8 0 Offset 0
OpMemberDecorate %8 1 Offset 4
OpMemberDecorate %8 2 Offset 8
OpMemberDecorate %8 3 Offset 12
OpDecorate %11 ArrayStride 16
OpMemberDecorate %12 0 Offset 0
OpMemberDecorate %12 1 Offset 16
OpDecorate %12 Block
OpDecorate %14 DescriptorSet 0
OpDecorate %14 Binding 0
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%6 = OpTypeInt 32 1
%7 = OpTypeFloat 32
%8 = OpTypeStruct %6 %7 %6 %6
%9 = OpTypeInt 32 0
%10 = OpConstant %9 10
%11 = OpTypeArray %9 %10
%12 = OpTypeStruct %8 %11
%13 = OpTypePointer Uniform %12
%14 = OpVariable %13 Uniform
%4 = OpFunction %2 None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
const auto env = SPV_ENV_UNIVERSAL_1_3;
const auto consumer = nullptr;
const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
ASSERT_TRUE(IsValid(env, context.get()));
FactManager fact_manager;
FuzzerContext fuzzer_context(MakeUnique<PseudoRandomGenerator>(0).get(), 100);
protobufs::TransformationSequence transformation_sequence;
// Add some uniform facts.
// buf.s.x == 200
ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), 200,
MakeUniformBufferElementDescriptor(0, 0, {0, 0})));
// buf.s.y == 0.5
const float float_value = 0.5;
uint32_t float_value_as_uint;
memcpy(&float_value_as_uint, &float_value, sizeof(float_value));
ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), float_value_as_uint,
MakeUniformBufferElementDescriptor(0, 0, {0, 1})));
// buf.s.z == 300
ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), 300,
MakeUniformBufferElementDescriptor(0, 0, {0, 2})));
// buf.s.w == 400
ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), 400,
MakeUniformBufferElementDescriptor(0, 0, {0, 3})));
// buf.w[6] = 22
ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), 22,
MakeUniformBufferElementDescriptor(0, 0, {1, 6})));
// buf.w[8] = 23
ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), 23,
MakeUniformBufferElementDescriptor(0, 0, {1, 8})));
// Assert some things about the module that are not true prior to adding the
// pass
{
// No uniform int pointer
opt::analysis::Integer temp_type_signed_int(32, true);
opt::analysis::Integer* registered_type_signed_int =
context->get_type_mgr()
->GetRegisteredType(&temp_type_signed_int)
->AsInteger();
opt::analysis::Pointer type_pointer_uniform_signed_int(
registered_type_signed_int, SpvStorageClassUniform);
ASSERT_EQ(0,
context->get_type_mgr()->GetId(&type_pointer_uniform_signed_int));
// No uniform uint pointer
opt::analysis::Integer temp_type_unsigned_int(32, false);
opt::analysis::Integer* registered_type_unsigned_int =
context->get_type_mgr()
->GetRegisteredType(&temp_type_unsigned_int)
->AsInteger();
opt::analysis::Pointer type_pointer_uniform_unsigned_int(
registered_type_unsigned_int, SpvStorageClassUniform);
ASSERT_EQ(
0, context->get_type_mgr()->GetId(&type_pointer_uniform_unsigned_int));
// No uniform float pointer
opt::analysis::Float temp_type_float(32);
opt::analysis::Float* registered_type_float =
context->get_type_mgr()->GetRegisteredType(&temp_type_float)->AsFloat();
opt::analysis::Pointer type_pointer_uniform_float(registered_type_float,
SpvStorageClassUniform);
ASSERT_EQ(0, context->get_type_mgr()->GetId(&type_pointer_uniform_float));
// No int constants 200, 300 nor 400
opt::analysis::IntConstant int_constant_200(registered_type_signed_int,
{200});
opt::analysis::IntConstant int_constant_300(registered_type_signed_int,
{300});
opt::analysis::IntConstant int_constant_400(registered_type_signed_int,
{400});
ASSERT_EQ(nullptr,
context->get_constant_mgr()->FindConstant(&int_constant_200));
ASSERT_EQ(nullptr,
context->get_constant_mgr()->FindConstant(&int_constant_300));
ASSERT_EQ(nullptr,
context->get_constant_mgr()->FindConstant(&int_constant_400));
// No float constant 0.5
opt::analysis::FloatConstant float_constant_zero_point_five(
registered_type_float, {float_value_as_uint});
ASSERT_EQ(nullptr, context->get_constant_mgr()->FindConstant(
&float_constant_zero_point_five));
// No uint constant 22
opt::analysis::IntConstant uint_constant_22(registered_type_unsigned_int,
{22});
ASSERT_EQ(nullptr,
context->get_constant_mgr()->FindConstant(&uint_constant_22));
// No uint constant 23
opt::analysis::IntConstant uint_constant_23(registered_type_unsigned_int,
{23});
ASSERT_EQ(nullptr,
context->get_constant_mgr()->FindConstant(&uint_constant_23));
// No int constants 0, 1, 2, 3, 6, 8
opt::analysis::IntConstant int_constant_0(registered_type_signed_int, {0});
opt::analysis::IntConstant int_constant_1(registered_type_signed_int, {1});
opt::analysis::IntConstant int_constant_2(registered_type_signed_int, {2});
opt::analysis::IntConstant int_constant_3(registered_type_signed_int, {3});
opt::analysis::IntConstant int_constant_6(registered_type_signed_int, {6});
opt::analysis::IntConstant int_constant_8(registered_type_signed_int, {8});
ASSERT_EQ(nullptr,
context->get_constant_mgr()->FindConstant(&int_constant_0));
ASSERT_EQ(nullptr,
context->get_constant_mgr()->FindConstant(&int_constant_1));
ASSERT_EQ(nullptr,
context->get_constant_mgr()->FindConstant(&int_constant_2));
ASSERT_EQ(nullptr,
context->get_constant_mgr()->FindConstant(&int_constant_3));
ASSERT_EQ(nullptr,
context->get_constant_mgr()->FindConstant(&int_constant_6));
ASSERT_EQ(nullptr,
context->get_constant_mgr()->FindConstant(&int_constant_8));
}
FuzzerPassAddUsefulConstructs pass(context.get(), &fact_manager,
&fuzzer_context, &transformation_sequence);
pass.Apply();
ASSERT_TRUE(IsValid(env, context.get()));
// Now assert some things about the module that should be true following the
// pass.
// We reconstruct all necessary types and constants to guard against the type
// and constant managers for the module having been invalidated.
{
// Uniform int pointer now present
opt::analysis::Integer temp_type_signed_int(32, true);
opt::analysis::Integer* registered_type_signed_int =
context->get_type_mgr()
->GetRegisteredType(&temp_type_signed_int)
->AsInteger();
opt::analysis::Pointer type_pointer_uniform_signed_int(
registered_type_signed_int, SpvStorageClassUniform);
ASSERT_NE(0,
context->get_type_mgr()->GetId(&type_pointer_uniform_signed_int));
// Uniform uint pointer now present
opt::analysis::Integer temp_type_unsigned_int(32, false);
opt::analysis::Integer* registered_type_unsigned_int =
context->get_type_mgr()
->GetRegisteredType(&temp_type_unsigned_int)
->AsInteger();
opt::analysis::Pointer type_pointer_uniform_unsigned_int(
registered_type_unsigned_int, SpvStorageClassUniform);
ASSERT_NE(
0, context->get_type_mgr()->GetId(&type_pointer_uniform_unsigned_int));
// Uniform float pointer now present
opt::analysis::Float temp_type_float(32);
opt::analysis::Float* registered_type_float =
context->get_type_mgr()->GetRegisteredType(&temp_type_float)->AsFloat();
opt::analysis::Pointer type_pointer_uniform_float(registered_type_float,
SpvStorageClassUniform);
ASSERT_NE(0, context->get_type_mgr()->GetId(&type_pointer_uniform_float));
// int constants 200, 300, 400 now present
opt::analysis::IntConstant int_constant_200(registered_type_signed_int,
{200});
opt::analysis::IntConstant int_constant_300(registered_type_signed_int,
{300});
opt::analysis::IntConstant int_constant_400(registered_type_signed_int,
{400});
ASSERT_NE(nullptr,
context->get_constant_mgr()->FindConstant(&int_constant_200));
ASSERT_NE(nullptr,
context->get_constant_mgr()->FindConstant(&int_constant_300));
ASSERT_NE(nullptr,
context->get_constant_mgr()->FindConstant(&int_constant_400));
// float constant 0.5 now present
opt::analysis::FloatConstant float_constant_zero_point_five(
registered_type_float, {float_value_as_uint});
ASSERT_NE(nullptr, context->get_constant_mgr()->FindConstant(
&float_constant_zero_point_five));
// uint constant 22 now present
opt::analysis::IntConstant uint_constant_22(registered_type_unsigned_int,
{22});
ASSERT_NE(nullptr,
context->get_constant_mgr()->FindConstant(&uint_constant_22));
// uint constant 23 now present
opt::analysis::IntConstant uint_constant_23(registered_type_unsigned_int,
{23});
ASSERT_NE(nullptr,
context->get_constant_mgr()->FindConstant(&uint_constant_23));
// int constants 0, 1, 2, 3, 6, 8 now present
opt::analysis::IntConstant int_constant_0(registered_type_signed_int, {0});
opt::analysis::IntConstant int_constant_1(registered_type_signed_int, {1});
opt::analysis::IntConstant int_constant_2(registered_type_signed_int, {2});
opt::analysis::IntConstant int_constant_3(registered_type_signed_int, {3});
opt::analysis::IntConstant int_constant_6(registered_type_signed_int, {6});
opt::analysis::IntConstant int_constant_8(registered_type_signed_int, {8});
ASSERT_NE(nullptr,
context->get_constant_mgr()->FindConstant(&int_constant_0));
ASSERT_NE(nullptr,
context->get_constant_mgr()->FindConstant(&int_constant_1));
ASSERT_NE(nullptr,
context->get_constant_mgr()->FindConstant(&int_constant_2));
ASSERT_NE(nullptr,
context->get_constant_mgr()->FindConstant(&int_constant_3));
ASSERT_NE(nullptr,
context->get_constant_mgr()->FindConstant(&int_constant_6));
ASSERT_NE(nullptr,
context->get_constant_mgr()->FindConstant(&int_constant_8));
}
}
} // namespace
} // namespace fuzz
} // namespace spvtools