Elide branches to continue block when continue block is also a merge.

This commit is contained in:
Hans-Kristian Arntzen 2019-08-26 14:21:35 +02:00
parent 903ef0e40a
commit 55c2ca90ae
4 changed files with 18 additions and 9 deletions

View File

@ -11,12 +11,10 @@ void main()
if (v0.x == 20.0)
{
FragColor += vec4(v0[_54 & 3]);
continue;
}
else
{
FragColor += vec4(v0[_54 & 1]);
continue;
}
continue;
}

View File

@ -15,12 +15,10 @@ void main()
if ((vA + _57) == 20)
{
_58 = 50;
continue;
}
else
{
_58 = ((vB + _57) == 40) ? 60 : _60;
continue;
}
continue;
}

View File

@ -11,12 +11,10 @@ void main()
if (v0.x == 20.0)
{
FragColor += vec4(v0[i & 3]);
continue;
}
else
{
FragColor += vec4(v0[i & 1]);
continue;
}
}
}

View File

@ -11285,7 +11285,7 @@ void CompilerGLSL::branch_to_continue(uint32_t from, uint32_t to)
// Some simplification for for-loops. We always end up with a useless continue;
// statement since we branch to a loop block.
// Walk the CFG, if we uncoditionally execute the block calling continue assuming we're in the loop block,
// Walk the CFG, if we unconditionally execute the block calling continue assuming we're in the loop block,
// we can avoid writing out an explicit continue statement.
// Similar optimization to return statements if we know we're outside flow control.
if (!outside_control_flow)
@ -11298,6 +11298,8 @@ void CompilerGLSL::branch(uint32_t from, uint32_t to)
flush_phi(from, to);
flush_control_dependent_expressions(from);
bool to_is_continue = is_continue(to);
// This is only a continue if we branch to our loop dominator.
if ((ir.block_meta[to] & ParsedIR::BLOCK_META_LOOP_HEADER_BIT) != 0 && get<SPIRBlock>(from).loop_dominator == to)
{
@ -11326,12 +11328,25 @@ void CompilerGLSL::branch(uint32_t from, uint32_t to)
}
statement("break;");
}
else if (is_continue(to) || (from == to))
else if (to_is_continue || from == to)
{
// For from == to case can happen for a do-while loop which branches into itself.
// We don't mark these cases as continue blocks, but the only possible way to branch into
// ourselves is through means of continue blocks.
branch_to_continue(from, to);
// If we are merging to a continue block, there is no need to emit the block chain for continue here.
// We can branch to the continue block after we merge execution.
// Here we make use of structured control flow rules from spec:
// 2.11: - the merge block declared by a header block cannot be a merge block declared by any other header block
// - each header block must strictly dominate its merge block, unless the merge block is unreachable in the CFG
// If we are branching to a merge block, we must be inside a construct which dominates the merge block.
auto &block_meta = ir.block_meta[to];
bool branching_to_merge =
(block_meta & (ParsedIR::BLOCK_META_SELECTION_MERGE_BIT | ParsedIR::BLOCK_META_MULTISELECT_MERGE_BIT |
ParsedIR::BLOCK_META_LOOP_MERGE_BIT)) != 0;
if (!to_is_continue || !branching_to_merge)
branch_to_continue(from, to);
}
else if (!is_conditional(to))
emit_block_chain(get<SPIRBlock>(to));