spirv-fuzz: Improve transformation test oracles (#4207)

To help ensure that optimizations that do less cautious invalidation
of analyses are implemented correctly, this change adds checks to the
tests of various transformations to ensure that analyses such as
def-use are up to date.
This commit is contained in:
Alastair Donaldson 2021-03-23 13:31:14 +00:00 committed by GitHub
parent edb8399b0f
commit 3d39517961
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 176 additions and 22 deletions

View File

@ -90,19 +90,34 @@ TEST(TransformationAddTypeArrayTest, BasicTest) {
ASSERT_FALSE(TransformationAddTypeArray(100, 11, 17)
.IsApplicable(context.get(), transformation_context));
TransformationAddTypeArray transformations[] = {
{
// %100 = OpTypeArray %10 %16
TransformationAddTypeArray(100, 10, 16),
// %101 = OpTypeArray %7 %12
TransformationAddTypeArray(101, 7, 12)};
for (auto& transformation : transformations) {
TransformationAddTypeArray transformation(100, 10, 16);
ASSERT_EQ(nullptr, context->get_def_use_mgr()->GetDef(100));
ASSERT_EQ(nullptr, context->get_type_mgr()->GetType(100));
ASSERT_TRUE(
transformation.IsApplicable(context.get(), transformation_context));
ApplyAndCheckFreshIds(transformation, context.get(),
&transformation_context);
ASSERT_EQ(SpvOpTypeArray,
context->get_def_use_mgr()->GetDef(100)->opcode());
ASSERT_NE(nullptr, context->get_type_mgr()->GetType(100)->AsArray());
}
{
// %101 = OpTypeArray %7 %12
TransformationAddTypeArray transformation(101, 7, 12);
ASSERT_EQ(nullptr, context->get_def_use_mgr()->GetDef(101));
ASSERT_EQ(nullptr, context->get_type_mgr()->GetType(101));
ASSERT_TRUE(
transformation.IsApplicable(context.get(), transformation_context));
ApplyAndCheckFreshIds(transformation, context.get(),
&transformation_context);
ASSERT_EQ(SpvOpTypeArray,
context->get_def_use_mgr()->GetDef(100)->opcode());
ASSERT_NE(nullptr, context->get_type_mgr()->GetType(100)->AsArray());
}
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
kConsoleMessageConsumer));

View File

@ -52,9 +52,13 @@ TEST(TransformationAddTypeBooleanTest, BasicTest) {
context.get(), transformation_context));
auto add_type_bool = TransformationAddTypeBoolean(100);
ASSERT_EQ(nullptr, context->get_def_use_mgr()->GetDef(100));
ASSERT_EQ(nullptr, context->get_type_mgr()->GetType(100));
ASSERT_TRUE(
add_type_bool.IsApplicable(context.get(), transformation_context));
ApplyAndCheckFreshIds(add_type_bool, context.get(), &transformation_context);
ASSERT_EQ(SpvOpTypeBool, context->get_def_use_mgr()->GetDef(100)->opcode());
ASSERT_NE(nullptr, context->get_type_mgr()->GetType(100)->AsBool());
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
kConsoleMessageConsumer));

View File

@ -103,15 +103,27 @@ TEST(TransformationAddTypeFloatTest, Apply) {
MakeUnique<FactManager>(context.get()), validator_options);
// Adds 16-bit float type.
auto transformation = TransformationAddTypeFloat(6, 16);
ASSERT_EQ(nullptr, context->get_def_use_mgr()->GetDef(6));
ASSERT_EQ(nullptr, context->get_type_mgr()->GetType(6));
ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
ASSERT_EQ(SpvOpTypeFloat, context->get_def_use_mgr()->GetDef(6)->opcode());
ASSERT_NE(nullptr, context->get_type_mgr()->GetType(6)->AsFloat());
// Adds 32-bit float type.
transformation = TransformationAddTypeFloat(7, 32);
ASSERT_EQ(nullptr, context->get_def_use_mgr()->GetDef(7));
ASSERT_EQ(nullptr, context->get_type_mgr()->GetType(7));
ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
ASSERT_EQ(SpvOpTypeFloat, context->get_def_use_mgr()->GetDef(7)->opcode());
ASSERT_NE(nullptr, context->get_type_mgr()->GetType(7)->AsFloat());
// Adds 64-bit float type.
transformation = TransformationAddTypeFloat(8, 64);
ASSERT_EQ(nullptr, context->get_def_use_mgr()->GetDef(8));
ASSERT_EQ(nullptr, context->get_type_mgr()->GetType(8));
ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
ASSERT_EQ(SpvOpTypeFloat, context->get_def_use_mgr()->GetDef(8)->opcode());
ASSERT_NE(nullptr, context->get_type_mgr()->GetType(8)->AsFloat());
std::string variant_shader = R"(
OpCapability Shader

