s.interface_blocks.clear();
r_any_resolved = false;
s.content.visit(*this);
- for(VariableDeclaration *v: redeclared_builtins)
- v->source = GENERATED_SOURCE;
+ for(Statement *b: redeclared_builtins)
+ b->source = GENERATED_SOURCE;
NodeRemover().apply(s, nodes_to_remove);
return r_any_resolved;
}
}
}
+void VariableResolver::redeclare_builtin(VariableDeclaration &existing, VariableDeclaration &var)
+{
+ if(var.layout)
+ {
+ if(existing.layout)
+ merge_layouts(*existing.layout, *var.layout);
+ else
+ existing.layout = var.layout;
+ }
+ if(var.array_size)
+ existing.array_size = var.array_size;
+
+ redeclared_builtins.push_back(&existing);
+}
+
void VariableResolver::visit(VariableDeclaration &var)
{
TraversingVisitor::visit(var);
- VariableDeclaration *&ptr = current_block->variables[var.name];
- if(!ptr)
- ptr = &var;
- else if(!current_block->parent && ptr->interface==var.interface && ptr->type==var.type)
+
+ auto i = current_block->variables.find(var.name);
+ VariableDeclaration *existing = 0;
+ InterfaceBlock *block = 0;
+ if(i!=current_block->variables.end())
+ existing = i->second;
+ else if(!current_block->parent)
{
- if(ptr->source==BUILTIN_SOURCE)
- redeclared_builtins.push_back(&var);
- else
- stage->diagnostics.push_back(Diagnostic(Diagnostic::WARN, var.source, var.line,
- format("Redeclaring non-builtin variable '%s' is deprecated", var.name)));
+ const map<string, InterfaceBlock *> &blocks = stage->interface_blocks;
+ for(auto j=blocks.begin(); j!=blocks.end(); ++j)
+ if(j->second->instance_name.empty() && j->second->struct_declaration)
+ {
+ map<string, VariableDeclaration *> &block_vars = j->second->struct_declaration->members.variables;
+ i = block_vars.find(var.name);
+ if(i!=block_vars.end())
+ {
+ existing = i->second;
+ block = j->second;
+ break;
+ }
+ }
+ }
- if(var.init_expression)
- ptr->init_expression = var.init_expression;
- if(var.layout)
+ if(!existing)
+ current_block->variables.insert(make_pair(var.name, &var));
+ else if(!current_block->parent && (block ? block->interface : existing->interface)==var.interface && existing->type==var.type && existing->array==var.array)
+ {
+ if(existing->source==BUILTIN_SOURCE)
{
- if(ptr->layout)
- merge_layouts(*ptr->layout, *var.layout);
- else
- ptr->layout = var.layout;
- }
- nodes_to_remove.insert(&var);
+ redeclare_builtin(*existing, var);
- r_any_resolved = true;
+ if(block)
+ {
+ redeclared_builtins.push_back(block);
+ for(const auto &kvp: block->struct_declaration->members.variables)
+ redeclared_builtins.push_back(kvp.second);
+ }
+
+ nodes_to_remove.insert(&var);
+ r_any_resolved = true;
+ }
+ else if(existing->array && !existing->array_size && !var.layout && !var.init_expression)
+ {
+ existing->array_size = var.array_size;
+ nodes_to_remove.insert(&var);
+ r_any_resolved = true;
+ }
}
}
void VariableResolver::visit(InterfaceBlock &iface)
{
- /* Block names can be reused in different interfaces. Prefix the name with
- the first character of the interface to avoid conflicts. */
- stage->interface_blocks.insert(make_pair(format("%s %s", iface.interface, iface.block_name), &iface));
- if(!iface.instance_name.empty())
- stage->interface_blocks.insert(make_pair(iface.instance_name, &iface));
+ string key = format("%s %s", iface.interface, iface.block_name);
+ auto i = stage->interface_blocks.find(key);
+ if(i!=stage->interface_blocks.end())
+ {
+ if(i->second->source==BUILTIN_SOURCE && iface.struct_declaration && i->second->struct_declaration)
+ {
+ const map<string, VariableDeclaration *> &vars = iface.struct_declaration->members.variables;
+ const map<string, VariableDeclaration *> &existing_vars = i->second->struct_declaration->members.variables;
+
+ bool found_all = true;
+ for(const auto &kvp: vars)
+ {
+ auto j = existing_vars.find(kvp.first);
+ if(j!=existing_vars.end() && j->second->type==kvp.second->type && j->second->array==kvp.second->array)
+ redeclare_builtin(*j->second, *kvp.second);
+ else
+ found_all = false;
+ }
+
+ if(found_all)
+ {
+ redeclared_builtins.push_back(i->second);
+ nodes_to_remove.insert(&iface);
+ nodes_to_remove.insert(iface.struct_declaration);
+ }
+ }
+ }
+ else
+ {
+ /* Block names can be reused in different interfaces. Prepend the interface
+ to the name to avoid conflicts. */
+ stage->interface_blocks.insert(make_pair(key, &iface));
+ if(!iface.instance_name.empty())
+ stage->interface_blocks.insert(make_pair(iface.instance_name, &iface));
+ }
TraversingVisitor::visit(iface);
}
{
unsigned column_count = basic->size&0xFFFF;
unsigned row_count = basic->size>>16;
+
+ vector<RefPtr<Expression> > columns;
+ columns.reserve(column_count);
+ bool changed_columns = false;
+
if(call.arguments.size()==1)
{
/* A matrix can be constructed from a single element or another
current_block->body.insert(insert_point, temporary);
// Create expressions to build each column.
- vector<RefPtr<Expression> > columns;
- columns.reserve(column_count);
for(unsigned j=0; j<column_count; ++j)
{
RefPtr<VariableReference> ref = new VariableReference;
truncate_vector(columns.back(), row_count);
}
- call.arguments.resize(column_count);
- copy(columns.begin(), columns.end(), call.arguments.begin());
-
- /* Let VariableResolver process the new nodes and finish
- resolving the constructor on the next pass. */
- r_any_resolved = true;
- return;
+ changed_columns = true;
}
else
return;
{
/* Construct a matrix from individual components in column-major
order. Arguments must align at column boundaries. */
- vector<RefPtr<Expression> > columns;
- columns.reserve(column_count);
-
vector<RefPtr<Expression> > column_args;
column_args.reserve(row_count);
unsigned column_component_count = 0;
else if(column_component_count>row_count)
// Argument alignment mismatch.
return;
+
+ changed_columns = true;
}
}
}
else
return;
+
+ if(changed_columns)
+ {
+ call.arguments.resize(column_count);
+ copy(columns.begin(), columns.end(), call.arguments.begin());
+
+ /* Let VariableResolver process the new nodes and finish
+ resolving the constructor on the next pass. */
+ r_any_resolved = true;
+ return;
+ }
}
else
return;
convert_to(var.init_expression, *var_basic);
}
+void ExpressionResolver::visit(FunctionDeclaration &func)
+{
+ SetForScope<const FunctionDeclaration *> set_func(current_function, &func);
+ TraversingVisitor::visit(func);
+}
+
+void ExpressionResolver::visit(Return &ret)
+{
+ TraversingVisitor::visit(ret);
+ if(!current_function || !ret.expression)
+ return;
+
+ BasicTypeDeclaration *ret_basic = dynamic_cast<BasicTypeDeclaration *>(current_function->return_type_declaration);
+ BasicTypeDeclaration *expr_basic = dynamic_cast<BasicTypeDeclaration *>(ret.expression->type);
+ if(!ret_basic || !expr_basic)
+ return;
+
+ Compatibility compat = get_compatibility(*ret_basic, *expr_basic);
+ if(compat==RIGHT_CONVERTIBLE)
+ convert_to(ret.expression, *ret_basic);
+}
+
bool FunctionResolver::apply(Stage &s)
{