[Mesa-dev] [PATCH 03/10] glsl: don't let an 'if' then-branch kill copy propagation for else-branch
Ian Romanick
idr at freedesktop.org
Thu Jun 28 05:31:49 UTC 2018
On 06/27/2018 06:18 PM, Caio Marcelo de Oliveira Filho wrote:
> When handling 'if' in copy propagation, if a certain variable was
> killed when processing the first branch of the 'if', then the second
> would get any propagation from previous nodes.
>
> x = y;
> if (...) {
> z = x; // This would turn into z = y.
> x = 22; // x gets killed.
> } else {
> w = x; // This would NOT turn into w = y.
> }
>
> With the change, we let copy propagation happen independently in the
> two branches and only then apply the killed values for the subsequent
> code.
>
> Results for Skylake:
>
> total instructions in shared programs: 15238463 -> 15238503 (<.01%)
> instructions in affected programs: 10317 -> 10357 (0.39%)
> helped: 0
> HURT: 20
>
> total cycles in shared programs: 571868000 -> 571868028 (<.01%)
> cycles in affected programs: 43507 -> 43535 (0.06%)
> helped: 14
> HURT: 6
>
> The hurt instruction count is caused because the extra propagation
> causes an input variable to be read from two branches of an
> if (load_input intrinsic in NIR). Depending on the complexity of each
> branch this might be a win or not in terms of cycles.
I just sent out a patch (nir/opt_peephole_select: Don't try to remove
flow control around indirect loads) that deals with a similar sort of
thing. Were the cases you observed also indirect loads? Maybe we
should add those to the class of things that don't get copy propagated.
> ---
> src/compiler/glsl/opt_copy_propagation.cpp | 44 ++++++++++++----------
> 1 file changed, 25 insertions(+), 19 deletions(-)
>
> diff --git a/src/compiler/glsl/opt_copy_propagation.cpp b/src/compiler/glsl/opt_copy_propagation.cpp
> index 206dffe4f1c..4ba5eedb2b1 100644
> --- a/src/compiler/glsl/opt_copy_propagation.cpp
> +++ b/src/compiler/glsl/opt_copy_propagation.cpp
> @@ -71,7 +71,7 @@ public:
>
> void add_copy(ir_assignment *ir);
> void kill(ir_variable *ir);
> - void handle_if_block(exec_list *instructions);
> + void handle_if_block(exec_list *instructions, set *kills, bool *killed_all);
>
> /** Hash of lhs->rhs: The available copies to propagate */
> hash_table *acp;
> @@ -207,14 +207,13 @@ ir_copy_propagation_visitor::visit_enter(ir_call *ir)
> }
>
> void
> -ir_copy_propagation_visitor::handle_if_block(exec_list *instructions)
> +ir_copy_propagation_visitor::handle_if_block(exec_list *instructions, set *kills, bool *killed_all)
> {
> hash_table *orig_acp = this->acp;
> set *orig_kills = this->kills;
> bool orig_killed_all = this->killed_all;
>
> - kills = _mesa_set_create(NULL, _mesa_hash_pointer,
> - _mesa_key_pointer_equal);
> + this->kills = kills;
> this->killed_all = false;
>
> /* Populate the initial acp with a copy of the original */
> @@ -222,22 +221,12 @@ ir_copy_propagation_visitor::handle_if_block(exec_list *instructions)
>
> visit_list_elements(this, instructions);
>
> - if (this->killed_all) {
> - _mesa_hash_table_clear(orig_acp, NULL);
> - }
> + _mesa_hash_table_destroy(acp, NULL);
> + *killed_all = this->killed_all;
>
> - set *new_kills = this->kills;
> this->kills = orig_kills;
> - _mesa_hash_table_destroy(acp, NULL);
> this->acp = orig_acp;
> - this->killed_all = this->killed_all || orig_killed_all;
> -
> - struct set_entry *s_entry;
> - set_foreach(new_kills, s_entry) {
> - kill((ir_variable *) s_entry->key);
> - }
> -
> - _mesa_set_destroy(new_kills, NULL);
> + this->killed_all = orig_killed_all;
> }
>
> ir_visitor_status
> @@ -245,8 +234,25 @@ ir_copy_propagation_visitor::visit_enter(ir_if *ir)
> {
> ir->condition->accept(this);
>
> - handle_if_block(&ir->then_instructions);
> - handle_if_block(&ir->else_instructions);
> + set *new_kills = _mesa_set_create(NULL, _mesa_hash_pointer,
> + _mesa_key_pointer_equal);
> + bool then_killed_all = false;
> + bool else_killed_all = false;
> +
> + handle_if_block(&ir->then_instructions, new_kills, &then_killed_all);
> + handle_if_block(&ir->else_instructions, new_kills, &else_killed_all);
> +
> + if (then_killed_all || else_killed_all) {
> + _mesa_hash_table_clear(acp, NULL);
> + killed_all = true;
> + } else {
> + struct set_entry *s_entry;
> + set_foreach(new_kills, s_entry) {
> + kill((ir_variable *) s_entry->key);
> + }
> + }
> +
> + _mesa_set_destroy(new_kills, NULL);
>
> /* handle_if_block() already descended into the children. */
> return visit_continue_with_parent;
>
More information about the mesa-dev
mailing list