2 * Copyright © 2016 Intel Corporation
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
27 add_src(nir_src
*src
, struct set
*invariants
)
30 _mesa_set_add(invariants
, src
->ssa
);
32 _mesa_set_add(invariants
, src
->reg
.reg
);
37 add_src_cb(nir_src
*src
, void *state
)
44 dest_is_invariant(nir_dest
*dest
, struct set
*invariants
)
47 return _mesa_set_search(invariants
, &dest
->ssa
);
49 return _mesa_set_search(invariants
, dest
->reg
.reg
);
54 add_cf_node(nir_cf_node
*cf
, struct set
*invariants
)
56 if (cf
->type
== nir_cf_node_if
) {
57 nir_if
*if_stmt
= nir_cf_node_as_if(cf
);
58 add_src(&if_stmt
->condition
, invariants
);
62 add_cf_node(cf
->parent
, invariants
);
66 add_var(nir_variable
*var
, struct set
*invariants
)
68 /* Because we pass the result of nir_intrinsic_get_var directly to this
69 * function, it's possible for var to be NULL if, for instance, there's a
70 * cast somewhere in the chain.
73 _mesa_set_add(invariants
, var
);
77 var_is_invariant(nir_variable
*var
, struct set
* invariants
)
79 /* Because we pass the result of nir_intrinsic_get_var directly to this
80 * function, it's possible for var to be NULL if, for instance, there's a
81 * cast somewhere in the chain.
83 return var
&& (var
->data
.invariant
|| _mesa_set_search(invariants
, var
));
87 propagate_invariant_instr(nir_instr
*instr
, struct set
*invariants
)
89 switch (instr
->type
) {
90 case nir_instr_type_alu
: {
91 nir_alu_instr
*alu
= nir_instr_as_alu(instr
);
92 if (!dest_is_invariant(&alu
->dest
.dest
, invariants
))
96 nir_foreach_src(instr
, add_src_cb
, invariants
);
100 case nir_instr_type_tex
: {
101 nir_tex_instr
*tex
= nir_instr_as_tex(instr
);
102 if (dest_is_invariant(&tex
->dest
, invariants
))
103 nir_foreach_src(instr
, add_src_cb
, invariants
);
107 case nir_instr_type_intrinsic
: {
108 nir_intrinsic_instr
*intrin
= nir_instr_as_intrinsic(instr
);
109 switch (intrin
->intrinsic
) {
110 case nir_intrinsic_copy_deref
:
111 /* If the destination is invariant then so is the source */
112 if (var_is_invariant(nir_intrinsic_get_var(intrin
, 0), invariants
))
113 add_var(nir_intrinsic_get_var(intrin
, 1), invariants
);
116 case nir_intrinsic_load_deref
:
117 if (dest_is_invariant(&intrin
->dest
, invariants
))
118 add_var(nir_intrinsic_get_var(intrin
, 0), invariants
);
121 case nir_intrinsic_store_deref
:
122 if (var_is_invariant(nir_intrinsic_get_var(intrin
, 0), invariants
))
123 add_src(&intrin
->src
[1], invariants
);
132 case nir_instr_type_deref
:
133 case nir_instr_type_jump
:
134 case nir_instr_type_ssa_undef
:
135 case nir_instr_type_load_const
:
136 break; /* Nothing to do */
138 case nir_instr_type_phi
: {
139 nir_phi_instr
*phi
= nir_instr_as_phi(instr
);
140 if (!dest_is_invariant(&phi
->dest
, invariants
))
143 nir_foreach_phi_src(src
, phi
) {
144 add_src(&src
->src
, invariants
);
145 add_cf_node(&src
->pred
->cf_node
, invariants
);
150 case nir_instr_type_call
:
151 unreachable("This pass must be run after function inlining");
153 case nir_instr_type_parallel_copy
:
155 unreachable("Cannot have this instruction type");
160 propagate_invariant_impl(nir_function_impl
*impl
, struct set
*invariants
)
162 bool progress
= false;
165 uint32_t prev_entries
= invariants
->entries
;
167 nir_foreach_block_reverse(block
, impl
) {
168 nir_foreach_instr_reverse(instr
, block
)
169 propagate_invariant_instr(instr
, invariants
);
172 /* Keep running until we make no more progress. */
173 if (invariants
->entries
> prev_entries
) {
182 nir_metadata_preserve(impl
, nir_metadata_block_index
|
183 nir_metadata_dominance
|
184 nir_metadata_live_ssa_defs
);
191 nir_propagate_invariant(nir_shader
*shader
)
193 /* Hash set of invariant things */
194 struct set
*invariants
= _mesa_pointer_set_create(NULL
);
196 bool progress
= false;
197 nir_foreach_function(function
, shader
) {
198 if (function
->impl
&& propagate_invariant_impl(function
->impl
, invariants
))
202 _mesa_set_destroy(invariants
, NULL
);