]> git.tdb.fi Git - libs/gl.git/commitdiff
Remove conditional and iteration statements with no effect from GLSL
authorMikko Rasa <tdb@tdb.fi>
Sun, 3 Oct 2021 13:15:05 +0000 (16:15 +0300)
committerMikko Rasa <tdb@tdb.fi>
Sun, 3 Oct 2021 16:34:36 +0000 (19:34 +0300)
source/glsl/optimize.cpp
source/glsl/optimize.h
tests/glsl/empty_conditional_removal.glsl [new file with mode: 0644]
tests/glsl/empty_loop_removal.glsl [new file with mode: 0644]
tests/glsl/keep_empty_loop_with_side_effects.glsl [new file with mode: 0644]

index 9388c04129cfc1b03020ef0f00da650bf2b46f1a..a24d85dd5f0b7f025e01ab7b13dca85238b09535 100644 (file)
@@ -909,6 +909,27 @@ void ConstantConditionEliminator::visit(RefPtr<Expression> &expr)
        r_ternary_result = 0;
 }
 
+void ConstantConditionEliminator::visit(UnaryExpression &unary)
+{
+       if(unary.oper->token[1]=='+' || unary.oper->token[1]=='-')
+               if(const VariableReference *var = dynamic_cast<const VariableReference *>(unary.expression.get()))
+               {
+                       auto i = current_block->variables.find(var->name);
+                       r_external_side_effects = (i==current_block->variables.end() || i->second!=var->declaration);
+                       return;
+               }
+
+       TraversingVisitor::visit(unary);
+}
+
+void ConstantConditionEliminator::visit(Assignment &assign)
+{
+       auto i = find_if(current_block->variables, [&assign](const pair<string, VariableDeclaration *> &kvp){ return kvp.second==assign.target.declaration; });
+       if(i==current_block->variables.end())
+               r_external_side_effects = true;
+       TraversingVisitor::visit(assign);
+}
+
 void ConstantConditionEliminator::visit(TernaryExpression &ternary)
 {
        ConstantStatus result = check_constant_condition(*ternary.condition);
@@ -918,6 +939,12 @@ void ConstantConditionEliminator::visit(TernaryExpression &ternary)
                r_ternary_result = 0;
 }
 
+void ConstantConditionEliminator::visit(FunctionCall &call)
+{
+       r_external_side_effects = true;
+       TraversingVisitor::visit(call);
+}
+
 void ConstantConditionEliminator::visit(Conditional &cond)
 {
        ConstantStatus result = check_constant_condition(*cond.condition);
@@ -930,7 +957,11 @@ void ConstantConditionEliminator::visit(Conditional &cond)
                return;
        }
 
+       r_external_side_effects = false;
        TraversingVisitor::visit(cond);
+
+       if(cond.body.body.empty() && cond.else_body.body.empty() && !r_external_side_effects)
+               nodes_to_remove.insert(&cond);
 }
 
 void ConstantConditionEliminator::visit(Iteration &iter)
@@ -945,7 +976,10 @@ void ConstantConditionEliminator::visit(Iteration &iter)
                }
        }
 
+       r_external_side_effects = false;
        TraversingVisitor::visit(iter);
+       if(iter.body.body.empty() && !r_external_side_effects)
+               nodes_to_remove.insert(&iter);
 }
 
 
index 6250130fb30a39bfd9b18c82cdc9acf654c347ad..92353a77ee1748c651d8d6f35ab266d6a429593c 100644 (file)
@@ -210,7 +210,8 @@ private:
 };
 
 /** Removes conditional statements and loops where the condition can be
-determined as constant at compile time. */
+determined as constant at compile time.  Also removes such statements where
+the body is empty and the condition has no side effects. */
 class ConstantConditionEliminator: private TraversingVisitor
 {
 private:
@@ -224,6 +225,7 @@ private:
        NodeList<Statement>::iterator insert_point;
        std::set<Node *> nodes_to_remove;
        RefPtr<Expression> r_ternary_result;
+       bool r_external_side_effects;
 
 public:
        void apply(Stage &);
@@ -233,7 +235,10 @@ private:
 
        virtual void visit(Block &);
        virtual void visit(RefPtr<Expression> &);
+       virtual void visit(UnaryExpression &);
+       virtual void visit(Assignment &);
        virtual void visit(TernaryExpression &);
+       virtual void visit(FunctionCall &);
        virtual void visit(Conditional &);
        virtual void visit(Iteration &);
 };
