+void ConstantSpecializer::visit(VariableDeclaration &var)
+{
+ bool specializable = false;
+ if(var.layout)
+ {
+ vector<Layout::Qualifier> &qualifiers = var.layout->qualifiers;
+ for(vector<Layout::Qualifier>::iterator i=qualifiers.begin(); i!=qualifiers.end(); ++i)
+ if(i->name=="constant_id")
+ {
+ specializable = true;
+ if(values)
+ qualifiers.erase(i);
+ else if(i->value==-1)
+ i->value = hash32(var.name)&0x7FFFFFFF;
+ break;
+ }
+
+ if(qualifiers.empty())
+ var.layout = 0;
+ }
+
+ if(specializable && values)
+ {
+ map<string, int>::const_iterator i = values->find(var.name);
+ if(i!=values->end())
+ {
+ RefPtr<Literal> literal = new Literal;
+ if(var.type=="bool")
+ {
+ literal->token = (i->second ? "true" : "false");
+ literal->value = static_cast<bool>(i->second);
+ }
+ else if(var.type=="int")
+ {
+ literal->token = lexical_cast<string>(i->second);
+ literal->value = i->second;
+ }
+ var.init_expression = literal;
+ }
+ }
+}
+
+
+void BlockHierarchyResolver::enter(Block &block)
+{
+ r_any_resolved |= (current_block!=block.parent);
+ block.parent = current_block;
+}
+
+
+TypeResolver::TypeResolver():
+ stage(0),
+ iface_block(0),
+ r_any_resolved(false)
+{ }
+
+bool TypeResolver::apply(Stage &s)
+{
+ stage = &s;
+ s.types.clear();
+ r_any_resolved = false;
+ s.content.visit(*this);
+ return r_any_resolved;
+}
+
+TypeDeclaration *TypeResolver::get_or_create_array_type(TypeDeclaration &type)
+{
+ map<TypeDeclaration *, TypeDeclaration *>::iterator i = array_types.find(&type);
+ if(i!=array_types.end())
+ return i->second;
+
+ BasicTypeDeclaration *array = new BasicTypeDeclaration;
+ array->source = BUILTIN_SOURCE;
+ array->name = type.name+"[]";
+ array->kind = BasicTypeDeclaration::ARRAY;
+ array->base = type.name;
+ array->base_type = &type;
+ stage->content.body.insert(type_insert_point, array);
+ array_types[&type] = array;
+ return array;
+}
+
+void TypeResolver::resolve_type(TypeDeclaration *&type, const string &name, bool array)
+{
+ TypeDeclaration *resolved = 0;
+ map<string, TypeDeclaration *>::iterator i = stage->types.find(name);
+ if(i!=stage->types.end())
+ {
+ map<TypeDeclaration *, TypeDeclaration *>::iterator j = alias_map.find(i->second);
+ resolved = (j!=alias_map.end() ? j->second : i->second);
+ }
+
+ if(resolved && array)
+ resolved = get_or_create_array_type(*resolved);
+
+ r_any_resolved |= (resolved!=type);
+ type=resolved;
+}
+
+void TypeResolver::visit(Block &block)
+{
+ for(NodeList<Statement>::iterator i=block.body.begin(); i!=block.body.end(); ++i)
+ {
+ if(!block.parent)
+ type_insert_point = i;
+ (*i)->visit(*this);
+ }
+}
+
+void TypeResolver::visit(BasicTypeDeclaration &type)
+{
+ resolve_type(type.base_type, type.base, false);
+
+ if(type.kind==BasicTypeDeclaration::VECTOR && type.base_type)
+ if(BasicTypeDeclaration *basic_base = dynamic_cast<BasicTypeDeclaration *>(type.base_type))
+ if(basic_base->kind==BasicTypeDeclaration::VECTOR)
+ {
+ type.kind = BasicTypeDeclaration::MATRIX;
+ /* A matrix's base type is its column vector type. This will put
+ the column vector's size, i.e. the matrix's row count, in the high
+ half of the size. */
+ type.size |= basic_base->size<<16;
+ }
+
+ if(type.kind==BasicTypeDeclaration::ALIAS && type.base_type)
+ alias_map[&type] = type.base_type;
+ else if(type.kind==BasicTypeDeclaration::ARRAY && type.base_type)
+ array_types[type.base_type] = &type;
+
+ stage->types.insert(make_pair(type.name, &type));
+}
+
+void TypeResolver::visit(ImageTypeDeclaration &type)
+{
+ resolve_type(type.base_type, type.base, false);
+ stage->types.insert(make_pair(type.name, &type));
+}
+
+void TypeResolver::visit(StructDeclaration &strct)
+{
+ stage->types.insert(make_pair(strct.name, &strct));
+ TraversingVisitor::visit(strct);
+}
+
+void TypeResolver::visit(VariableDeclaration &var)
+{
+ resolve_type(var.type_declaration, var.type, var.array);
+ if(iface_block && var.interface==iface_block->interface)
+ var.interface.clear();
+}
+
+void TypeResolver::visit(InterfaceBlock &iface)
+{
+ if(iface.members)
+ {
+ SetForScope<InterfaceBlock *> set_iface(iface_block, &iface);
+ iface.members->visit(*this);
+
+ StructDeclaration *strct = new StructDeclaration;
+ strct->source = INTERNAL_SOURCE;
+ strct->name = format("_%s_%s", iface.interface, iface.name);
+ strct->members.body.splice(strct->members.body.begin(), iface.members->body);
+ stage->content.body.insert(type_insert_point, strct);
+ stage->types.insert(make_pair(strct->name, strct));
+
+ iface.members = 0;
+ strct->interface_block = &iface;
+ iface.struct_declaration = strct;
+ }
+
+ TypeDeclaration *type = iface.struct_declaration;
+ if(type && iface.array)
+ type = get_or_create_array_type(*type);
+ r_any_resolved = (type!=iface.type_declaration);
+ iface.type_declaration = type;
+}
+
+void TypeResolver::visit(FunctionDeclaration &func)
+{
+ resolve_type(func.return_type_declaration, func.return_type, false);
+ TraversingVisitor::visit(func);
+}
+
+
+VariableResolver::VariableResolver():
+ stage(0),
+ r_any_resolved(false),
+ record_target(false),
+ r_self_referencing(false)
+{ }
+
+bool VariableResolver::apply(Stage &s)
+{
+ stage = &s;
+ s.interface_blocks.clear();
+ r_any_resolved = false;
+ s.content.visit(*this);
+ for(vector<VariableDeclaration *>::const_iterator i=redeclared_builtins.begin(); i!=redeclared_builtins.end(); ++i)
+ (*i)->source = GENERATED_SOURCE;
+ NodeRemover().apply(s, nodes_to_remove);
+ return r_any_resolved;
+}
+
+void VariableResolver::enter(Block &block)
+{
+ block.variables.clear();
+}
+
+void VariableResolver::visit(RefPtr<Expression> &expr)
+{
+ r_replacement_expr = 0;
+ expr->visit(*this);
+ 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;
+
+ /* Look for variable declarations in the block hierarchy first. Interface
+ blocks are always defined in the top level so we can't accidentally skip
+ one. */
+ for(Block *block=current_block; (!declaration && block); block=block->parent)
+ {
+ map<string, VariableDeclaration *>::iterator i = block->variables.find(var.name);
+ if(i!=block->variables.end())
+ declaration = i->second;
+ }
+
+ if(!declaration)
+ {
+ const map<string, InterfaceBlock *> &blocks = stage->interface_blocks;
+ map<string, InterfaceBlock *>::const_iterator i = blocks.find("_"+var.name);
+ if(i!=blocks.end())
+ {
+ /* The name refers to an interface block with an instance name rather
+ than a variable. Prepare a new syntax tree node accordingly. */
+ InterfaceBlockReference *iface_ref = new InterfaceBlockReference;
+ iface_ref->source = var.source;
+ iface_ref->line = var.line;
+ iface_ref->name = var.name;
+ iface_ref->declaration = i->second;
+ r_replacement_expr = iface_ref;
+ }
+ else
+ {
+ // Look for the variable in anonymous interface blocks.
+ for(i=blocks.begin(); (!declaration && i!=blocks.end()); ++i)
+ if(i->second->instance_name.empty() && i->second->struct_declaration)
+ {
+ const map<string, VariableDeclaration *> &iface_vars = i->second->struct_declaration->members.variables;
+ map<string, VariableDeclaration *>::const_iterator j = iface_vars.find(var.name);
+ if(j!=iface_vars.end())
+ declaration = j->second;
+ }
+ }
+ }
+
+ r_any_resolved |= (declaration!=var.declaration);
+ var.declaration = declaration;
+
+ check_assignment_target(var.declaration);
+}
+
+void VariableResolver::visit(InterfaceBlockReference &iface)
+{
+ map<string, InterfaceBlock *>::iterator i = stage->interface_blocks.find("_"+iface.name);
+ 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)
+{
+ TraversingVisitor::visit(memacc);
+
+ VariableDeclaration *declaration = 0;
+ if(StructDeclaration *strct = dynamic_cast<StructDeclaration *>(memacc.left->type))
+ {
+ 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))
+ {
+ bool scalar_swizzle = ((basic->kind==BasicTypeDeclaration::INT || basic->kind==BasicTypeDeclaration::FLOAT) && memacc.member.size()==1);
+ bool vector_swizzle = (basic->kind==BasicTypeDeclaration::VECTOR && memacc.member.size()<=4);
+ if(scalar_swizzle || vector_swizzle)
+ {
+ static const char component_names[] = { 'x', 'r', 's', 'y', 'g', 't', 'z', 'b', 'p', 'w', 'a', 'q' };
+
+ bool ok = true;
+ UInt8 components[4] = { };
+ for(unsigned i=0; (ok && i<memacc.member.size()); ++i)
+ ok = ((components[i] = (find(component_names, component_names+12, memacc.member[i])-component_names)/3) < 4);
+
+ if(ok)
+ {
+ Swizzle *swizzle = new Swizzle;
+ swizzle->source = memacc.source;
+ swizzle->line = memacc.line;
+ swizzle->oper = memacc.oper;
+ swizzle->left = memacc.left;
+ swizzle->component_group = memacc.member;
+ swizzle->count = memacc.member.size();
+ copy(components, components+memacc.member.size(), swizzle->components);
+ r_replacement_expr = swizzle;
+ }
+ }
+ }
+
+ r_any_resolved |= (declaration!=memacc.declaration);
+ memacc.declaration = declaration;
+}
+
+void VariableResolver::visit(Swizzle &swizzle)
+{
+ TraversingVisitor::visit(swizzle);
+
+ 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(BinaryExpression &binary)
+{
+ if(binary.oper->token[0]=='[')
+ {
+ {
+ /* The subscript expression is not a part of the primary assignment
+ target. */
+ SetFlag set(record_target, false);
+ visit(binary.right);
+ }
+ visit(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
+ TraversingVisitor::visit(binary);
+}
+
+void VariableResolver::visit(Assignment &assign)