var->type = type;
}
-/**
- * Rewrite any clip/cull distances to refer to the new combined array.
- */
static void
-rewrite_references(nir_instr *instr,
+rewrite_clip_cull_deref(nir_builder *b,
+ nir_deref_instr *deref,
+ const struct glsl_type *type,
+ unsigned tail_offset)
+{
+ deref->type = type;
+
+ if (glsl_type_is_array(type)) {
+ const struct glsl_type *child_type = glsl_get_array_element(type);
+ nir_foreach_use(src, &deref->dest.ssa) {
+ rewrite_clip_cull_deref(b, nir_instr_as_deref(src->parent_instr),
+ child_type, tail_offset);
+ }
+ } else {
+ assert(glsl_type_is_scalar(type));
+
+ /* This is the end of the line. Add the tail offset if needed */
+ if (tail_offset > 0) {
+ b->cursor = nir_before_instr(&deref->instr);
+ assert(deref->deref_type == nir_deref_type_array);
+ nir_ssa_def *index = nir_iadd(b, deref->arr.index.ssa,
+ nir_imm_int(b, tail_offset));
+ nir_instr_rewrite_src(&deref->instr, &deref->arr.index,
+ nir_src_for_ssa(index));
+ }
+ }
+}
+
+static void
+rewrite_references(nir_builder *b,
+ nir_instr *instr,
nir_variable *combined,
unsigned cull_offset)
{
- if (instr->type != nir_instr_type_intrinsic)
+ if (instr->type != nir_instr_type_deref)
return;
- nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr);
-
- /* copy_var needs to be lowered to load/store before calling this pass */
- assert(intrin->intrinsic != nir_intrinsic_copy_var);
-
- if (intrin->intrinsic != nir_intrinsic_load_var &&
- intrin->intrinsic != nir_intrinsic_store_var)
+ nir_deref_instr *deref = nir_instr_as_deref(instr);
+ if (deref->deref_type != nir_deref_type_var)
return;
- nir_deref_var *var_ref = intrin->variables[0];
- if (var_ref->var->data.mode != combined->data.mode)
+ if (deref->var->data.mode != combined->data.mode)
return;
- if (var_ref->var->data.location != VARYING_SLOT_CLIP_DIST0 &&
- var_ref->var->data.location != VARYING_SLOT_CULL_DIST0)
+ const unsigned location = deref->var->data.location;
+ if (location != VARYING_SLOT_CLIP_DIST0 &&
+ location != VARYING_SLOT_CULL_DIST0)
return;
- /* Update types along the deref chain */
- const struct glsl_type *type = combined->type;
- nir_deref *deref = &var_ref->deref;
- while (deref) {
- deref->type = type;
- deref = deref->child;
- type = glsl_get_array_element(type);
- }
-
- /* For cull distances, add an offset to the array index */
- if (var_ref->var->data.location == VARYING_SLOT_CULL_DIST0) {
- nir_deref *tail = nir_deref_tail(&intrin->variables[0]->deref);
- nir_deref_array *array_ref = nir_deref_as_array(tail);
-
- array_ref->base_offset += cull_offset;
- }
-
- /* Point the deref at the combined array */
- var_ref->var = combined;
-
- /* There's no need to update writemasks; it's a scalar array. */
+ deref->var = combined;
+ if (location == VARYING_SLOT_CULL_DIST0)
+ rewrite_clip_cull_deref(b, deref, combined->type, cull_offset);
+ else
+ rewrite_clip_cull_deref(b, deref, combined->type, 0);
}
static bool
/* Rewrite CullDistance to reference the combined array */
nir_foreach_function(function, nir) {
if (function->impl) {
+ nir_builder b;
+ nir_builder_init(&b, function->impl);
+
nir_foreach_block(block, function->impl) {
nir_foreach_instr(instr, block) {
- rewrite_references(instr, clip, clip_array_size);
+ rewrite_references(&b, instr, clip, clip_array_size);
}
}
}