diff options
Diffstat (limited to 'src/compiler/nir/nir_search.c')
-rw-r--r-- | src/compiler/nir/nir_search.c | 126 |
1 files changed, 126 insertions, 0 deletions
diff --git a/src/compiler/nir/nir_search.c b/src/compiler/nir/nir_search.c index d126319b256..db2a606c7b6 100644 --- a/src/compiler/nir/nir_search.c +++ b/src/compiler/nir/nir_search.c @@ -692,3 +692,129 @@ nir_replace_instr(nir_builder *build, nir_alu_instr *instr, return ssa_val; } + +static void +nir_algebraic_automaton(nir_block *block, uint16_t *states, + const struct per_op_table *pass_op_table) +{ + nir_foreach_instr(instr, block) { + switch (instr->type) { + case nir_instr_type_alu: { + nir_alu_instr *alu = nir_instr_as_alu(instr); + nir_op op = alu->op; + uint16_t search_op = nir_search_op_for_nir_op(op); + const struct per_op_table *tbl = &pass_op_table[search_op]; + if (tbl->num_filtered_states == 0) + continue; + + /* Calculate the index into the transition table. Note the index + * calculated must match the iteration order of Python's + * itertools.product(), which was used to emit the transition + * table. + */ + uint16_t index = 0; + for (unsigned i = 0; i < nir_op_infos[op].num_inputs; i++) { + index *= tbl->num_filtered_states; + index += tbl->filter[states[alu->src[i].src.ssa->index]]; + } + states[alu->dest.dest.ssa.index] = tbl->table[index]; + break; + } + + case nir_instr_type_load_const: { + nir_load_const_instr *load_const = nir_instr_as_load_const(instr); + states[load_const->def.index] = CONST_STATE; + break; + } + + default: + break; + } + } +} + +static bool +nir_algebraic_block(nir_builder *build, nir_block *block, + struct hash_table *range_ht, + const bool *condition_flags, + const struct transform **transforms, + const uint16_t *transform_counts, + const uint16_t *states) +{ + bool progress = false; + const unsigned execution_mode = build->shader->info.float_controls_execution_mode; + + nir_foreach_instr_reverse_safe(instr, block) { + if (instr->type != nir_instr_type_alu) + continue; + + nir_alu_instr *alu = nir_instr_as_alu(instr); + if (!alu->dest.dest.is_ssa) + continue; + + unsigned bit_size = alu->dest.dest.ssa.bit_size; + const bool ignore_inexact = + nir_is_float_control_signed_zero_inf_nan_preserve(execution_mode, bit_size) || + nir_is_denorm_flush_to_zero(execution_mode, bit_size); + + int xform_idx = states[alu->dest.dest.ssa.index]; + for (uint16_t i = 0; i < transform_counts[xform_idx]; i++) { + const struct transform *xform = &transforms[xform_idx][i]; + if (condition_flags[xform->condition_offset] && + !(xform->search->inexact && ignore_inexact) && + nir_replace_instr(build, alu, range_ht, + xform->search, xform->replace)) { + _mesa_hash_table_clear(range_ht, NULL); + progress = true; + break; + } + } + } + + return progress; +} + +bool +nir_algebraic_impl(nir_function_impl *impl, + const bool *condition_flags, + const struct transform **transforms, + const uint16_t *transform_counts, + const struct per_op_table *pass_op_table) +{ + bool progress = false; + + nir_builder build; + nir_builder_init(&build, impl); + + /* Note: it's important here that we're allocating a zeroed array, since + * state 0 is the default state, which means we don't have to visit + * anything other than constants and ALU instructions. + */ + uint16_t *states = calloc(impl->ssa_alloc, sizeof(*states)); + + struct hash_table *range_ht = _mesa_pointer_hash_table_create(NULL); + + nir_foreach_block(block, impl) { + nir_algebraic_automaton(block, states, pass_op_table); + } + + nir_foreach_block_reverse(block, impl) { + progress |= nir_algebraic_block(&build, block, range_ht, condition_flags, + transforms, transform_counts, + states); + } + + ralloc_free(range_ht); + free(states); + + if (progress) { + nir_metadata_preserve(impl, nir_metadata_block_index | + nir_metadata_dominance); + } else { +#ifndef NDEBUG + impl->valid_metadata &= ~nir_metadata_not_properly_reset; +#endif + } + + return progress; +} |