}
bool
-nir_instr_set_add_or_rewrite(struct set *instr_set, nir_instr *instr)
+nir_instr_set_add_or_rewrite(struct set *instr_set, nir_instr *instr,
+ bool (*cond_function) (const nir_instr *a,
+ const nir_instr *b))
{
if (!instr_can_rewrite(instr))
return false;
struct set_entry *e = _mesa_set_search_or_add(instr_set, instr, NULL);
nir_instr *match = (nir_instr *) e->key;
- if (match != instr) {
+ if (match == instr)
+ return false;
+
+ if (!cond_function || cond_function(match, instr)) {
+ /* rewrite instruction if condition is matched */
nir_ssa_def *def = nir_instr_get_dest_ssa_def(instr);
nir_ssa_def *new_def = nir_instr_get_dest_ssa_def(match);
nir_instr_as_alu(match)->exact = true;
nir_ssa_def_rewrite_uses(def, new_def);
+
+ nir_instr_remove(instr);
+
return true;
+ } else {
+ /* otherwise, replace hashed instruction */
+ e->key = instr;
+ return false;
}
-
- return false;
}
void
void nir_instr_set_destroy(struct set *instr_set);
/**
- * Adds an instruction to an instruction set if it doesn't exist, or if it
+ * Adds an instruction to an instruction set if it doesn't exist. If it
* does already exist, rewrites all uses of it to point to the other
* already-inserted instruction. Returns 'true' if the uses of the instruction
- * were rewritten.
+ * were rewritten. Otherwise, replaces the already-inserted instruction
+ * with the new one.
+ *
+ * If cond_function() is given, only rewrites uses if
+ * cond_function(old_instr, new_instr) returns true.
*/
-bool nir_instr_set_add_or_rewrite(struct set *instr_set, nir_instr *instr);
+bool nir_instr_set_add_or_rewrite(struct set *instr_set, nir_instr *instr,
+ bool (*cond_function)(const nir_instr *a,
+ const nir_instr *b));
/**
* Removes an instruction from an instruction set, so that other instructions
* Implements common subexpression elimination
*/
-/*
- * Visits and CSEs the given block and all its descendants in the dominance
- * tree recursively. Note that the instr_set is guaranteed to only ever
- * contain instructions that dominate the current block.
- */
-
static bool
-cse_block(nir_block *block, struct set *dominance_set)
+dominates(const nir_instr *old_instr, const nir_instr *new_instr)
{
- bool progress = false;
- struct set *instr_set = _mesa_set_clone(dominance_set, NULL);
-
- nir_foreach_instr_safe(instr, block) {
- if (nir_instr_set_add_or_rewrite(instr_set, instr)) {
- progress = true;
- nir_instr_remove(instr);
- }
- }
-
- for (unsigned i = 0; i < block->num_dom_children; i++) {
- nir_block *child = block->dom_children[i];
- progress |= cse_block(child, instr_set);
- }
-
- _mesa_set_destroy(instr_set, NULL);
-
- return progress;
+ return nir_block_dominates(old_instr->block, new_instr->block);
}
static bool
nir_metadata_require(impl, nir_metadata_dominance);
- bool progress = cse_block(nir_start_block(impl), instr_set);
+ bool progress = false;
+ nir_foreach_block(block, impl) {
+ nir_foreach_instr_safe(instr, block)
+ progress |= nir_instr_set_add_or_rewrite(instr_set, instr, dominates);
+ }
if (progress) {
nir_metadata_preserve(impl, nir_metadata_block_index |
if (value_number) {
struct set *gvn_set = nir_instr_set_create(NULL);
foreach_list_typed_safe(nir_instr, instr, node, &state.instrs) {
- if (nir_instr_set_add_or_rewrite(gvn_set, instr)) {
- nir_instr_remove(instr);
+ if (nir_instr_set_add_or_rewrite(gvn_set, instr, NULL))
state.progress = true;
- }
}
nir_instr_set_destroy(gvn_set);
}