mirror of
https://github.com/KhronosGroup/SPIRV-Cross.git
synced 2024-11-12 15:10:30 +00:00
Lift variable accesses in continue blocks out to loop header.
This commit is contained in:
parent
adcda90d34
commit
b737d2bc07
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user