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 _mesa_set_add(invariants
, var
);
72 var_is_invariant(nir_variable
*var
, struct set
* invariants
)
74 return var
->data
.invariant
|| _mesa_set_search(invariants
, var
);
78 intrinsic_get_var(nir_intrinsic_instr
*intrin
, unsigned i
)
80 return nir_deref_instr_get_variable(nir_src_as_deref(intrin
->src
[i
]));
84 propagate_invariant_instr(nir_instr
*instr
, struct set
*invariants
)
86 switch (instr
->type
) {
87 case nir_instr_type_alu
: {
88 nir_alu_instr
*alu
= nir_instr_as_alu(instr
);
89 if (!dest_is_invariant(&alu
->dest
.dest
, invariants
))
93 nir_foreach_src(instr
, add_src_cb
, invariants
);
97 case nir_instr_type_tex
: {
98 nir_tex_instr
*tex
= nir_instr_as_tex(instr
);
99 if (dest_is_invariant(&tex
->dest
, invariants
))
100 nir_foreach_src(instr
, add_src_cb
, invariants
);
104 case nir_instr_type_intrinsic
: {
105 nir_intrinsic_instr
*intrin
= nir_instr_as_intrinsic(instr
);
106 switch (intrin
->intrinsic
) {
107 case nir_intrinsic_copy_deref
:
108 /* If the destination is invariant then so is the source */
109 if (var_is_invariant(intrinsic_get_var(intrin
, 0), invariants
))
110 add_var(intrinsic_get_var(intrin
, 1), invariants
);
113 case nir_intrinsic_load_deref
:
114 if (dest_is_invariant(&intrin
->dest
, invariants
))
115 add_var(intrinsic_get_var(intrin
, 0), invariants
);
118 case nir_intrinsic_store_deref
:
119 if (var_is_invariant(intrinsic_get_var(intrin
, 0), invariants
))
120 add_src(&intrin
->src
[1], invariants
);
129 case nir_instr_type_deref
:
130 case nir_instr_type_jump
:
131 case nir_instr_type_ssa_undef
:
132 case nir_instr_type_load_const
:
133 break; /* Nothing to do */
135 case nir_instr_type_phi
: {
136 nir_phi_instr
*phi
= nir_instr_as_phi(instr
);
137 if (!dest_is_invariant(&phi
->dest
, invariants
))
140 nir_foreach_phi_src(src
, phi
) {
141 add_src(&src
->src
, invariants
);
142 add_cf_node(&src
->pred
->cf_node
, invariants
);
147 case nir_instr_type_call
:
148 unreachable("This pass must be run after function inlining");
150 case nir_instr_type_parallel_copy
:
152 unreachable("Cannot have this instruction type");
157 propagate_invariant_impl(nir_function_impl
*impl
, struct set
*invariants
)
159 bool progress
= false;
162 uint32_t prev_entries
= invariants
->entries
;
164 nir_foreach_block_reverse(block
, impl
) {
165 nir_foreach_instr_reverse(instr
, block
)
166 propagate_invariant_instr(instr
, invariants
);
169 /* Keep running until we make no more progress. */
170 if (invariants
->entries
> prev_entries
) {
179 nir_metadata_preserve(impl
, nir_metadata_block_index
|
180 nir_metadata_dominance
|
181 nir_metadata_live_ssa_defs
);
188 nir_propagate_invariant(nir_shader
*shader
)
190 /* Hash set of invariant things */
191 struct set
*invariants
= _mesa_set_create(NULL
, _mesa_hash_pointer
,
192 _mesa_key_pointer_equal
);
194 nir_assert_unlowered_derefs(shader
, nir_lower_load_store_derefs
);
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
);