Emit complex continue blocks "properly".

This commit is contained in:
Hans-Kristian Arntzen 2018-03-08 17:51:55 +01:00
parent 54549a624f
commit 28cccc3dbb
5 changed files with 62 additions and 16 deletions

View File

@ -28,11 +28,15 @@ void main()
float _58;
_55 = 0.0;
_58 = 0.0;
float _64;
vec4 _72;
float _78;
for (int _60 = -3; _60 <= 3; _64 = float(_60), _72 = texture(SPIRV_Cross_CombinedmapTexturemapSampler, IN_uv + (vec2(0.0, _8.CB1.TextureSize.w) * _64)), _78 = exp(((-_64) * _64) * 0.2222220003604888916015625) * float(abs(_72.y - _50) < clamp((_50 * 80.0) * 0.0007999999797903001308441162109375, 7.999999797903001308441162109375e-05, 0.008000000379979610443115234375)), _55 += (_72.x * _78), _58 += _78, _60++)
for (int _60 = -3; _60 <= 3; )
{
float _64 = float(_60);
vec4 _72 = texture(SPIRV_Cross_CombinedmapTexturemapSampler, IN_uv + (vec2(0.0, _8.CB1.TextureSize.w) * _64));
float _78 = exp(((-_64) * _64) * 0.2222220003604888916015625) * float(abs(_72.y - _50) < clamp((_50 * 80.0) * 0.0007999999797903001308441162109375, 7.999999797903001308441162109375e-05, 0.008000000379979610443115234375));
_55 += (_72.x * _78);
_58 += _78;
_60++;
continue;
}
_entryPointOutput = vec4(_55 / _58, _50, 0.0, 1.0);
}

View File

@ -28,11 +28,15 @@ void main()
float _58;
_55 = 0.0;
_58 = 0.0;
float _64;
vec4 _72;
float _78;
for (int _60 = -3; _60 <= 3; _64 = float(_60), _72 = texture(SPIRV_Cross_CombinedmapTexturemapSampler, IN_uv + (vec2(0.0, _8.CB1.TextureSize.w) * _64)), _78 = exp(((-_64) * _64) * 0.2222220003604888916015625) * float(abs(_72.y - _50) < clamp((_50 * 80.0) * 0.0007999999797903001308441162109375, 7.999999797903001308441162109375e-05, 0.008000000379979610443115234375)), _55 += (_72.x * _78), _58 += _78, _60++)
for (int _60 = -3; _60 <= 3; )
{
float _64 = float(_60);
vec4 _72 = texture(SPIRV_Cross_CombinedmapTexturemapSampler, IN_uv + (vec2(0.0, _8.CB1.TextureSize.w) * _64));
float _78 = exp(((-_64) * _64) * 0.2222220003604888916015625) * float(abs(_72.y - _50) < clamp((_50 * 80.0) * 0.0007999999797903001308441162109375, 7.999999797903001308441162109375e-05, 0.008000000379979610443115234375));
_55 += (_72.x * _78);
_58 += _78;
_60++;
continue;
}
_entryPointOutput = vec4(_55 / _58, _50, 0.0, 1.0);
}

View File

@ -460,7 +460,8 @@ struct SPIRBlock : IVariant
enum Method
{
MergeToSelectForLoop,
MergeToDirectForLoop
MergeToDirectForLoop,
MergeToSelectContinueForLoop
};
enum ContinueBlockType

View File

