spirv-fuzz: Fix OutlineFunction in presence of unreachable blocks (#4308)

This change prevents TransformationOutlineFunction from outlining a
region of blocks if some block in the region has an unreachable
predecessor. This avoids a bug whereby the region would be outlined,
and the unreachable predecessors would be left behind, referring to
blocks that are no longer in the function.
This commit is contained in:
Alastair Donaldson 2021-06-01 11:44:21 +01:00 committed by GitHub
parent 9646c733e9
commit 0861a8fa21
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 52 additions and 0 deletions

View File

@ -175,6 +175,19 @@ bool TransformationOutlineFunction::IsApplicable(
// This is achieved by going through every block in the function that contains
// the region.
for (auto& block : *entry_block->GetParent()) {
if (region_set.count(&block) != 0) {
// The block is in the region. Check that it does not have any unreachable
// predecessors. If it does, then we do not regard the region as single-
// entry-single-exit and hence do not outline it.
for (auto pred : ir_context->cfg()->preds(block.id())) {
if (!fuzzerutil::BlockIsReachableInItsFunction(
ir_context, ir_context->cfg()->block(pred))) {
// The predecessor is unreachable.
return false;
}
}
}
if (&block == exit_block) {
// It is OK (and typically expected) for the exit block of the region to
// have successors outside the region.

View File

@ -3207,6 +3207,45 @@ TEST(TransformationOutlineFunctionTest, Miscellaneous4) {
ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
}
TEST(TransformationOutlineFunctionTest, NoOutlineWithUnreachableBlocks) {
// This checks that outlining will not be performed if a node in the region
// has an unreachable predecessor.
std::string shader = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %4 "main"
OpExecutionMode %4 OriginUpperLeft
OpSource ESSL 310
OpName %4 "main"
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%4 = OpFunction %2 None %3
%7 = OpLabel
OpBranch %5
%5 = OpLabel
OpReturn
%6 = OpLabel
OpBranch %5
OpFunctionEnd
)";
const auto env = SPV_ENV_UNIVERSAL_1_4;
const auto consumer = nullptr;
const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
spvtools::ValidatorOptions validator_options;
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
kConsoleMessageConsumer));
TransformationContext transformation_context(
MakeUnique<FactManager>(context.get()), validator_options);
TransformationOutlineFunction transformation(5, 5, /* not relevant */ 200,
100, 101, 102, 103,
/* not relevant */ 201, {}, {});
ASSERT_FALSE(
transformation.IsApplicable(context.get(), transformation_context));
}
} // namespace
} // namespace fuzz
} // namespace spvtools