aboutsummaryrefslogtreecommitdiffstats
path: root/src/compiler/nir/nir_search.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/compiler/nir/nir_search.c')
-rw-r--r--src/compiler/nir/nir_search.c126
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;
+}