From 961715848c111907b5f443c5b545a429b40583e6 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Fri, 11 Nov 2016 11:05:15 +0200 Subject: [PATCH] Streamline interface declarations Out variables can now be declared inside functions and will be exported to global scope. In variables don't need to be declared at all; they are pulled in from the previous stage. There's a new passthrough statement to copy all inputs to outputs. --- source/programcompiler.cpp | 204 ++++++++++++++++++++++++++++++++++++- source/programcompiler.h | 30 ++++++ source/programparser.cpp | 20 +++- source/programparser.h | 2 + source/programsyntax.cpp | 18 +++- source/programsyntax.h | 14 +++ 6 files changed, 283 insertions(+), 5 deletions(-) diff --git a/source/programcompiler.cpp b/source/programcompiler.cpp index 92dec9c7..6bf5ba66 100644 --- a/source/programcompiler.cpp +++ b/source/programcompiler.cpp @@ -62,8 +62,15 @@ void ProgramCompiler::process(Context &context) { inject_block(context.content, module->global_context.content); - VariableResolver resolver; - context.content.visit(resolver); + resolve_variables(context); + + InterfaceGenerator generator; + generator.visit(context); + + resolve_variables(context); + + VariableRenamer renamer; + context.content.visit(renamer); while(1) { @@ -86,6 +93,12 @@ void ProgramCompiler::inject_block(Block &target, const Block &source) target.body.insert(insert_point, (*i)->clone()); } +void ProgramCompiler::resolve_variables(Context &context) +{ + VariableResolver resolver; + context.content.visit(resolver); +} + string ProgramCompiler::format_context(Context &context) { Formatter formatter; @@ -395,6 +408,193 @@ void ProgramCompiler::VariableResolver::visit(InterfaceBlock &iface) } +ProgramCompiler::InterfaceGenerator::InterfaceGenerator(): + context(0), + scope_level(0), + remove_node(false) +{ } + +string ProgramCompiler::InterfaceGenerator::get_out_prefix(ContextType type) +{ + if(type==VERTEX) + return "_vs_out_"; + else if(type==GEOMETRY) + return "_gs_out_"; + else + return string(); +} + +void ProgramCompiler::InterfaceGenerator::visit(Context &ctx) +{ + SetForScope set(context, &ctx); + if(context->previous) + in_prefix = get_out_prefix(context->previous->type); + out_prefix = get_out_prefix(context->type); + ctx.content.visit(*this); +} + +void ProgramCompiler::InterfaceGenerator::visit(Block &block) +{ + SetForScope set(scope_level, scope_level+1); + for(list >::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) + { + list >::iterator k = block.body.insert(i, j->second); + (*k)->visit(*this); + } + iface_declarations.clear(); + } + + for(list >::iterator j=insert_nodes.begin(); j!=insert_nodes.end(); ++j) + block.body.insert(i, *j); + insert_nodes.clear(); + + if(remove_node) + block.body.erase(i++); + else + ++i; + remove_node = false; + } +} + +string ProgramCompiler::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 ProgramCompiler::InterfaceGenerator::generate_interface(VariableDeclaration &out, const string &iface, const string &name) +{ + const map &context_vars = (iface=="in" ? context->in_variables : context->out_variables); + if(context_vars.count(name) || iface_declarations.count(name)) + return false; + + VariableDeclaration* iface_var = new VariableDeclaration; + iface_var->sampling = out.sampling; + iface_var->interface = iface; + iface_var->type = out.type; + iface_var->type_declaration = out.type_declaration; + iface_var->name = name; + iface_var->array = (out.array || (context->type==GEOMETRY && iface=="in")); + iface_var->array_size = out.array_size; + if(iface=="in") + iface_var->linked_declaration = &out; + iface_declarations[iface_var->name] = iface_var; + + return true; +} + +void ProgramCompiler::InterfaceGenerator::insert_assignment(const string &left, ProgramSyntax::Expression *right) +{ + BinaryExpression *assign = new BinaryExpression; + VariableReference *ref = new VariableReference; + ref->name = left; + assign->left = ref; + assign->oper = "="; + assign->right = right; + assign->assignment = true; + + ExpressionStatement *stmt = new ExpressionStatement; + stmt->expression = assign; + insert_nodes.push_back(stmt); +} + +void ProgramCompiler::InterfaceGenerator::visit(VariableReference &var) +{ + if(var.declaration || !context->previous) + return; + if(iface_declarations.count(var.name)) + return; + + const map &prev_out = context->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", var.name); +} + +void ProgramCompiler::InterfaceGenerator::visit(VariableDeclaration &var) +{ + if(var.interface=="out") + { + if(scope_level==1) + context->out_variables[var.name] = &var; + else if(generate_interface(var, "out", change_prefix(var.name, string()))) + { + remove_node = true; + if(var.init_expression) + insert_assignment(var.name, var.init_expression->clone()); + } + } + else if(var.interface=="in") + { + context->in_variables[var.name] = &var; + if(context->previous) + { + const map &prev_out = context->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 ProgramCompiler::InterfaceGenerator::visit(Passthrough &pass) +{ + if(context->previous) + { + const map &prev_out = context->previous->out_variables; + for(map::const_iterator i=prev_out.begin(); i!=prev_out.end(); ++i) + { + string out_name = change_prefix(i->second->name, out_prefix); + generate_interface(*i->second, "in", i->second->name); + generate_interface(*i->second, "out", out_name); + + VariableReference *ref = new VariableReference; + ref->name = i->first; + 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; +} + + +void ProgramCompiler::VariableRenamer::visit(VariableReference &var) +{ + if(var.declaration) + var.name = var.declaration->name; +} + +void ProgramCompiler::VariableRenamer::visit(VariableDeclaration &var) +{ + if(var.linked_declaration) + var.name = var.linked_declaration->name; + TraversingVisitor::visit(var); +} + + void ProgramCompiler::UnusedVariableLocator::visit(VariableReference &var) { unused_variables.erase(var.declaration); diff --git a/source/programcompiler.h b/source/programcompiler.h index 0ea485a9..978b01e2 100644 --- a/source/programcompiler.h +++ b/source/programcompiler.h @@ -59,6 +59,35 @@ private: virtual void visit(ProgramSyntax::InterfaceBlock &); }; + struct InterfaceGenerator: ProgramSyntax::TraversingVisitor + { + ProgramSyntax::Context *context; + std::string in_prefix; + std::string out_prefix; + unsigned scope_level; + std::map > iface_declarations; + bool remove_node; + std::list > insert_nodes; + + InterfaceGenerator(); + + static std::string get_out_prefix(ProgramSyntax::ContextType); + void visit(ProgramSyntax::Context &); + virtual void visit(ProgramSyntax::Block &); + std::string change_prefix(const std::string &, const std::string &) const; + bool generate_interface(ProgramSyntax::VariableDeclaration &, const std::string &, const std::string &); + void insert_assignment(const std::string &, ProgramSyntax::Expression *); + virtual void visit(ProgramSyntax::VariableReference &); + virtual void visit(ProgramSyntax::VariableDeclaration &); + virtual void visit(ProgramSyntax::Passthrough &); + }; + + struct VariableRenamer: ProgramSyntax::TraversingVisitor + { + virtual void visit(ProgramSyntax::VariableReference &); + virtual void visit(ProgramSyntax::VariableDeclaration &); + }; + struct UnusedVariableLocator: ProgramSyntax::TraversingVisitor { std::set unused_variables; @@ -96,6 +125,7 @@ private: void process(); void process(ProgramSyntax::Context &); static void inject_block(ProgramSyntax::Block &, const ProgramSyntax::Block &); + static void resolve_variables(ProgramSyntax::Context &); std::string format_context(ProgramSyntax::Context &); }; diff --git a/source/programparser.cpp b/source/programparser.cpp index c6cdfd06..58649ec0 100644 --- a/source/programparser.cpp +++ b/source/programparser.cpp @@ -81,14 +81,15 @@ Module &ProgramParser::parse(IO::Base &io) void ProgramParser::parse_source(Module &module) { cur_module = &module; + cur_context = &module.global_context; iter = source.begin(); - Context *cur_context = &module.global_context; while(1) { while(Node *statement = parse_global_declaration()) cur_context->content.body.push_back(statement); cur_context->present = !cur_context->content.body.empty(); + Context *prev_context = cur_context; parse_token(); string token = parse_token(); if(token.empty()) @@ -103,6 +104,7 @@ void ProgramParser::parse_source(Module &module) cur_context = &module.fragment_context; else throw runtime_error(format("Parse error at '%s': expected context identifier", token)); + cur_context->previous = prev_context; for(; (iter!=source.end() && *iter!='\n'); ++iter) ; } @@ -355,6 +357,8 @@ Node *ProgramParser::parse_statement() return parse_conditional(); else if(token=="for") return parse_iteration(); + else if(token=="passthrough") + return parse_passthrough(); else if(token=="return") return parse_return(); else if(is_qualifier(token) || is_type(token)) @@ -693,6 +697,20 @@ Iteration *ProgramParser::parse_iteration() return loop.release(); } +Passthrough *ProgramParser::parse_passthrough() +{ + expect("passthrough"); + RefPtr pass = new Passthrough; + if(cur_context->type==GEOMETRY) + { + expect("["); + pass->subscript = parse_expression(); + expect("]"); + } + expect(";"); + return pass.release(); +} + Return *ProgramParser::parse_return() { expect("return"); diff --git a/source/programparser.h b/source/programparser.h index 390f19cb..40fdcd89 100644 --- a/source/programparser.h +++ b/source/programparser.h @@ -41,6 +41,7 @@ private: std::deque next_tokens; ProgramSyntax::Module main_module; ProgramSyntax::Module *cur_module; + ProgramSyntax::Context *cur_context; std::set declared_types; static Operator operators[]; @@ -85,6 +86,7 @@ private: ProgramSyntax::InterfaceBlock *parse_interface_block(); ProgramSyntax::Conditional *parse_conditional(); ProgramSyntax::Iteration *parse_iteration(); + ProgramSyntax::Passthrough *parse_passthrough(); ProgramSyntax::Return *parse_return(); }; diff --git a/source/programsyntax.cpp b/source/programsyntax.cpp index f64493ee..299e23b4 100644 --- a/source/programsyntax.cpp +++ b/source/programsyntax.cpp @@ -100,7 +100,8 @@ void StructDeclaration::visit(NodeVisitor &visitor) VariableDeclaration::VariableDeclaration(): constant(false), type_declaration(0), - array(false) + array(false), + linked_declaration(0) { } void VariableDeclaration::visit(NodeVisitor &visitor) @@ -136,6 +137,12 @@ void Conditional::visit(NodeVisitor &visitor) } +void Passthrough::visit(NodeVisitor &visitor) +{ + visitor.visit(*this); +} + + void Return::visit(NodeVisitor &visitor) { visitor.visit(*this); @@ -228,6 +235,12 @@ void TraversingVisitor::visit(Iteration &iter) iter.body.visit(*this); } +void TraversingVisitor::visit(Passthrough &pass) +{ + if(pass.subscript) + pass.subscript->visit(*this); +} + void TraversingVisitor::visit(Return &ret) { if(ret.expression) @@ -237,7 +250,8 @@ void TraversingVisitor::visit(Return &ret) Context::Context(ContextType t): type(t), - present(false) + present(false), + previous(0) { } diff --git a/source/programsyntax.h b/source/programsyntax.h index 11a67430..c8b0e1f7 100644 --- a/source/programsyntax.h +++ b/source/programsyntax.h @@ -187,6 +187,7 @@ struct VariableDeclaration: Node bool array; NodePtr array_size; NodePtr init_expression; + VariableDeclaration *linked_declaration; VariableDeclaration(); @@ -241,6 +242,14 @@ struct Iteration: Node virtual void visit(NodeVisitor &); }; +struct Passthrough: Node +{ + NodePtr subscript; + + virtual Passthrough *clone() const { return new Passthrough(*this); } + virtual void visit(NodeVisitor &); +}; + struct Return: Node { NodePtr expression; @@ -269,6 +278,7 @@ struct NodeVisitor virtual void visit(FunctionDeclaration &) { } virtual void visit(Conditional &) { } virtual void visit(Iteration &) { } + virtual void visit(Passthrough &) { } virtual void visit(Return &) { } }; @@ -287,6 +297,7 @@ struct TraversingVisitor: NodeVisitor virtual void visit(FunctionDeclaration &); virtual void visit(Conditional &); virtual void visit(Iteration &); + virtual void visit(Passthrough &); virtual void visit(Return &); }; @@ -302,7 +313,10 @@ struct Context { ContextType type; bool present; + Context *previous; ProgramSyntax::Block content; + std::map in_variables; + std::map out_variables; Context(ContextType); }; -- 2.43.0