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;