spirv-reduce: Allow merging unreachable blocks (#4303)

This change allows the reducer to merge together blocks even when they
are unreachable, but keeps the restriction of reachability in place
for the optimizer.

Fixes #4302.
This commit is contained in:
Alastair Donaldson 2021-06-28 23:05:30 +01:00 committed by GitHub
parent 4fcdc58946
commit b8587c984a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 65 additions and 4 deletions

View File

@ -43,6 +43,9 @@ bool TransformationMergeBlocks::IsApplicable(
}
auto first_block = ir_context->cfg()->block(predecessors.at(0));
if (!ir_context->IsReachable(*first_block)) {
return false;
}
return opt::blockmergeutil::CanMergeWithSuccessor(ir_context, first_block);
}

View File

@ -31,6 +31,7 @@ class TransformationMergeBlocks : public Transformation {
TransformationMergeBlocks(uint32_t block_id);
// - |message_.block_id| must be the id of a block, b
// - b must be statically reachable in the control flow graph of its function
// - b must have a single predecessor, a
// - b must be the sole successor of a
// - Replacing a with the merge of a and b (and removing b) must lead to a

View File

@ -28,7 +28,9 @@ namespace opt {
bool BlockMergePass::MergeBlocks(Function* func) {
bool modified = false;
for (auto bi = func->begin(); bi != func->end();) {
if (blockmergeutil::CanMergeWithSuccessor(context(), &*bi)) {
// Don't bother trying to merge unreachable blocks.
if (context()->IsReachable(*bi) &&
blockmergeutil::CanMergeWithSuccessor(context(), &*bi)) {
blockmergeutil::MergeWithSuccessor(context(), func, bi);
// Reprocess block.
modified = true;

View File

@ -103,9 +103,6 @@ bool CanMergeWithSuccessor(IRContext* context, BasicBlock* block) {
return false;
}
// Don't bother trying to merge unreachable blocks.
if (!context->IsReachable(*block)) return false;
Instruction* merge_inst = block->GetMergeInst();
const bool pred_is_header = IsHeader(block);
if (pred_is_header && lab_id != merge_inst->GetSingleWordInOperand(0u)) {

View File

@ -647,6 +647,64 @@ TEST(MergeBlocksReductionPassTest, LoopReturnReverse) {
MergeBlocksReductionPassTest_LoopReturn_Helper(true);
}
TEST(MergeBlocksReductionPassTest, MergeUnreachable) {
std::string shader = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %4 "main"
OpExecutionMode %4 OriginUpperLeft
OpSource ESSL 320
OpName %4 "main"
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%11 = OpTypeBool
%12 = OpConstantFalse %11
%4 = OpFunction %2 None %3
%5 = OpLabel
OpReturn
%9 = OpLabel
OpBranch %100
%100 = OpLabel
OpReturn
OpFunctionEnd
)";
const auto env = SPV_ENV_UNIVERSAL_1_3;
const auto consumer = nullptr;
const auto context =
BuildModule(env, consumer, shader, kReduceAssembleOption);
const auto ops =
MergeBlocksReductionOpportunityFinder().GetAvailableOpportunities(
context.get(), 0);
ASSERT_EQ(1, ops.size());
ASSERT_TRUE(ops[0]->PreconditionHolds());
ops[0]->TryToApply();
std::string after = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %4 "main"
OpExecutionMode %4 OriginUpperLeft
OpSource ESSL 320
OpName %4 "main"
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%11 = OpTypeBool
%12 = OpConstantFalse %11
%4 = OpFunction %2 None %3
%5 = OpLabel
OpReturn
%9 = OpLabel
OpReturn
OpFunctionEnd
)";
CheckEqual(env, after, context.get());
}
} // namespace
} // namespace reduce
} // namespace spvtools