<p dir="ltr"><br>
On Jul 16, 2015 5:19 PM, "Kenneth Graunke" <<a href="mailto:kenneth@whitecape.org">kenneth@whitecape.org</a>> wrote:<br>
><br>
> From: Connor Abbott <<a href="mailto:connor.w.abbott@intel.com">connor.w.abbott@intel.com</a>><br>
><br>
> This will split the block containing the instruction and put the CF node<br>
> in between.<br>
><br>
> v2: (by Kenneth Graunke)<br>
> - Simplify split_block_after_instr()'s implementation by using<br>
> split_block_end() rather than duplicating code.<br>
> - Fix a bug in nir_cf_node_insert_after_instr() where inserting a<br>
> non-block after the last instruction would cause update_if_uses()<br>
> to be called twice, making us try to add the same SSA def to the<br>
> if_uses list twice, corrupting the list.<br>
> - Comment changes.<br>
><br>
> Cc: Jason Ekstrand <<a href="mailto:jason@jlekstrand.net">jason@jlekstrand.net</a>><br>
> Signed-off-by: Kenneth Graunke <<a href="mailto:kenneth@whitecape.org">kenneth@whitecape.org</a>><br>
> ---<br>
> src/glsl/nir/nir.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++<br>
> src/glsl/nir/nir.h | 3 +++<br>
> 2 files changed, 65 insertions(+)<br>
><br>
> Nothing uses this yet, but I've tested it with my SIMD8 geometry shader patches,<br>
> which use this to replace emit_vertex intrinsics with if blocks (for "safety<br>
> checks" that make sure the program hasn't emitted too many vertices). It seems<br>
> to work just fine, and seems like a really useful piece of infrastructure to<br>
> have, so I'm submitting it now.<br>
><br>
> Jason, would you mind reviewing it, since Connor and I both hacked on it?<br>
> It would be nice to have a non-author take a look at it :)<br>
><br>
> diff --git a/src/glsl/nir/nir.c b/src/glsl/nir/nir.c<br>
> index 78ff886..0c53bab 100644<br>
> --- a/src/glsl/nir/nir.c<br>
> +++ b/src/glsl/nir/nir.c<br>
> @@ -843,6 +843,29 @@ split_block_end(nir_block *block)<br>
> }<br>
><br>
> /**<br>
> + * Creates a new block, and moves all the instructions after the given<br>
> + * instruction to the new block.<br>
> + */<br>
> +static nir_block *<br>
> +split_block_after_instr(nir_instr *instr)<br>
> +{<br>
> + /* We don't have to do anything special for handling jump instructions,<br>
> + * as this will move the successors associated with the jump to the new<br>
> + * block already.<br>
> + */<br>
> + nir_block *new_block = split_block_end(instr->block);<br>
> +<br>
> + nir_instr *cur_instr;<br>
> + while ((cur_instr = nir_instr_next(instr)) != NULL) {</p>
<p dir="ltr">Please use a for loop or pull the iteration expression out. This is really obtuse.</p>
<p dir="ltr">Otherwise, at first glance this looks pretty good. I'd like to take a longer look before I call it reviewed though.</p>
<p dir="ltr">> + exec_node_remove(&cur_instr->node);<br>
> + exec_list_push_tail(&new_block->instr_list, &cur_instr->node);</p>
<p dir="ltr">At some point we should get a better mechanism for list splicing. Don't bother with it now because I'm hoping to move NIR to the list in until before too long. We can make the change then.</p>
<p dir="ltr">> + cur_instr->block = new_block;<br>
> + }<br>
> +<br>
> + return new_block;<br>
> +}<br>
> +<br>
> +/**<br>
> * Inserts a non-basic block between two basic blocks and links them together.<br>
> */<br>
><br>
> @@ -1124,6 +1147,45 @@ nir_cf_node_insert_after(nir_cf_node *node, nir_cf_node *after)<br>
> }<br>
><br>
> void<br>
> +nir_cf_node_insert_after_instr(nir_instr *instr, nir_cf_node *after)<br>
> +{<br>
> + /* If the instruction is the last in its block, then this is equivalent<br>
> + * to inserting the CF node after this block. Just call that, to avoid<br>
> + * attempting to split blocks unnecessarily.<br>
> + */<br>
> + if (nir_instr_is_last(instr)) {<br>
> + nir_cf_node_insert_after(&instr->block->cf_node, after);<br>
> + return;<br>
> + }<br>
> +<br>
> + update_if_uses(after);<br>
> +<br>
> + if (after->type == nir_cf_node_block) {<br>
> + /* We're attempting to insert a block after an instruction; instead,<br>
> + * just move all of the instructions into the existing block. Actually<br>
> + * removing and adding them would involve removing and adding uses/defs,<br>
> + * which we don't need to do, so just take them off the list directly.<br>
> + */<br>
> + nir_block *after_block = nir_cf_node_as_block(after);<br>
> + nir_foreach_instr_safe_reverse(after_block, new_instr) {<br>
> + exec_node_remove(&new_instr->node);<br>
> + new_instr->block = instr->block;<br>
> + exec_node_insert_after(&instr->node, &new_instr->node);<br>
> + }<br>
> + } else {<br>
> + /* We're inserting a loop or if after an instruction. Split up the<br>
> + * basic block and insert it between those two blocks.<br>
> + */<br>
> + nir_block *before_block = instr->block;<br>
> + nir_block *after_block = split_block_after_instr(instr);<br>
> + insert_non_block(before_block, after, after_block);<br>
> + }<br>
> +<br>
> + nir_function_impl *impl = nir_cf_node_get_function(&instr->block->cf_node);<br>
> + nir_metadata_preserve(impl, nir_metadata_none);<br>
> +}<br>
> +<br>
> +void<br>
> nir_cf_node_insert_before(nir_cf_node *node, nir_cf_node *before)<br>
> {<br>
> update_if_uses(before);<br>
> diff --git a/src/glsl/nir/nir.h b/src/glsl/nir/nir.h<br>
> index 62cdbd4..6efbc18 100644<br>
> --- a/src/glsl/nir/nir.h<br>
> +++ b/src/glsl/nir/nir.h<br>
> @@ -1506,6 +1506,9 @@ void nir_cf_node_insert_after(nir_cf_node *node, nir_cf_node *after);<br>
> /** puts a control flow node immediately before another control flow node */<br>
> void nir_cf_node_insert_before(nir_cf_node *node, nir_cf_node *before);<br>
><br>
> +/** puts a control flow node immediately after a given instruction */<br>
> +void nir_cf_node_insert_after_instr(nir_instr *instr, nir_cf_node *after);<br>
> +<br>
> /** puts a control flow node at the beginning of a list from an if, loop, or function */<br>
> void nir_cf_node_insert_begin(struct exec_list *list, nir_cf_node *node);<br>
><br>
> --<br>
> 2.4.5<br>
><br>
</p>