diff options
author | Jason Ekstrand <[email protected]> | 2015-11-12 08:40:17 -0800 |
---|---|---|
committer | Jason Ekstrand <[email protected]> | 2015-11-23 11:04:49 -0800 |
commit | 7e83fd85aa9e448aa588b3e981fdc8e026dd51b9 (patch) | |
tree | 986547ee7ac3a26d4ca20affbcd1fd04c4a5376c | |
parent | 384396a69bdfec9971337863ae69266c7fa4a2e8 (diff) |
nir: Add a ssa_def_rewrite_uses_after helper
Reviewed-by: Connor Abbott <[email protected]>
-rw-r--r-- | src/glsl/nir/nir.c | 49 | ||||
-rw-r--r-- | src/glsl/nir/nir.h | 2 |
2 files changed, 51 insertions, 0 deletions
diff --git a/src/glsl/nir/nir.c b/src/glsl/nir/nir.c index 470469429dd..bfec11e53ff 100644 --- a/src/glsl/nir/nir.c +++ b/src/glsl/nir/nir.c @@ -1319,6 +1319,55 @@ nir_ssa_def_rewrite_uses(nir_ssa_def *def, nir_src new_src) nir_if_rewrite_condition(use_src->parent_if, new_src); } +static bool +is_instr_between(nir_instr *start, nir_instr *end, nir_instr *between) +{ + assert(start->block == end->block); + + if (between->block != start->block) + return false; + + /* Search backwards looking for "between" */ + while (start != end) { + if (between == end) + return true; + + end = nir_instr_prev(end); + assert(end); + } + + return false; +} + +/* Replaces all uses of the given SSA def with the given source but only if + * the use comes after the after_me instruction. This can be useful if you + * are emitting code to fix up the result of some instruction: you can freely + * use the result in that code and then call rewrite_uses_after and pass the + * last fixup instruction as after_me and it will replace all of the uses you + * want without touching the fixup code. + * + * This function assumes that after_me is in the same block as + * def->parent_instr and that after_me comes after def->parent_instr. + */ +void +nir_ssa_def_rewrite_uses_after(nir_ssa_def *def, nir_src new_src, + nir_instr *after_me) +{ + assert(!new_src.is_ssa || def != new_src.ssa); + + nir_foreach_use_safe(def, use_src) { + assert(use_src->parent_instr != def->parent_instr); + /* Since def already dominates all of its uses, the only way a use can + * not be dominated by after_me is if it is between def and after_me in + * the instruction list. + */ + if (!is_instr_between(def->parent_instr, after_me, use_src->parent_instr)) + nir_instr_rewrite_src(use_src->parent_instr, use_src, new_src); + } + + nir_foreach_if_use_safe(def, use_src) + nir_if_rewrite_condition(use_src->parent_if, new_src); +} static bool foreach_cf_node(nir_cf_node *node, nir_foreach_block_cb cb, bool reverse, void *state); diff --git a/src/glsl/nir/nir.h b/src/glsl/nir/nir.h index 28c85459021..2bdfcb80faf 100644 --- a/src/glsl/nir/nir.h +++ b/src/glsl/nir/nir.h @@ -1868,6 +1868,8 @@ void nir_ssa_dest_init(nir_instr *instr, nir_dest *dest, void nir_ssa_def_init(nir_instr *instr, nir_ssa_def *def, unsigned num_components, const char *name); void nir_ssa_def_rewrite_uses(nir_ssa_def *def, nir_src new_src); +void nir_ssa_def_rewrite_uses_after(nir_ssa_def *def, nir_src new_src, + nir_instr *after_me); /* visits basic blocks in source-code order */ typedef bool (*nir_foreach_block_cb)(nir_block *block, void *state); |