Lift variable accesses in continue blocks out to loop header.

This commit is contained in:
Hans-Kristian Arntzen 2017-12-05 17:40:23 +01:00
parent adcda90d34
commit b737d2bc07
3 changed files with 32 additions and 8 deletions

View File

@ -1976,6 +1976,8 @@ void Compiler::parse(const Instruction &instruction)
loop_blocks.insert(current_block->self);
loop_merge_targets.insert(current_block->merge_block);
continue_block_to_loop_header[current_block->continue_block] = current_block->self;
// Don't add loop headers to continue blocks,
// which would make it impossible branch into the loop header since
// they are treated as continues.
@ -3214,6 +3216,10 @@ void Compiler::analyze_variable_scope(SPIRFunction &entry)
auto *var = compiler.maybe_get<SPIRVariable>(ptr);
if (var && var->storage == StorageClassFunction)
accessed_variables_to_block[var->self].insert(current_block->self);
for (uint32_t i = 3; i < length; i++)
if (id_is_phi_variable(args[i]))
accessed_variables_to_block[args[i]].insert(current_block->self);
break;
}
@ -3352,16 +3358,27 @@ void Compiler::analyze_variable_scope(SPIRFunction &entry)
{
// If we're accessing a variable inside a continue block, this variable might be a loop variable.
// We can only use loop variables with scalars, as we cannot track static expressions for vectors.
if (this->is_continue(block) && type.vecsize == 1 && type.columns == 1)
if (this->is_continue(block))
{
// The variable is used in multiple continue blocks, this is not a loop
// candidate, signal that by setting block to -1u.
auto &potential = potential_loop_variables[var.first];
// Potentially awkward case to check for.
// We might have a variable inside a loop, which is touched by the continue block,
// but is not actually a loop variable.
// The continue block is dominated by the inner part of the loop, which does not make sense in high-level
// language output because it will be declared before the body,
// so we will have to lift the dominator up to the relevant loop header instead.
builder.add_block(continue_block_to_loop_header[block]);
if (potential == 0)
potential = block;
else
potential = ~(0u);
if (type.vecsize == 1 && type.columns == 1)
{
// The variable is used in multiple continue blocks, this is not a loop
// candidate, signal that by setting block to -1u.
auto &potential = potential_loop_variables[var.first];
if (potential == 0)
potential = block;
else
potential = ~(0u);
}
}
builder.add_block(block);
}
@ -3370,6 +3387,7 @@ void Compiler::analyze_variable_scope(SPIRFunction &entry)
// Add it to a per-block list of variables.
uint32_t dominating_block = builder.get_dominator();
// If all blocks here are dead code, this will be 0, so the variable in question
// will be completely eliminated.
if (dominating_block)

View File

@ -511,6 +511,7 @@ protected:
std::unordered_set<uint32_t> loop_merge_targets;
std::unordered_set<uint32_t> selection_merge_targets;
std::unordered_set<uint32_t> multiselect_merge_targets;
std::unordered_map<uint32_t, uint32_t> continue_block_to_loop_header;
virtual std::string to_name(uint32_t id, bool allow_alias = true) const;
bool is_builtin_variable(const SPIRVariable &var) const;

View File

@ -7846,6 +7846,9 @@ bool CompilerGLSL::attempt_emit_loop_header(SPIRBlock &block, SPIRBlock::Method
{
case SPIRBlock::ForLoop:
{
// This block may be a dominating block, so make sure we flush undeclared variables before building the for loop header.
flush_undeclared_variables(block);
// Important that we do this in this order because
// emitting the continue block can invalidate the condition expression.
auto initializer = emit_for_loop_initializers(block);
@ -7856,6 +7859,8 @@ bool CompilerGLSL::attempt_emit_loop_header(SPIRBlock &block, SPIRBlock::Method
}
case SPIRBlock::WhileLoop:
// This block may be a dominating block, so make sure we flush undeclared variables before building the while loop header.
flush_undeclared_variables(block);
statement("while (", to_expression(block.condition), ")");
break;