#include <msp/core/algorithm.h>
#include <msp/core/raii.h>
+#include <msp/strings/regex.h>
#include <msp/strings/utils.h>
#include "reflect.h"
#include "resolve.h"
TypeDeclaration *TypeResolver::get_or_create_array_type(TypeDeclaration &type)
{
- auto i = array_types.find(&type);
+ bool extended_alignment = iface_block;
+ auto key = make_pair(&type, extended_alignment);
+ auto i = array_types.find(key);
if(i!=array_types.end())
return i->second;
array->source = INTERNAL_SOURCE;
array->name = type.name+"[]";
array->kind = BasicTypeDeclaration::ARRAY;
+ array->extended_alignment = extended_alignment;
array->base = type.name;
array->base_type = &type;
stage->content.body.insert(type_insert_point, array);
- array_types[&type] = array;
+ array_types[key] = array;
return array;
}
-void TypeResolver::resolve_type(TypeDeclaration *&type, const string &name, bool array)
+TypeDeclaration *TypeResolver::get_or_create_image_type(ImageTypeDeclaration &type, const std::string &texel_format)
+{
+ if(texel_format.empty())
+ return &type;
+
+ auto key = make_pair(&type, texel_format);
+ auto i = image_types.find(key);
+ if(i!=image_types.end())
+ return i->second;
+
+ ImageTypeDeclaration *image = new ImageTypeDeclaration(type);
+ image->source = INTERNAL_SOURCE;
+ image->name = format("%s_%s", type.name, texel_format);
+ image->format = texel_format;
+ image->base_image = &type;
+ stage->content.body.insert(type_insert_point, image);
+ image_types[key] = image;
+ return image;
+}
+
+void TypeResolver::resolve_type(TypeDeclaration *&type, const string &name, bool array, const Layout *layout)
{
TypeDeclaration *resolved = 0;
auto i = stage->types.find(name);
resolved = (j!=alias_map.end() ? j->second : i->second);
}
- if(resolved && array)
- resolved = get_or_create_array_type(*resolved);
+ if(resolved)
+ {
+ if(ImageTypeDeclaration *image = dynamic_cast<ImageTypeDeclaration *>(resolved))
+ if(layout)
+ {
+ static const Regex r_format("^(r|rg|rgba)(8|16|8_snorm|16_snorm|16f|32f)$");
+ for(const Layout::Qualifier &q: layout->qualifiers)
+ if(r_format.match(q.name))
+ {
+ resolved = get_or_create_image_type(*image, q.name);
+ break;
+ }
+ }
+
+ if(array)
+ resolved = get_or_create_array_type(*resolved);
+ }
r_any_resolved |= (resolved!=type);
type=resolved;
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;
+ array_types[make_pair(type.base_type, type.extended_alignment)] = &type;
stage->types.insert(make_pair(type.name, &type));
}
void TypeResolver::visit(ImageTypeDeclaration &type)
{
resolve_type(type.base_type, type.base, false);
+
+ if(!type.format.empty() && type.base_image)
+ image_types[make_pair(type.base_image, type.format)] = &type;
+
stage->types.insert(make_pair(type.name, &type));
}
void TypeResolver::visit(StructDeclaration &strct)
{
stage->types.insert(make_pair(strct.name, &strct));
- TraversingVisitor::visit(strct);
+ if(strct.block_name.empty())
+ {
+ SetForScope<VariableDeclaration *> set_iface(iface_block, strct.block_declaration);
+ TraversingVisitor::visit(strct);
+ }
+ else
+ block_member_type_ins_pt = type_insert_point;
}
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();
-}
+ resolve_type(var.type_declaration, var.type, var.array, var.layout.get());
-void TypeResolver::visit(InterfaceBlock &iface)
-{
- if(iface.members)
+ var.block_declaration = 0;
+ if(StructDeclaration *strct = dynamic_cast<StructDeclaration *>(get_ultimate_base_type(var.type_declaration)))
+ if(!strct->block_name.empty())
+ {
+ var.block_declaration = strct;
+ strct->block_declaration = &var;
+ strct->extended_alignment = true;
+
+ SetForScope<NodeList<Statement>::iterator> set_ins_pt(type_insert_point, block_member_type_ins_pt);
+ SetForScope<VariableDeclaration *> set_iface(iface_block, &var);
+ TraversingVisitor::visit(*strct);
+ }
+
+ if(iface_block)
{
- 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.block_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;
+ if(var.interface==iface_block->interface)
+ var.interface.clear();
+ if(StructDeclaration *strct = dynamic_cast<StructDeclaration *>(var.type_declaration))
+ strct->extended_alignment = true;
}
-
- 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)
r_replacement_expr = 0;
}
-void VariableResolver::check_assignment_target(Statement *declaration)
+void VariableResolver::check_assignment_target(VariableDeclaration *declaration)
{
if(record_target)
{
if(!declaration)
{
- const map<string, InterfaceBlock *> &blocks = stage->interface_blocks;
- auto i = blocks.find(var.name);
- if(i==blocks.end())
- {
- // Look for the variable in anonymous interface blocks.
- for(i=blocks.begin(); i!=blocks.end(); ++i)
- if(i->second->instance_name.empty() && i->second->struct_declaration)
- if(i->second->struct_declaration->members.variables.count(var.name))
- break;
- }
-
- if(i!=blocks.end())
- {
- /* The name refers to either an interface block with an instance name
- or a variable declared inside an anonymous interface block. Prepare
- new syntax tree nodes accordingly. */
- InterfaceBlockReference *iface_ref = new InterfaceBlockReference;
- iface_ref->source = var.source;
- iface_ref->line = var.line;
- iface_ref->declaration = i->second;
-
- if(i->second->instance_name.empty())
+ for(const auto &kvp: stage->interface_blocks)
+ if(kvp.second->name.find(' ')!=string::npos && kvp.second->block_declaration->members.variables.count(var.name))
{
- iface_ref->name = format("%s %s", i->second->interface, i->second->block_name);
+ /* The name refers a member of an anonymous interface block. Prepare
+ new syntax tree nodes accordingly. */
+ VariableReference *iface_ref = new VariableReference;
+ iface_ref->name = kvp.first;
+ iface_ref->source = var.source;
+ iface_ref->line = var.line;
+ iface_ref->declaration = kvp.second;
MemberAccess *memacc = new MemberAccess;
memacc->source = var.source;
memacc->member = var.name;
r_replacement_expr = memacc;
+ break;
}
- else
- {
- iface_ref->name = var.name;
- r_replacement_expr = iface_ref;
- }
- }
}
r_any_resolved |= (declaration!=var.declaration);
check_assignment_target(var.declaration);
}
-void VariableResolver::visit(InterfaceBlockReference &iface)
-{
- auto 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::visit(MemberAccess &memacc)
{
TraversingVisitor::visit(memacc);
auto i = current_block->variables.find(var.name);
VariableDeclaration *existing = 0;
- InterfaceBlock *block = 0;
+ VariableDeclaration *block = 0;
if(i!=current_block->variables.end())
existing = i->second;
else if(!current_block->parent)
{
- const map<string, InterfaceBlock *> &blocks = stage->interface_blocks;
+ const map<string, VariableDeclaration *> &blocks = stage->interface_blocks;
for(auto j=blocks.begin(); j!=blocks.end(); ++j)
- if(j->second->instance_name.empty() && j->second->struct_declaration)
+ if(j->second->name.find(' ')!=string::npos)
{
- map<string, VariableDeclaration *> &block_vars = j->second->struct_declaration->members.variables;
- i = block_vars.find(var.name);
- if(i!=block_vars.end())
+ const map<string, VariableDeclaration *> &block_vars = j->second->block_declaration->members.variables;
+ auto k = block_vars.find(var.name);
+ if(k!=block_vars.end())
{
- existing = i->second;
+ existing = k->second;
block = j->second;
break;
}
}
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(var.block_declaration)
+ {
+ stage->interface_blocks.insert(make_pair(format("%s %s", var.interface, var.block_declaration->block_name), &var));
+ if(var.name.find(' ')==string::npos)
+ stage->interface_blocks.insert(make_pair(var.name, &var));
+ }
+ }
+ else if(!current_block->parent && (block ? block->interface : existing->interface)==var.interface && existing->array==var.array)
{
if(existing->source==BUILTIN_SOURCE)
{
- redeclare_builtin(*existing, var);
-
- if(block)
+ if(var.block_declaration && existing->block_declaration && var.block_declaration->block_name==existing->block_declaration->block_name)
{
- redeclared_builtins.push_back(block);
- for(const auto &kvp: block->struct_declaration->members.variables)
- redeclared_builtins.push_back(kvp.second);
+ const map<string, VariableDeclaration *> &vars = var.block_declaration->members.variables;
+ const map<string, VariableDeclaration *> &existing_vars = existing->block_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(existing);
+ nodes_to_remove.insert(&var);
+ // The block struct will be removed during unused type removal
+ //nodes_to_remove.insert(var.block_declaration);
+ }
}
+ else if(!var.block_declaration && !existing->block_declaration && var.type==existing->type)
+ {
+ redeclare_builtin(*existing, var);
- nodes_to_remove.insert(&var);
- r_any_resolved = true;
+ if(block)
+ {
+ /* Cause the block and its members to be marked as not builtin
+ so it will be emitted in output */
+ redeclared_builtins.push_back(block);
+ for(const auto &kvp: block->block_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)
+ else if(existing->array && !existing->array_size && var.type==existing->type && !var.layout && !var.init_expression)
{
existing->array_size = var.array_size;
nodes_to_remove.insert(&var);
}
}
-void VariableResolver::visit(InterfaceBlock &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);
-}
-
bool ExpressionResolver::apply(Stage &s)
{
resolve(var, var.declaration->type_declaration, true);
}
-void ExpressionResolver::visit(InterfaceBlockReference &iface)
-{
- if(iface.declaration)
- resolve(iface, iface.declaration->type_declaration, true);
-}
-
void ExpressionResolver::visit(MemberAccess &memacc)
{
TraversingVisitor::visit(memacc);
TraversingVisitor::visit(call);
if(call.declaration)
+ {
+ for(unsigned i=0; i<call.arguments.size(); ++i)
+ {
+ TypeDeclaration *arg_type = call.arguments[i]->type;
+ TypeDeclaration *param_type = call.declaration->parameters[i]->type_declaration;
+ if(arg_type==param_type)
+ continue;
+ else if(!arg_type || !param_type)
+ return;
+
+ BasicTypeDeclaration *arg_basic = dynamic_cast<BasicTypeDeclaration *>(arg_type);
+ BasicTypeDeclaration *param_basic = dynamic_cast<BasicTypeDeclaration *>(param_type);
+ if(arg_basic && param_basic)
+ {
+ Compatibility compat = get_compatibility(*param_basic, *arg_basic);
+ if(compat==RIGHT_CONVERTIBLE)
+ convert_to(call.arguments[i], *param_basic);
+ else if(compat!=SAME_TYPE)
+ return;
+ }
+ else
+ {
+ ImageTypeDeclaration *arg_image = dynamic_cast<ImageTypeDeclaration *>(arg_type);
+ ImageTypeDeclaration *param_image = dynamic_cast<ImageTypeDeclaration *>(param_type);
+ if(!arg_image || !param_image || arg_image->base_image!=param_image)
+ return;
+ }
+ }
resolve(call, call.declaration->return_type_declaration, false);
+ }
else if(call.constructor)
visit_constructor(call);
}
bool has_signature = true;
for(auto i=call.arguments.begin(); (has_signature && i!=call.arguments.end()); ++i)
{
- if((*i)->type)
- append(arg_types, ",", (*i)->type->name);
+ if(const TypeDeclaration *type = (*i)->type)
+ {
+ if(const ImageTypeDeclaration *image = dynamic_cast<const ImageTypeDeclaration *>(type))
+ if(image->base_image)
+ type = image->base_image;
+ append(arg_types, ",", type->name);
+ }
else
has_signature = false;
}