mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2024-11-26 21:30:07 +00:00
51b0d5ce50
* 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.
394 lines
15 KiB
C++
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
|