From cc3f4aaaf8d2b34347f69b026c10f82797059aa4 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Tue, 9 Mar 2021 09:43:08 +0200 Subject: [PATCH] Record assignment targets more precisely If the assignment is to a structure or vector field or an array element, it's recorded to the node so optimizers can better match assignments and references (they don't do that yet). --- source/glsl/compatibility.cpp | 4 +- source/glsl/debug.cpp | 28 +++++++++++- source/glsl/generate.cpp | 83 +++++++++++++++++++++++++++-------- source/glsl/generate.h | 4 +- source/glsl/optimize.cpp | 9 ++-- source/glsl/syntax.cpp | 24 ++++++++-- source/glsl/syntax.h | 20 ++++++++- 7 files changed, 139 insertions(+), 33 deletions(-) diff --git a/source/glsl/compatibility.cpp b/source/glsl/compatibility.cpp index 3700a9c9..193ae123 100644 --- a/source/glsl/compatibility.cpp +++ b/source/glsl/compatibility.cpp @@ -172,8 +172,8 @@ void LegacyConverter::visit(VariableReference &var) void LegacyConverter::visit(Assignment &assign) { TraversingVisitor::visit(assign); - if(assign.target_declaration==frag_out && !supports_unified_interface_syntax()) - assign.target_declaration = 0; + if(assign.target.declaration==frag_out && !supports_unified_interface_syntax()) + assign.target.declaration = 0; } bool LegacyConverter::supports_unified_sampling_functions() const diff --git a/source/glsl/debug.cpp b/source/glsl/debug.cpp index fd1fd667..ef9e3e0e 100644 --- a/source/glsl/debug.cpp +++ b/source/glsl/debug.cpp @@ -208,8 +208,32 @@ void DumpTree::visit(Assignment &assign) { append(format("Assignment: %s%s -> %s", assign.oper->token, (assign.self_referencing ? " (self-referencing)" : ""), format_type(assign.type))); begin_sub(); - if(assign.target_declaration) - append(format("Target: %%%d %s %s", get_label(*assign.target_declaration), assign.target_declaration->type, assign.target_declaration->name)); + if(assign.target.declaration) + { + string text = format("Target: %%%d", get_label(*assign.target.declaration)); + + static const char swizzle[4] = { 'x', 'y', 'z', 'w' }; + for(unsigned i=0; i(component&0xC0)) + { + case Assignment::Target::MEMBER: + text += format(" .%d", component&0x3F); + break; + case Assignment::Target::SWIZZLE: + text += " ."; + for(unsigned j=0; j<4; ++j) + if(component&(1<visit(*this); last_branch(); assign.right->visit(*this); diff --git a/source/glsl/generate.cpp b/source/glsl/generate.cpp index 3e53c152..8547152e 100644 --- a/source/glsl/generate.cpp +++ b/source/glsl/generate.cpp @@ -257,8 +257,7 @@ VariableResolver::VariableResolver(): stage(0), r_any_resolved(false), record_target(false), - r_self_referencing(false), - r_assignment_target(0) + r_self_referencing(false) { } bool VariableResolver::apply(Stage &s) @@ -282,11 +281,33 @@ void VariableResolver::visit_and_replace(RefPtr &expr) if(r_replacement_expr) { expr = r_replacement_expr; + /* Don't record assignment target when doing a replacement, because chain + information won't be correct. */ + r_assignment_target.declaration = 0; r_any_resolved = true; } r_replacement_expr = 0; } +void VariableResolver::check_assignment_target(Statement *declaration) +{ + if(record_target) + { + if(r_assignment_target.declaration) + { + /* More than one reference found in assignment target. Unable to + determine what the primary target is. */ + record_target = false; + r_assignment_target.declaration = 0; + } + else + r_assignment_target.declaration = declaration; + } + // TODO This check is overly broad and may prevent some optimizations. + else if(declaration && declaration==r_assignment_target.declaration) + r_self_referencing = true; +} + void VariableResolver::visit(VariableReference &var) { VariableDeclaration *declaration = 0; @@ -333,20 +354,7 @@ void VariableResolver::visit(VariableReference &var) r_any_resolved |= (declaration!=var.declaration); var.declaration = declaration; - if(record_target) - { - if(r_assignment_target) - { - /* More than one variable reference found in assignment target. - Unable to determine what the primary target is. */ - record_target = false; - r_assignment_target = 0; - } - else - r_assignment_target = var.declaration; - } - else if(var.declaration && var.declaration==r_assignment_target) - r_self_referencing = true; + check_assignment_target(var.declaration); } void VariableResolver::visit(InterfaceBlockReference &iface) @@ -355,6 +363,15 @@ void VariableResolver::visit(InterfaceBlockReference &iface) InterfaceBlock *declaration = (i!=stage->interface_blocks.end() ? i->second : 0); r_any_resolved |= (declaration!=iface.declaration); iface.declaration = declaration; + + check_assignment_target(iface.declaration); +} + +void VariableResolver::add_to_chain(Assignment::Target::ChainType type, unsigned index) +{ + if(r_assignment_target.chain_len<7) + r_assignment_target.chain[r_assignment_target.chain_len] = type | min(index, 0x3F); + ++r_assignment_target.chain_len; } void VariableResolver::visit(MemberAccess &memacc) @@ -366,7 +383,18 @@ void VariableResolver::visit(MemberAccess &memacc) { map::iterator i = strct->members.variables.find(memacc.member); if(i!=strct->members.variables.end()) + { declaration = i->second; + + if(record_target) + { + unsigned index = 0; + for(NodeList::const_iterator j=strct->members.body.begin(); (j!=strct->members.body.end() && j->get()!=i->second); ++j) + ++index; + + add_to_chain(Assignment::Target::MEMBER, index); + } + } } else if(BasicTypeDeclaration *basic = dynamic_cast(memacc.left->type)) { @@ -403,6 +431,14 @@ void VariableResolver::visit(MemberAccess &memacc) void VariableResolver::visit(Swizzle &swizzle) { visit_and_replace(swizzle.left); + + if(record_target) + { + unsigned mask = 0; + for(unsigned i=0; i(binary.right.get())) + if(literal_subscript->value.check_type()) + index = literal_subscript->value.value(); + add_to_chain(Assignment::Target::ARRAY, index); + } } else { @@ -433,10 +478,10 @@ void VariableResolver::visit(Assignment &assign) { { SetFlag set(record_target); - r_assignment_target = 0; + r_assignment_target = Assignment::Target(); visit_and_replace(assign.left); - r_any_resolved |= (r_assignment_target!=assign.target_declaration); - assign.target_declaration = r_assignment_target; + r_any_resolved |= (r_assignment_target &); + void check_assignment_target(Statement *); virtual void visit(VariableReference &); virtual void visit(InterfaceBlockReference &); + void add_to_chain(Assignment::Target::ChainType, unsigned); virtual void visit(MemberAccess &); virtual void visit(Swizzle &); virtual void visit(UnaryExpression &); diff --git a/source/glsl/optimize.cpp b/source/glsl/optimize.cpp index 414cf387..85f97fae 100644 --- a/source/glsl/optimize.cpp +++ b/source/glsl/optimize.cpp @@ -479,9 +479,9 @@ void ExpressionInliner::visit(Assignment &assign) r_oper = 0; visit_and_record(assign.right, assign.oper, true); - if(assign.target_declaration) + if(VariableDeclaration *target_var = dynamic_cast(assign.target.declaration)) { - map::iterator i = expressions.find(assign.target_declaration); + map::iterator i = expressions.find(target_var); if(i!=expressions.end()) { /* Self-referencing assignments can't be inlined without additional @@ -838,8 +838,9 @@ void UnusedVariableRemover::visit(ExpressionStatement &expr) r_assign_to_subfield = false; r_side_effects = false; TraversingVisitor::visit(expr); - if(r_assignment && r_assignment->target_declaration) - record_assignment(*r_assignment->target_declaration, expr, (r_assignment->self_referencing || r_assign_to_subfield)); + if(r_assignment && r_assignment->target.declaration) + if(VariableDeclaration *target_var = dynamic_cast(r_assignment->target.declaration)) + record_assignment(*target_var, expr, (r_assignment->self_referencing || r_assign_to_subfield)); if(!r_side_effects) unused_nodes.insert(&expr); } diff --git a/source/glsl/syntax.cpp b/source/glsl/syntax.cpp index 85d805d1..71e5c39a 100644 --- a/source/glsl/syntax.cpp +++ b/source/glsl/syntax.cpp @@ -186,14 +186,12 @@ void BinaryExpression::visit(NodeVisitor &visitor) Assignment::Assignment(): - self_referencing(false), - target_declaration(0) + self_referencing(false) { } Assignment::Assignment(const Assignment &other): BinaryExpression(other), - self_referencing(other.self_referencing), - target_declaration(0) + self_referencing(other.self_referencing) { } void Assignment::visit(NodeVisitor &visitor) @@ -202,6 +200,24 @@ void Assignment::visit(NodeVisitor &visitor) } +Assignment::Target::Target(Statement *d): + declaration(d), + chain_len(0) +{ + fill(chain, chain+7, 0); +} + +bool Assignment::Target::operator<(const Target &other) const +{ + if(declaration!=other.declaration) + return declaration