From 696a97bd7411d69953c1a9e4b5f3dfb4c1d848f1 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Mon, 15 Feb 2021 11:13:07 +0200 Subject: [PATCH] Split SL::Compiler into several files It was getting rather unwieldy at over 2000 lines, but now that this subsystem has its own directory and namespace I can organize it better without interfering with the other parts. --- source/glsl/builtin.cpp | 62 ++ source/glsl/builtin.h | 16 + source/glsl/compatibility.cpp | 300 ++++++ source/glsl/compatibility.h | 67 ++ source/glsl/compiler.cpp | 1845 +-------------------------------- source/glsl/compiler.h | 370 +------ source/glsl/evaluate.cpp | 98 ++ source/glsl/evaluate.h | 39 + source/glsl/generate.cpp | 564 ++++++++++ source/glsl/generate.h | 124 +++ source/glsl/optimize.cpp | 452 ++++++++ source/glsl/optimize.h | 145 +++ source/glsl/output.cpp | 350 +++++++ source/glsl/output.h | 63 ++ source/glsl/syntax.cpp | 108 +- source/glsl/syntax.h | 50 - source/glsl/visitor.cpp | 199 ++++ source/glsl/visitor.h | 134 +++ 18 files changed, 2620 insertions(+), 2366 deletions(-) create mode 100644 source/glsl/builtin.cpp create mode 100644 source/glsl/builtin.h create mode 100644 source/glsl/compatibility.cpp create mode 100644 source/glsl/compatibility.h create mode 100644 source/glsl/evaluate.cpp create mode 100644 source/glsl/evaluate.h create mode 100644 source/glsl/generate.cpp create mode 100644 source/glsl/generate.h create mode 100644 source/glsl/optimize.cpp create mode 100644 source/glsl/optimize.h create mode 100644 source/glsl/output.cpp create mode 100644 source/glsl/output.h create mode 100644 source/glsl/visitor.cpp create mode 100644 source/glsl/visitor.h diff --git a/source/glsl/builtin.cpp b/source/glsl/builtin.cpp new file mode 100644 index 00000000..7aecda3c --- /dev/null +++ b/source/glsl/builtin.cpp @@ -0,0 +1,62 @@ +#include "builtin.h" +#include "generate.h" +#include "parser.h" + +using namespace std; + +namespace { + +const char builtins_src[] = + "#pragma MSP stage(vertex)\n" + "out gl_PerVertex {\n" + " vec4 gl_Position;\n" + " float gl_ClipDistance[];\n" + "};\n" + "#pragma MSP stage(geometry)\n" + "in gl_PerVertex {\n" + " vec4 gl_Position;\n" + " float gl_ClipDistance[];\n" + "} gl_in[];\n" + "out gl_PerVertex {\n" + " vec4 gl_Position;\n" + " float gl_ClipDistance[];\n" + "};\n"; + +} + +namespace Msp { +namespace GL { +namespace SL { + +Module *create_builtins_module() +{ + Parser parser; + Module *module = new Module(parser.parse(builtins_src, "")); + for(list::iterator i=module->stages.begin(); i!=module->stages.end(); ++i) + { + VariableResolver resolver; + i->content.visit(resolver); + for(map::iterator j=i->content.variables.begin(); j!=i->content.variables.end(); ++j) + j->second->linked_declaration = j->second; + } + return module; +} + +Module &get_builtins_module() +{ + static RefPtr builtins_module = create_builtins_module(); + return *builtins_module; +} + +Stage *get_builtins(StageType type) +{ + Module &module = get_builtins_module(); + for(list::iterator i=module.stages.begin(); i!=module.stages.end(); ++i) + if(i->type==type) + return &*i; + return 0; +} + +} // namespace SL +} // namespace GL +} // namespace Msp diff --git a/source/glsl/builtin.h b/source/glsl/builtin.h new file mode 100644 index 00000000..59e5ed89 --- /dev/null +++ b/source/glsl/builtin.h @@ -0,0 +1,16 @@ +#ifndef MSP_GL_SL_BUILTIN_H_ +#define MSP_GL_SL_BUILTIN_H_ + +#include "syntax.h" + +namespace Msp { +namespace GL { +namespace SL { + +Stage *get_builtins(StageType); + +} // namespace SL +} // namespace GL +} // namespace Msp + +#endif diff --git a/source/glsl/compatibility.cpp b/source/glsl/compatibility.cpp new file mode 100644 index 00000000..0c312d02 --- /dev/null +++ b/source/glsl/compatibility.cpp @@ -0,0 +1,300 @@ +#include +#include +#include +#include +#include +#include +#include +#include "compatibility.h" + +using namespace std; + +namespace Msp { +namespace GL { +namespace SL { + +DefaultPrecisionGenerator::DefaultPrecisionGenerator(): + toplevel(true) +{ } + +void DefaultPrecisionGenerator::visit(Block &block) +{ + if(toplevel) + { + SetForScope set(toplevel, false); + BlockModifier::visit(block); + } + else + StageVisitor::visit(block); +} + +void DefaultPrecisionGenerator::visit(Precision &prec) +{ + have_default.insert(prec.type); +} + +void DefaultPrecisionGenerator::visit(VariableDeclaration &var) +{ + if(var.type_declaration) + return; + + string type = var.type; + if(!type.compare(0, 3, "vec") || !type.compare(0, 3, "mat")) + type = "float"; + else if(!type.compare(0, 3, "ivec") || type=="uint") + type = "int"; + + if(!have_default.count(type)) + { + Precision *prec = new Precision; + if(!type.compare(0, 7, "sampler")) + prec->precision = "lowp"; + else if(stage->type==FRAGMENT) + prec->precision = "mediump"; + else + prec->precision = "highp"; + prec->type = type; + insert_nodes.push_back(prec); + + have_default.insert(type); + } +} + + +void PrecisionRemover::visit(Precision &) +{ + remove_node = true; +} + +void PrecisionRemover::visit(VariableDeclaration &var) +{ + var.precision.clear(); +} + + +LegacyConverter::LegacyConverter(): + target_api(get_gl_api()), + target_version(get_glsl_version()), + frag_out(0) +{ } + +LegacyConverter::LegacyConverter(const Version &v): + target_api(get_gl_api()), + target_version(v), + frag_out(0) +{ } + +bool LegacyConverter::check_version(const Version &feature_version) const +{ + if(target_versionrequired_versionrequired_version = feature_version; + + return true; +} + +bool LegacyConverter::check_extension(const Extension &extension) const +{ + if(!extension) + return false; + + vector::iterator i = find(stage->required_extensions, &extension); + if(i==stage->required_extensions.end()) + stage->required_extensions.push_back(&extension); + + return true; +} + +bool LegacyConverter::supports_unified_interface_syntax() const +{ + if(target_api==OPENGL_ES2) + return check_version(Version(3, 0)); + else + return check_version(Version(1, 30)); +} + +void LegacyConverter::visit(VariableReference &var) +{ + if(var.declaration==frag_out && !supports_unified_interface_syntax()) + { + var.name = "gl_FragColor"; + var.declaration = 0; + type = "vec4"; + } + else if(var.declaration) + type = var.declaration->type; + else + type = string(); +} + +void LegacyConverter::visit(Assignment &assign) +{ + TraversingVisitor::visit(assign); + if(assign.target_declaration==frag_out && !supports_unified_interface_syntax()) + assign.target_declaration = 0; +} + +bool LegacyConverter::supports_unified_sampling_functions() const +{ + if(target_api==OPENGL_ES2) + return check_version(Version(3, 0)); + else + return check_version(Version(1, 30)); +} + +void LegacyConverter::visit(FunctionCall &call) +{ + if(call.name=="texture" && !call.declaration && !supports_unified_sampling_functions()) + { + NodeArray::iterator i = call.arguments.begin(); + if(i!=call.arguments.end()) + { + (*i)->visit(*this); + if(type=="sampler1D") + call.name = "texture1D"; + else if(type=="sampler2D") + call.name = "texture2D"; + else if(type=="sampler3D") + call.name = "texture3D"; + else if(type=="samplerCube") + call.name = "textureCube"; + else if(type=="sampler1DShadow") + call.name = "shadow1D"; + else if(type=="sampler2DShadow") + call.name = "shadow2D"; + else if(type=="sampler1DArray") + { + check_extension(EXT_texture_array); + call.name = "texture1DArray"; + } + else if(type=="sampler2DArray") + { + check_extension(EXT_texture_array); + call.name = "texture2DArray"; + } + else if(type=="sampler1DArrayShadow") + { + check_extension(EXT_texture_array); + call.name = "shadow1DArray"; + } + else if(type=="sampler2DArrayShadow") + { + check_extension(EXT_texture_array); + call.name = "shadow2DArray"; + } + + for(; i!=call.arguments.end(); ++i) + (*i)->visit(*this); + } + } + else + TraversingVisitor::visit(call); +} + +bool LegacyConverter::supports_interface_layouts() const +{ + if(target_api==OPENGL_ES2) + return check_version(Version(3, 0)); + else if(check_version(Version(3, 30))) + return true; + else + return check_extension(ARB_explicit_attrib_location); +} + +bool LegacyConverter::supports_centroid_sampling() const +{ + if(target_api==OPENGL_ES2) + return check_version(Version(3, 0)); + else if(check_version(Version(1, 20))) + return true; + else + return check_extension(EXT_gpu_shader4); +} + +bool LegacyConverter::supports_sample_sampling() const +{ + if(target_api==OPENGL_ES2) + return check_version(Version(3, 20)); + else if(check_version(Version(4, 0))) + return true; + else + return check_extension(ARB_gpu_shader5); +} + +void LegacyConverter::visit(VariableDeclaration &var) +{ + if(var.layout && !supports_interface_layouts()) + { + vector::iterator i; + for(i=var.layout->qualifiers.begin(); (i!=var.layout->qualifiers.end() && i->identifier!="location"); ++i) ; + if(i!=var.layout->qualifiers.end()) + { + unsigned location = lexical_cast(i->value); + if(stage->type==VERTEX && var.interface=="in") + { + stage->locations[var.name] = location; + var.layout->qualifiers.erase(i); + } + else if(stage->type==FRAGMENT && var.interface=="out") + { + if(location!=0) + static Require _req(EXT_gpu_shader4); + stage->locations[var.name] = location; + var.layout->qualifiers.erase(i); + } + + if(var.layout->qualifiers.empty()) + var.layout = 0; + } + } + + if(var.sampling=="centroid") + { + if(!supports_centroid_sampling()) + var.sampling = string(); + } + else if(var.sampling=="sample") + { + if(!supports_sample_sampling()) + var.sampling = string(); + } + + if((var.interface=="in" || var.interface=="out") && !supports_unified_interface_syntax()) + { + if(stage->type==FRAGMENT && var.interface=="out") + { + frag_out = &var; + remove_node = true; + } + } + + TraversingVisitor::visit(var); +} + +bool LegacyConverter::supports_interface_blocks(const string &iface) const +{ + if(target_api==OPENGL_ES2) + { + if(iface=="uniform") + return check_version(Version(3, 0)); + else + return check_version(Version(3, 20)); + } + else if(check_version(Version(1, 50))) + return true; + else if(iface=="uniform") + return check_extension(ARB_uniform_buffer_object); + else + return false; +} + +void LegacyConverter::visit(InterfaceBlock &iface) +{ + if(!supports_interface_blocks(iface.interface)) + flatten_block(iface.members); +} + +} // namespace SL +} // namespace GL +} // namespace Msp diff --git a/source/glsl/compatibility.h b/source/glsl/compatibility.h new file mode 100644 index 00000000..f3376876 --- /dev/null +++ b/source/glsl/compatibility.h @@ -0,0 +1,67 @@ +#ifndef MSP_GL_SL_COMPATIBILITY_H_ +#define MSP_GL_SL_COMPATIBILITY_H_ + +#include +#include "visitor.h" + +namespace Msp { +namespace GL { +namespace SL { + +class DefaultPrecisionGenerator: public BlockModifier +{ +private: + bool toplevel; + std::set have_default; + +public: + DefaultPrecisionGenerator(); + + using StageVisitor::visit; + virtual void visit(Block &); + virtual void visit(Precision &); + virtual void visit(VariableDeclaration &); +}; + +class PrecisionRemover: public BlockModifier +{ +public: + using StageVisitor::visit; + virtual void visit(Precision &); + virtual void visit(VariableDeclaration &); +}; + +class LegacyConverter: public BlockModifier +{ +private: + GLApi target_api; + Version target_version; + std::string type; + VariableDeclaration *frag_out; + +public: + LegacyConverter(); + LegacyConverter(const Version &); + +private: + bool check_version(const Version &) const; + bool check_extension(const Extension &) const; + using StageVisitor::visit; + bool supports_unified_interface_syntax() const; + virtual void visit(VariableReference &); + virtual void visit(Assignment &); + bool supports_unified_sampling_functions() const; + virtual void visit(FunctionCall &); + bool supports_interface_layouts() const; + bool supports_centroid_sampling() const; + bool supports_sample_sampling() const; + virtual void visit(VariableDeclaration &); + bool supports_interface_blocks(const std::string &) const; + virtual void visit(InterfaceBlock &); +}; + +} // namespace SL +} // namespace GL +} // namespace Msp + +#endif diff --git a/source/glsl/compiler.cpp b/source/glsl/compiler.cpp index b862ef20..031ae265 100644 --- a/source/glsl/compiler.cpp +++ b/source/glsl/compiler.cpp @@ -1,41 +1,20 @@ #include -#include -#include -#include -#include #include -#include #include #include #include -#include "error.h" +#include "compatibility.h" #include "compiler.h" +#include "error.h" +#include "generate.h" +#include "optimize.h" +#include "output.h" #include "shader.h" #undef interface using namespace std; -namespace { - -const char builtins_src[] = - "#pragma MSP stage(vertex)\n" - "out gl_PerVertex {\n" - " vec4 gl_Position;\n" - " float gl_ClipDistance[];\n" - "};\n" - "#pragma MSP stage(geometry)\n" - "in gl_PerVertex {\n" - " vec4 gl_Position;\n" - " float gl_ClipDistance[];\n" - "} gl_in[];\n" - "out gl_PerVertex {\n" - " vec4 gl_Position;\n" - " float gl_ClipDistance[];\n" - "};\n"; - -} - namespace Msp { namespace GL { namespace SL { @@ -143,35 +122,6 @@ void Compiler::add_shaders(Program &program) } } -Module *Compiler::create_builtins_module() -{ - Parser parser; - Module *module = new Module(parser.parse(builtins_src, "")); - for(list::iterator i=module->stages.begin(); i!=module->stages.end(); ++i) - { - VariableResolver resolver; - i->content.visit(resolver); - for(map::iterator j=i->content.variables.begin(); j!=i->content.variables.end(); ++j) - j->second->linked_declaration = j->second; - } - return module; -} - -Module &Compiler::get_builtins_module() -{ - static RefPtr builtins_module = create_builtins_module(); - return *builtins_module; -} - -Stage *Compiler::get_builtins(StageType type) -{ - Module &module = get_builtins_module(); - for(list::iterator i=module.stages.begin(); i!=module.stages.end(); ++i) - if(i->type==type) - return &*i; - return 0; -} - void Compiler::append_module(Module &mod) { vector imports = apply >(mod.shared); @@ -304,1791 +254,6 @@ typename T::ResultType Compiler::apply(Stage &stage, const A &arg) return visitor.get_result(); } - -Compiler::Visitor::Visitor(): - stage(0) -{ } - -void Compiler::Visitor::apply(Stage &s) -{ - SetForScope set(stage, &s); - stage->content.visit(*this); -} - - -Compiler::BlockModifier::BlockModifier(): - remove_node(false) -{ } - -void Compiler::BlockModifier::flatten_block(Block &block) -{ - insert_nodes.insert(insert_nodes.end(), block.body.begin(), block.body.end()); - remove_node = true; -} - -void Compiler::BlockModifier::apply_and_increment(Block &block, NodeList::iterator &i) -{ - block.body.insert(i, insert_nodes.begin(), insert_nodes.end()); - insert_nodes.clear(); - - if(remove_node) - block.body.erase(i++); - else - ++i; - remove_node = false; -} - -void Compiler::BlockModifier::visit(Block &block) -{ - for(NodeList::iterator i=block.body.begin(); i!=block.body.end(); ) - { - (*i)->visit(*this); - apply_and_increment(block, i); - } -} - - -Compiler::Formatter::Formatter(): - source_index(0), - source_line(1), - indent(0), - parameter_list(false) -{ } - -void Compiler::Formatter::apply(Stage &s) -{ - GLApi api = get_gl_api(); - const Version &ver = s.required_version; - - if(ver) - { - append(format("#version %d%02d", ver.major, ver.minor)); - if(api==OPENGL_ES2 && ver>=Version(3, 0)) - append(" es"); - formatted += '\n'; - } - - for(vector::const_iterator i=s.required_extensions.begin(); i!=s.required_extensions.end(); ++i) - append(format("#extension %s: require\n", (*i)->get_name())); - if(!s.required_extensions.empty()) - formatted += '\n'; - - Visitor::apply(s); -} - -void Compiler::Formatter::append(const string &text) -{ - formatted += text; - for(string::const_iterator i=text.begin(); i!=text.end(); ++i) - if(*i=='\n') - ++source_line; -} - -void Compiler::Formatter::append(char c) -{ - formatted += c; - if(c=='\n') - ++source_line; -} - -void Compiler::Formatter::set_source(unsigned index, unsigned line) -{ - if(index!=source_index || (index && line!=source_line)) - { - if(index==source_index && line==source_line+1) - formatted += '\n'; - else - { - unsigned l = line; - if(stage->required_versionvisit(*this); - append(')'); -} - -void Compiler::Formatter::visit(VariableReference &var) -{ - append(var.name); -} - -void Compiler::Formatter::visit(MemberAccess &memacc) -{ - memacc.left->visit(*this); - append(format(".%s", memacc.member)); -} - -void Compiler::Formatter::visit(UnaryExpression &unary) -{ - if(unary.prefix) - append(unary.oper); - unary.expression->visit(*this); - if(!unary.prefix) - append(unary.oper); -} - -void Compiler::Formatter::visit(BinaryExpression &binary) -{ - binary.left->visit(*this); - append(binary.oper); - binary.right->visit(*this); - append(binary.after); -} - -void Compiler::Formatter::visit(Assignment &assign) -{ - assign.left->visit(*this); - append(format(" %s ", assign.oper)); - assign.right->visit(*this); -} - -void Compiler::Formatter::visit(FunctionCall &call) -{ - append(format("%s(", call.name)); - for(NodeArray::iterator i=call.arguments.begin(); i!=call.arguments.end(); ++i) - { - if(i!=call.arguments.begin()) - append(", "); - (*i)->visit(*this); - } - append(')'); -} - -void Compiler::Formatter::visit(ExpressionStatement &expr) -{ - expr.expression->visit(*this); - append(';'); -} - -void Compiler::Formatter::visit(Block &block) -{ - unsigned brace_indent = indent; - bool use_braces = (block.use_braces || (indent && block.body.size()!=1)); - if(use_braces) - append(format("%s{\n", string(brace_indent*2, ' '))); - - SetForScope set(indent, indent+(indent>0 || use_braces)); - string spaces(indent*2, ' '); - for(NodeList::iterator i=block.body.begin(); i!=block.body.end(); ++i) - { - if(i!=block.body.begin()) - append('\n'); - set_source((*i)->source, (*i)->line); - append(spaces); - (*i)->visit(*this); - } - - if(use_braces) - append(format("\n%s}", string(brace_indent*2, ' '))); -} - -void Compiler::Formatter::visit(Import &import) -{ - append(format("import %s;", import.module)); -} - -void Compiler::Formatter::visit(Precision &prec) -{ - append(format("precision %s %s;", prec.precision, prec.type)); -} - -void Compiler::Formatter::visit(Layout &layout) -{ - append("layout("); - for(vector::const_iterator i=layout.qualifiers.begin(); i!=layout.qualifiers.end(); ++i) - { - if(i!=layout.qualifiers.begin()) - append(", "); - append(i->identifier); - if(!i->value.empty()) - append(format("=%s", i->value)); - } - append(')'); -} - -void Compiler::Formatter::visit(InterfaceLayout &layout) -{ - layout.layout.visit(*this); - append(format(" %s;", layout.interface)); -} - -void Compiler::Formatter::visit(StructDeclaration &strct) -{ - append(format("struct %s\n", strct.name)); - strct.members.visit(*this); - append(';'); -} - -void Compiler::Formatter::visit(VariableDeclaration &var) -{ - if(var.layout) - { - var.layout->visit(*this); - append(' '); - } - if(var.constant) - append("const "); - if(!var.interpolation.empty()) - append(format("%s ", var.interpolation)); - if(!var.sampling.empty()) - append(format("%s ", var.sampling)); - if(!var.interface.empty() && var.interface!=block_interface) - { - string interface = var.interface; - if(stage->required_versiontype==VERTEX && var.interface=="in") - interface = "attribute"; - else if((stage->type==VERTEX && var.interface=="out") || (stage->type==FRAGMENT && var.interface=="in")) - interface = "varying"; - } - append(format("%s ", interface)); - } - if(!var.precision.empty()) - append(format("%s ", var.precision)); - append(format("%s %s", var.type, var.name)); - if(var.array) - { - append('['); - if(var.array_size) - var.array_size->visit(*this); - append(']'); - } - if(var.init_expression) - { - append(" = "); - var.init_expression->visit(*this); - } - if(!parameter_list) - append(';'); -} - -void Compiler::Formatter::visit(InterfaceBlock &iface) -{ - SetForScope set(block_interface, iface.interface); - append(format("%s %s\n", iface.interface, iface.name)); - iface.members.visit(*this); - append(';'); -} - -void Compiler::Formatter::visit(FunctionDeclaration &func) -{ - append(format("%s %s(", func.return_type, func.name)); - for(NodeArray::iterator i=func.parameters.begin(); i!=func.parameters.end(); ++i) - { - if(i!=func.parameters.begin()) - append(", "); - SetFlag set(parameter_list); - (*i)->visit(*this); - } - append(')'); - if(func.definition==&func) - { - append('\n'); - func.body.visit(*this); - } - else - append(';'); -} - -void Compiler::Formatter::visit(Conditional &cond) -{ - append("if("); - cond.condition->visit(*this); - append(")\n"); - - cond.body.visit(*this); - if(!cond.else_body.body.empty()) - { - Conditional *else_cond = dynamic_cast(cond.else_body.body.front().get()); - if(cond.else_body.body.size()==1 && else_cond) - { - append('\n'); - set_source(else_cond->source, else_cond->line); - append(format("%selse ", string(indent*2, ' '))); - else_cond->visit(*this); - } - else - { - append(format("\n%selse\n", string(indent*2, ' '))); - cond.else_body.visit(*this); - } - } -} - -void Compiler::Formatter::visit(Iteration &iter) -{ - if(!iter.init_statement && iter.condition && !iter.loop_expression) - { - append("while("); - iter.condition->visit(*this); - append(')'); - } - else - { - append("for("); - if(iter.init_statement) - iter.init_statement->visit(*this); - else - append(';'); - if(iter.condition) - { - append(' '); - iter.condition->visit(*this); - } - append(';'); - if(iter.loop_expression) - { - append(' '); - iter.loop_expression->visit(*this); - } - append(')'); - } - - if(iter.body.body.empty()) - append(" { }"); - else - { - append('\n'); - iter.body.visit(*this); - } -} - -void Compiler::Formatter::visit(Return &ret) -{ - append("return"); - if(ret.expression) - { - append(' '); - ret.expression->visit(*this); - } - append(';'); -} - -void Compiler::Formatter::visit(Jump &jump) -{ - append(jump.keyword); - append(';'); -} - - -Compiler::DeclarationCombiner::DeclarationCombiner(): - toplevel(true) -{ } - -void Compiler::DeclarationCombiner::visit(Block &block) -{ - if(!toplevel) - return; - - SetForScope set(toplevel, false); - BlockModifier::visit(block); -} - -void Compiler::DeclarationCombiner::visit(FunctionDeclaration &func) -{ - vector &decls = functions[func.name]; - if(func.definition) - { - for(vector::iterator i=decls.begin(); i!=decls.end(); ++i) - { - (*i)->definition = func.definition; - (*i)->body.body.clear(); - } - } - decls.push_back(&func); -} - -void Compiler::DeclarationCombiner::visit(VariableDeclaration &var) -{ - VariableDeclaration *&ptr = variables[var.name]; - if(ptr) - { - ptr->type = var.type; - if(var.init_expression) - ptr->init_expression = var.init_expression; - if(var.layout) - { - if(ptr->layout) - { - for(vector::iterator i=var.layout->qualifiers.begin(); i!=var.layout->qualifiers.end(); ++i) - { - bool found = false; - for(vector::iterator j=ptr->layout->qualifiers.begin(); (!found && j!=ptr->layout->qualifiers.end()); ++j) - if(j->identifier==i->identifier) - { - j->value = i->value; - found = true; - } - - if(!found) - ptr->layout->qualifiers.push_back(*i); - } - } - else - ptr->layout = var.layout; - } - remove_node = true; - } - else - ptr = &var; -} - - -Compiler::VariableResolver::VariableResolver(): - anonymous(false), - record_target(false), - assignment_target(0), - self_referencing(false) -{ } - -void Compiler::VariableResolver::apply(Stage &s) -{ - SetForScope set(stage, &s); - Stage *builtins = get_builtins(stage->type); - if(builtins) - blocks.push_back(&builtins->content); - stage->content.visit(*this); - if(builtins) - blocks.pop_back(); -} - -void Compiler::VariableResolver::visit(Block &block) -{ - blocks.push_back(&block); - block.variables.clear(); - TraversingVisitor::visit(block); - blocks.pop_back(); -} - -void Compiler::VariableResolver::visit(VariableReference &var) -{ - var.declaration = 0; - type = 0; - for(vector::iterator i=blocks.end(); i!=blocks.begin(); ) - { - --i; - map::iterator j = (*i)->variables.find(var.name); - if(j!=(*i)->variables.end()) - { - var.declaration = j->second; - type = j->second->type_declaration; - break; - } - } - - if(record_target) - { - if(assignment_target) - { - record_target = false; - assignment_target = 0; - } - else - assignment_target = var.declaration; - } - else if(var.declaration && var.declaration==assignment_target) - self_referencing = true; -} - -void Compiler::VariableResolver::visit(MemberAccess &memacc) -{ - type = 0; - TraversingVisitor::visit(memacc); - memacc.declaration = 0; - if(type) - { - map::iterator i = type->members.variables.find(memacc.member); - if(i!=type->members.variables.end()) - { - memacc.declaration = i->second; - type = i->second->type_declaration; - } - else - type = 0; - } -} - -void Compiler::VariableResolver::visit(BinaryExpression &binary) -{ - if(binary.oper=="[") - { - { - SetForScope set(record_target, false); - binary.right->visit(*this); - } - type = 0; - binary.left->visit(*this); - } - else - { - TraversingVisitor::visit(binary); - type = 0; - } -} - -void Compiler::VariableResolver::visit(Assignment &assign) -{ - { - SetFlag set(record_target); - assignment_target = 0; - assign.left->visit(*this); - } - - self_referencing = false; - assign.right->visit(*this); - - assign.self_referencing = (self_referencing || assign.oper!="="); - assign.target_declaration = assignment_target; -} - -void Compiler::VariableResolver::visit(StructDeclaration &strct) -{ - TraversingVisitor::visit(strct); - blocks.back()->types[strct.name] = &strct; -} - -void Compiler::VariableResolver::visit(VariableDeclaration &var) -{ - for(vector::iterator i=blocks.end(); i!=blocks.begin(); ) - { - --i; - map::iterator j = (*i)->types.find(var.type); - if(j!=(*i)->types.end()) - var.type_declaration = j->second; - } - - if(!block_interface.empty() && var.interface.empty()) - var.interface = block_interface; - - TraversingVisitor::visit(var); - blocks.back()->variables[var.name] = &var; - if(anonymous && blocks.size()>1) - blocks[blocks.size()-2]->variables[var.name] = &var; -} - -void Compiler::VariableResolver::visit(InterfaceBlock &iface) -{ - SetFlag set(anonymous); - SetForScope set2(block_interface, iface.interface); - TraversingVisitor::visit(iface); -} - - -void Compiler::FunctionResolver::visit(FunctionCall &call) -{ - map >::iterator i = functions.find(call.name); - if(i!=functions.end()) - call.declaration = i->second.back(); - - TraversingVisitor::visit(call); -} - -void Compiler::FunctionResolver::visit(FunctionDeclaration &func) -{ - vector &decls = functions[func.name]; - if(func.definition) - { - for(vector::iterator i=decls.begin(); i!=decls.end(); ++i) - (*i)->definition = func.definition; - decls.clear(); - decls.push_back(&func); - } - else if(!decls.empty() && decls.back()->definition) - func.definition = decls.back()->definition; - else - decls.push_back(&func); - - TraversingVisitor::visit(func); -} - - -Compiler::InterfaceGenerator::InterfaceGenerator(): - scope_level(0) -{ } - -string Compiler::InterfaceGenerator::get_out_prefix(StageType type) -{ - if(type==VERTEX) - return "_vs_out_"; - else if(type==GEOMETRY) - return "_gs_out_"; - else - return string(); -} - -void Compiler::InterfaceGenerator::apply(Stage &s) -{ - SetForScope set(stage, &s); - if(stage->previous) - in_prefix = get_out_prefix(stage->previous->type); - out_prefix = get_out_prefix(stage->type); - stage->content.visit(*this); -} - -void Compiler::InterfaceGenerator::visit(Block &block) -{ - SetForScope set(scope_level, scope_level+1); - for(NodeList::iterator i=block.body.begin(); i!=block.body.end(); ) - { - (*i)->visit(*this); - - if(scope_level==1) - { - for(map >::iterator j=iface_declarations.begin(); j!=iface_declarations.end(); ++j) - { - NodeList::iterator k = block.body.insert(i, j->second); - (*k)->visit(*this); - } - iface_declarations.clear(); - } - - apply_and_increment(block, i); - } -} - -string Compiler::InterfaceGenerator::change_prefix(const string &name, const string &prefix) const -{ - unsigned offset = (name.compare(0, in_prefix.size(), in_prefix) ? 0 : in_prefix.size()); - return prefix+name.substr(offset); -} - -bool Compiler::InterfaceGenerator::generate_interface(VariableDeclaration &var, const string &iface, const string &name) -{ - const map &stage_vars = (iface=="in" ? stage->in_variables : stage->out_variables); - if(stage_vars.count(name) || iface_declarations.count(name)) - return false; - - VariableDeclaration* iface_var = new VariableDeclaration; - iface_var->sampling = var.sampling; - iface_var->interface = iface; - iface_var->type = var.type; - iface_var->type_declaration = var.type_declaration; - iface_var->name = name; - if(stage->type==GEOMETRY) - iface_var->array = ((var.array && var.interface!="in") || iface=="in"); - else - iface_var->array = var.array; - if(iface_var->array) - iface_var->array_size = var.array_size; - if(iface=="in") - iface_var->linked_declaration = &var; - iface_declarations[name] = iface_var; - - return true; -} - -ExpressionStatement &Compiler::InterfaceGenerator::insert_assignment(const string &left, Expression *right) -{ - Assignment *assign = new Assignment; - VariableReference *ref = new VariableReference; - ref->name = left; - assign->left = ref; - assign->oper = "="; - assign->right = right; - - ExpressionStatement *stmt = new ExpressionStatement; - stmt->expression = assign; - stmt->visit(*this); - insert_nodes.push_back(stmt); - - return *stmt; -} - -void Compiler::InterfaceGenerator::visit(VariableReference &var) -{ - if(var.declaration || !stage->previous) - return; - if(iface_declarations.count(var.name)) - return; - - const map &prev_out = stage->previous->out_variables; - map::const_iterator i = prev_out.find(var.name); - if(i==prev_out.end()) - i = prev_out.find(in_prefix+var.name); - if(i!=prev_out.end()) - { - generate_interface(*i->second, "in", i->second->name); - var.name = i->second->name; - } -} - -void Compiler::InterfaceGenerator::visit(VariableDeclaration &var) -{ - if(var.interface=="out") - { - if(scope_level==1) - stage->out_variables[var.name] = &var; - else if(generate_interface(var, "out", change_prefix(var.name, string()))) - { - remove_node = true; - if(var.init_expression) - { - ExpressionStatement &stmt = insert_assignment(var.name, var.init_expression->clone()); - stmt.source = var.source; - stmt.line = var.line; - return; - } - } - } - else if(var.interface=="in") - { - stage->in_variables[var.name] = &var; - if(var.linked_declaration) - var.linked_declaration->linked_declaration = &var; - else if(stage->previous) - { - const map &prev_out = stage->previous->out_variables; - map::const_iterator i = prev_out.find(var.name); - if(i!=prev_out.end()) - { - var.linked_declaration = i->second; - i->second->linked_declaration = &var; - } - } - } - - TraversingVisitor::visit(var); -} - -void Compiler::InterfaceGenerator::visit(Passthrough &pass) -{ - vector pass_vars; - - for(map::const_iterator i=stage->in_variables.begin(); i!=stage->in_variables.end(); ++i) - pass_vars.push_back(i->second); - for(map >::const_iterator i=iface_declarations.begin(); i!=iface_declarations.end(); ++i) - if(i->second->interface=="in") - pass_vars.push_back(i->second.get()); - - if(stage->previous) - { - const map &prev_out = stage->previous->out_variables; - for(map::const_iterator i=prev_out.begin(); i!=prev_out.end(); ++i) - { - bool linked = false; - for(vector::const_iterator j=pass_vars.begin(); (!linked && j!=pass_vars.end()); ++j) - linked = ((*j)->linked_declaration==i->second); - - if(!linked && generate_interface(*i->second, "in", i->second->name)) - pass_vars.push_back(i->second); - } - } - - if(stage->type==GEOMETRY) - { - VariableReference *ref = new VariableReference; - ref->name = "gl_in"; - - BinaryExpression *subscript = new BinaryExpression; - subscript->left = ref; - subscript->oper = "["; - subscript->right = pass.subscript; - subscript->after = "]"; - - MemberAccess *memacc = new MemberAccess; - memacc->left = subscript; - memacc->member = "gl_Position"; - - insert_assignment("gl_Position", memacc); - } - - for(vector::const_iterator i=pass_vars.begin(); i!=pass_vars.end(); ++i) - { - string out_name = change_prefix((*i)->name, out_prefix); - generate_interface(**i, "out", out_name); - - VariableReference *ref = new VariableReference; - ref->name = (*i)->name; - if(pass.subscript) - { - BinaryExpression *subscript = new BinaryExpression; - subscript->left = ref; - subscript->oper = "["; - subscript->right = pass.subscript; - subscript->after = "]"; - insert_assignment(out_name, subscript); - } - else - insert_assignment(out_name, ref); - } - - remove_node = true; -} - - -Compiler::DeclarationReorderer::DeclarationReorderer(): - scope_level(0), - kind(NO_DECLARATION) -{ } - -void Compiler::DeclarationReorderer::visit(FunctionCall &call) -{ - FunctionDeclaration *def = call.declaration; - if(def) - def = def->definition; - if(def && !ordered_funcs.count(def)) - needed_funcs.insert(def); -} - -void Compiler::DeclarationReorderer::visit(Block &block) -{ - SetForScope set(scope_level, scope_level+1); - if(scope_level>1) - return Visitor::visit(block); - - NodeList::iterator struct_insert_point = block.body.end(); - NodeList::iterator variable_insert_point = block.body.end(); - NodeList::iterator function_insert_point = block.body.end(); - unsigned unordered_func_count = 0; - bool ordered_any_funcs = false; - - for(NodeList::iterator i=block.body.begin(); i!=block.body.end(); ) - { - kind = NO_DECLARATION; - (*i)->visit(*this); - - bool moved = false; - if(kind==STRUCT && struct_insert_point!=block.body.end()) - { - block.body.insert(struct_insert_point, *i); - moved = true; - } - else if(kind>STRUCT && struct_insert_point==block.body.end()) - struct_insert_point = i; - - if(kind==VARIABLE && variable_insert_point!=block.body.end()) - { - block.body.insert(variable_insert_point, *i); - moved = true; - } - else if(kind>VARIABLE && variable_insert_point==block.body.end()) - variable_insert_point = i; - - if(kind==FUNCTION) - { - if(function_insert_point==block.body.end()) - function_insert_point = i; - - if(needed_funcs.empty()) - { - ordered_funcs.insert(i->get()); - if(i!=function_insert_point) - { - block.body.insert(function_insert_point, *i); - moved = true; - } - else - ++function_insert_point; - ordered_any_funcs = true; - } - else - ++unordered_func_count; - } - - if(moved) - { - if(function_insert_point==i) - ++function_insert_point; - block.body.erase(i++); - } - else - ++i; - - if(i==block.body.end() && unordered_func_count) - { - if(!ordered_any_funcs) - // A subset of the remaining functions forms a recursive loop - /* TODO pick a function and move it up, adding any necessary - declarations */ - break; - - i = function_insert_point; - unordered_func_count = 0; - } - } -} - -void Compiler::DeclarationReorderer::visit(VariableDeclaration &var) -{ - Visitor::visit(var); - kind = VARIABLE; -} - -void Compiler::DeclarationReorderer::visit(FunctionDeclaration &func) -{ - needed_funcs.clear(); - func.body.visit(*this); - needed_funcs.erase(&func); - kind = FUNCTION; -} - - -Compiler::InlineableFunctionLocator::InlineableFunctionLocator(): - in_function(0) -{ } - -void Compiler::InlineableFunctionLocator::visit(FunctionCall &call) -{ - FunctionDeclaration *def = call.declaration; - if(def && def->definition!=def) - def = def->definition; - - if(def) - { - unsigned &count = refcounts[def]; - ++count; - if(count>1 || def==in_function) - inlineable.erase(def); - } - - TraversingVisitor::visit(call); -} - -void Compiler::InlineableFunctionLocator::visit(FunctionDeclaration &func) -{ - unsigned &count = refcounts[func.definition]; - if(!count && func.parameters.empty()) - inlineable.insert(func.definition); - - SetForScope set(in_function, &func); - TraversingVisitor::visit(func); -} - - -Compiler::FunctionInliner::FunctionInliner(): - extract_result(0) -{ } - -Compiler::FunctionInliner::FunctionInliner(const set &in): - inlineable(in), - extract_result(0) -{ } - -void Compiler::FunctionInliner::visit_and_inline(RefPtr &ptr) -{ - inline_result = 0; - ptr->visit(*this); - if(inline_result) - ptr = inline_result; -} - -void Compiler::FunctionInliner::visit(Block &block) -{ - if(extract_result) - --extract_result; - - for(NodeList::iterator i=block.body.begin(); i!=block.body.end(); ++i) - { - (*i)->visit(*this); - if(extract_result) - --extract_result; - } -} - -void Compiler::FunctionInliner::visit(UnaryExpression &unary) -{ - visit_and_inline(unary.expression); - inline_result = 0; -} - -void Compiler::FunctionInliner::visit(BinaryExpression &binary) -{ - visit_and_inline(binary.left); - visit_and_inline(binary.right); - inline_result = 0; -} - -void Compiler::FunctionInliner::visit(MemberAccess &memacc) -{ - visit_and_inline(memacc.left); - inline_result = 0; -} - -void Compiler::FunctionInliner::visit(FunctionCall &call) -{ - for(NodeArray::iterator i=call.arguments.begin(); i!=call.arguments.end(); ++i) - visit_and_inline(*i); - - FunctionDeclaration *def = call.declaration; - if(def && def->definition!=def) - def = def->definition; - - if(def && inlineable.count(def)) - { - extract_result = 2; - def->visit(*this); - } - else - inline_result = 0; -} - -void Compiler::FunctionInliner::visit(VariableDeclaration &var) -{ - if(var.init_expression) - visit_and_inline(var.init_expression); - inline_result = 0; -} - -void Compiler::FunctionInliner::visit(Return &ret) -{ - TraversingVisitor::visit(ret); - - if(extract_result) - inline_result = ret.expression->clone(); -} - - -Compiler::ExpressionEvaluator::ExpressionEvaluator(): - variable_values(0), - result(0.0f), - result_valid(false) -{ } - -Compiler::ExpressionEvaluator::ExpressionEvaluator(const ValueMap &v): - variable_values(&v), - result(0.0f), - result_valid(false) -{ } - -void Compiler::ExpressionEvaluator::visit(Literal &literal) -{ - if(literal.token=="true") - result = 1.0f; - else if(literal.token=="false") - result = 0.0f; - else - result = lexical_cast(literal.token); - result_valid = true; -} - -void Compiler::ExpressionEvaluator::visit(ParenthesizedExpression &parexp) -{ - parexp.expression->visit(*this); -} - -void Compiler::ExpressionEvaluator::visit(VariableReference &var) -{ - if(!var.declaration) - return; - - if(variable_values) - { - ValueMap::const_iterator i = variable_values->find(var.declaration); - if(i!=variable_values->end()) - i->second->visit(*this); - } - else if(var.declaration->init_expression) - var.declaration->init_expression->visit(*this); -} - -void Compiler::ExpressionEvaluator::visit(UnaryExpression &unary) -{ - result_valid = false; - unary.expression->visit(*this); - if(!result_valid) - return; - - if(unary.oper=="!") - result = !result; - else - result_valid = false; -} - -void Compiler::ExpressionEvaluator::visit(BinaryExpression &binary) -{ - result_valid = false; - binary.left->visit(*this); - if(!result_valid) - return; - - float left_result = result; - result_valid = false; - binary.right->visit(*this); - if(!result_valid) - return; - - if(binary.oper=="<") - result = (left_result") - result = (left_result>result); - else if(binary.oper==">=") - result = (left_result>=result); - else if(binary.oper=="==") - result = (left_result==result); - else if(binary.oper=="!=") - result = (left_result!=result); - else if(binary.oper=="&&") - result = (left_result && result); - else if(binary.oper=="||") - result = (left_result || result); - else - result_valid = false; -} - - -Compiler::ConstantConditionEliminator::ConstantConditionEliminator(): - scope_level(0), - record_only(false) -{ } - -void Compiler::ConstantConditionEliminator::visit(Block &block) -{ - SetForScope set(scope_level, scope_level+1); - BlockModifier::visit(block); - - for(map::const_iterator i=block.variables.begin(); i!=block.variables.end(); ++i) - variable_values.erase(i->second); -} - -void Compiler::ConstantConditionEliminator::visit(UnaryExpression &unary) -{ - if(VariableReference *var = dynamic_cast(unary.expression.get())) - if(unary.oper=="++" || unary.oper=="--") - variable_values.erase(var->declaration); -} - -void Compiler::ConstantConditionEliminator::visit(Assignment &assign) -{ - variable_values.erase(assign.target_declaration); -} - -void Compiler::ConstantConditionEliminator::visit(VariableDeclaration &var) -{ - if(var.constant || scope_level>1) - variable_values[&var] = var.init_expression.get(); -} - -void Compiler::ConstantConditionEliminator::visit(Conditional &cond) -{ - if(!record_only) - { - ExpressionEvaluator eval(variable_values); - cond.condition->visit(eval); - if(eval.result_valid) - { - flatten_block(eval.result ? cond.body : cond.else_body); - return; - } - } - - TraversingVisitor::visit(cond); -} - -void Compiler::ConstantConditionEliminator::visit(Iteration &iter) -{ - if(!record_only) - { - if(iter.condition) - { - /* If the loop condition is always false on the first iteration, the - entire loop can be removed */ - if(iter.init_statement) - iter.init_statement->visit(*this); - ExpressionEvaluator eval(variable_values); - iter.condition->visit(eval); - if(eval.result_valid && !eval.result) - { - remove_node = true; - return; - } - } - - /* Record all assignments that occur inside the loop body so those - variables won't be considered as constant */ - SetFlag set_record(record_only); - TraversingVisitor::visit(iter); - } - - TraversingVisitor::visit(iter); - - if(VariableDeclaration *init_decl = dynamic_cast(iter.init_statement.get())) - variable_values.erase(init_decl); -} - - -Compiler::UnusedVariableLocator::UnusedVariableLocator(): - aggregate(0), - assignment(0), - assignment_target(false), - assign_to_subscript(false), - global_scope(true) -{ } - -void Compiler::UnusedVariableLocator::apply(Stage &s) -{ - variables.push_back(BlockVariableMap()); - Visitor::apply(s); - BlockVariableMap &global_variables = variables.back(); - for(BlockVariableMap::iterator i=global_variables.begin(); i!=global_variables.end(); ++i) - { - if(i->first->interface=="out" && (s.type==FRAGMENT || i->first->linked_declaration || !i->first->name.compare(0, 3, "gl_"))) - continue; - if(!i->second.referenced) - { - unused_nodes.insert(i->first); - clear_assignments(i->second, true); - } - } - variables.pop_back(); -} - -void Compiler::UnusedVariableLocator::visit(VariableReference &var) -{ - map::iterator i = aggregates.find(var.declaration); - if(i!=aggregates.end()) - unused_nodes.erase(i->second); - - if(var.declaration && !assignment_target) - { - VariableInfo &var_info = variables.back()[var.declaration]; - var_info.assignments.clear(); - var_info.referenced = true; - } -} - -void Compiler::UnusedVariableLocator::visit(MemberAccess &memacc) -{ - TraversingVisitor::visit(memacc); - unused_nodes.erase(memacc.declaration); -} - -void Compiler::UnusedVariableLocator::visit(BinaryExpression &binary) -{ - if(binary.oper=="[") - { - if(assignment_target) - assign_to_subscript = true; - binary.left->visit(*this); - SetForScope set(assignment_target, false); - binary.right->visit(*this); - } - else - TraversingVisitor::visit(binary); -} - -void Compiler::UnusedVariableLocator::visit(Assignment &assign) -{ - { - assign_to_subscript = false; - SetForScope set(assignment_target, !assign.self_referencing); - assign.left->visit(*this); - } - assign.right->visit(*this); - assignment = &assign; -} - -void Compiler::UnusedVariableLocator::record_assignment(VariableDeclaration &var, Node &node, bool chained) -{ - VariableInfo &var_info = variables.back()[&var]; - if(!chained) - clear_assignments(var_info, true); - var_info.assignments.push_back(&node); - var_info.conditionally_assigned = false; -} - -void Compiler::UnusedVariableLocator::clear_assignments(VariableInfo &var_info, bool mark_unused) -{ - if(mark_unused) - { - for(vector::iterator i=var_info.assignments.begin(); i!=var_info.assignments.end(); ++i) - unused_nodes.insert(*i); - } - var_info.assignments.clear(); -} - -void Compiler::UnusedVariableLocator::visit(ExpressionStatement &expr) -{ - assignment = 0; - TraversingVisitor::visit(expr); - if(assignment && assignment->target_declaration) - record_assignment(*assignment->target_declaration, expr, (assignment->self_referencing || assign_to_subscript)); -} - -void Compiler::UnusedVariableLocator::visit(StructDeclaration &strct) -{ - SetForScope set(aggregate, &strct); - unused_nodes.insert(&strct); - TraversingVisitor::visit(strct); -} - -void Compiler::UnusedVariableLocator::visit(VariableDeclaration &var) -{ - if(aggregate) - aggregates[&var] = aggregate; - else - { - variables.back()[&var].local = true; - if(var.init_expression) - record_assignment(var, *var.init_expression, false); - } - unused_nodes.erase(var.type_declaration); - TraversingVisitor::visit(var); -} - -void Compiler::UnusedVariableLocator::visit(InterfaceBlock &iface) -{ - SetForScope set(aggregate, &iface); - unused_nodes.insert(&iface); - TraversingVisitor::visit(iface); -} - -void Compiler::UnusedVariableLocator::visit(FunctionDeclaration &func) -{ - variables.push_back(BlockVariableMap()); - - { - SetForScope set(global_scope, false); - for(NodeArray::iterator i=func.parameters.begin(); i!=func.parameters.end(); ++i) - (*i)->visit(*this); - func.body.visit(*this); - } - - BlockVariableMap &block_variables = variables.back(); - for(BlockVariableMap::iterator i=block_variables.begin(); i!=block_variables.end(); ++i) - i->second.conditionally_assigned = true; - for(NodeArray::iterator i=func.parameters.begin(); i!=func.parameters.end(); ++i) - block_variables[i->get()].referenced = true; - merge_down_variables(); -} - -void Compiler::UnusedVariableLocator::merge_down_variables() -{ - BlockVariableMap &parent_variables = variables[variables.size()-2]; - BlockVariableMap &block_variables = variables.back(); - for(BlockVariableMap::iterator i=block_variables.begin(); i!=block_variables.end(); ++i) - { - if(i->second.local) - { - if(!i->second.referenced) - unused_nodes.insert(i->first); - clear_assignments(i->second, i->first->interface!="out"); - continue; - } - - BlockVariableMap::iterator j = parent_variables.find(i->first); - if(j==parent_variables.end()) - parent_variables.insert(*i); - else - { - if(i->second.referenced || !i->second.conditionally_assigned) - clear_assignments(j->second, !i->second.referenced); - j->second.conditionally_assigned = i->second.conditionally_assigned; - j->second.referenced |= i->second.referenced; - j->second.assignments.insert(j->second.assignments.end(), i->second.assignments.begin(), i->second.assignments.end()); - } - } - variables.pop_back(); -} - -void Compiler::UnusedVariableLocator::visit(Conditional &cond) -{ - cond.condition->visit(*this); - variables.push_back(BlockVariableMap()); - cond.body.visit(*this); - - BlockVariableMap if_variables; - swap(variables.back(), if_variables); - cond.else_body.visit(*this); - - BlockVariableMap &else_variables = variables.back(); - for(BlockVariableMap::iterator i=else_variables.begin(); i!=else_variables.end(); ++i) - { - BlockVariableMap::iterator j = if_variables.find(i->first); - if(j!=if_variables.end()) - { - i->second.assignments.insert(i->second.assignments.end(), j->second.assignments.begin(), j->second.assignments.end()); - i->second.conditionally_assigned |= j->second.conditionally_assigned; - if_variables.erase(j); - } - else - i->second.conditionally_assigned = true; - } - - for(BlockVariableMap::iterator i=if_variables.begin(); i!=if_variables.end(); ++i) - { - i->second.conditionally_assigned = true; - else_variables.insert(*i); - } - - merge_down_variables(); -} - -void Compiler::UnusedVariableLocator::visit(Iteration &iter) -{ - variables.push_back(BlockVariableMap()); - TraversingVisitor::visit(iter); - - BlockVariableMap &block_variables = variables.back(); - for(BlockVariableMap::iterator i=block_variables.begin(); i!=block_variables.end(); ++i) - if(!i->second.local && i->second.referenced) - i->second.assignments.clear(); - - merge_down_variables(); -} - - -Compiler::UnusedVariableLocator::VariableInfo::VariableInfo(): - local(false), - conditionally_assigned(false), - referenced(false) -{ } - - -void Compiler::UnusedFunctionLocator::visit(FunctionCall &call) -{ - TraversingVisitor::visit(call); - - unused_nodes.erase(call.declaration); - if(call.declaration && call.declaration->definition!=call.declaration) - used_definitions.insert(call.declaration->definition); -} - -void Compiler::UnusedFunctionLocator::visit(FunctionDeclaration &func) -{ - TraversingVisitor::visit(func); - - if((func.name!="main" || func.body.body.empty()) && !used_definitions.count(&func)) - unused_nodes.insert(&func); -} - - -Compiler::NodeRemover::NodeRemover(const set &r): - to_remove(r) -{ } - -void Compiler::NodeRemover::visit(Block &block) -{ - for(NodeList::iterator i=block.body.begin(); i!=block.body.end(); ) - { - (*i)->visit(*this); - if(to_remove.count(i->get())) - block.body.erase(i++); - else - ++i; - } -} - -void Compiler::NodeRemover::visit(VariableDeclaration &var) -{ - if(to_remove.count(&var)) - { - stage->in_variables.erase(var.name); - stage->out_variables.erase(var.name); - stage->locations.erase(var.name); - if(var.linked_declaration) - var.linked_declaration->linked_declaration = 0; - } - else if(var.init_expression && to_remove.count(var.init_expression.get())) - var.init_expression = 0; -} - -void Compiler::NodeRemover::visit(Iteration &iter) -{ - if(to_remove.count(iter.init_statement.get())) - iter.init_statement = 0; - TraversingVisitor::visit(iter); -} - - -void Compiler::PrecisionRemover::visit(Precision &) -{ - remove_node = true; -} - -void Compiler::PrecisionRemover::visit(VariableDeclaration &var) -{ - var.precision.clear(); -} - - -Compiler::DefaultPrecisionGenerator::DefaultPrecisionGenerator(): - toplevel(true) -{ } - -void Compiler::DefaultPrecisionGenerator::visit(Block &block) -{ - if(toplevel) - { - SetForScope set(toplevel, false); - BlockModifier::visit(block); - } - else - Visitor::visit(block); -} - -void Compiler::DefaultPrecisionGenerator::visit(Precision &prec) -{ - have_default.insert(prec.type); -} - -void Compiler::DefaultPrecisionGenerator::visit(VariableDeclaration &var) -{ - if(var.type_declaration) - return; - - string type = var.type; - if(!type.compare(0, 3, "vec") || !type.compare(0, 3, "mat")) - type = "float"; - else if(!type.compare(0, 3, "ivec") || type=="uint") - type = "int"; - - if(!have_default.count(type)) - { - Precision *prec = new Precision; - if(!type.compare(0, 7, "sampler")) - prec->precision = "lowp"; - else if(stage->type==FRAGMENT) - prec->precision = "mediump"; - else - prec->precision = "highp"; - prec->type = type; - insert_nodes.push_back(prec); - - have_default.insert(type); - } -} - - -Compiler::LegacyConverter::LegacyConverter(): - target_api(get_gl_api()), - target_version(get_glsl_version()), - frag_out(0) -{ } - -Compiler::LegacyConverter::LegacyConverter(const Version &v): - target_api(get_gl_api()), - target_version(v), - frag_out(0) -{ } - -bool Compiler::LegacyConverter::check_version(const Version &feature_version) const -{ - if(target_versionrequired_versionrequired_version = feature_version; - - return true; -} - -bool Compiler::LegacyConverter::check_extension(const Extension &extension) const -{ - if(!extension) - return false; - - vector::iterator i = find(stage->required_extensions, &extension); - if(i==stage->required_extensions.end()) - stage->required_extensions.push_back(&extension); - - return true; -} - -bool Compiler::LegacyConverter::supports_unified_interface_syntax() const -{ - if(target_api==OPENGL_ES2) - return check_version(Version(3, 0)); - else - return check_version(Version(1, 30)); -} - -void Compiler::LegacyConverter::visit(VariableReference &var) -{ - if(var.declaration==frag_out && !supports_unified_interface_syntax()) - { - var.name = "gl_FragColor"; - var.declaration = 0; - type = "vec4"; - } - else if(var.declaration) - type = var.declaration->type; - else - type = string(); -} - -void Compiler::LegacyConverter::visit(Assignment &assign) -{ - TraversingVisitor::visit(assign); - if(assign.target_declaration==frag_out && !supports_unified_interface_syntax()) - assign.target_declaration = 0; -} - -bool Compiler::LegacyConverter::supports_unified_sampling_functions() const -{ - if(target_api==OPENGL_ES2) - return check_version(Version(3, 0)); - else - return check_version(Version(1, 30)); -} - -void Compiler::LegacyConverter::visit(FunctionCall &call) -{ - if(call.name=="texture" && !call.declaration && !supports_unified_sampling_functions()) - { - NodeArray::iterator i = call.arguments.begin(); - if(i!=call.arguments.end()) - { - (*i)->visit(*this); - if(type=="sampler1D") - call.name = "texture1D"; - else if(type=="sampler2D") - call.name = "texture2D"; - else if(type=="sampler3D") - call.name = "texture3D"; - else if(type=="samplerCube") - call.name = "textureCube"; - else if(type=="sampler1DShadow") - call.name = "shadow1D"; - else if(type=="sampler2DShadow") - call.name = "shadow2D"; - else if(type=="sampler1DArray") - { - check_extension(EXT_texture_array); - call.name = "texture1DArray"; - } - else if(type=="sampler2DArray") - { - check_extension(EXT_texture_array); - call.name = "texture2DArray"; - } - else if(type=="sampler1DArrayShadow") - { - check_extension(EXT_texture_array); - call.name = "shadow1DArray"; - } - else if(type=="sampler2DArrayShadow") - { - check_extension(EXT_texture_array); - call.name = "shadow2DArray"; - } - - for(; i!=call.arguments.end(); ++i) - (*i)->visit(*this); - } - } - else - TraversingVisitor::visit(call); -} - -bool Compiler::LegacyConverter::supports_interface_layouts() const -{ - if(target_api==OPENGL_ES2) - return check_version(Version(3, 0)); - else if(check_version(Version(3, 30))) - return true; - else - return check_extension(ARB_explicit_attrib_location); -} - -bool Compiler::LegacyConverter::supports_centroid_sampling() const -{ - if(target_api==OPENGL_ES2) - return check_version(Version(3, 0)); - else if(check_version(Version(1, 20))) - return true; - else - return check_extension(EXT_gpu_shader4); -} - -bool Compiler::LegacyConverter::supports_sample_sampling() const -{ - if(target_api==OPENGL_ES2) - return check_version(Version(3, 20)); - else if(check_version(Version(4, 0))) - return true; - else - return check_extension(ARB_gpu_shader5); -} - -void Compiler::LegacyConverter::visit(VariableDeclaration &var) -{ - if(var.layout && !supports_interface_layouts()) - { - vector::iterator i; - for(i=var.layout->qualifiers.begin(); (i!=var.layout->qualifiers.end() && i->identifier!="location"); ++i) ; - if(i!=var.layout->qualifiers.end()) - { - unsigned location = lexical_cast(i->value); - if(stage->type==VERTEX && var.interface=="in") - { - stage->locations[var.name] = location; - var.layout->qualifiers.erase(i); - } - else if(stage->type==FRAGMENT && var.interface=="out") - { - if(location!=0) - static Require _req(EXT_gpu_shader4); - stage->locations[var.name] = location; - var.layout->qualifiers.erase(i); - } - - if(var.layout->qualifiers.empty()) - var.layout = 0; - } - } - - if(var.sampling=="centroid") - { - if(!supports_centroid_sampling()) - var.sampling = string(); - } - else if(var.sampling=="sample") - { - if(!supports_sample_sampling()) - var.sampling = string(); - } - - if((var.interface=="in" || var.interface=="out") && !supports_unified_interface_syntax()) - { - if(stage->type==FRAGMENT && var.interface=="out") - { - frag_out = &var; - remove_node = true; - } - } - - TraversingVisitor::visit(var); -} - -bool Compiler::LegacyConverter::supports_interface_blocks(const string &iface) const -{ - if(target_api==OPENGL_ES2) - { - if(iface=="uniform") - return check_version(Version(3, 0)); - else - return check_version(Version(3, 20)); - } - else if(check_version(Version(1, 50))) - return true; - else if(iface=="uniform") - return check_extension(ARB_uniform_buffer_object); - else - return false; -} - -void Compiler::LegacyConverter::visit(InterfaceBlock &iface) -{ - if(!supports_interface_blocks(iface.interface)) - flatten_block(iface.members); -} - } // namespace SL } // namespace GL } // namespace Msp diff --git a/source/glsl/compiler.h b/source/glsl/compiler.h index 853a399a..c8cb565f 100644 --- a/source/glsl/compiler.h +++ b/source/glsl/compiler.h @@ -1,7 +1,7 @@ #ifndef MSP_GL_SL_COMPILER_H_ #define MSP_GL_SL_COMPILER_H_ -#include +#include #include "parser.h" #include "program.h" #include "resources.h" @@ -14,371 +14,6 @@ namespace SL { class Compiler { private: - struct Visitor: TraversingVisitor - { - typedef void ResultType; - - Stage *stage; - - Visitor(); - - virtual void apply(Stage &); - void get_result() const { } - }; - - struct BlockModifier: Visitor - { - bool remove_node; - std::vector > insert_nodes; - - BlockModifier(); - - void flatten_block(Block &); - void apply_and_increment(Block &, NodeList::iterator &); - using Visitor::visit; - virtual void visit(Block &); - }; - - struct Formatter: Visitor - { - typedef std::string ResultType; - - std::string formatted; - unsigned source_index; - unsigned source_line; - unsigned indent; - bool parameter_list; - std::string block_interface; - - Formatter(); - - virtual void apply(Stage &); - const std::string &get_result() const { return formatted; } - using Visitor::visit; - void append(const std::string &); - void append(char); - void set_source(unsigned, unsigned); - virtual void visit(Block &); - virtual void visit(Literal &); - virtual void visit(ParenthesizedExpression &); - virtual void visit(VariableReference &); - virtual void visit(MemberAccess &); - virtual void visit(UnaryExpression &); - virtual void visit(BinaryExpression &); - virtual void visit(Assignment &); - virtual void visit(FunctionCall &); - virtual void visit(ExpressionStatement &); - virtual void visit(Import &); - virtual void visit(Precision &); - virtual void visit(Layout &); - virtual void visit(InterfaceLayout &); - virtual void visit(StructDeclaration &); - virtual void visit(VariableDeclaration &); - virtual void visit(InterfaceBlock &); - virtual void visit(FunctionDeclaration &); - virtual void visit(Conditional &); - virtual void visit(Iteration &); - virtual void visit(Return &); - virtual void visit(Jump &); - }; - - template - struct NodeGatherer: Visitor - { - typedef std::vector ResultType; - - std::vector nodes; - - const ResultType &get_result() const { return nodes; } - using Visitor::visit; - virtual void visit(T &n) { nodes.push_back(&n); } - }; - - struct DeclarationCombiner: BlockModifier - { - bool toplevel; - std::map > functions; - std::map variables; - - DeclarationCombiner(); - - using Visitor::visit; - virtual void visit(Block &); - virtual void visit(FunctionDeclaration &); - virtual void visit(VariableDeclaration &); - }; - - struct VariableResolver: Visitor - { - std::vector blocks; - StructDeclaration *type; - bool anonymous; - std::string block_interface; - bool record_target; - VariableDeclaration *assignment_target; - bool self_referencing; - - VariableResolver(); - - virtual void apply(Stage &); - using Visitor::visit; - virtual void visit(Block &); - virtual void visit(VariableReference &); - virtual void visit(MemberAccess &); - virtual void visit(BinaryExpression &); - virtual void visit(Assignment &); - virtual void visit(StructDeclaration &); - virtual void visit(VariableDeclaration &); - virtual void visit(InterfaceBlock &); - }; - - struct FunctionResolver: Visitor - { - std::map > functions; - - using Visitor::visit; - virtual void visit(FunctionCall &); - virtual void visit(FunctionDeclaration &); - }; - - struct InterfaceGenerator: BlockModifier - { - std::string in_prefix; - std::string out_prefix; - unsigned scope_level; - std::map > iface_declarations; - - InterfaceGenerator(); - - static std::string get_out_prefix(StageType); - virtual void apply(Stage &); - using Visitor::visit; - virtual void visit(Block &); - std::string change_prefix(const std::string &, const std::string &) const; - bool generate_interface(VariableDeclaration &, const std::string &, const std::string &); - ExpressionStatement &insert_assignment(const std::string &, Expression *); - virtual void visit(VariableReference &); - virtual void visit(VariableDeclaration &); - virtual void visit(Passthrough &); - }; - - struct DeclarationReorderer: Visitor - { - enum DeclarationKind - { - NO_DECLARATION, - LAYOUT, - STRUCT, - VARIABLE, - FUNCTION - }; - - unsigned scope_level; - DeclarationKind kind; - std::set ordered_funcs; - std::set needed_funcs; - - DeclarationReorderer(); - - using Visitor::visit; - virtual void visit(Block &); - virtual void visit(FunctionCall &); - virtual void visit(InterfaceLayout &) { kind = LAYOUT; } - virtual void visit(StructDeclaration &) { kind = STRUCT; } - virtual void visit(VariableDeclaration &); - virtual void visit(InterfaceBlock &) { kind = VARIABLE; } - virtual void visit(FunctionDeclaration &); - }; - - struct InlineableFunctionLocator: Visitor - { - typedef std::set ResultType; - - std::map refcounts; - std::set inlineable; - FunctionDeclaration *in_function; - - InlineableFunctionLocator(); - - const ResultType &get_result() const { return inlineable; } - using Visitor::visit; - virtual void visit(FunctionCall &); - virtual void visit(FunctionDeclaration &); - }; - - struct FunctionInliner: Visitor - { - std::set inlineable; - unsigned extract_result; - RefPtr inline_result; - - FunctionInliner(); - FunctionInliner(const std::set &); - - void visit_and_inline(RefPtr &); - using Visitor::visit; - virtual void visit(Block &); - virtual void visit(UnaryExpression &); - virtual void visit(BinaryExpression &); - virtual void visit(MemberAccess &); - virtual void visit(FunctionCall &); - virtual void visit(VariableDeclaration &); - virtual void visit(Return &); - }; - - struct ExpressionEvaluator: NodeVisitor - { - typedef std::map ValueMap; - - const ValueMap *variable_values; - float result; - bool result_valid; - - ExpressionEvaluator(); - ExpressionEvaluator(const ValueMap &); - - using NodeVisitor::visit; - virtual void visit(Literal &); - virtual void visit(ParenthesizedExpression &); - virtual void visit(VariableReference &); - virtual void visit(UnaryExpression &); - virtual void visit(BinaryExpression &); - }; - - struct ConstantConditionEliminator: BlockModifier - { - unsigned scope_level; - bool record_only; - ExpressionEvaluator::ValueMap variable_values; - - ConstantConditionEliminator(); - - using Visitor::visit; - virtual void visit(Block &); - virtual void visit(UnaryExpression &); - virtual void visit(Assignment &); - virtual void visit(VariableDeclaration &); - virtual void visit(Conditional &); - virtual void visit(Iteration &); - }; - - struct UnusedVariableLocator: Visitor - { - struct VariableInfo - { - bool local; - std::vector assignments; - bool conditionally_assigned; - bool referenced; - - VariableInfo(); - }; - - typedef std::set ResultType; - typedef std::map BlockVariableMap; - - std::set unused_nodes; - std::map aggregates; - Node *aggregate; - std::vector variables; - Assignment *assignment; - bool assignment_target; - bool assign_to_subscript; - bool global_scope; - - UnusedVariableLocator(); - - virtual void apply(Stage &); - const ResultType &get_result() const { return unused_nodes; } - using Visitor::visit; - virtual void visit(VariableReference &); - virtual void visit(MemberAccess &); - virtual void visit(BinaryExpression &); - virtual void visit(Assignment &); - void record_assignment(VariableDeclaration &, Node &, bool); - void clear_assignments(VariableInfo &, bool); - virtual void visit(ExpressionStatement &); - virtual void visit(StructDeclaration &); - virtual void visit(VariableDeclaration &); - virtual void visit(InterfaceBlock &); - virtual void visit(FunctionDeclaration &); - void merge_down_variables(); - virtual void visit(Conditional &); - virtual void visit(Iteration &); - }; - - struct UnusedFunctionLocator: Visitor - { - typedef std::set ResultType; - - std::set unused_nodes; - std::set used_definitions; - - const ResultType &get_result() const { return unused_nodes; } - using Visitor::visit; - virtual void visit(FunctionCall &); - virtual void visit(FunctionDeclaration &); - }; - - struct NodeRemover: Visitor - { - std::set to_remove; - - NodeRemover() { } - NodeRemover(const std::set &); - - using Visitor::visit; - virtual void visit(Block &); - virtual void visit(VariableDeclaration &); - virtual void visit(Iteration &); - }; - - struct PrecisionRemover: BlockModifier - { - using Visitor::visit; - virtual void visit(Precision &); - virtual void visit(VariableDeclaration &); - }; - - struct DefaultPrecisionGenerator: BlockModifier - { - bool toplevel; - std::set have_default; - - DefaultPrecisionGenerator(); - - using Visitor::visit; - virtual void visit(Block &); - virtual void visit(Precision &); - virtual void visit(VariableDeclaration &); - }; - - struct LegacyConverter: BlockModifier - { - GLApi target_api; - Version target_version; - std::string type; - VariableDeclaration *frag_out; - - LegacyConverter(); - LegacyConverter(const Version &); - - bool check_version(const Version &) const; - bool check_extension(const Extension &) const; - using Visitor::visit; - bool supports_unified_interface_syntax() const; - virtual void visit(VariableReference &); - virtual void visit(Assignment &); - bool supports_unified_sampling_functions() const; - virtual void visit(FunctionCall &); - bool supports_interface_layouts() const; - bool supports_centroid_sampling() const; - bool supports_sample_sampling() const; - virtual void visit(VariableDeclaration &); - bool supports_interface_blocks(const std::string &) const; - virtual void visit(InterfaceBlock &); - }; - Resources *resources; Module *module; std::vector imported_names; @@ -393,9 +28,6 @@ public: void add_shaders(Program &); private: - static Module *create_builtins_module(); - static Module &get_builtins_module(); - static Stage *get_builtins(StageType); void append_module(Module &); void append_stage(Stage &); void process(); diff --git a/source/glsl/evaluate.cpp b/source/glsl/evaluate.cpp new file mode 100644 index 00000000..96a80fa7 --- /dev/null +++ b/source/glsl/evaluate.cpp @@ -0,0 +1,98 @@ +#include "evaluate.h" + +namespace Msp { +namespace GL { +namespace SL { + +ExpressionEvaluator::ExpressionEvaluator(): + variable_values(0), + result(0.0f), + result_valid(false) +{ } + +ExpressionEvaluator::ExpressionEvaluator(const ValueMap &v): + variable_values(&v), + result(0.0f), + result_valid(false) +{ } + +void ExpressionEvaluator::visit(Literal &literal) +{ + if(literal.token=="true") + result = 1.0f; + else if(literal.token=="false") + result = 0.0f; + else + result = lexical_cast(literal.token); + result_valid = true; +} + +void ExpressionEvaluator::visit(ParenthesizedExpression &parexp) +{ + parexp.expression->visit(*this); +} + +void ExpressionEvaluator::visit(VariableReference &var) +{ + if(!var.declaration) + return; + + if(variable_values) + { + ValueMap::const_iterator i = variable_values->find(var.declaration); + if(i!=variable_values->end()) + i->second->visit(*this); + } + else if(var.declaration->init_expression) + var.declaration->init_expression->visit(*this); +} + +void ExpressionEvaluator::visit(UnaryExpression &unary) +{ + result_valid = false; + unary.expression->visit(*this); + if(!result_valid) + return; + + if(unary.oper=="!") + result = !result; + else + result_valid = false; +} + +void ExpressionEvaluator::visit(BinaryExpression &binary) +{ + result_valid = false; + binary.left->visit(*this); + if(!result_valid) + return; + + float left_result = result; + result_valid = false; + binary.right->visit(*this); + if(!result_valid) + return; + + if(binary.oper=="<") + result = (left_result") + result = (left_result>result); + else if(binary.oper==">=") + result = (left_result>=result); + else if(binary.oper=="==") + result = (left_result==result); + else if(binary.oper=="!=") + result = (left_result!=result); + else if(binary.oper=="&&") + result = (left_result && result); + else if(binary.oper=="||") + result = (left_result || result); + else + result_valid = false; +} + +} // namespace SL +} // namespace GL +} // namespace Msp diff --git a/source/glsl/evaluate.h b/source/glsl/evaluate.h new file mode 100644 index 00000000..6cbc6cb4 --- /dev/null +++ b/source/glsl/evaluate.h @@ -0,0 +1,39 @@ +#ifndef MSP_GL_SL_EVALUATE_H_ +#define MSP_GL_SL_EVALUATE_H_ + +#include "visitor.h" + +namespace Msp { +namespace GL { +namespace SL { + +class ExpressionEvaluator: public NodeVisitor +{ +public: + typedef std::map ValueMap; + +private: + const ValueMap *variable_values; + float result; + bool result_valid; + +public: + ExpressionEvaluator(); + ExpressionEvaluator(const ValueMap &); + + float get_result() const { return result; } + bool is_result_valid() const { return result_valid; } + + using NodeVisitor::visit; + virtual void visit(Literal &); + virtual void visit(ParenthesizedExpression &); + virtual void visit(VariableReference &); + virtual void visit(UnaryExpression &); + virtual void visit(BinaryExpression &); +}; + +} // namespace SL +} // namespace GL +} // namespace Msp + +#endif diff --git a/source/glsl/generate.cpp b/source/glsl/generate.cpp new file mode 100644 index 00000000..55687924 --- /dev/null +++ b/source/glsl/generate.cpp @@ -0,0 +1,564 @@ +#include +#include "builtin.h" +#include "generate.h" + +using namespace std; + +namespace Msp { +namespace GL { +namespace SL { + +DeclarationCombiner::DeclarationCombiner(): + toplevel(true) +{ } + +void DeclarationCombiner::visit(Block &block) +{ + if(!toplevel) + return; + + SetForScope set(toplevel, false); + BlockModifier::visit(block); +} + +void DeclarationCombiner::visit(FunctionDeclaration &func) +{ + vector &decls = functions[func.name]; + if(func.definition) + { + for(vector::iterator i=decls.begin(); i!=decls.end(); ++i) + { + (*i)->definition = func.definition; + (*i)->body.body.clear(); + } + } + decls.push_back(&func); +} + +void DeclarationCombiner::visit(VariableDeclaration &var) +{ + VariableDeclaration *&ptr = variables[var.name]; + if(ptr) + { + ptr->type = var.type; + if(var.init_expression) + ptr->init_expression = var.init_expression; + if(var.layout) + { + if(ptr->layout) + { + for(vector::iterator i=var.layout->qualifiers.begin(); i!=var.layout->qualifiers.end(); ++i) + { + bool found = false; + for(vector::iterator j=ptr->layout->qualifiers.begin(); (!found && j!=ptr->layout->qualifiers.end()); ++j) + if(j->identifier==i->identifier) + { + j->value = i->value; + found = true; + } + + if(!found) + ptr->layout->qualifiers.push_back(*i); + } + } + else + ptr->layout = var.layout; + } + remove_node = true; + } + else + ptr = &var; +} + + +VariableResolver::VariableResolver(): + anonymous(false), + record_target(false), + assignment_target(0), + self_referencing(false) +{ } + +void VariableResolver::apply(Stage &s) +{ + SetForScope set(stage, &s); + Stage *builtins = get_builtins(stage->type); + if(builtins) + blocks.push_back(&builtins->content); + stage->content.visit(*this); + if(builtins) + blocks.pop_back(); +} + +void VariableResolver::visit(Block &block) +{ + blocks.push_back(&block); + block.variables.clear(); + TraversingVisitor::visit(block); + blocks.pop_back(); +} + +void VariableResolver::visit(VariableReference &var) +{ + var.declaration = 0; + type = 0; + for(vector::iterator i=blocks.end(); i!=blocks.begin(); ) + { + --i; + map::iterator j = (*i)->variables.find(var.name); + if(j!=(*i)->variables.end()) + { + var.declaration = j->second; + type = j->second->type_declaration; + break; + } + } + + if(record_target) + { + if(assignment_target) + { + record_target = false; + assignment_target = 0; + } + else + assignment_target = var.declaration; + } + else if(var.declaration && var.declaration==assignment_target) + self_referencing = true; +} + +void VariableResolver::visit(MemberAccess &memacc) +{ + type = 0; + TraversingVisitor::visit(memacc); + memacc.declaration = 0; + if(type) + { + map::iterator i = type->members.variables.find(memacc.member); + if(i!=type->members.variables.end()) + { + memacc.declaration = i->second; + type = i->second->type_declaration; + } + else + type = 0; + } +} + +void VariableResolver::visit(BinaryExpression &binary) +{ + if(binary.oper=="[") + { + { + SetForScope set(record_target, false); + binary.right->visit(*this); + } + type = 0; + binary.left->visit(*this); + } + else + { + TraversingVisitor::visit(binary); + type = 0; + } +} + +void VariableResolver::visit(Assignment &assign) +{ + { + SetFlag set(record_target); + assignment_target = 0; + assign.left->visit(*this); + } + + self_referencing = false; + assign.right->visit(*this); + + assign.self_referencing = (self_referencing || assign.oper!="="); + assign.target_declaration = assignment_target; +} + +void VariableResolver::visit(StructDeclaration &strct) +{ + TraversingVisitor::visit(strct); + blocks.back()->types[strct.name] = &strct; +} + +void VariableResolver::visit(VariableDeclaration &var) +{ + for(vector::iterator i=blocks.end(); i!=blocks.begin(); ) + { + --i; + map::iterator j = (*i)->types.find(var.type); + if(j!=(*i)->types.end()) + var.type_declaration = j->second; + } + + if(!block_interface.empty() && var.interface.empty()) + var.interface = block_interface; + + TraversingVisitor::visit(var); + blocks.back()->variables[var.name] = &var; + if(anonymous && blocks.size()>1) + blocks[blocks.size()-2]->variables[var.name] = &var; +} + +void VariableResolver::visit(InterfaceBlock &iface) +{ + SetFlag set(anonymous); + SetForScope set2(block_interface, iface.interface); + TraversingVisitor::visit(iface); +} + + +void FunctionResolver::visit(FunctionCall &call) +{ + map >::iterator i = functions.find(call.name); + if(i!=functions.end()) + call.declaration = i->second.back(); + + TraversingVisitor::visit(call); +} + +void FunctionResolver::visit(FunctionDeclaration &func) +{ + vector &decls = functions[func.name]; + if(func.definition) + { + for(vector::iterator i=decls.begin(); i!=decls.end(); ++i) + (*i)->definition = func.definition; + decls.clear(); + decls.push_back(&func); + } + else if(!decls.empty() && decls.back()->definition) + func.definition = decls.back()->definition; + else + decls.push_back(&func); + + TraversingVisitor::visit(func); +} + + +InterfaceGenerator::InterfaceGenerator(): + scope_level(0) +{ } + +string InterfaceGenerator::get_out_prefix(StageType type) +{ + if(type==VERTEX) + return "_vs_out_"; + else if(type==GEOMETRY) + return "_gs_out_"; + else + return string(); +} + +void InterfaceGenerator::apply(Stage &s) +{ + SetForScope set(stage, &s); + if(stage->previous) + in_prefix = get_out_prefix(stage->previous->type); + out_prefix = get_out_prefix(stage->type); + stage->content.visit(*this); +} + +void InterfaceGenerator::visit(Block &block) +{ + SetForScope set(scope_level, scope_level+1); + for(NodeList::iterator i=block.body.begin(); i!=block.body.end(); ) + { + (*i)->visit(*this); + + if(scope_level==1) + { + for(map >::iterator j=iface_declarations.begin(); j!=iface_declarations.end(); ++j) + { + NodeList::iterator k = block.body.insert(i, j->second); + (*k)->visit(*this); + } + iface_declarations.clear(); + } + + apply_and_increment(block, i); + } +} + +string InterfaceGenerator::change_prefix(const string &name, const string &prefix) const +{ + unsigned offset = (name.compare(0, in_prefix.size(), in_prefix) ? 0 : in_prefix.size()); + return prefix+name.substr(offset); +} + +bool InterfaceGenerator::generate_interface(VariableDeclaration &var, const string &iface, const string &name) +{ + const map &stage_vars = (iface=="in" ? stage->in_variables : stage->out_variables); + if(stage_vars.count(name) || iface_declarations.count(name)) + return false; + + VariableDeclaration* iface_var = new VariableDeclaration; + iface_var->sampling = var.sampling; + iface_var->interface = iface; + iface_var->type = var.type; + iface_var->type_declaration = var.type_declaration; + iface_var->name = name; + if(stage->type==GEOMETRY) + iface_var->array = ((var.array && var.interface!="in") || iface=="in"); + else + iface_var->array = var.array; + if(iface_var->array) + iface_var->array_size = var.array_size; + if(iface=="in") + iface_var->linked_declaration = &var; + iface_declarations[name] = iface_var; + + return true; +} + +ExpressionStatement &InterfaceGenerator::insert_assignment(const string &left, Expression *right) +{ + Assignment *assign = new Assignment; + VariableReference *ref = new VariableReference; + ref->name = left; + assign->left = ref; + assign->oper = "="; + assign->right = right; + + ExpressionStatement *stmt = new ExpressionStatement; + stmt->expression = assign; + stmt->visit(*this); + insert_nodes.push_back(stmt); + + return *stmt; +} + +void InterfaceGenerator::visit(VariableReference &var) +{ + if(var.declaration || !stage->previous) + return; + if(iface_declarations.count(var.name)) + return; + + const map &prev_out = stage->previous->out_variables; + map::const_iterator i = prev_out.find(var.name); + if(i==prev_out.end()) + i = prev_out.find(in_prefix+var.name); + if(i!=prev_out.end()) + { + generate_interface(*i->second, "in", i->second->name); + var.name = i->second->name; + } +} + +void InterfaceGenerator::visit(VariableDeclaration &var) +{ + if(var.interface=="out") + { + if(scope_level==1) + stage->out_variables[var.name] = &var; + else if(generate_interface(var, "out", change_prefix(var.name, string()))) + { + remove_node = true; + if(var.init_expression) + { + ExpressionStatement &stmt = insert_assignment(var.name, var.init_expression->clone()); + stmt.source = var.source; + stmt.line = var.line; + return; + } + } + } + else if(var.interface=="in") + { + stage->in_variables[var.name] = &var; + if(var.linked_declaration) + var.linked_declaration->linked_declaration = &var; + else if(stage->previous) + { + const map &prev_out = stage->previous->out_variables; + map::const_iterator i = prev_out.find(var.name); + if(i!=prev_out.end()) + { + var.linked_declaration = i->second; + i->second->linked_declaration = &var; + } + } + } + + TraversingVisitor::visit(var); +} + +void InterfaceGenerator::visit(Passthrough &pass) +{ + vector pass_vars; + + for(map::const_iterator i=stage->in_variables.begin(); i!=stage->in_variables.end(); ++i) + pass_vars.push_back(i->second); + for(map >::const_iterator i=iface_declarations.begin(); i!=iface_declarations.end(); ++i) + if(i->second->interface=="in") + pass_vars.push_back(i->second.get()); + + if(stage->previous) + { + const map &prev_out = stage->previous->out_variables; + for(map::const_iterator i=prev_out.begin(); i!=prev_out.end(); ++i) + { + bool linked = false; + for(vector::const_iterator j=pass_vars.begin(); (!linked && j!=pass_vars.end()); ++j) + linked = ((*j)->linked_declaration==i->second); + + if(!linked && generate_interface(*i->second, "in", i->second->name)) + pass_vars.push_back(i->second); + } + } + + if(stage->type==GEOMETRY) + { + VariableReference *ref = new VariableReference; + ref->name = "gl_in"; + + BinaryExpression *subscript = new BinaryExpression; + subscript->left = ref; + subscript->oper = "["; + subscript->right = pass.subscript; + subscript->after = "]"; + + MemberAccess *memacc = new MemberAccess; + memacc->left = subscript; + memacc->member = "gl_Position"; + + insert_assignment("gl_Position", memacc); + } + + for(vector::const_iterator i=pass_vars.begin(); i!=pass_vars.end(); ++i) + { + string out_name = change_prefix((*i)->name, out_prefix); + generate_interface(**i, "out", out_name); + + VariableReference *ref = new VariableReference; + ref->name = (*i)->name; + if(pass.subscript) + { + BinaryExpression *subscript = new BinaryExpression; + subscript->left = ref; + subscript->oper = "["; + subscript->right = pass.subscript; + subscript->after = "]"; + insert_assignment(out_name, subscript); + } + else + insert_assignment(out_name, ref); + } + + remove_node = true; +} + + +DeclarationReorderer::DeclarationReorderer(): + scope_level(0), + kind(NO_DECLARATION) +{ } + +void DeclarationReorderer::visit(FunctionCall &call) +{ + FunctionDeclaration *def = call.declaration; + if(def) + def = def->definition; + if(def && !ordered_funcs.count(def)) + needed_funcs.insert(def); +} + +void DeclarationReorderer::visit(Block &block) +{ + SetForScope set(scope_level, scope_level+1); + if(scope_level>1) + return StageVisitor::visit(block); + + NodeList::iterator struct_insert_point = block.body.end(); + NodeList::iterator variable_insert_point = block.body.end(); + NodeList::iterator function_insert_point = block.body.end(); + unsigned unordered_func_count = 0; + bool ordered_any_funcs = false; + + for(NodeList::iterator i=block.body.begin(); i!=block.body.end(); ) + { + kind = NO_DECLARATION; + (*i)->visit(*this); + + bool moved = false; + if(kind==STRUCT && struct_insert_point!=block.body.end()) + { + block.body.insert(struct_insert_point, *i); + moved = true; + } + else if(kind>STRUCT && struct_insert_point==block.body.end()) + struct_insert_point = i; + + if(kind==VARIABLE && variable_insert_point!=block.body.end()) + { + block.body.insert(variable_insert_point, *i); + moved = true; + } + else if(kind>VARIABLE && variable_insert_point==block.body.end()) + variable_insert_point = i; + + if(kind==FUNCTION) + { + if(function_insert_point==block.body.end()) + function_insert_point = i; + + if(needed_funcs.empty()) + { + ordered_funcs.insert(i->get()); + if(i!=function_insert_point) + { + block.body.insert(function_insert_point, *i); + moved = true; + } + else + ++function_insert_point; + ordered_any_funcs = true; + } + else + ++unordered_func_count; + } + + if(moved) + { + if(function_insert_point==i) + ++function_insert_point; + block.body.erase(i++); + } + else + ++i; + + if(i==block.body.end() && unordered_func_count) + { + if(!ordered_any_funcs) + // A subset of the remaining functions forms a recursive loop + /* TODO pick a function and move it up, adding any necessary + declarations */ + break; + + i = function_insert_point; + unordered_func_count = 0; + } + } +} + +void DeclarationReorderer::visit(VariableDeclaration &var) +{ + StageVisitor::visit(var); + kind = VARIABLE; +} + +void DeclarationReorderer::visit(FunctionDeclaration &func) +{ + needed_funcs.clear(); + func.body.visit(*this); + needed_funcs.erase(&func); + kind = FUNCTION; +} + +} // namespace SL +} // namespace GL +} // namespace Msp diff --git a/source/glsl/generate.h b/source/glsl/generate.h new file mode 100644 index 00000000..aae570c4 --- /dev/null +++ b/source/glsl/generate.h @@ -0,0 +1,124 @@ +#ifndef MSP_GL_SL_GENERATE_H_ +#define MSP_GL_SL_GENERATE_H_ + +#include +#include +#include +#include +#include "visitor.h" + +namespace Msp { +namespace GL { +namespace SL { + +class DeclarationCombiner: public BlockModifier +{ +private: + bool toplevel; + std::map > functions; + std::map variables; + +public: + DeclarationCombiner(); + + using StageVisitor::visit; + virtual void visit(Block &); + virtual void visit(FunctionDeclaration &); + virtual void visit(VariableDeclaration &); +}; + +class VariableResolver: public StageVisitor +{ +private: + std::vector blocks; + StructDeclaration *type; + bool anonymous; + std::string block_interface; + bool record_target; + VariableDeclaration *assignment_target; + bool self_referencing; + +public: + VariableResolver(); + + virtual void apply(Stage &); + using StageVisitor::visit; + virtual void visit(Block &); + virtual void visit(VariableReference &); + virtual void visit(MemberAccess &); + virtual void visit(BinaryExpression &); + virtual void visit(Assignment &); + virtual void visit(StructDeclaration &); + virtual void visit(VariableDeclaration &); + virtual void visit(InterfaceBlock &); +}; + +class FunctionResolver: public StageVisitor +{ +private: + std::map > functions; + +public: + using StageVisitor::visit; + virtual void visit(FunctionCall &); + virtual void visit(FunctionDeclaration &); +}; + +class InterfaceGenerator: public BlockModifier +{ +private: + std::string in_prefix; + std::string out_prefix; + unsigned scope_level; + std::map > iface_declarations; + +public: + InterfaceGenerator(); + + static std::string get_out_prefix(StageType); + virtual void apply(Stage &); + using StageVisitor::visit; + virtual void visit(Block &); + std::string change_prefix(const std::string &, const std::string &) const; + bool generate_interface(VariableDeclaration &, const std::string &, const std::string &); + ExpressionStatement &insert_assignment(const std::string &, Expression *); + virtual void visit(VariableReference &); + virtual void visit(VariableDeclaration &); + virtual void visit(Passthrough &); +}; + +class DeclarationReorderer: public StageVisitor +{ +private: + enum DeclarationKind + { + NO_DECLARATION, + LAYOUT, + STRUCT, + VARIABLE, + FUNCTION + }; + + unsigned scope_level; + DeclarationKind kind; + std::set ordered_funcs; + std::set needed_funcs; + +public: + DeclarationReorderer(); + + using StageVisitor::visit; + virtual void visit(Block &); + virtual void visit(FunctionCall &); + virtual void visit(InterfaceLayout &) { kind = LAYOUT; } + virtual void visit(StructDeclaration &) { kind = STRUCT; } + virtual void visit(VariableDeclaration &); + virtual void visit(InterfaceBlock &) { kind = VARIABLE; } + virtual void visit(FunctionDeclaration &); +}; + +} // namespace SL +} // namespace GL +} // namespace Msp + +#endif diff --git a/source/glsl/optimize.cpp b/source/glsl/optimize.cpp new file mode 100644 index 00000000..25115a59 --- /dev/null +++ b/source/glsl/optimize.cpp @@ -0,0 +1,452 @@ +#include +#include "optimize.h" + +using namespace std; + +namespace Msp { +namespace GL { +namespace SL { + +InlineableFunctionLocator::InlineableFunctionLocator(): + in_function(0) +{ } + +void InlineableFunctionLocator::visit(FunctionCall &call) +{ + FunctionDeclaration *def = call.declaration; + if(def && def->definition!=def) + def = def->definition; + + if(def) + { + unsigned &count = refcounts[def]; + ++count; + if(count>1 || def==in_function) + inlineable.erase(def); + } + + TraversingVisitor::visit(call); +} + +void InlineableFunctionLocator::visit(FunctionDeclaration &func) +{ + unsigned &count = refcounts[func.definition]; + if(!count && func.parameters.empty()) + inlineable.insert(func.definition); + + SetForScope set(in_function, &func); + TraversingVisitor::visit(func); +} + + +FunctionInliner::FunctionInliner(): + extract_result(0) +{ } + +FunctionInliner::FunctionInliner(const set &in): + inlineable(in), + extract_result(0) +{ } + +void FunctionInliner::visit_and_inline(RefPtr &ptr) +{ + inline_result = 0; + ptr->visit(*this); + if(inline_result) + ptr = inline_result; +} + +void FunctionInliner::visit(Block &block) +{ + if(extract_result) + --extract_result; + + for(NodeList::iterator i=block.body.begin(); i!=block.body.end(); ++i) + { + (*i)->visit(*this); + if(extract_result) + --extract_result; + } +} + +void FunctionInliner::visit(UnaryExpression &unary) +{ + visit_and_inline(unary.expression); + inline_result = 0; +} + +void FunctionInliner::visit(BinaryExpression &binary) +{ + visit_and_inline(binary.left); + visit_and_inline(binary.right); + inline_result = 0; +} + +void FunctionInliner::visit(MemberAccess &memacc) +{ + visit_and_inline(memacc.left); + inline_result = 0; +} + +void FunctionInliner::visit(FunctionCall &call) +{ + for(NodeArray::iterator i=call.arguments.begin(); i!=call.arguments.end(); ++i) + visit_and_inline(*i); + + FunctionDeclaration *def = call.declaration; + if(def && def->definition!=def) + def = def->definition; + + if(def && inlineable.count(def)) + { + extract_result = 2; + def->visit(*this); + } + else + inline_result = 0; +} + +void FunctionInliner::visit(VariableDeclaration &var) +{ + if(var.init_expression) + visit_and_inline(var.init_expression); + inline_result = 0; +} + +void FunctionInliner::visit(Return &ret) +{ + TraversingVisitor::visit(ret); + + if(extract_result) + inline_result = ret.expression->clone(); +} + + +ConstantConditionEliminator::ConstantConditionEliminator(): + scope_level(0), + record_only(false) +{ } + +void ConstantConditionEliminator::visit(Block &block) +{ + SetForScope set(scope_level, scope_level+1); + BlockModifier::visit(block); + + for(map::const_iterator i=block.variables.begin(); i!=block.variables.end(); ++i) + variable_values.erase(i->second); +} + +void ConstantConditionEliminator::visit(UnaryExpression &unary) +{ + if(VariableReference *var = dynamic_cast(unary.expression.get())) + if(unary.oper=="++" || unary.oper=="--") + variable_values.erase(var->declaration); +} + +void ConstantConditionEliminator::visit(Assignment &assign) +{ + variable_values.erase(assign.target_declaration); +} + +void ConstantConditionEliminator::visit(VariableDeclaration &var) +{ + if(var.constant || scope_level>1) + variable_values[&var] = var.init_expression.get(); +} + +void ConstantConditionEliminator::visit(Conditional &cond) +{ + if(!record_only) + { + ExpressionEvaluator eval(variable_values); + cond.condition->visit(eval); + if(eval.is_result_valid()) + { + flatten_block(eval.get_result() ? cond.body : cond.else_body); + return; + } + } + + TraversingVisitor::visit(cond); +} + +void ConstantConditionEliminator::visit(Iteration &iter) +{ + if(!record_only) + { + if(iter.condition) + { + /* If the loop condition is always false on the first iteration, the + entire loop can be removed */ + if(iter.init_statement) + iter.init_statement->visit(*this); + ExpressionEvaluator eval(variable_values); + iter.condition->visit(eval); + if(eval.is_result_valid() && !eval.get_result()) + { + remove_node = true; + return; + } + } + + /* Record all assignments that occur inside the loop body so those + variables won't be considered as constant */ + SetFlag set_record(record_only); + TraversingVisitor::visit(iter); + } + + TraversingVisitor::visit(iter); + + if(VariableDeclaration *init_decl = dynamic_cast(iter.init_statement.get())) + variable_values.erase(init_decl); +} + + +UnusedVariableLocator::VariableInfo::VariableInfo(): + local(false), + conditionally_assigned(false), + referenced(false) +{ } + + +UnusedVariableLocator::UnusedVariableLocator(): + aggregate(0), + assignment(0), + assignment_target(false), + assign_to_subscript(false), + global_scope(true) +{ } + +void UnusedVariableLocator::apply(Stage &s) +{ + variables.push_back(BlockVariableMap()); + StageVisitor::apply(s); + BlockVariableMap &global_variables = variables.back(); + for(BlockVariableMap::iterator i=global_variables.begin(); i!=global_variables.end(); ++i) + { + if(i->first->interface=="out" && (s.type==FRAGMENT || i->first->linked_declaration || !i->first->name.compare(0, 3, "gl_"))) + continue; + if(!i->second.referenced) + { + unused_nodes.insert(i->first); + clear_assignments(i->second, true); + } + } + variables.pop_back(); +} + +void UnusedVariableLocator::visit(VariableReference &var) +{ + map::iterator i = aggregates.find(var.declaration); + if(i!=aggregates.end()) + unused_nodes.erase(i->second); + + if(var.declaration && !assignment_target) + { + VariableInfo &var_info = variables.back()[var.declaration]; + var_info.assignments.clear(); + var_info.referenced = true; + } +} + +void UnusedVariableLocator::visit(MemberAccess &memacc) +{ + TraversingVisitor::visit(memacc); + unused_nodes.erase(memacc.declaration); +} + +void UnusedVariableLocator::visit(BinaryExpression &binary) +{ + if(binary.oper=="[") + { + if(assignment_target) + assign_to_subscript = true; + binary.left->visit(*this); + SetForScope set(assignment_target, false); + binary.right->visit(*this); + } + else + TraversingVisitor::visit(binary); +} + +void UnusedVariableLocator::visit(Assignment &assign) +{ + { + assign_to_subscript = false; + SetForScope set(assignment_target, !assign.self_referencing); + assign.left->visit(*this); + } + assign.right->visit(*this); + assignment = &assign; +} + +void UnusedVariableLocator::record_assignment(VariableDeclaration &var, Node &node, bool chained) +{ + VariableInfo &var_info = variables.back()[&var]; + if(!chained) + clear_assignments(var_info, true); + var_info.assignments.push_back(&node); + var_info.conditionally_assigned = false; +} + +void UnusedVariableLocator::clear_assignments(VariableInfo &var_info, bool mark_unused) +{ + if(mark_unused) + { + for(vector::iterator i=var_info.assignments.begin(); i!=var_info.assignments.end(); ++i) + unused_nodes.insert(*i); + } + var_info.assignments.clear(); +} + +void UnusedVariableLocator::visit(ExpressionStatement &expr) +{ + assignment = 0; + TraversingVisitor::visit(expr); + if(assignment && assignment->target_declaration) + record_assignment(*assignment->target_declaration, expr, (assignment->self_referencing || assign_to_subscript)); +} + +void UnusedVariableLocator::visit(StructDeclaration &strct) +{ + SetForScope set(aggregate, &strct); + unused_nodes.insert(&strct); + TraversingVisitor::visit(strct); +} + +void UnusedVariableLocator::visit(VariableDeclaration &var) +{ + if(aggregate) + aggregates[&var] = aggregate; + else + { + variables.back()[&var].local = true; + if(var.init_expression) + record_assignment(var, *var.init_expression, false); + } + unused_nodes.erase(var.type_declaration); + TraversingVisitor::visit(var); +} + +void UnusedVariableLocator::visit(InterfaceBlock &iface) +{ + SetForScope set(aggregate, &iface); + unused_nodes.insert(&iface); + TraversingVisitor::visit(iface); +} + +void UnusedVariableLocator::visit(FunctionDeclaration &func) +{ + variables.push_back(BlockVariableMap()); + + { + SetForScope set(global_scope, false); + for(NodeArray::iterator i=func.parameters.begin(); i!=func.parameters.end(); ++i) + (*i)->visit(*this); + func.body.visit(*this); + } + + BlockVariableMap &block_variables = variables.back(); + for(BlockVariableMap::iterator i=block_variables.begin(); i!=block_variables.end(); ++i) + i->second.conditionally_assigned = true; + for(NodeArray::iterator i=func.parameters.begin(); i!=func.parameters.end(); ++i) + block_variables[i->get()].referenced = true; + merge_down_variables(); +} + +void UnusedVariableLocator::merge_down_variables() +{ + BlockVariableMap &parent_variables = variables[variables.size()-2]; + BlockVariableMap &block_variables = variables.back(); + for(BlockVariableMap::iterator i=block_variables.begin(); i!=block_variables.end(); ++i) + { + if(i->second.local) + { + if(!i->second.referenced) + unused_nodes.insert(i->first); + clear_assignments(i->second, i->first->interface!="out"); + continue; + } + + BlockVariableMap::iterator j = parent_variables.find(i->first); + if(j==parent_variables.end()) + parent_variables.insert(*i); + else + { + if(i->second.referenced || !i->second.conditionally_assigned) + clear_assignments(j->second, !i->second.referenced); + j->second.conditionally_assigned = i->second.conditionally_assigned; + j->second.referenced |= i->second.referenced; + j->second.assignments.insert(j->second.assignments.end(), i->second.assignments.begin(), i->second.assignments.end()); + } + } + variables.pop_back(); +} + +void UnusedVariableLocator::visit(Conditional &cond) +{ + cond.condition->visit(*this); + variables.push_back(BlockVariableMap()); + cond.body.visit(*this); + + BlockVariableMap if_variables; + swap(variables.back(), if_variables); + cond.else_body.visit(*this); + + BlockVariableMap &else_variables = variables.back(); + for(BlockVariableMap::iterator i=else_variables.begin(); i!=else_variables.end(); ++i) + { + BlockVariableMap::iterator j = if_variables.find(i->first); + if(j!=if_variables.end()) + { + i->second.assignments.insert(i->second.assignments.end(), j->second.assignments.begin(), j->second.assignments.end()); + i->second.conditionally_assigned |= j->second.conditionally_assigned; + if_variables.erase(j); + } + else + i->second.conditionally_assigned = true; + } + + for(BlockVariableMap::iterator i=if_variables.begin(); i!=if_variables.end(); ++i) + { + i->second.conditionally_assigned = true; + else_variables.insert(*i); + } + + merge_down_variables(); +} + +void UnusedVariableLocator::visit(Iteration &iter) +{ + variables.push_back(BlockVariableMap()); + TraversingVisitor::visit(iter); + + BlockVariableMap &block_variables = variables.back(); + for(BlockVariableMap::iterator i=block_variables.begin(); i!=block_variables.end(); ++i) + if(!i->second.local && i->second.referenced) + i->second.assignments.clear(); + + merge_down_variables(); +} + + +void UnusedFunctionLocator::visit(FunctionCall &call) +{ + TraversingVisitor::visit(call); + + unused_nodes.erase(call.declaration); + if(call.declaration && call.declaration->definition!=call.declaration) + used_definitions.insert(call.declaration->definition); +} + +void UnusedFunctionLocator::visit(FunctionDeclaration &func) +{ + TraversingVisitor::visit(func); + + if((func.name!="main" || func.body.body.empty()) && !used_definitions.count(&func)) + unused_nodes.insert(&func); +} + +} // namespace SL +} // namespace GL +} // namespace Msp diff --git a/source/glsl/optimize.h b/source/glsl/optimize.h new file mode 100644 index 00000000..698aa0b2 --- /dev/null +++ b/source/glsl/optimize.h @@ -0,0 +1,145 @@ +#ifndef MSP_GL_SL_OPTIMIZE_H_ +#define MSP_GL_SL_OPTIMIZE_H_ + +#include +#include +#include "evaluate.h" +#include "visitor.h" + +namespace Msp { +namespace GL { +namespace SL { + +class InlineableFunctionLocator: public StageVisitor +{ +public: + typedef std::set ResultType; + +private: + std::map refcounts; + std::set inlineable; + FunctionDeclaration *in_function; + +public: + InlineableFunctionLocator(); + + const ResultType &get_result() const { return inlineable; } + using StageVisitor::visit; + virtual void visit(FunctionCall &); + virtual void visit(FunctionDeclaration &); +}; + +class FunctionInliner: public StageVisitor +{ +private: + std::set inlineable; + unsigned extract_result; + RefPtr inline_result; + +public: + FunctionInliner(); + FunctionInliner(const std::set &); + +private: + void visit_and_inline(RefPtr &); +public: + using StageVisitor::visit; + virtual void visit(Block &); + virtual void visit(UnaryExpression &); + virtual void visit(BinaryExpression &); + virtual void visit(MemberAccess &); + virtual void visit(FunctionCall &); + virtual void visit(VariableDeclaration &); + virtual void visit(Return &); +}; + +class ConstantConditionEliminator: public BlockModifier +{ +private: + unsigned scope_level; + bool record_only; + ExpressionEvaluator::ValueMap variable_values; + +public: + ConstantConditionEliminator(); + + using StageVisitor::visit; + virtual void visit(Block &); + virtual void visit(UnaryExpression &); + virtual void visit(Assignment &); + virtual void visit(VariableDeclaration &); + virtual void visit(Conditional &); + virtual void visit(Iteration &); +}; + +class UnusedVariableLocator: public StageVisitor +{ +public: + typedef std::set ResultType; + +private: + struct VariableInfo + { + bool local; + std::vector assignments; + bool conditionally_assigned; + bool referenced; + + VariableInfo(); + }; + + typedef std::map BlockVariableMap; + + std::set unused_nodes; + std::map aggregates; + Node *aggregate; + std::vector variables; + Assignment *assignment; + bool assignment_target; + bool assign_to_subscript; + bool global_scope; + +public: + UnusedVariableLocator(); + + virtual void apply(Stage &); + const ResultType &get_result() const { return unused_nodes; } +private: + using StageVisitor::visit; + virtual void visit(VariableReference &); + virtual void visit(MemberAccess &); + virtual void visit(BinaryExpression &); + virtual void visit(Assignment &); + void record_assignment(VariableDeclaration &, Node &, bool); + void clear_assignments(VariableInfo &, bool); + virtual void visit(ExpressionStatement &); + virtual void visit(StructDeclaration &); + virtual void visit(VariableDeclaration &); + virtual void visit(InterfaceBlock &); + virtual void visit(FunctionDeclaration &); + void merge_down_variables(); + virtual void visit(Conditional &); + virtual void visit(Iteration &); +}; + +class UnusedFunctionLocator: public StageVisitor +{ +public: + typedef std::set ResultType; + +private: + std::set unused_nodes; + std::set used_definitions; + +public: + const ResultType &get_result() const { return unused_nodes; } + using StageVisitor::visit; + virtual void visit(FunctionCall &); + virtual void visit(FunctionDeclaration &); +}; + +} // namespace SL +} // namespace GL +} // namespace Msp + +#endif diff --git a/source/glsl/output.cpp b/source/glsl/output.cpp new file mode 100644 index 00000000..aaba1dc4 --- /dev/null +++ b/source/glsl/output.cpp @@ -0,0 +1,350 @@ +#include +#include +#include "output.h" + +using namespace std; + +namespace Msp { +namespace GL { +namespace SL { + +Formatter::Formatter(): + source_index(0), + source_line(1), + indent(0), + parameter_list(false) +{ } + +void Formatter::apply(Stage &s) +{ + GLApi api = get_gl_api(); + const Version &ver = s.required_version; + + if(ver) + { + append(format("#version %d%02d", ver.major, ver.minor)); + if(api==OPENGL_ES2 && ver>=Version(3, 0)) + append(" es"); + formatted += '\n'; + } + + for(vector::const_iterator i=s.required_extensions.begin(); i!=s.required_extensions.end(); ++i) + append(format("#extension %s: require\n", (*i)->get_name())); + if(!s.required_extensions.empty()) + formatted += '\n'; + + StageVisitor::apply(s); +} + +void Formatter::append(const string &text) +{ + formatted += text; + for(string::const_iterator i=text.begin(); i!=text.end(); ++i) + if(*i=='\n') + ++source_line; +} + +void Formatter::append(char c) +{ + formatted += c; + if(c=='\n') + ++source_line; +} + +void Formatter::set_source(unsigned index, unsigned line) +{ + if(index!=source_index || (index && line!=source_line)) + { + if(index==source_index && line==source_line+1) + formatted += '\n'; + else + { + unsigned l = line; + if(stage->required_versionvisit(*this); + append(')'); +} + +void Formatter::visit(VariableReference &var) +{ + append(var.name); +} + +void Formatter::visit(MemberAccess &memacc) +{ + memacc.left->visit(*this); + append(format(".%s", memacc.member)); +} + +void Formatter::visit(UnaryExpression &unary) +{ + if(unary.prefix) + append(unary.oper); + unary.expression->visit(*this); + if(!unary.prefix) + append(unary.oper); +} + +void Formatter::visit(BinaryExpression &binary) +{ + binary.left->visit(*this); + append(binary.oper); + binary.right->visit(*this); + append(binary.after); +} + +void Formatter::visit(Assignment &assign) +{ + assign.left->visit(*this); + append(format(" %s ", assign.oper)); + assign.right->visit(*this); +} + +void Formatter::visit(FunctionCall &call) +{ + append(format("%s(", call.name)); + for(NodeArray::iterator i=call.arguments.begin(); i!=call.arguments.end(); ++i) + { + if(i!=call.arguments.begin()) + append(", "); + (*i)->visit(*this); + } + append(')'); +} + +void Formatter::visit(ExpressionStatement &expr) +{ + expr.expression->visit(*this); + append(';'); +} + +void Formatter::visit(Block &block) +{ + unsigned brace_indent = indent; + bool use_braces = (block.use_braces || (indent && block.body.size()!=1)); + if(use_braces) + append(format("%s{\n", string(brace_indent*2, ' '))); + + SetForScope set(indent, indent+(indent>0 || use_braces)); + string spaces(indent*2, ' '); + for(NodeList::iterator i=block.body.begin(); i!=block.body.end(); ++i) + { + if(i!=block.body.begin()) + append('\n'); + set_source((*i)->source, (*i)->line); + append(spaces); + (*i)->visit(*this); + } + + if(use_braces) + append(format("\n%s}", string(brace_indent*2, ' '))); +} + +void Formatter::visit(Import &import) +{ + append(format("import %s;", import.module)); +} + +void Formatter::visit(Precision &prec) +{ + append(format("precision %s %s;", prec.precision, prec.type)); +} + +void Formatter::visit(Layout &layout) +{ + append("layout("); + for(vector::const_iterator i=layout.qualifiers.begin(); i!=layout.qualifiers.end(); ++i) + { + if(i!=layout.qualifiers.begin()) + append(", "); + append(i->identifier); + if(!i->value.empty()) + append(format("=%s", i->value)); + } + append(')'); +} + +void Formatter::visit(InterfaceLayout &layout) +{ + layout.layout.visit(*this); + append(format(" %s;", layout.interface)); +} + +void Formatter::visit(StructDeclaration &strct) +{ + append(format("struct %s\n", strct.name)); + strct.members.visit(*this); + append(';'); +} + +void Formatter::visit(VariableDeclaration &var) +{ + if(var.layout) + { + var.layout->visit(*this); + append(' '); + } + if(var.constant) + append("const "); + if(!var.interpolation.empty()) + append(format("%s ", var.interpolation)); + if(!var.sampling.empty()) + append(format("%s ", var.sampling)); + if(!var.interface.empty() && var.interface!=block_interface) + { + string interface = var.interface; + if(stage->required_versiontype==VERTEX && var.interface=="in") + interface = "attribute"; + else if((stage->type==VERTEX && var.interface=="out") || (stage->type==FRAGMENT && var.interface=="in")) + interface = "varying"; + } + append(format("%s ", interface)); + } + if(!var.precision.empty()) + append(format("%s ", var.precision)); + append(format("%s %s", var.type, var.name)); + if(var.array) + { + append('['); + if(var.array_size) + var.array_size->visit(*this); + append(']'); + } + if(var.init_expression) + { + append(" = "); + var.init_expression->visit(*this); + } + if(!parameter_list) + append(';'); +} + +void Formatter::visit(InterfaceBlock &iface) +{ + SetForScope set(block_interface, iface.interface); + append(format("%s %s\n", iface.interface, iface.name)); + iface.members.visit(*this); + append(';'); +} + +void Formatter::visit(FunctionDeclaration &func) +{ + append(format("%s %s(", func.return_type, func.name)); + for(NodeArray::iterator i=func.parameters.begin(); i!=func.parameters.end(); ++i) + { + if(i!=func.parameters.begin()) + append(", "); + SetFlag set(parameter_list); + (*i)->visit(*this); + } + append(')'); + if(func.definition==&func) + { + append('\n'); + func.body.visit(*this); + } + else + append(';'); +} + +void Formatter::visit(Conditional &cond) +{ + append("if("); + cond.condition->visit(*this); + append(")\n"); + + cond.body.visit(*this); + if(!cond.else_body.body.empty()) + { + Conditional *else_cond = dynamic_cast(cond.else_body.body.front().get()); + if(cond.else_body.body.size()==1 && else_cond) + { + append('\n'); + set_source(else_cond->source, else_cond->line); + append(format("%selse ", string(indent*2, ' '))); + else_cond->visit(*this); + } + else + { + append(format("\n%selse\n", string(indent*2, ' '))); + cond.else_body.visit(*this); + } + } +} + +void Formatter::visit(Iteration &iter) +{ + if(!iter.init_statement && iter.condition && !iter.loop_expression) + { + append("while("); + iter.condition->visit(*this); + append(')'); + } + else + { + append("for("); + if(iter.init_statement) + iter.init_statement->visit(*this); + else + append(';'); + if(iter.condition) + { + append(' '); + iter.condition->visit(*this); + } + append(';'); + if(iter.loop_expression) + { + append(' '); + iter.loop_expression->visit(*this); + } + append(')'); + } + + if(iter.body.body.empty()) + append(" { }"); + else + { + append('\n'); + iter.body.visit(*this); + } +} + +void Formatter::visit(Return &ret) +{ + append("return"); + if(ret.expression) + { + append(' '); + ret.expression->visit(*this); + } + append(';'); +} + +void Formatter::visit(Jump &jump) +{ + append(jump.keyword); + append(';'); +} + +} // namespace SL +} // namespace GL +} // namespace Msp diff --git a/source/glsl/output.h b/source/glsl/output.h new file mode 100644 index 00000000..b58c3f96 --- /dev/null +++ b/source/glsl/output.h @@ -0,0 +1,63 @@ +#ifndef MSP_GL_SL_OUTPUT_H_ +#define MSP_GL_SL_OUTPUT_H_ + +#include "syntax.h" +#include "visitor.h" + +namespace Msp { +namespace GL { +namespace SL { + +class Formatter: public StageVisitor +{ +public: + typedef std::string ResultType; + +private: + std::string formatted; + unsigned source_index; + unsigned source_line; + unsigned indent; + bool parameter_list; + std::string block_interface; + +public: + Formatter(); + + virtual void apply(Stage &); + const std::string &get_result() const { return formatted; } +private: + void append(const std::string &); + void append(char); + void set_source(unsigned, unsigned); +public: + using StageVisitor::visit; + virtual void visit(Block &); + virtual void visit(Literal &); + virtual void visit(ParenthesizedExpression &); + virtual void visit(VariableReference &); + virtual void visit(MemberAccess &); + virtual void visit(UnaryExpression &); + virtual void visit(BinaryExpression &); + virtual void visit(Assignment &); + virtual void visit(FunctionCall &); + virtual void visit(ExpressionStatement &); + virtual void visit(Import &); + virtual void visit(Precision &); + virtual void visit(Layout &); + virtual void visit(InterfaceLayout &); + virtual void visit(StructDeclaration &); + virtual void visit(VariableDeclaration &); + virtual void visit(InterfaceBlock &); + virtual void visit(FunctionDeclaration &); + virtual void visit(Conditional &); + virtual void visit(Iteration &); + virtual void visit(Return &); + virtual void visit(Jump &); +}; + +} // namespace SL +} // namespace GL +} // namespace Msp + +#endif diff --git a/source/glsl/syntax.cpp b/source/glsl/syntax.cpp index e7a5c155..e508ed89 100644 --- a/source/glsl/syntax.cpp +++ b/source/glsl/syntax.cpp @@ -1,4 +1,5 @@ #include "syntax.h" +#include "visitor.h" using namespace std; @@ -261,113 +262,6 @@ void Jump::visit(NodeVisitor &visitor) } -void NodeVisitor::visit(Assignment &assign) -{ - visit(static_cast(assign)); -} - - -void TraversingVisitor::visit(Block &block) -{ - for(NodeList::iterator i=block.body.begin(); i!=block.body.end(); ++i) - (*i)->visit(*this); -} - -void TraversingVisitor::visit(ParenthesizedExpression &parexpr) -{ - parexpr.expression->visit(*this); -} - -void TraversingVisitor::visit(MemberAccess &memacc) -{ - memacc.left->visit(*this); -} - -void TraversingVisitor::visit(UnaryExpression &unary) -{ - unary.expression->visit(*this); -} - -void TraversingVisitor::visit(BinaryExpression &binary) -{ - binary.left->visit(*this); - binary.right->visit(*this); -} - -void TraversingVisitor::visit(FunctionCall &call) -{ - for(NodeArray::iterator i=call.arguments.begin(); i!=call.arguments.end(); ++i) - (*i)->visit(*this); -} - -void TraversingVisitor::visit(ExpressionStatement &expr) -{ - expr.expression->visit(*this); -} - -void TraversingVisitor::visit(InterfaceLayout &layout) -{ - layout.layout.visit(*this); -} - -void TraversingVisitor::visit(StructDeclaration &strct) -{ - strct.members.visit(*this); -} - -void TraversingVisitor::visit(VariableDeclaration &var) -{ - if(var.layout) - var.layout->visit(*this); - if(var.init_expression) - var.init_expression->visit(*this); - if(var.array_size) - var.array_size->visit(*this); -} - -void TraversingVisitor::visit(InterfaceBlock &iface) -{ - iface.members.visit(*this); -} - -void TraversingVisitor::visit(FunctionDeclaration &func) -{ - for(NodeArray::iterator i=func.parameters.begin(); i!=func.parameters.end(); ++i) - (*i)->visit(*this); - func.body.visit(*this); -} - -void TraversingVisitor::visit(Conditional &cond) -{ - cond.condition->visit(*this); - cond.body.visit(*this); - cond.else_body.visit(*this); -} - -void TraversingVisitor::visit(Iteration &iter) -{ - if(iter.init_statement) - iter.init_statement->visit(*this); - if(iter.condition) - iter.condition->visit(*this); - if(iter.loop_expression) - iter.loop_expression->visit(*this); - iter.body.visit(*this); -} - -void TraversingVisitor::visit(Passthrough &pass) -{ - if(pass.subscript) - pass.subscript->visit(*this); -} - -void TraversingVisitor::visit(Return &ret) -{ - if(ret.expression) - ret.expression->visit(*this); -} - - Stage::Stage(StageType t): type(t), previous(0) diff --git a/source/glsl/syntax.h b/source/glsl/syntax.h index deb2c780..549e5e89 100644 --- a/source/glsl/syntax.h +++ b/source/glsl/syntax.h @@ -360,56 +360,6 @@ struct Jump: Statement virtual void visit(NodeVisitor &); }; -struct NodeVisitor -{ - virtual ~NodeVisitor() { } - - virtual void visit(Block &) { } - virtual void visit(Literal &) { } - virtual void visit(ParenthesizedExpression &) { } - virtual void visit(VariableReference &) { } - virtual void visit(MemberAccess &) { } - virtual void visit(UnaryExpression &) { } - virtual void visit(BinaryExpression &) { } - virtual void visit(Assignment &); - virtual void visit(FunctionCall &) { } - virtual void visit(ExpressionStatement &) { } - virtual void visit(Import &) { } - virtual void visit(Precision &) { } - virtual void visit(Layout &) { } - virtual void visit(InterfaceLayout &) { } - virtual void visit(StructDeclaration &) { } - virtual void visit(VariableDeclaration &) { } - virtual void visit(InterfaceBlock &) { } - virtual void visit(FunctionDeclaration &) { } - virtual void visit(Conditional &) { } - virtual void visit(Iteration &) { } - virtual void visit(Passthrough &) { } - virtual void visit(Return &) { } - virtual void visit(Jump &) { } -}; - -struct TraversingVisitor: NodeVisitor -{ - using NodeVisitor::visit; - virtual void visit(Block &); - virtual void visit(ParenthesizedExpression &); - virtual void visit(MemberAccess &); - virtual void visit(UnaryExpression &); - virtual void visit(BinaryExpression &); - virtual void visit(FunctionCall &); - virtual void visit(ExpressionStatement &); - virtual void visit(InterfaceLayout &); - virtual void visit(StructDeclaration &); - virtual void visit(VariableDeclaration &); - virtual void visit(InterfaceBlock &); - virtual void visit(FunctionDeclaration &); - virtual void visit(Conditional &); - virtual void visit(Iteration &); - virtual void visit(Passthrough &); - virtual void visit(Return &); -}; - enum StageType { SHARED, diff --git a/source/glsl/visitor.cpp b/source/glsl/visitor.cpp new file mode 100644 index 00000000..58d323ab --- /dev/null +++ b/source/glsl/visitor.cpp @@ -0,0 +1,199 @@ +#include +#include "visitor.h" + +using namespace std; + +namespace Msp { +namespace GL { +namespace SL { + +void NodeVisitor::visit(Assignment &assign) +{ + visit(static_cast(assign)); +} + + +void TraversingVisitor::visit(Block &block) +{ + for(NodeList::iterator i=block.body.begin(); i!=block.body.end(); ++i) + (*i)->visit(*this); +} + +void TraversingVisitor::visit(ParenthesizedExpression &parexpr) +{ + parexpr.expression->visit(*this); +} + +void TraversingVisitor::visit(MemberAccess &memacc) +{ + memacc.left->visit(*this); +} + +void TraversingVisitor::visit(UnaryExpression &unary) +{ + unary.expression->visit(*this); +} + +void TraversingVisitor::visit(BinaryExpression &binary) +{ + binary.left->visit(*this); + binary.right->visit(*this); +} + +void TraversingVisitor::visit(FunctionCall &call) +{ + for(NodeArray::iterator i=call.arguments.begin(); i!=call.arguments.end(); ++i) + (*i)->visit(*this); +} + +void TraversingVisitor::visit(ExpressionStatement &expr) +{ + expr.expression->visit(*this); +} + +void TraversingVisitor::visit(InterfaceLayout &layout) +{ + layout.layout.visit(*this); +} + +void TraversingVisitor::visit(StructDeclaration &strct) +{ + strct.members.visit(*this); +} + +void TraversingVisitor::visit(VariableDeclaration &var) +{ + if(var.layout) + var.layout->visit(*this); + if(var.init_expression) + var.init_expression->visit(*this); + if(var.array_size) + var.array_size->visit(*this); +} + +void TraversingVisitor::visit(InterfaceBlock &iface) +{ + iface.members.visit(*this); +} + +void TraversingVisitor::visit(FunctionDeclaration &func) +{ + for(NodeArray::iterator i=func.parameters.begin(); i!=func.parameters.end(); ++i) + (*i)->visit(*this); + func.body.visit(*this); +} + +void TraversingVisitor::visit(Conditional &cond) +{ + cond.condition->visit(*this); + cond.body.visit(*this); + cond.else_body.visit(*this); +} + +void TraversingVisitor::visit(Iteration &iter) +{ + if(iter.init_statement) + iter.init_statement->visit(*this); + if(iter.condition) + iter.condition->visit(*this); + if(iter.loop_expression) + iter.loop_expression->visit(*this); + iter.body.visit(*this); +} + +void TraversingVisitor::visit(Passthrough &pass) +{ + if(pass.subscript) + pass.subscript->visit(*this); +} + +void TraversingVisitor::visit(Return &ret) +{ + if(ret.expression) + ret.expression->visit(*this); +} + + +StageVisitor::StageVisitor(): + stage(0) +{ } + +void StageVisitor::apply(Stage &s) +{ + SetForScope set(stage, &s); + stage->content.visit(*this); +} + + +BlockModifier::BlockModifier(): + remove_node(false) +{ } + +void BlockModifier::flatten_block(Block &block) +{ + insert_nodes.insert(insert_nodes.end(), block.body.begin(), block.body.end()); + remove_node = true; +} + +void BlockModifier::apply_and_increment(Block &block, NodeList::iterator &i) +{ + block.body.insert(i, insert_nodes.begin(), insert_nodes.end()); + insert_nodes.clear(); + + if(remove_node) + block.body.erase(i++); + else + ++i; + remove_node = false; +} + +void BlockModifier::visit(Block &block) +{ + for(NodeList::iterator i=block.body.begin(); i!=block.body.end(); ) + { + (*i)->visit(*this); + apply_and_increment(block, i); + } +} + + +NodeRemover::NodeRemover(const set &r): + to_remove(r) +{ } + +void NodeRemover::visit(Block &block) +{ + for(NodeList::iterator i=block.body.begin(); i!=block.body.end(); ) + { + (*i)->visit(*this); + if(to_remove.count(i->get())) + block.body.erase(i++); + else + ++i; + } +} + +void NodeRemover::visit(VariableDeclaration &var) +{ + if(to_remove.count(&var)) + { + stage->in_variables.erase(var.name); + stage->out_variables.erase(var.name); + stage->locations.erase(var.name); + if(var.linked_declaration) + var.linked_declaration->linked_declaration = 0; + } + else if(var.init_expression && to_remove.count(var.init_expression.get())) + var.init_expression = 0; +} + +void NodeRemover::visit(Iteration &iter) +{ + if(to_remove.count(iter.init_statement.get())) + iter.init_statement = 0; + TraversingVisitor::visit(iter); +} + +} // namespace SL +} // namespace GL +} // namespace Msp diff --git a/source/glsl/visitor.h b/source/glsl/visitor.h new file mode 100644 index 00000000..582628bb --- /dev/null +++ b/source/glsl/visitor.h @@ -0,0 +1,134 @@ +#ifndef MSP_GL_SL_VISITOR_H_ +#define MSP_GL_SL_VISITOR_H_ + +#include +#include +#include "syntax.h" + +namespace Msp { +namespace GL { +namespace SL { + +class NodeVisitor +{ +protected: + NodeVisitor() { } +public: + virtual ~NodeVisitor() { } + + virtual void visit(Block &) { } + virtual void visit(Literal &) { } + virtual void visit(ParenthesizedExpression &) { } + virtual void visit(VariableReference &) { } + virtual void visit(MemberAccess &) { } + virtual void visit(UnaryExpression &) { } + virtual void visit(BinaryExpression &) { } + virtual void visit(Assignment &); + virtual void visit(FunctionCall &) { } + virtual void visit(ExpressionStatement &) { } + virtual void visit(Import &) { } + virtual void visit(Precision &) { } + virtual void visit(Layout &) { } + virtual void visit(InterfaceLayout &) { } + virtual void visit(StructDeclaration &) { } + virtual void visit(VariableDeclaration &) { } + virtual void visit(InterfaceBlock &) { } + virtual void visit(FunctionDeclaration &) { } + virtual void visit(Conditional &) { } + virtual void visit(Iteration &) { } + virtual void visit(Passthrough &) { } + virtual void visit(Return &) { } + virtual void visit(Jump &) { } +}; + +class TraversingVisitor: public NodeVisitor +{ +protected: + TraversingVisitor() { } + +public: + using NodeVisitor::visit; + virtual void visit(Block &); + virtual void visit(ParenthesizedExpression &); + virtual void visit(MemberAccess &); + virtual void visit(UnaryExpression &); + virtual void visit(BinaryExpression &); + virtual void visit(FunctionCall &); + virtual void visit(ExpressionStatement &); + virtual void visit(InterfaceLayout &); + virtual void visit(StructDeclaration &); + virtual void visit(VariableDeclaration &); + virtual void visit(InterfaceBlock &); + virtual void visit(FunctionDeclaration &); + virtual void visit(Conditional &); + virtual void visit(Iteration &); + virtual void visit(Passthrough &); + virtual void visit(Return &); +}; + +class StageVisitor: public TraversingVisitor +{ +public: + typedef void ResultType; + +protected: + Stage *stage; + + StageVisitor(); + +public: + virtual void apply(Stage &); + void get_result() const { } +}; + +class BlockModifier: public StageVisitor +{ +protected: + bool remove_node; + std::vector > insert_nodes; + + BlockModifier(); + + void flatten_block(Block &); + void apply_and_increment(Block &, NodeList::iterator &); + +public: + using StageVisitor::visit; + virtual void visit(Block &); +}; + +template +class NodeGatherer: public StageVisitor +{ +public: + typedef std::vector ResultType; + +private: + std::vector nodes; + +public: + const ResultType &get_result() const { return nodes; } + using StageVisitor::visit; + virtual void visit(T &n) { nodes.push_back(&n); } +}; + +class NodeRemover: public StageVisitor +{ +private: + std::set to_remove; + +public: + NodeRemover() { } + NodeRemover(const std::set &); + + using StageVisitor::visit; + virtual void visit(Block &); + virtual void visit(VariableDeclaration &); + virtual void visit(Iteration &); +}; + +} // namespace SL +} // namespace GL +} // namespace Msp + +#endif -- 2.45.2