glsl: pull mark_array_elements_referenced() out into common helper

We will reuse this helper in the NIR linker in the following
patches.

Reviewed-by: Alejandro Piñeiro <apinheiro@igalia.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/4623>
This commit is contained in:
Timothy Arceri
2020-03-31 13:49:30 +11:00
committed by Marge Bot
parent 5d992b539e
commit 6afd0954e1
5 changed files with 130 additions and 121 deletions

View File

@@ -75,54 +75,6 @@ ir_array_refcount_entry::~ir_array_refcount_entry()
delete [] bits; delete [] bits;
} }
void
ir_array_refcount_entry::mark_array_elements_referenced(const array_deref_range *dr,
unsigned count)
{
if (count != array_depth)
return;
mark_array_elements_referenced(dr, count, 1, 0);
}
void
ir_array_refcount_entry::mark_array_elements_referenced(const array_deref_range *dr,
unsigned count,
unsigned scale,
unsigned linearized_index)
{
/* Walk through the list of array dereferences in least- to
* most-significant order. Along the way, accumulate the current
* linearized offset and the scale factor for each array-of-.
*/
for (unsigned i = 0; i < count; i++) {
if (dr[i].index < dr[i].size) {
linearized_index += dr[i].index * scale;
scale *= dr[i].size;
} else {
/* For each element in the current array, update the count and
* offset, then recurse to process the remaining arrays.
*
* There is some inefficency here if the last element in the
* array_deref_range list specifies the entire array. In that case,
* the loop will make recursive calls with count == 0. In the call,
* all that will happen is the bit will be set.
*/
for (unsigned j = 0; j < dr[i].size; j++) {
mark_array_elements_referenced(&dr[i + 1],
count - (i + 1),
scale * dr[i].size,
linearized_index + (j * scale));
}
return;
}
}
BITSET_SET(bits, linearized_index);
}
ir_array_refcount_entry * ir_array_refcount_entry *
ir_array_refcount_visitor::get_variable_entry(ir_variable *var) ir_array_refcount_visitor::get_variable_entry(ir_variable *var)
{ {
@@ -224,7 +176,9 @@ ir_array_refcount_visitor::visit_enter(ir_dereference_array *ir)
if (entry == NULL) if (entry == NULL)
return visit_stop; return visit_stop;
entry->mark_array_elements_referenced(derefs, num_derefs); link_util_mark_array_elements_referenced(derefs, num_derefs,
entry->array_depth,
entry->bits);
return visit_continue; return visit_continue;
} }

View File

@@ -32,26 +32,10 @@
#include "ir.h" #include "ir.h"
#include "ir_visitor.h" #include "ir_visitor.h"
#include "linker_util.h"
#include "compiler/glsl_types.h" #include "compiler/glsl_types.h"
#include "util/bitset.h" #include "util/bitset.h"
/**
* Describes an access of an array element or an access of the whole array
*/
struct array_deref_range {
/**
* Index that was accessed.
*
* All valid array indices are less than the size of the array. If index
* is equal to the size of the array, this means the entire array has been
* accessed (e.g., due to use of a non-constant index).
*/
unsigned index;
/** Size of the array. Used for offset calculations. */
unsigned size;
};
class ir_array_refcount_entry class ir_array_refcount_entry
{ {
public: public:
@@ -63,33 +47,11 @@ public:
/** Has the variable been referenced? */ /** Has the variable been referenced? */
bool is_referenced; bool is_referenced;
/** /** Count of nested arrays in the type. */
* Mark a set of array elements as accessed. unsigned array_depth;
*
* If every \c array_deref_range is for a single index, only a single /** Set of bit-flags to note which array elements have been accessed. */
* element will be marked. If any \c array_deref_range is for an entire BITSET_WORD *bits;
* array-of-, then multiple elements will be marked.
*
* Items in the \c array_deref_range list appear in least- to
* most-significant order. This is the \b opposite order the indices
* appear in the GLSL shader text. An array access like
*
* x = y[1][i][3];
*
* would appear as
*
* { { 3, n }, { m, m }, { 1, p } }
*
* where n, m, and p are the sizes of the arrays-of-arrays.
*
* The set of marked array elements can later be queried by
* \c ::is_linearized_index_referenced.
*
* \param dr List of array_deref_range elements to be processed.
* \param count Number of array_deref_range elements to be processed.
*/
void mark_array_elements_referenced(const array_deref_range *dr,
unsigned count);
/** Has a linearized array index been referenced? */ /** Has a linearized array index been referenced? */
bool is_linearized_index_referenced(unsigned linearized_index) const bool is_linearized_index_referenced(unsigned linearized_index) const
@@ -101,8 +63,6 @@ public:
} }
private: private:
/** Set of bit-flags to note which array elements have been accessed. */
BITSET_WORD *bits;
/** /**
* Total number of bits referenced by \c bits. * Total number of bits referenced by \c bits.
@@ -111,27 +71,6 @@ private:
*/ */
unsigned num_bits; unsigned num_bits;
/** Count of nested arrays in the type. */
unsigned array_depth;
/**
* Recursive part of the public mark_array_elements_referenced method.
*
* The recursion occurs when an entire array-of- is accessed. See the
* implementation for more details.
*
* \param dr List of array_deref_range elements to be
* processed.
* \param count Number of array_deref_range elements to be
* processed.
* \param scale Current offset scale.
* \param linearized_index Current accumulated linearized array index.
*/
void mark_array_elements_referenced(const array_deref_range *dr,
unsigned count,
unsigned scale,
unsigned linearized_index);
friend class array_refcount_test; friend class array_refcount_test;
}; };

