From c39bb707ff8678d0675538994dc05182e61da193 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Sun, 3 Oct 2021 16:15:05 +0300 Subject: [PATCH] Remove conditional and iteration statements with no effect from GLSL --- source/glsl/optimize.cpp | 34 ++++++++++ source/glsl/optimize.h | 7 ++- tests/glsl/empty_conditional_removal.glsl | 63 +++++++++++++++++++ tests/glsl/empty_loop_removal.glsl | 60 ++++++++++++++++++ .../keep_empty_loop_with_side_effects.glsl | 44 +++++++++++++ 5 files changed, 207 insertions(+), 1 deletion(-) create mode 100644 tests/glsl/empty_conditional_removal.glsl create mode 100644 tests/glsl/empty_loop_removal.glsl create mode 100644 tests/glsl/keep_empty_loop_with_side_effects.glsl diff --git a/source/glsl/optimize.cpp b/source/glsl/optimize.cpp index 9388c041..a24d85dd 100644 --- a/source/glsl/optimize.cpp +++ b/source/glsl/optimize.cpp @@ -909,6 +909,27 @@ void ConstantConditionEliminator::visit(RefPtr &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(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 &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); } diff --git a/source/glsl/optimize.h b/source/glsl/optimize.h index 6250130f..92353a77 100644 --- a/source/glsl/optimize.h +++ b/source/glsl/optimize.h @@ -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::iterator insert_point; std::set nodes_to_remove; RefPtr 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 &); + 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 index 00000000..e40d176e --- /dev/null +++ b/tests/glsl/empty_conditional_removal.glsl @@ -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 index 00000000..5a4cf84b --- /dev/null +++ b/tests/glsl/empty_loop_removal.glsl @@ -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 index 00000000..b0c16262 --- /dev/null +++ b/tests/glsl/keep_empty_loop_with_side_effects.glsl @@ -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