View File

@ -118,8 +118,14 @@ TEST(TransformationAddTypeIntTest, Apply) {
TransformationContext transformation_context(
MakeUnique<FactManager>(context.get()), validator_options);
// Adds signed 8-bit integer type.
// For this transformation we also check that the def-use manager and type
// manager are updated appropriately.
auto transformation = TransformationAddTypeInt(6, 8, true);
ASSERT_EQ(nullptr, context->get_def_use_mgr()->GetDef(6));
ASSERT_EQ(nullptr, context->get_type_mgr()->GetType(6));
ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
ASSERT_EQ(SpvOpTypeInt, context->get_def_use_mgr()->GetDef(6)->opcode());
ASSERT_NE(nullptr, context->get_type_mgr()->GetType(6)->AsInteger());
// Adds signed 16-bit integer type.
transformation = TransformationAddTypeInt(7, 16, true);

View File

@ -63,10 +63,21 @@ TEST(TransformationAddTypeMatrixTest, BasicTest) {
ASSERT_FALSE(TransformationAddTypeMatrix(100, 11, 2)
.IsApplicable(context.get(), transformation_context));
TransformationAddTypeMatrix transformations[] = {
{
// %100 = OpTypeMatrix %8 2
TransformationAddTypeMatrix(100, 8, 2),
TransformationAddTypeMatrix transformation(100, 8, 2);
ASSERT_EQ(nullptr, context->get_def_use_mgr()->GetDef(100));
ASSERT_EQ(nullptr, context->get_type_mgr()->GetType(100));
ASSERT_TRUE(
transformation.IsApplicable(context.get(), transformation_context));
ApplyAndCheckFreshIds(transformation, context.get(),
&transformation_context);
ASSERT_EQ(SpvOpTypeMatrix,
context->get_def_use_mgr()->GetDef(100)->opcode());
ASSERT_NE(nullptr, context->get_type_mgr()->GetType(100)->AsMatrix());
}
TransformationAddTypeMatrix transformations[] = {
// %101 = OpTypeMatrix %8 3
TransformationAddTypeMatrix(101, 8, 3),

View File

@ -133,10 +133,24 @@ TEST(TransformationAddTypePointerTest, BasicTest) {
ASSERT_FALSE(bad_result_id_is_not_fresh.IsApplicable(context.get(),
transformation_context));
{
auto& transformation = good_new_private_pointer_to_t;
ASSERT_EQ(nullptr, context->get_def_use_mgr()->GetDef(101));
ASSERT_EQ(nullptr, context->get_type_mgr()->GetType(101));
ASSERT_TRUE(
transformation.IsApplicable(context.get(), transformation_context));
ApplyAndCheckFreshIds(transformation, context.get(),
&transformation_context);
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
context.get(), validator_options, kConsoleMessageConsumer));
ASSERT_EQ(SpvOpTypePointer,
context->get_def_use_mgr()->GetDef(101)->opcode());
ASSERT_NE(nullptr, context->get_type_mgr()->GetType(101)->AsPointer());
}
for (auto& transformation :
{good_new_private_pointer_to_t, good_new_uniform_pointer_to_t,
good_another_function_pointer_to_s, good_new_uniform_pointer_to_s,
good_another_private_pointer_to_float,
{good_new_uniform_pointer_to_t, good_another_function_pointer_to_s,
good_new_uniform_pointer_to_s, good_another_private_pointer_to_float,
good_new_private_pointer_to_private_pointer_to_float,
good_new_uniform_pointer_to_vec2,
good_new_private_pointer_to_uniform_pointer_to_vec2}) {

View File

@ -63,10 +63,21 @@ TEST(TransformationAddTypeStructTest, BasicTest) {
ASSERT_FALSE(TransformationAddTypeStruct(100, {3}).IsApplicable(
context.get(), transformation_context));
TransformationAddTypeStruct transformations[] = {
{
// %100 = OpTypeStruct %6 %7 %8 %9 %10 %11
TransformationAddTypeStruct(100, {6, 7, 8, 9, 10, 11}),
TransformationAddTypeStruct transformation(100, {6, 7, 8, 9, 10, 11});
ASSERT_EQ(nullptr, context->get_def_use_mgr()->GetDef(100));
ASSERT_EQ(nullptr, context->get_type_mgr()->GetType(100));
ASSERT_TRUE(
transformation.IsApplicable(context.get(), transformation_context));
ApplyAndCheckFreshIds(transformation, context.get(),
&transformation_context);
ASSERT_EQ(SpvOpTypeStruct,
context->get_def_use_mgr()->GetDef(100)->opcode());
ASSERT_NE(nullptr, context->get_type_mgr()->GetType(100)->AsStruct());
}
TransformationAddTypeStruct transformations[] = {
// %101 = OpTypeStruct
TransformationAddTypeStruct(101, {}),

View File

@ -57,10 +57,21 @@ TEST(TransformationAddTypeVectorTest, BasicTest) {
ASSERT_FALSE(TransformationAddTypeVector(100, 1, 2).IsApplicable(
context.get(), transformation_context));
TransformationAddTypeVector transformations[] = {
{
// %100 = OpTypeVector %6 2
TransformationAddTypeVector(100, 6, 2),
TransformationAddTypeVector transformation(100, 6, 2);
ASSERT_EQ(nullptr, context->get_def_use_mgr()->GetDef(100));
ASSERT_EQ(nullptr, context->get_type_mgr()->GetType(100));
ASSERT_TRUE(
transformation.IsApplicable(context.get(), transformation_context));
ApplyAndCheckFreshIds(transformation, context.get(),
&transformation_context);
ASSERT_EQ(SpvOpTypeVector,
context->get_def_use_mgr()->GetDef(100)->opcode());
ASSERT_NE(nullptr, context->get_type_mgr()->GetType(100)->AsVector());
}
TransformationAddTypeVector transformations[] = {
// %101 = OpTypeVector %7 3
TransformationAddTypeVector(101, 7, 3),

View File

@ -146,8 +146,19 @@ TEST(TransformationCompositeConstructTest, ConstructArrays) {
transformation_context));
ASSERT_FALSE(make_vec2_array_length_3_bad.IsApplicable(
context.get(), transformation_context));
ASSERT_EQ(nullptr, context->get_def_use_mgr()->GetDef(200));
ASSERT_EQ(nullptr, context->get_instr_block(200));
uint32_t num_uses_of_41_before = context->get_def_use_mgr()->NumUses(41);
uint32_t num_uses_of_45_before = context->get_def_use_mgr()->NumUses(45);
uint32_t num_uses_of_27_before = context->get_def_use_mgr()->NumUses(27);
ApplyAndCheckFreshIds(make_vec2_array_length_3, context.get(),
&transformation_context);
ASSERT_EQ(SpvOpCompositeConstruct,
context->get_def_use_mgr()->GetDef(200)->opcode());
ASSERT_EQ(34, context->get_instr_block(200)->id());
ASSERT_EQ(num_uses_of_41_before + 1, context->get_def_use_mgr()->NumUses(41));
ASSERT_EQ(num_uses_of_45_before + 1, context->get_def_use_mgr()->NumUses(45));
ASSERT_EQ(num_uses_of_27_before + 1, context->get_def_use_mgr()->NumUses(27));
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
kConsoleMessageConsumer));
ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(

View File

@ -143,10 +143,18 @@ TEST(TransformationCompositeExtractTest, BasicTest) {
TransformationCompositeExtract transformation_1(
MakeInstructionDescriptor(36, SpvOpConvertFToS, 0), 201, 100, {2});
ASSERT_EQ(nullptr, context->get_def_use_mgr()->GetDef(201));
ASSERT_EQ(nullptr, context->get_instr_block(201));
uint32_t num_uses_of_100_before = context->get_def_use_mgr()->NumUses(100);
ASSERT_TRUE(
transformation_1.IsApplicable(context.get(), transformation_context));
ApplyAndCheckFreshIds(transformation_1, context.get(),
&transformation_context);
ASSERT_EQ(SpvOpCompositeExtract,
context->get_def_use_mgr()->GetDef(201)->opcode());
ASSERT_EQ(15, context->get_instr_block(201)->id());
ASSERT_EQ(num_uses_of_100_before + 1,
context->get_def_use_mgr()->NumUses(100));
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
kConsoleMessageConsumer));

View File

@ -102,8 +102,12 @@ TEST(TransformationEquationInstructionTest, SignedNegate) {
14, SpvOpSNegate, {7}, return_instruction);
ASSERT_TRUE(
transformation1.IsApplicable(context.get(), transformation_context));
ASSERT_EQ(nullptr, context->get_def_use_mgr()->GetDef(14));
ASSERT_EQ(nullptr, context->get_instr_block(14));
ApplyAndCheckFreshIds(transformation1, context.get(),
&transformation_context);
ASSERT_EQ(SpvOpSNegate, context->get_def_use_mgr()->GetDef(14)->opcode());
ASSERT_EQ(13, context->get_instr_block(14)->id());
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
kConsoleMessageConsumer));

View File

@ -105,6 +105,23 @@ TEST(TransformationPermutePhiOperandsTest, BasicTest) {
transformation.IsApplicable(context.get(), transformation_context));
ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
// Check that the def-use manager knows that the phi instruction's ids have
// been permuted.
std::vector<std::pair<uint32_t, uint32_t>> phi_operand_to_new_operand_index =
{{20, 4}, {16, 5}, {24, 2}, {21, 3}};
for (std::pair<uint32_t, uint32_t>& entry :
phi_operand_to_new_operand_index) {
context->get_def_use_mgr()->WhileEachUse(
entry.first,
[&entry](opt::Instruction* inst, uint32_t operand_index) -> bool {
if (inst->result_id() == 25) {
EXPECT_EQ(entry.second, operand_index);
return false;
}
return true;
});
}
std::string after_transformation = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"

View File

@ -303,10 +303,18 @@ TEST(TransformationReplaceIdWithSynonymTest, LegalTransformations) {
auto global_constant_synonym = TransformationReplaceIdWithSynonym(
MakeIdUseDescriptor(19, MakeInstructionDescriptor(47, SpvOpStore, 0), 1),
210);
uint32_t num_uses_of_original_id_before_replacement =
context->get_def_use_mgr()->NumUses(19);
uint32_t num_uses_of_synonym_before_replacement =
context->get_def_use_mgr()->NumUses(210);
ASSERT_TRUE(global_constant_synonym.IsApplicable(context.get(),
transformation_context));
ApplyAndCheckFreshIds(global_constant_synonym, context.get(),
&transformation_context);
ASSERT_EQ(num_uses_of_original_id_before_replacement - 1,
context->get_def_use_mgr()->NumUses(19));
ASSERT_EQ(num_uses_of_synonym_before_replacement + 1,
context->get_def_use_mgr()->NumUses(210));
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
kConsoleMessageConsumer));

View File

@ -958,8 +958,8 @@ TEST(TransformationSetLoopControlTest, CheckSPIRVVersionsRespected) {
context.get(), validator_options, kConsoleMessageConsumer));
TransformationContext transformation_context(
MakeUnique<FactManager>(context.get()), validator_options);
TransformationSetLoopControl peel_count(
10, SpvLoopControlPeelCountMask, 4, 0);
TransformationSetLoopControl peel_count(10, SpvLoopControlPeelCountMask, 4,
0);
TransformationSetLoopControl partial_count(
10, SpvLoopControlPartialCountMask, 0, 4);

View File

@ -91,9 +91,31 @@ TEST(TransformationSwapConditionalBranchOperandsTest, BasicTest) {
TransformationSwapConditionalBranchOperands transformation(
MakeInstructionDescriptor(15, SpvOpBranchConditional, 0), 26);
ASSERT_EQ(nullptr, context->get_def_use_mgr()->GetDef(26));
ASSERT_EQ(nullptr, context->get_instr_block(26));
ASSERT_TRUE(
transformation.IsApplicable(context.get(), transformation_context));
ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
ASSERT_EQ(SpvOpLogicalNot, context->get_def_use_mgr()->GetDef(26)->opcode());
ASSERT_EQ(5, context->get_instr_block(26)->id());
ASSERT_EQ(1, context->get_def_use_mgr()->NumUses(26));
// Check that the def-use manager knows that the conditional branch operands
// have been swapped.
std::vector<std::pair<uint32_t, uint32_t>> phi_operand_to_new_operand_index =
{{16, 2}, {21, 1}};
for (std::pair<uint32_t, uint32_t>& entry :
phi_operand_to_new_operand_index) {
context->get_def_use_mgr()->WhileEachUse(
entry.first,
[&entry](opt::Instruction* inst, uint32_t operand_index) -> bool {
if (inst->opcode() == SpvOpBranchConditional) {
EXPECT_EQ(entry.second, operand_index);
return false;
}
return true;
});
}
std::string after_transformation = R"(
OpCapability Shader