@ -2108,7 +2108,7 @@ bool Compiler::block_is_loop_candidate(const SPIRBlock &block, SPIRBlock::Method
if (block.disable_block_optimization || block.complex_continue)
return false;
if (method == SPIRBlock::MergeToSelectForLoop)
if (method == SPIRBlock::MergeToSelectForLoop || method == SPIRBlock::MergeToSelectContinueForLoop)
{
// Try to detect common for loop pattern
// which the code backend can use to create cleaner code.
@ -2118,6 +2118,9 @@ bool Compiler::block_is_loop_candidate(const SPIRBlock &block, SPIRBlock::Method
block.true_block != block.merge_block && block.true_block != block.self &&
block.false_block == block.merge_block;
if (ret && method == SPIRBlock::MergeToSelectContinueForLoop)
ret = block.true_block == block.continue_block;
// If we have OpPhi which depends on branches which came from our own block,
// we need to flush phi variables in else block instead of a trivial break,
// so we cannot assume this is a for loop candidate.

View File

@ -8635,7 +8635,7 @@ bool CompilerGLSL::attempt_emit_loop_header(SPIRBlock &block, SPIRBlock::Method
{
SPIRBlock::ContinueBlockType continue_type = continue_block_type(get<SPIRBlock>(block.continue_block));
if (method == SPIRBlock::MergeToSelectForLoop)
if (method == SPIRBlock::MergeToSelectForLoop || method == SPIRBlock::MergeToSelectContinueForLoop)
{
uint32_t current_count = statement_count;
// If we're trying to create a true for loop,
@ -8659,8 +8659,13 @@ bool CompilerGLSL::attempt_emit_loop_header(SPIRBlock &block, SPIRBlock::Method
// emitting the continue block can invalidate the condition expression.
auto initializer = emit_for_loop_initializers(block);
auto condition = to_expression(block.condition);
auto continue_block = emit_continue_block(block.continue_block);
statement("for (", initializer, "; ", condition, "; ", continue_block, ")");
if (method != SPIRBlock::MergeToSelectContinueForLoop)
{
auto continue_block = emit_continue_block(block.continue_block);
statement("for (", initializer, "; ", condition, "; ", continue_block, ")");
}
else
statement("for (", initializer, "; ", condition, "; )");
break;
}
@ -8763,6 +8768,7 @@ void CompilerGLSL::emit_block_chain(SPIRBlock &block)
bool select_branch_to_true_block = false;
bool skip_direct_branch = false;
bool emitted_for_loop_header = false;
bool force_complex_continue_block = false;
// If we need to force temporaries for certain IDs due to continue blocks, do it before starting loop header.
// Need to sort these to ensure that reference output is stable.
@ -8787,8 +8793,22 @@ void CompilerGLSL::emit_block_chain(SPIRBlock &block)
for (auto var : block.loop_variables)
get<SPIRVariable>(var).loop_variable_enable = true;
// This is the method often used by spirv-opt to implement loops.
// The loop header goes straight into the continue block.
// However, don't attempt this on ESSL 1.0, because if a loop variable is used in a continue block,
// it *MUST* be used in the continue block. This loop method will not work.
if (!is_legacy_es() && block_is_loop_candidate(block, SPIRBlock::MergeToSelectContinueForLoop))
{
flush_undeclared_variables(block);
if (attempt_emit_loop_header(block, SPIRBlock::MergeToSelectContinueForLoop))
{
select_branch_to_true_block = true;
emitted_for_loop_header = true;
force_complex_continue_block = true;
}
}
// This is the older loop behavior in glslang which branches to loop body directly from the loop header.
if (block_is_loop_candidate(block, SPIRBlock::MergeToSelectForLoop))
else if (block_is_loop_candidate(block, SPIRBlock::MergeToSelectForLoop))
{
flush_undeclared_variables(block);
if (attempt_emit_loop_header(block, SPIRBlock::MergeToSelectForLoop))
@ -8869,9 +8889,23 @@ void CompilerGLSL::emit_block_chain(SPIRBlock &block)
break;
case SPIRBlock::Select:
// True if MergeToSelectForLoop succeeded.
// True if MergeToSelectForLoop or MergeToSelectContinueForLoop succeeded.
if (select_branch_to_true_block)
branch(block.self, block.true_block);
{
if (force_complex_continue_block)
{
assert(block.true_block == block.continue_block);
// We're going to emit a continue block directly here, so make sure it's marked as complex.
auto &complex_continue = get<SPIRBlock>(block.continue_block).complex_continue;
bool old_complex = complex_continue;
complex_continue = true;
branch(block.self, block.true_block);
complex_continue = old_complex;
}
else
branch(block.self, block.true_block);
}
else
branch(block.self, block.condition, block.true_block, block.false_block);
break;