2 * Copyright © 2014 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 DEALINGS
24 * Jason Ekstrand (jason@jlekstrand.net)
29 #include "compiler/nir_types.h"
32 * Lowers all copy intrinsics to sequences of load/store intrinsics.
35 /* Walks down the deref chain and returns the next deref in the chain whose
36 * child is a wildcard. In other words, given the chain a[1].foo[*].bar,
37 * this function will return the deref to foo. Calling it a second time
38 * with the [*].bar, it will return NULL.
41 deref_next_wildcard_parent(nir_deref
*deref
)
43 for (nir_deref
*tail
= deref
; tail
->child
; tail
= tail
->child
) {
44 if (tail
->child
->deref_type
!= nir_deref_type_array
)
47 nir_deref_array
*arr
= nir_deref_as_array(tail
->child
);
49 if (arr
->deref_array_type
== nir_deref_array_type_wildcard
)
56 /* This function recursively walks the given deref chain and replaces the
57 * given copy instruction with an equivalent sequence load/store
60 * @copy_instr The copy instruction to replace; new instructions will be
61 * inserted before this one
63 * @dest_head The head of the destination variable deref chain
65 * @src_head The head of the source variable deref chain
67 * @dest_tail The current tail of the destination variable deref chain;
68 * this is used for recursion and external callers of this
69 * function should call it with tail == head
71 * @src_tail The current tail of the source variable deref chain;
72 * this is used for recursion and external callers of this
73 * function should call it with tail == head
75 * @state The current variable lowering state
78 emit_copy_load_store(nir_intrinsic_instr
*copy_instr
,
79 nir_deref_var
*dest_head
, nir_deref_var
*src_head
,
80 nir_deref
*dest_tail
, nir_deref
*src_tail
, void *mem_ctx
)
82 /* Find the next pair of wildcards */
83 nir_deref
*src_arr_parent
= deref_next_wildcard_parent(src_tail
);
84 nir_deref
*dest_arr_parent
= deref_next_wildcard_parent(dest_tail
);
86 if (src_arr_parent
|| dest_arr_parent
) {
87 /* Wildcards had better come in matched pairs */
88 assert(dest_arr_parent
&& dest_arr_parent
);
90 nir_deref_array
*src_arr
= nir_deref_as_array(src_arr_parent
->child
);
91 nir_deref_array
*dest_arr
= nir_deref_as_array(dest_arr_parent
->child
);
93 unsigned length
= glsl_get_length(src_arr_parent
->type
);
94 /* The wildcards should represent the same number of elements */
95 assert(length
== glsl_get_length(dest_arr_parent
->type
));
98 /* Walk over all of the elements that this wildcard refers to and
99 * call emit_copy_load_store on each one of them */
100 src_arr
->deref_array_type
= nir_deref_array_type_direct
;
101 dest_arr
->deref_array_type
= nir_deref_array_type_direct
;
102 for (unsigned i
= 0; i
< length
; i
++) {
103 src_arr
->base_offset
= i
;
104 dest_arr
->base_offset
= i
;
105 emit_copy_load_store(copy_instr
, dest_head
, src_head
,
106 &dest_arr
->deref
, &src_arr
->deref
, mem_ctx
);
108 src_arr
->deref_array_type
= nir_deref_array_type_wildcard
;
109 dest_arr
->deref_array_type
= nir_deref_array_type_wildcard
;
111 /* In this case, we have no wildcards anymore, so all we have to do
112 * is just emit the load and store operations. */
113 src_tail
= nir_deref_tail(src_tail
);
114 dest_tail
= nir_deref_tail(dest_tail
);
116 assert(src_tail
->type
== dest_tail
->type
);
118 unsigned num_components
= glsl_get_vector_elements(src_tail
->type
);
120 glsl_get_bit_size(glsl_get_base_type(src_tail
->type
));
122 nir_intrinsic_instr
*load
=
123 nir_intrinsic_instr_create(mem_ctx
, nir_intrinsic_load_var
);
124 load
->num_components
= num_components
;
125 load
->variables
[0] = nir_deref_as_var(nir_copy_deref(load
, &src_head
->deref
));
126 nir_ssa_dest_init(&load
->instr
, &load
->dest
, num_components
, bit_size
,
129 nir_instr_insert_before(©_instr
->instr
, &load
->instr
);
131 nir_intrinsic_instr
*store
=
132 nir_intrinsic_instr_create(mem_ctx
, nir_intrinsic_store_var
);
133 store
->num_components
= num_components
;
134 nir_intrinsic_set_write_mask(store
, (1 << num_components
) - 1);
135 store
->variables
[0] = nir_deref_as_var(nir_copy_deref(store
, &dest_head
->deref
));
137 store
->src
[0].is_ssa
= true;
138 store
->src
[0].ssa
= &load
->dest
.ssa
;
140 nir_instr_insert_before(©_instr
->instr
, &store
->instr
);
144 /* Lowers a copy instruction to a sequence of load/store instructions
146 * The new instructions are placed before the copy instruction in the IR.
149 nir_lower_var_copy_instr(nir_intrinsic_instr
*copy
, void *mem_ctx
)
151 assert(copy
->intrinsic
== nir_intrinsic_copy_var
);
152 emit_copy_load_store(copy
, copy
->variables
[0], copy
->variables
[1],
153 ©
->variables
[0]->deref
,
154 ©
->variables
[1]->deref
, mem_ctx
);
158 lower_var_copies_block(nir_block
*block
, void *mem_ctx
)
160 nir_foreach_instr_safe(block
, instr
) {
161 if (instr
->type
!= nir_instr_type_intrinsic
)
164 nir_intrinsic_instr
*copy
= nir_instr_as_intrinsic(instr
);
165 if (copy
->intrinsic
!= nir_intrinsic_copy_var
)
168 nir_lower_var_copy_instr(copy
, mem_ctx
);
170 nir_instr_remove(©
->instr
);
178 lower_var_copies_impl(nir_function_impl
*impl
)
180 nir_foreach_block_call(impl
, lower_var_copies_block
, ralloc_parent(impl
));
183 /* Lowers every copy_var instruction in the program to a sequence of
184 * load/store instructions.
187 nir_lower_var_copies(nir_shader
*shader
)
189 nir_foreach_function(shader
, function
) {
191 lower_var_copies_impl(function
->impl
);