]> git.tdb.fi Git - libs/gl.git/blobdiff - source/programcompiler.cpp
Fix various issues with constant condition elimination
[libs/gl.git] / source / programcompiler.cpp
index 1c84a96dc925f18095368d63aa13aaaf19a7d88d..1f014f72c654d3e678f706cfff28f9d5173407f4 100644 (file)
@@ -557,8 +557,12 @@ void ProgramCompiler::Formatter::visit(Iteration &iter)
 
 void ProgramCompiler::Formatter::visit(Return &ret)
 {
-       formatted += "return ";
-       ret.expression->visit(*this);
+       formatted += "return";
+       if(ret.expression)
+       {
+               formatted += ' ';
+               ret.expression->visit(*this);
+       }
        formatted += ';';
 }
 
@@ -1171,6 +1175,12 @@ void ProgramCompiler::FunctionInliner::visit(BinaryExpression &binary)
        inline_result = 0;
 }
 
+void ProgramCompiler::FunctionInliner::visit(MemberAccess &memacc)
+{
+       visit_and_inline(memacc.left);
+       inline_result = 0;
+}
+
 void ProgramCompiler::FunctionInliner::visit(FunctionCall &call)
 {
        for(vector<RefPtr<Expression> >::iterator i=call.arguments.begin(); i!=call.arguments.end(); ++i)
@@ -1289,7 +1299,8 @@ void ProgramCompiler::ExpressionEvaluator::visit(BinaryExpression &binary)
 
 
 ProgramCompiler::ConstantConditionEliminator::ConstantConditionEliminator():
-       scope_level(0)
+       scope_level(0),
+       record_only(false)
 { }
 
 void ProgramCompiler::ConstantConditionEliminator::visit(Block &block)
@@ -1301,6 +1312,13 @@ void ProgramCompiler::ConstantConditionEliminator::visit(Block &block)
                variable_values.erase(i->second);
 }
 
+void ProgramCompiler::ConstantConditionEliminator::visit(UnaryExpression &unary)
+{
+       if(VariableReference *var = dynamic_cast<VariableReference *>(unary.expression.get()))
+               if(unary.oper=="++" || unary.oper=="--")
+                       variable_values.erase(var->declaration);
+}
+
 void ProgramCompiler::ConstantConditionEliminator::visit(Assignment &assign)
 {
        variable_values.erase(assign.target_declaration);
@@ -1314,28 +1332,49 @@ void ProgramCompiler::ConstantConditionEliminator::visit(VariableDeclaration &va
 
 void ProgramCompiler::ConstantConditionEliminator::visit(Conditional &cond)
 {
-       ExpressionEvaluator eval(variable_values);
-       cond.condition->visit(eval);
-       if(eval.result_valid)
-               flatten_block(eval.result ? cond.body : cond.else_body);
-       else
-               TraversingVisitor::visit(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 ProgramCompiler::ConstantConditionEliminator::visit(Iteration &iter)
 {
-       if(iter.condition)
+       if(!record_only)
        {
-               ExpressionEvaluator eval;
-               iter.condition->visit(eval);
-               if(eval.result_valid && !eval.result)
+               if(iter.condition)
                {
-                       remove_node = true;
-                       return;
+                       /* 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<VariableDeclaration *>(iter.init_statement.get()))
+               variable_values.erase(init_decl);
 }