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
{
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<assign.target.chain_len; ++i)
+ {
+ unsigned component = assign.target.chain[i];
+ switch(static_cast<Assignment::Target::ChainType>(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<<j))
+ text += swizzle[j];
+ break;
+ case Assignment::Target::ARRAY:
+ text += format(" [%d]", component&0x3F);
+ break;
+ }
+ }
+ append(text);
+ }
assign.left->visit(*this);
last_branch();
assign.right->visit(*this);
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)
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;
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)
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<unsigned>(index, 0x3F);
+ ++r_assignment_target.chain_len;
}
void VariableResolver::visit(MemberAccess &memacc)
{
map<string, VariableDeclaration *>::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<Statement>::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<BasicTypeDeclaration *>(memacc.left->type))
{
void VariableResolver::visit(Swizzle &swizzle)
{
visit_and_replace(swizzle.left);
+
+ if(record_target)
+ {
+ unsigned mask = 0;
+ for(unsigned i=0; i<swizzle.count; ++i)
+ mask |= 1<<swizzle.components[i];
+ add_to_chain(Assignment::Target::SWIZZLE, mask);
+ }
}
void VariableResolver::visit(UnaryExpression &unary)
visit_and_replace(binary.right);
}
visit_and_replace(binary.left);
+
+ if(record_target)
+ {
+ unsigned index = 0x3F;
+ if(Literal *literal_subscript = dynamic_cast<Literal *>(binary.right.get()))
+ if(literal_subscript->value.check_type<int>())
+ index = literal_subscript->value.value<int>();
+ add_to_chain(Assignment::Target::ARRAY, index);
+ }
}
else
{
{
{
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<assign.target || assign.target<r_assignment_target);
+ assign.target = r_assignment_target;
}
r_self_referencing = false;
bool r_any_resolved;
bool record_target;
bool r_self_referencing;
- VariableDeclaration *r_assignment_target;
+ Assignment::Target r_assignment_target;
public:
VariableResolver();
private:
virtual void enter(Block &);
void visit_and_replace(RefPtr<Expression> &);
+ 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 &);
r_oper = 0;
visit_and_record(assign.right, assign.oper, true);
- if(assign.target_declaration)
+ if(VariableDeclaration *target_var = dynamic_cast<VariableDeclaration *>(assign.target.declaration))
{
- map<VariableDeclaration *, ExpressionInfo>::iterator i = expressions.find(assign.target_declaration);
+ map<VariableDeclaration *, ExpressionInfo>::iterator i = expressions.find(target_var);
if(i!=expressions.end())
{
/* Self-referencing assignments can't be inlined without additional
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<VariableDeclaration *>(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);
}
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)
}
+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<other.declaration;
+ for(unsigned i=0; (i<7 && i<chain_len && i<other.chain_len); ++i)
+ if(chain[i]!=other.chain[i])
+ return chain[i]<other.chain[i];
+ return chain_len<other.chain_len;
+}
+
+
FunctionCall::FunctionCall():
constructor(false),
declaration(0)
struct Assignment: BinaryExpression
{
+ struct Target
+ {
+ enum ChainType
+ {
+ MEMBER = 0x40,
+ SWIZZLE = 0x80,
+ ARRAY = 0xC0
+ };
+
+ Statement *declaration;
+ Msp::UInt8 chain_len;
+ Msp::UInt8 chain[7];
+
+ Target(Statement * = 0);
+
+ bool operator<(const Target &) const;
+ };
+
bool self_referencing;
- VariableDeclaration *target_declaration;
+ Target target;
Assignment();
Assignment(const Assignment &);