Distinguish between cross edges and back edges.
Handle the weird opcodes CopyMemory/CopyObject.
This commit is contained in:
Родитель
edbe867b74
Коммит
0c9683cd85
|
@ -70,22 +70,31 @@ void CFG::build_immediate_dominators()
|
|||
|
||||
for (auto &edge : pred)
|
||||
{
|
||||
if (!immediate_dominators[block])
|
||||
immediate_dominators[block] = edge;
|
||||
else
|
||||
if (immediate_dominators[block])
|
||||
{
|
||||
assert(immediate_dominators[edge]);
|
||||
immediate_dominators[block] = update_common_dominator(block, edge);
|
||||
}
|
||||
else
|
||||
immediate_dominators[block] = edge;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CFG::is_back_edge(uint32_t to) const
|
||||
{
|
||||
// We have a back edge if the visit order is set with the temporary magic value 0.
|
||||
// Crossing edges will have already been recorded with a visit order.
|
||||
return visit_order[to] == 0;
|
||||
}
|
||||
|
||||
bool CFG::post_order_visit(uint32_t block_id)
|
||||
{
|
||||
// If we have already branched to this block (back edge), stop recursion.
|
||||
// If our branches are back-edges, we do not record them.
|
||||
// We have to record crossing edges however.
|
||||
if (visit_order[block_id] >= 0)
|
||||
return false;
|
||||
return !is_back_edge(block_id);
|
||||
|
||||
// Block back-edges from recursively revisiting ourselves.
|
||||
visit_order[block_id] = 0;
|
||||
|
@ -120,8 +129,8 @@ bool CFG::post_order_visit(uint32_t block_id)
|
|||
break;
|
||||
}
|
||||
|
||||
// Then visit ourselves.
|
||||
visit_order[block_id] = visit_count++;
|
||||
// Then visit ourselves. Start counting at one, to let 0 be a magic value for testing back vs. crossing edges.
|
||||
visit_order[block_id] = ++visit_count;
|
||||
post_order.push_back(block_id);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -59,6 +59,7 @@ private:
|
|||
uint32_t visit_count = 0;
|
||||
|
||||
uint32_t update_common_dominator(uint32_t a, uint32_t b);
|
||||
bool is_back_edge(uint32_t to) const;
|
||||
};
|
||||
|
||||
class DominatorBuilder
|
||||
|
|
|
@ -82,6 +82,7 @@ bool Compiler::block_is_pure(const SPIRBlock &block)
|
|||
break;
|
||||
}
|
||||
|
||||
case OpCopyMemory:
|
||||
case OpStore:
|
||||
{
|
||||
auto &type = expression_type(ops[0]);
|
||||
|
@ -486,9 +487,25 @@ bool Compiler::InterfaceVariableAccessHandler::handle(Op opcode, const uint32_t
|
|||
variable = args[0];
|
||||
break;
|
||||
|
||||
case OpCopyMemory:
|
||||
{
|
||||
if (length < 3)
|
||||
return false;
|
||||
|
||||
auto *var = compiler.maybe_get<SPIRVariable>(args[0]);
|
||||
if (var && storage_class_is_interface(var->storage))
|
||||
variables.insert(variable);
|
||||
|
||||
var = compiler.maybe_get<SPIRVariable>(args[1]);
|
||||
if (var && storage_class_is_interface(var->storage))
|
||||
variables.insert(variable);
|
||||
break;
|
||||
}
|
||||
|
||||
case OpAccessChain:
|
||||
case OpInBoundsAccessChain:
|
||||
case OpLoad:
|
||||
case OpCopyObject:
|
||||
case OpImageTexelPointer:
|
||||
case OpAtomicLoad:
|
||||
case OpAtomicExchange:
|
||||
|
@ -2725,6 +2742,7 @@ void Compiler::analyze_variable_scope(SPIRFunction &entry)
|
|||
: compiler(compiler_)
|
||||
{
|
||||
}
|
||||
|
||||
bool follow_function_call(const SPIRFunction &)
|
||||
{
|
||||
// Only analyze within this function.
|
||||
|
@ -2798,6 +2816,34 @@ void Compiler::analyze_variable_scope(SPIRFunction &entry)
|
|||
break;
|
||||
}
|
||||
|
||||
case OpCopyMemory:
|
||||
{
|
||||
if (length < 3)
|
||||
return false;
|
||||
|
||||
uint32_t lhs = args[0];
|
||||
uint32_t rhs = args[1];
|
||||
auto *var = compiler.maybe_get_backing_variable(lhs);
|
||||
if (var && var->storage == StorageClassFunction)
|
||||
accessed_variables_to_block[var->self].insert(current_block->self);
|
||||
|
||||
var = compiler.maybe_get_backing_variable(rhs);
|
||||
if (var && var->storage == StorageClassFunction)
|
||||
accessed_variables_to_block[var->self].insert(current_block->self);
|
||||
break;
|
||||
}
|
||||
|
||||
case OpCopyObject:
|
||||
{
|
||||
if (length < 3)
|
||||
return false;
|
||||
|
||||
auto *var = compiler.maybe_get_backing_variable(args[2]);
|
||||
if (var && var->storage == StorageClassFunction)
|
||||
accessed_variables_to_block[var->self].insert(current_block->self);
|
||||
break;
|
||||
}
|
||||
|
||||
case OpLoad:
|
||||
{
|
||||
if (length < 3)
|
||||
|
@ -2809,7 +2855,34 @@ void Compiler::analyze_variable_scope(SPIRFunction &entry)
|
|||
break;
|
||||
}
|
||||
|
||||
// TODO: OpFunctionCall and other opcodes which access variables.
|
||||
case OpFunctionCall:
|
||||
{
|
||||
if (length < 3)
|
||||
return false;
|
||||
|
||||
length -= 3;
|
||||
args += 3;
|
||||
for (uint32_t i = 0; i < length; i++)
|
||||
{
|
||||
auto *var = compiler.maybe_get_backing_variable(args[i]);
|
||||
if (var && var->storage == StorageClassFunction)
|
||||
accessed_variables_to_block[var->self].insert(current_block->self);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case OpPhi:
|
||||
{
|
||||
if (length < 2)
|
||||
return false;
|
||||
|
||||
// Phi nodes are implemented as function variables, so register an access here.
|
||||
accessed_variables_to_block[args[1]].insert(current_block->self);
|
||||
break;
|
||||
}
|
||||
|
||||
// Atomics shouldn't be able to access function-local variables.
|
||||
// Some GLSL builtins access a pointer.
|
||||
|
||||
default:
|
||||
break;
|
||||
|
|
|
@ -3678,14 +3678,31 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
|
|||
break;
|
||||
}
|
||||
|
||||
case OpCopyMemory:
|
||||
{
|
||||
uint32_t lhs = ops[0];
|
||||
uint32_t rhs = ops[1];
|
||||
if (lhs != rhs)
|
||||
{
|
||||
flush_variable_declaration(lhs);
|
||||
flush_variable_declaration(rhs);
|
||||
statement(to_expression(lhs), " = ", to_expression(rhs), ";");
|
||||
register_write(lhs);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case OpCopyObject:
|
||||
{
|
||||
uint32_t result_type = ops[0];
|
||||
uint32_t id = ops[1];
|
||||
uint32_t rhs = ops[2];
|
||||
if (expression_is_lvalue(rhs))
|
||||
bool pointer = get<SPIRType>(result_type).pointer;
|
||||
|
||||
if (expression_is_lvalue(rhs) && !pointer)
|
||||
{
|
||||
// Need a copy.
|
||||
// For pointer types, we copy the pointer itself.
|
||||
statement(declare_temporary(result_type, id), to_expression(rhs), ";");
|
||||
set<SPIRExpression>(id, to_name(id), result_type, true);
|
||||
}
|
||||
|
@ -3694,7 +3711,12 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
|
|||
// RHS expression is immutable, so just forward it.
|
||||
// Copying these things really make no sense, but
|
||||
// seems to be allowed anyways.
|
||||
set<SPIRExpression>(id, to_expression(rhs), result_type, true);
|
||||
auto &e = set<SPIRExpression>(id, to_expression(rhs), result_type, true);
|
||||
if (pointer)
|
||||
{
|
||||
auto *var = maybe_get_backing_variable(rhs);
|
||||
e.loaded_from = var ? var->self : 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче