From: Nicolai Hähnle <nicolai.haeh...@amd.com>
Save some passes over the IR.
---
src/compiler/glsl/linker.cpp | 88
+++++++++++++++++++++++++-------------------
1 file changed, 50 insertions(+), 38 deletions(-)
diff --git a/src/compiler/glsl/linker.cpp
b/src/compiler/glsl/linker.cpp
index 5366200..cfda263 100644
--- a/src/compiler/glsl/linker.cpp
+++ b/src/compiler/glsl/linker.cpp
@@ -88,75 +88,82 @@
#include "main/enums.h"
namespace {
/**
* Visitor that determines whether or not a variable is ever written.
*/
class find_assignment_visitor : public ir_hierarchical_visitor {
public:
- find_assignment_visitor(const char *name)
- : name(name), found(false)
+ find_assignment_visitor(unsigned int num_names, const char *
const *names)
+ : num_names(num_names), names(names), found(0)
{
- /* empty */
+ assert(num_names <= 32);
}
virtual ir_visitor_status visit_enter(ir_assignment *ir)
{
ir_variable *const var = ir->lhs->variable_referenced();
- if (strcmp(name, var->name) == 0) {
- found = true;
- return visit_stop;
- }
-
- return visit_continue_with_parent;
+ return check_variable_name(var->name);
}
virtual ir_visitor_status visit_enter(ir_call *ir)
{
foreach_two_lists(formal_node, &ir->callee->parameters,
actual_node, &ir->actual_parameters) {
ir_rvalue *param_rval = (ir_rvalue *) actual_node;
ir_variable *sig_param = (ir_variable *) formal_node;
if (sig_param->data.mode == ir_var_function_out ||
sig_param->data.mode == ir_var_function_inout) {
ir_variable *var = param_rval->variable_referenced();
- if (var && strcmp(name, var->name) == 0) {
- found = true;
+ if (var && check_variable_name(var->name) == visit_stop)
return visit_stop;
- }
}
}
if (ir->return_deref != NULL) {
ir_variable *const var =
ir->return_deref->variable_referenced();
- if (strcmp(name, var->name) == 0) {
- found = true;
+ if (check_variable_name(var->name) == visit_stop)
return visit_stop;
- }
}
return visit_continue_with_parent;
}
- bool variable_found()
+ bool variable_found(unsigned idx)
{
- return found;
+ return found & (1u << idx);
}
private:
- const char *name; /**< Find writes to a variable with this
name. */
- bool found; /**< Was a write to the variable found? */
+ ir_visitor_status check_variable_name(const char *name)
+ {
+ for (unsigned i = 0; i < num_names; ++i) {
+ if (strcmp(names[i], name) == 0) {
+ found |= 1u << i;
+ if (found == u_bit_consecutive(0, num_names))
+ return visit_stop;
+ break;
+ }
+ }
+
+ return visit_continue_with_parent;
+ }
+
+private:
+ unsigned int num_names;
+ const char * const * names; /**< Find writes to variables with
these names. */
+ uint32_t found; /**< Was a write to the variable
found? */
};
/**
* Visitor that determines whether or not a variable is ever read.
*/
class find_deref_visitor : public ir_hierarchical_visitor {
public:
find_deref_visitor(const char *name)
: name(name), found(false)
@@ -560,61 +567,63 @@ analyze_clip_cull_usage(struct
gl_shader_program *prog,
/* From section 7.1 (Vertex Shader Special Variables) of the
* GLSL 1.30 spec:
*
* "It is an error for a shader to statically write both
* gl_ClipVertex and gl_ClipDistance."
*
* This does not apply to GLSL ES shaders, since GLSL ES
defines neither
* gl_ClipVertex nor gl_ClipDistance. However with
* GL_EXT_clip_cull_distance, this functionality is exposed
in ES 3.0.
*/
- find_assignment_visitor clip_distance("gl_ClipDistance");
- find_assignment_visitor cull_distance("gl_CullDistance");
+ static const char * const variable_names[] = {
+ "gl_ClipDistance",
+ "gl_CullDistance",
+ "gl_ClipVertex"
+ };
+
+ find_assignment_visitor clipcull_visitor(!prog->IsES ? 3 : 2,
variable_names);
- clip_distance.run(shader->ir);
- cull_distance.run(shader->ir);
+ clipcull_visitor.run(shader->ir);
/* From the ARB_cull_distance spec:
*
* It is a compile-time or link-time error for the set of
shaders forming
* a program to statically read or write both gl_ClipVertex
and either
* gl_ClipDistance or gl_CullDistance.
*
* This does not apply to GLSL ES shaders, since GLSL ES
doesn't define
* gl_ClipVertex.
*/
if (!prog->IsES) {
- find_assignment_visitor clip_vertex("gl_ClipVertex");
-
- clip_vertex.run(shader->ir);
-
- if (clip_vertex.variable_found() &&
clip_distance.variable_found()) {
+ if (clipcull_visitor.variable_found(2) &&
+ clipcull_visitor.variable_found(0)) {