diff --git a/tests/glsl/empty_conditional_removal.glsl b/tests/glsl/empty_conditional_removal.glsl
new file mode 100644 (file)
index 0000000..e40d176
--- /dev/null
@@ -0,0 +1,63 @@
+uniform Lighting
+{
+       vec3 light_dir;
+       mat4 shadow_matrix;
+       int shadow_enabled;
+};
+uniform Transform
+{
+       mat4 vp;
+       mat4 model;
+};
+uniform sampler2DShadow shadow_map;
+const bool use_light = false;
+
+#pragma MSP stage(vertex)
+layout(location=0) in vec4 vertex;
+layout(location=1) in vec3 normal;
+void main()
+{
+       vec4 world_vertex = model*vertex;
+       out vec3 world_normal = mat3(model)*normal;
+       gl_Position = vp*world_vertex;
+       if(shadow_enabled!=0)
+       {
+               out vec3 shadow_coord = (shadow_matrix*world_vertex).xyz;
+       }
+}
+
+#pragma MSP stage(fragment)
+layout(location=0) out vec4 frag_color;
+void main()
+{
+       vec3 color = vec3(1.0);
+       if(use_light)
+       {
+               float intensity = max(dot(normalize(world_normal), light_dir), 0.0);
+               if(shadow_enabled!=0)
+                       intensity *= texture(shadow_map, shadow_coord);
+               color *= intensity;
+       }
+       frag_color = vec4(color, 1.0);
+}
+
+/* Expected output: vertex
+layout(binding=48) uniform Transform
+{
+       mat4 vp;
+       mat4 model;
+};
+layout(location=0) in vec4 vertex;
+void main()
+{
+       gl_Position = vp*model*vertex;
+}
+*/
+
+/* Expected output: fragment
+layout(location=0) out vec4 frag_color;
+void main()
+{
+       frag_color = vec4(vec3(1.0), 1.0);
+}
+*/
diff --git a/tests/glsl/empty_loop_removal.glsl b/tests/glsl/empty_loop_removal.glsl
new file mode 100644 (file)
index 0000000..5a4cf84
--- /dev/null
@@ -0,0 +1,60 @@
+uniform Lighting
+{
+       vec4 light_dir[2];
+};
+uniform Transform
+{
+       mat4 vp;
+       mat4 model;
+};
+const bool use_light = false;
+
+#pragma MSP stage(vertex)
+layout(location=0) in vec4 vertex;
+layout(location=1) in vec3 normal;
+out vec3 world_light_dir[2];
+void main()
+{
+       vec4 world_vertex = model*vertex;
+       out vec3 world_normal = mat3(model)*normal;
+       gl_Position = vp*world_vertex;
+       for(int i=0; i<2; ++i)
+               world_light_dir[i] = light_dir[i].xyz-world_vertex.xyz*light_dir[i].w;
+}
+
+#pragma MSP stage(fragment)
+layout(location=0) out vec4 frag_color;
+void main()
+{
+       vec3 color = vec3(0.1);
+       if(use_light)
+       {
+               for(int i=0; i<2; ++i)
+               {
+                       float intensity = max(dot(normalize(world_normal), world_light_dir[i]), 0.0);
+                       color += intensity;
+               }
+       }
+       frag_color = vec4(color, 1.0);
+}
+
+/* Expected output: vertex
+layout(binding=48) uniform Transform
+{
+       mat4 vp;
+       mat4 model;
+};
+layout(location=0) in vec4 vertex;
+void main()
+{
+       gl_Position = vp*model*vertex;
+}
+*/
+
+/* Expected output: fragment
+layout(location=0) out vec4 frag_color;
+void main()
+{
+       frag_color = vec4(vec3(0.1), 1.0);
+}
+*/
diff --git a/tests/glsl/keep_empty_loop_with_side_effects.glsl b/tests/glsl/keep_empty_loop_with_side_effects.glsl
new file mode 100644 (file)
index 0000000..b0c1626
--- /dev/null
@@ -0,0 +1,44 @@
+uniform sampler2D tex;
+
+#pragma MSP stage(vertex)
+layout(location=0) in vec4 vertex;
+layout(location=1) in vec2 texcoord;
+void main()
+{
+       gl_Position = vertex;
+       passthrough;
+}
+
+#pragma MSP stage(fragment)
+layout(location=0) out float result;
+void main()
+{
+       float value = texture(tex, texcoord).r;
+       float pot;
+       for(pot=0; pot<value; pot*=2) { }
+       result = pot;
+}
+
+/* Expected output: vertex
+layout(location=0) in vec4 vertex;
+layout(location=1) in vec2 texcoord;
+layout(location=0) out vec2 _vs_out_texcoord;
+void main()
+{
+       gl_Position = vertex;
+       _vs_out_texcoord = texcoord;
+}
+*/
+
+/* Expected output: fragment
+layout(location=0, binding=71) uniform sampler2D tex;
+layout(location=0) out float result;
+layout(location=0) in vec2 _vs_out_texcoord;
+void main()
+{
+       float value = texture(tex, _vs_out_texcoord).r;
+       float pot;
+       for(pot = 0.0; pot<value; pot *= 2.0) { }
+       result = pot;
+}
+*/