spirv-fuzz: Support identical predecessors in TransformationPropagateInstructionUp (#3689)

Support identical predecessors in TransformationPropagateInstructionUp.

A basic block may have multiple identical predecessors as follows:

%1 = OpLabel
OpSelectionMerge %2 None
OpBranchConditional %true %2 %2
%2 = OpLabel
...

This case wasn't supported before.
This commit is contained in:
Vasyl Teliman 2020-08-14 14:29:36 +03:00 committed by GitHub
parent b4c4da3e76
commit 72ea7bec4a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 95 additions and 3 deletions

View File

@ -44,7 +44,13 @@ void FuzzerPassPropagateInstructionsUp::Apply() {
GetIRContext(), block.id())) {
std::map<uint32_t, uint32_t> fresh_ids;
for (auto id : GetIRContext()->cfg()->preds(block.id())) {
fresh_ids[id] = GetFuzzerContext()->GetFreshId();
auto& fresh_id = fresh_ids[id];
if (!fresh_id) {
// Create a fresh id if it hasn't been created yet. |fresh_id| will
// be default-initialized to 0 in this case.
fresh_id = GetFuzzerContext()->GetFreshId();
}
}
ApplyTransformation(

View File

@ -99,15 +99,18 @@ bool TransformationPropagateInstructionUp::IsApplicable(
const auto predecessor_id_to_fresh_id = fuzzerutil::RepeatedUInt32PairToMap(
message_.predecessor_id_to_fresh_id());
std::vector<uint32_t> maybe_fresh_ids;
for (auto id : ir_context->cfg()->preds(message_.block_id())) {
// Each predecessor must have a fresh id in the |predecessor_id_to_fresh_id|
// map.
if (!predecessor_id_to_fresh_id.count(id)) {
return false;
}
}
maybe_fresh_ids.push_back(predecessor_id_to_fresh_id.at(id));
std::vector<uint32_t> maybe_fresh_ids;
maybe_fresh_ids.reserve(predecessor_id_to_fresh_id.size());
for (const auto& entry : predecessor_id_to_fresh_id) {
maybe_fresh_ids.push_back(entry.second);
}
// All ids must be unique and fresh.
@ -129,7 +132,15 @@ void TransformationPropagateInstructionUp::Apply(
opt::Instruction::OperandList op_phi_operands;
const auto predecessor_id_to_fresh_id = fuzzerutil::RepeatedUInt32PairToMap(
message_.predecessor_id_to_fresh_id());
std::unordered_set<uint32_t> visited_predecessors;
for (auto predecessor_id : ir_context->cfg()->preds(message_.block_id())) {
// A block can have multiple identical predecessors.
if (visited_predecessors.count(predecessor_id)) {
continue;
}
visited_predecessors.insert(predecessor_id);
auto new_result_id = predecessor_id_to_fresh_id.at(predecessor_id);
// Compute InOperands for the OpPhi instruction to be inserted later.

View File

@ -815,6 +815,81 @@ TEST(TransformationPropagateInstructionUpTest,
ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
}
TEST(TransformationPropagateInstructionUpTest, MultipleIdenticalPredecessors) {
std::string shader = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %4 "main"
OpExecutionMode %4 OriginUpperLeft
OpSource ESSL 310
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%6 = OpTypeFloat 32
%11 = OpConstant %6 23
%12 = OpTypeBool
%13 = OpConstantTrue %12
%4 = OpFunction %2 None %3
%5 = OpLabel
OpSelectionMerge %9 None
OpBranchConditional %13 %9 %9
%9 = OpLabel
%14 = OpPhi %6 %11 %5
%10 = OpCopyObject %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;
spvtools::ValidatorOptions validator_options;
TransformationContext transformation_context(&fact_manager,
validator_options);
TransformationPropagateInstructionUp transformation(9, {{{5, 40}}});
ASSERT_TRUE(
transformation.IsApplicable(context.get(), transformation_context));
transformation.Apply(context.get(), &transformation_context);
ASSERT_TRUE(IsValid(env, context.get()));
std::string after_transformation = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %4 "main"
OpExecutionMode %4 OriginUpperLeft
OpSource ESSL 310
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%6 = OpTypeFloat 32
%11 = OpConstant %6 23
%12 = OpTypeBool
%13 = OpConstantTrue %12
%4 = OpFunction %2 None %3
%5 = OpLabel
%40 = OpCopyObject %6 %11
OpSelectionMerge %9 None
OpBranchConditional %13 %9 %9
%9 = OpLabel
%10 = OpPhi %6 %40 %5
%14 = OpPhi %6 %11 %5
OpReturn
OpFunctionEnd
)";
ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
}
} // namespace
} // namespace fuzz
} // namespace spvtools