nir: fix partial loop unroll OOB check for loops not starting at 0

is_access_out_of_bounds() decides whether the residual loop (created
by partial_unroll) will access arrays out of bounds by checking whether
array_length is less than or equal to trip_count. That assumes the
induction variable starts at 0. For example glamor gradient shader
shader-db/shaders/glamor/4.shader_test:

   uniform float stops[18];
   for (i = 1; i < n_stop; i++)
      if (stop_len < stops[i]) break;

trip_count is guessed as 17 from the array indexing, so the residual
loop's index begins at 18, out of bounds for the 18-element array, yet
18 <= 17 is false, so the OOB removal is skipped and the residual loop
is not eliminated.

Correctly consider the start value for the OOB check. This lets glamor
gradient shaders with loops starting at i=1 unroll the same way as i=0
loops.

Reviewed-by: Timothy Arceri <tarceri@itsqueeze.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/41203>
This commit is contained in:
Pavel Ondračka 2026-04-22 14:01:40 +02:00 committed by Marge Bot
parent 04055256ec
commit 959f59b3f0
3 changed files with 9 additions and 3 deletions

View file

@ -3584,6 +3584,9 @@ typedef struct nir_loop_terminator {
/** Condition instruction that contains the induction variable */
nir_instr *conditional_instr;
/** Init source of the induction variable used in conditional_instr. */
nir_src *init_src;
/** Block within ::nif that has the break instruction. */
nir_block *break_block;

View file

@ -1201,6 +1201,7 @@ find_trip_count(loop_info_state *state, unsigned execution_mode,
*/
nir_loop_induction_variable *lv = get_loop_var(basic_ind.def, state);
terminator->init_src = lv->init_src;
/* The basic induction var might be a vector but, because we guarantee
* earlier that the phi source has a scalar swizzle, we can take the

View file

@ -627,11 +627,13 @@ is_access_out_of_bounds(nir_loop_terminator *term, nir_deref_instr *deref,
/* We have already unrolled the loop and the new one will be imbedded in
* the innermost continue branch. So unless the array is greater than
* the trip count any iteration over the loop will be an out of bounds
* access of the array.
* the initial value plus the trip count any iteration over the loop
* will be an out of bounds access of the array.
*/
unsigned length = glsl_type_is_vector(parent->type) ? glsl_get_vector_elements(parent->type) : glsl_get_length(parent->type);
return length <= trip_count;
unsigned init_value = nir_src_is_const(*term->init_src) ?
nir_src_as_uint(*term->init_src) : 0;
return length <= init_value + trip_count;
}
return false;