View File

@@ -287,3 +287,90 @@ link_util_calculate_subroutine_compat(struct gl_shader_program *prog)
} }
} }
} }
/**
* Recursive part of the public mark_array_elements_referenced function.
*
* The recursion occurs when an entire array-of- is accessed. See the
* implementation for more details.
*
* \param dr List of array_deref_range elements to be
* processed.
* \param count Number of array_deref_range elements to be
* processed.
* \param scale Current offset scale.
* \param linearized_index Current accumulated linearized array index.
*/
void
_mark_array_elements_referenced(const struct array_deref_range *dr,
unsigned count, unsigned scale,
unsigned linearized_index,
BITSET_WORD *bits)
{
/* Walk through the list of array dereferences in least- to
* most-significant order. Along the way, accumulate the current
* linearized offset and the scale factor for each array-of-.
*/
for (unsigned i = 0; i < count; i++) {
if (dr[i].index < dr[i].size) {
linearized_index += dr[i].index * scale;
scale *= dr[i].size;
} else {
/* For each element in the current array, update the count and
* offset, then recurse to process the remaining arrays.
*
* There is some inefficency here if the last eBITSET_WORD *bitslement in the
* array_deref_range list specifies the entire array. In that case,
* the loop will make recursive calls with count == 0. In the call,
* all that will happen is the bit will be set.
*/
for (unsigned j = 0; j < dr[i].size; j++) {
_mark_array_elements_referenced(&dr[i + 1],
count - (i + 1),
scale * dr[i].size,
linearized_index + (j * scale),
bits);
}
return;
}
}
BITSET_SET(bits, linearized_index);
}
/**
* Mark a set of array elements as accessed.
*
* If every \c array_deref_range is for a single index, only a single
* element will be marked. If any \c array_deref_range is for an entire
* array-of-, then multiple elements will be marked.
*
* Items in the \c array_deref_range list appear in least- to
* most-significant order. This is the \b opposite order the indices
* appear in the GLSL shader text. An array access like
*
* x = y[1][i][3];
*
* would appear as
*
* { { 3, n }, { m, m }, { 1, p } }
*
* where n, m, and p are the sizes of the arrays-of-arrays.
*
* The set of marked array elements can later be queried by
* \c ::is_linearized_index_referenced.
*
* \param dr List of array_deref_range elements to be processed.
* \param count Number of array_deref_range elements to be processed.
*/
void
link_util_mark_array_elements_referenced(const struct array_deref_range *dr,
unsigned count, unsigned array_depth,
BITSET_WORD *bits)
{
if (count != array_depth)
return;
_mark_array_elements_referenced(dr, count, 1, 0, bits);
}

View File

