diff --git a/source/fuzz/transformation_outline_function.cpp b/source/fuzz/transformation_outline_function.cpp index 6ee912259..84e8ac2c3 100644 --- a/source/fuzz/transformation_outline_function.cpp +++ b/source/fuzz/transformation_outline_function.cpp @@ -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. diff --git a/test/fuzz/transformation_outline_function_test.cpp b/test/fuzz/transformation_outline_function_test.cpp index c567680c1..cc62049d2 100644 --- a/test/fuzz/transformation_outline_function_test.cpp +++ b/test/fuzz/transformation_outline_function_test.cpp @@ -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(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