nir: Factor out most of the algebraic passes C code to .c/.h.

Working on the algebraic implementation, I was being driven nuts by my
editor not highlighting and handling indentation for the C code.  It turns
out that it's basically not pass-specific code, and we can move it over to
the relevant .c file.  Replaces 30KB of code with 34KB of data on my i965
build.  No perf diff on shader-db (n=3)

Reviewed-by: Ian Romanick <ian.d.romainck@intel.com>
Reviewed-by: Connor Abbott <cwabbott0@gmail.com>
This commit is contained in:
Eric Anholt
2019-09-23 14:36:32 -07:00
parent c23db0df18
commit 3cc914921e
3 changed files with 173 additions and 146 deletions

View File

@@ -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;
}