@@ -24,6 +24,8 @@
#ifndef GLSL_LINKER_UTIL_H #ifndef GLSL_LINKER_UTIL_H
#define GLSL_LINKER_UTIL_H #define GLSL_LINKER_UTIL_H
#include "util/bitset.h"
struct gl_context; struct gl_context;
struct gl_shader_program; struct gl_shader_program;
struct gl_uniform_storage; struct gl_uniform_storage;
@@ -45,6 +47,23 @@ struct empty_uniform_block {
unsigned slots; unsigned slots;
}; };
/**
* Describes an access of an array element or an access of the whole array
*/
struct array_deref_range {
/**
* Index that was accessed.
*
* All valid array indices are less than the size of the array. If index
* is equal to the size of the array, this means the entire array has been
* accessed (e.g., due to use of a non-constant index).
*/
unsigned index;
/** Size of the array. Used for offset calculations. */
unsigned size;
};
void void
linker_error(struct gl_shader_program *prog, const char *fmt, ...); linker_error(struct gl_shader_program *prog, const char *fmt, ...);
@@ -81,6 +100,11 @@ link_util_check_uniform_resources(struct gl_context *ctx,
void void
link_util_calculate_subroutine_compat(struct gl_shader_program *prog); link_util_calculate_subroutine_compat(struct gl_shader_program *prog);
void
link_util_mark_array_elements_referenced(const struct array_deref_range *dr,
unsigned count, unsigned array_depth,
BITSET_WORD *bits);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@@ -283,7 +283,8 @@ TEST_F(array_refcount_test, mark_array_elements_referenced_simple)
}; };
const unsigned accessed_element = 0 + (1 * 5) + (2 * 4 * 5); const unsigned accessed_element = 0 + (1 * 5) + (2 * 4 * 5);
entry.mark_array_elements_referenced(dr, 3); link_util_mark_array_elements_referenced(dr, 3, entry.array_depth,
entry.bits);
for (unsigned i = 0; i < total_elements; i++) for (unsigned i = 0; i < total_elements; i++)
EXPECT_EQ(i == accessed_element, entry.is_linearized_index_referenced(i)); EXPECT_EQ(i == accessed_element, entry.is_linearized_index_referenced(i));
@@ -302,7 +303,8 @@ TEST_F(array_refcount_test, mark_array_elements_referenced_whole_first_array)
{ 0, 5 }, { 1, 4 }, { 3, 3 } { 0, 5 }, { 1, 4 }, { 3, 3 }
}; };
entry.mark_array_elements_referenced(dr, 3); link_util_mark_array_elements_referenced(dr, 3, entry.array_depth,
entry.bits);
for (unsigned i = 0; i < 3; i++) { for (unsigned i = 0; i < 3; i++) {
for (unsigned j = 0; j < 4; j++) { for (unsigned j = 0; j < 4; j++) {
@@ -330,7 +332,8 @@ TEST_F(array_refcount_test, mark_array_elements_referenced_whole_second_array)
{ 0, 5 }, { 4, 4 }, { 1, 3 } { 0, 5 }, { 4, 4 }, { 1, 3 }
}; };
entry.mark_array_elements_referenced(dr, 3); link_util_mark_array_elements_referenced(dr, 3, entry.array_depth,
entry.bits);
for (unsigned i = 0; i < 3; i++) { for (unsigned i = 0; i < 3; i++) {
for (unsigned j = 0; j < 4; j++) { for (unsigned j = 0; j < 4; j++) {
@@ -358,7 +361,8 @@ TEST_F(array_refcount_test, mark_array_elements_referenced_whole_third_array)
{ 5, 5 }, { 2, 4 }, { 1, 3 } { 5, 5 }, { 2, 4 }, { 1, 3 }
}; };
entry.mark_array_elements_referenced(dr, 3); link_util_mark_array_elements_referenced(dr, 3, entry.array_depth,
entry.bits);
for (unsigned i = 0; i < 3; i++) { for (unsigned i = 0; i < 3; i++) {
for (unsigned j = 0; j < 4; j++) { for (unsigned j = 0; j < 4; j++) {
@@ -386,7 +390,8 @@ TEST_F(array_refcount_test, mark_array_elements_referenced_whole_first_and_third
{ 5, 5 }, { 3, 4 }, { 3, 3 } { 5, 5 }, { 3, 4 }, { 3, 3 }
}; };
entry.mark_array_elements_referenced(dr, 3); link_util_mark_array_elements_referenced(dr, 3, entry.array_depth,
entry.bits);
for (unsigned i = 0; i < 3; i++) { for (unsigned i = 0; i < 3; i++) {
for (unsigned j = 0; j < 4; j++) { for (unsigned j = 0; j < 4; j++) {