size_align(var->type, &var_size, &var_align);
assert(var->data.location % var_align == 0);
+ UNUSED unsigned deref_size, deref_align;
+ size_align(deref->type, &deref_size, &deref_align);
+
nir_intrinsic_instr *load =
nir_intrinsic_instr_create(b->shader, nir_intrinsic_load_constant);
load->num_components = num_components;
nir_intrinsic_set_base(load, var->data.location);
nir_intrinsic_set_range(load, var_size);
+ nir_intrinsic_set_align(load, deref_align, 0);
load->src[0] = nir_src_for_ssa(nir_build_deref_offset(b, deref, size_align));
nir_ssa_dest_init(&load->instr, &load->dest,
num_components, bit_size, NULL);
if (load->dest.ssa.bit_size < 8) {
/* Booleans are special-cased to be 32-bit */
assert(glsl_type_is_boolean(deref->type));
+ assert(deref_size == num_components * 4);
load->dest.ssa.bit_size = 32;
return nir_b2b1(b, &load->dest.ssa);
} else {
+ assert(deref_size == num_components * bit_size / 8);
return &load->dest.ssa;
}
}
/* This only works with a single entrypoint */
nir_function_impl *impl = nir_shader_get_entrypoint(shader);
- /* This pass can only be run once */
- assert(shader->constant_data == NULL && shader->constant_data_size == 0);
-
- unsigned num_locals = exec_list_length(&impl->locals);
- nir_index_vars(shader, impl, nir_var_function_temp);
+ unsigned num_locals = nir_function_impl_index_vars(impl);
- if (num_locals == 0)
+ if (num_locals == 0) {
+ nir_shader_preserve_all_metadata(shader);
return false;
+ }
struct var_info *var_infos = ralloc_array(NULL, struct var_info, num_locals);
- nir_foreach_variable(var, &impl->locals) {
+ nir_foreach_function_temp_variable(var, impl) {
var_infos[var->index] = (struct var_info) {
.var = var,
.is_constant = true,
*/
nir_foreach_block(block, impl) {
nir_foreach_instr(instr, block) {
+ if (instr->type == nir_instr_type_deref) {
+ /* If we ever see a complex use of a deref_var, we have to assume
+ * that variable is non-constant because we can't guarantee we
+ * will find all of the writers of that variable.
+ */
+ nir_deref_instr *deref = nir_instr_as_deref(instr);
+ if (deref->deref_type == nir_deref_type_var &&
+ deref->mode == nir_var_function_temp &&
+ nir_deref_instr_has_complex_use(deref))
+ var_infos[deref->var->index].is_constant = false;
+ continue;
+ }
+
if (instr->type != nir_instr_type_intrinsic)
continue;
if (dst_deref && dst_deref->mode == nir_var_function_temp) {
nir_variable *var = nir_deref_instr_get_variable(dst_deref);
+ if (var == NULL)
+ continue;
+
assert(var->data.mode == nir_var_function_temp);
struct var_info *info = &var_infos[var->index];
if (src_deref && src_deref->mode == nir_var_function_temp) {
nir_variable *var = nir_deref_instr_get_variable(src_deref);
+ if (var == NULL)
+ continue;
+
assert(var->data.mode == nir_var_function_temp);
/* We only consider variables constant if all the reads are
* data. We sort them by size and content so we can easily find
* duplicates.
*/
- shader->constant_data_size = 0;
+ const unsigned old_constant_data_size = shader->constant_data_size;
qsort(var_infos, num_locals, sizeof(struct var_info), var_info_cmp);
for (int i = 0; i < num_locals; i++) {
struct var_info *info = &var_infos[i];
}
}
- if (shader->constant_data_size == 0) {
+ if (shader->constant_data_size == old_constant_data_size) {
+ nir_shader_preserve_all_metadata(shader);
ralloc_free(var_infos);
return false;
}
- shader->constant_data = rzalloc_size(shader, shader->constant_data_size);
+ assert(shader->constant_data_size > old_constant_data_size);
+ shader->constant_data = rerzalloc_size(shader, shader->constant_data,
+ old_constant_data_size,
+ shader->constant_data_size);
for (int i = 0; i < num_locals; i++) {
struct var_info *info = &var_infos[i];
if (!info->duplicate && info->is_constant) {
continue;
nir_variable *var = nir_deref_instr_get_variable(deref);
+ if (var == NULL)
+ continue;
+
struct var_info *info = &var_infos[var->index];
if (info->is_constant) {
b.cursor = nir_after_instr(&intrin->instr);
continue;
nir_variable *var = nir_deref_instr_get_variable(deref);
+ if (var == NULL)
+ continue;
+
struct var_info *info = &var_infos[var->index];
if (info->is_constant) {
nir_instr_remove(&intrin->instr);