1 /*
2 * Copyright © 2014 Intel Corporation
3 *
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:
10 *
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
13 * Software.
14 *
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
21 * IN THE SOFTWARE.
22 */
23
24 #include "compiler/glsl_types.h"
25 #include "nir.h"
26 #include "nir_builder.h"
27 #include "nir_deref.h"
28
29 /*
30 * Lowers all copy intrinsics to sequences of load/store intrinsics.
31 */
32
33 static nir_deref_instr *
build_deref_to_next_wildcard(nir_builder * b,nir_deref_instr * parent,nir_deref_instr *** deref_arr)34 build_deref_to_next_wildcard(nir_builder *b,
35 nir_deref_instr *parent,
36 nir_deref_instr ***deref_arr)
37 {
38 for (; **deref_arr; (*deref_arr)++) {
39 if ((**deref_arr)->deref_type == nir_deref_type_array_wildcard)
40 return parent;
41
42 parent = nir_build_deref_follower(b, parent, **deref_arr);
43 }
44
45 assert(**deref_arr == NULL);
46 *deref_arr = NULL;
47 return parent;
48 }
49
50 static void
emit_deref_copy_load_store(nir_builder * b,nir_deref_instr * dst_deref,nir_deref_instr ** dst_deref_arr,nir_deref_instr * src_deref,nir_deref_instr ** src_deref_arr,enum gl_access_qualifier dst_access,enum gl_access_qualifier src_access)51 emit_deref_copy_load_store(nir_builder *b,
52 nir_deref_instr *dst_deref,
53 nir_deref_instr **dst_deref_arr,
54 nir_deref_instr *src_deref,
55 nir_deref_instr **src_deref_arr,
56 enum gl_access_qualifier dst_access,
57 enum gl_access_qualifier src_access)
58 {
59 if (dst_deref_arr || src_deref_arr) {
60 assert(dst_deref_arr && src_deref_arr);
61 dst_deref = build_deref_to_next_wildcard(b, dst_deref, &dst_deref_arr);
62 src_deref = build_deref_to_next_wildcard(b, src_deref, &src_deref_arr);
63 }
64
65 if (dst_deref_arr || src_deref_arr) {
66 assert(dst_deref_arr && src_deref_arr);
67 assert((*dst_deref_arr)->deref_type == nir_deref_type_array_wildcard);
68 assert((*src_deref_arr)->deref_type == nir_deref_type_array_wildcard);
69
70 unsigned length = glsl_get_length(src_deref->type);
71 /* The wildcards should represent the same number of elements */
72 assert(length == glsl_get_length(dst_deref->type));
73 assert(length > 0);
74
75 for (unsigned i = 0; i < length; i++) {
76 emit_deref_copy_load_store(b,
77 nir_build_deref_array_imm(b, dst_deref, i),
78 dst_deref_arr + 1,
79 nir_build_deref_array_imm(b, src_deref, i),
80 src_deref_arr + 1, dst_access, src_access);
81 }
82 } else {
83 assert(glsl_get_bare_type(dst_deref->type) ==
84 glsl_get_bare_type(src_deref->type));
85 assert(glsl_type_is_vector_or_scalar(dst_deref->type));
86
87 nir_store_deref_with_access(b, dst_deref,
88 nir_load_deref_with_access(b, src_deref, src_access),
89 ~0, src_access);
90 }
91 }
92
93 void
nir_lower_deref_copy_instr(nir_builder * b,nir_intrinsic_instr * copy)94 nir_lower_deref_copy_instr(nir_builder *b, nir_intrinsic_instr *copy)
95 {
96 /* Unfortunately, there's just no good way to handle wildcards except to
97 * flip the chain around and walk the list from variable to final pointer.
98 */
99 nir_deref_instr *dst = nir_instr_as_deref(copy->src[0].ssa->parent_instr);
100 nir_deref_instr *src = nir_instr_as_deref(copy->src[1].ssa->parent_instr);
101
102 nir_deref_path dst_path, src_path;
103 nir_deref_path_init(&dst_path, dst, NULL);
104 nir_deref_path_init(&src_path, src, NULL);
105
106 b->cursor = nir_before_instr(©->instr);
107 emit_deref_copy_load_store(b, dst_path.path[0], &dst_path.path[1],
108 src_path.path[0], &src_path.path[1],
109 nir_intrinsic_dst_access(copy),
110 nir_intrinsic_src_access(copy));
111
112 nir_deref_path_finish(&dst_path);
113 nir_deref_path_finish(&src_path);
114 }
115
116 static bool
lower_var_copies_instr(nir_builder * b,nir_intrinsic_instr * copy,void * data)117 lower_var_copies_instr(nir_builder *b, nir_intrinsic_instr *copy, void *data)
118 {
119 if (copy->intrinsic != nir_intrinsic_copy_deref)
120 return false;
121
122 nir_lower_deref_copy_instr(b, copy);
123
124 nir_instr_remove(©->instr);
125 nir_deref_instr_remove_if_unused(nir_src_as_deref(copy->src[0]));
126 nir_deref_instr_remove_if_unused(nir_src_as_deref(copy->src[1]));
127
128 nir_instr_free(©->instr);
129 return true;
130 }
131
132 /* Lowers every copy_var instruction in the program to a sequence of
133 * load/store instructions.
134 */
135 bool
nir_lower_var_copies(nir_shader * shader)136 nir_lower_var_copies(nir_shader *shader)
137 {
138 shader->info.var_copies_lowered = true;
139
140 return nir_shader_intrinsics_pass(shader, lower_var_copies_instr,
141 nir_metadata_control_flow,
142 NULL);
143 }
144