]> 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 a1be91ca4f575228fe2f48ccb374fb0097c6dccb..1f014f72c654d3e678f706cfff28f9d5173407f4 100644 (file)
@@ -1210,14 +1210,12 @@ void ProgramCompiler::FunctionInliner::visit(Return &ret)
 
 ProgramCompiler::ExpressionEvaluator::ExpressionEvaluator():
        variable_values(0),
-       const_only(false),
        result(0.0f),
        result_valid(false)
 { }
 
-ProgramCompiler::ExpressionEvaluator::ExpressionEvaluator(const ValueMap *v, bool c):
-       variable_values(v),
-       const_only(c),
+ProgramCompiler::ExpressionEvaluator::ExpressionEvaluator(const ValueMap &v):
+       variable_values(&v),
        result(0.0f),
        result_valid(false)
 { }
@@ -1242,8 +1240,6 @@ void ProgramCompiler::ExpressionEvaluator::visit(VariableReference &var)
 {
        if(!var.declaration)
                return;
-       if(const_only && !var.declaration->constant)
-               return;
 
        if(variable_values)
        {
@@ -1304,7 +1300,7 @@ void ProgramCompiler::ExpressionEvaluator::visit(BinaryExpression &binary)
 
 ProgramCompiler::ConstantConditionEliminator::ConstantConditionEliminator():
        scope_level(0),
-       in_loop(false)
+       record_only(false)
 { }
 
 void ProgramCompiler::ConstantConditionEliminator::visit(Block &block)
@@ -1316,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);
@@ -1329,30 +1332,49 @@ void ProgramCompiler::ConstantConditionEliminator::visit(VariableDeclaration &va
 
 void ProgramCompiler::ConstantConditionEliminator::visit(Conditional &cond)
 {
-       ExpressionEvaluator eval(&variable_values, in_loop);
-       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)
 {
-       // XXX Should this not visit init_statement first?
-       if(iter.condition)
+       if(!record_only)
        {
-               ExpressionEvaluator eval(0, in_loop);
-               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);
        }
 
-       SetFlag set_loop(in_loop);
        TraversingVisitor::visit(iter);
+
+       if(VariableDeclaration *init_decl = dynamic_cast<VariableDeclaration *>(iter.init_statement.get()))
+               variable_values.erase(init_decl);
 }