spirv-fuzz: Fix to transformation that adds a synonym via a loop (#3898)

Fixes #3897.
This commit is contained in:
Alastair Donaldson 2020-10-13 14:26:47 +01:00 committed by GitHub
parent 4b884928db
commit 2e6cf706ee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 113 additions and 6 deletions

View File

@ -932,7 +932,7 @@ message TransformationAddLoopToCreateIntConstantSynonym {
// A transformation that uses a loop to create a synonym for an integer
// constant C (scalar or vector) using an initial value I, a step value S and
// a number of iterations N such that C = I - N * S. For each iteration, S is
// added to the total.
// subtracted from the total.
// The loop can be made up of one or two blocks, and it is inserted before a
// block with a single predecessor. In the one-block case, it is of the form:
//
@ -942,7 +942,7 @@ message TransformationAddLoopToCreateIntConstantSynonym {
// %eventual_syn_id = OpISub %type_of_I %temp_id %step_val_id
// %incremented_ctr_id = OpIAdd %int %ctr_id %int_1
// %cond_id = OpSLessThan %bool %incremented_ctr_id %num_iterations_id
// OpLoopMerge %block_after_loop_id %loop_id %none
// OpLoopMerge %block_after_loop_id %loop_id None
// OpBranchConditional %cond_id %loop_id %block_after_loop_id
//
// A new OpPhi instruction is then added to %block_after_loop_id, as follows:

View File

@ -387,12 +387,12 @@ void TransformationAddLoopToCreateIntConstantSynonym::Apply(
[this](opt::Instruction* instruction, uint32_t operand_index) {
assert(instruction->opcode() != SpvOpLoopMerge &&
instruction->opcode() != SpvOpSelectionMerge &&
instruction->opcode() != SpvOpSwitch &&
"The block should not be referenced by OpLoopMerge, "
"OpSelectionMerge or OpSwitch instructions, by construction.");
"The block should not be referenced by OpLoopMerge or "
"OpSelectionMerge, by construction.");
// Replace all uses of the label inside branch instructions.
if (instruction->opcode() == SpvOpBranch ||
instruction->opcode() == SpvOpBranchConditional) {
instruction->opcode() == SpvOpBranchConditional ||
instruction->opcode() == SpvOpSwitch) {
instruction->SetOperand(operand_index, {message_.loop_id()});
}
});

View File

@ -1021,6 +1021,113 @@ TEST(TransformationAddLoopToCreateIntConstantSynonymTest,
.IsApplicable(context.get(), transformation_context));
}
TEST(TransformationAddLoopToCreateIntConstantSynonymTest, InserBeforeOpSwitch) {
// Checks that it is acceptable for a loop to be added before a target of an
// OpSwitch instruction.
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
%7 = OpConstant %6 0
%20 = OpConstant %6 1
%21 = OpConstant %6 2
%22 = OpTypeBool
%4 = OpFunction %2 None %3
%5 = OpLabel
OpSelectionMerge %10 None
OpSwitch %7 %9 0 %8
%9 = OpLabel
OpBranch %10
%8 = 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()));
spvtools::ValidatorOptions validator_options;
TransformationContext transformation_context(
MakeUnique<FactManager>(context.get()), validator_options);
auto transformation1 = TransformationAddLoopToCreateIntConstantSynonym(
20, 21, 20, 20, 9, 100, 101, 102, 103, 104, 105, 106, 0);
ASSERT_TRUE(
transformation1.IsApplicable(context.get(), transformation_context));
ApplyAndCheckFreshIds(transformation1, context.get(),
&transformation_context);
ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
MakeDataDescriptor(20, {}), MakeDataDescriptor(100, {})));
ASSERT_TRUE(IsValid(env, context.get()));
auto transformation2 = TransformationAddLoopToCreateIntConstantSynonym(
20, 21, 20, 20, 8, 200, 201, 202, 203, 204, 205, 206, 0);
ASSERT_TRUE(
transformation2.IsApplicable(context.get(), transformation_context));
ApplyAndCheckFreshIds(transformation2, context.get(),
&transformation_context);
ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
MakeDataDescriptor(20, {}), MakeDataDescriptor(200, {})));
ASSERT_TRUE(IsValid(env, context.get()));
std::string after_transformations = 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
%7 = OpConstant %6 0
%20 = OpConstant %6 1
%21 = OpConstant %6 2
%22 = OpTypeBool
%4 = OpFunction %2 None %3
%5 = OpLabel
OpSelectionMerge %10 None
OpSwitch %7 %101 0 %201
%101 = OpLabel
%102 = OpPhi %6 %7 %5 %105 %101
%103 = OpPhi %6 %21 %5 %104 %101
%104 = OpISub %6 %103 %20
%105 = OpIAdd %6 %102 %20
%106 = OpSLessThan %22 %105 %20
OpLoopMerge %9 %101 None
OpBranchConditional %106 %101 %9
%9 = OpLabel
%100 = OpPhi %6 %104 %101
OpBranch %10
%201 = OpLabel
%202 = OpPhi %6 %7 %5 %205 %201
%203 = OpPhi %6 %21 %5 %204 %201
%204 = OpISub %6 %203 %20
%205 = OpIAdd %6 %202 %20
%206 = OpSLessThan %22 %205 %20
OpLoopMerge %8 %201 None
OpBranchConditional %206 %201 %8
%8 = OpLabel
%200 = OpPhi %6 %204 %201
OpBranch %10
%10 = OpLabel
OpReturn
OpFunctionEnd
)";
ASSERT_TRUE(IsEqual(env, after_transformations, context.get()));
}
} // namespace
} // namespace fuzz
} // namespace spvtools