1 /*
2 * Copyright © 2020 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 "nir_builder.h"
25
26 static bool
lower_vec3_to_vec4_instr(nir_builder * b,nir_instr * instr,void * data)27 lower_vec3_to_vec4_instr(nir_builder *b, nir_instr *instr, void *data)
28 {
29 nir_variable_mode modes = *((nir_variable_mode *)data);
30
31 switch (instr->type) {
32 case nir_instr_type_deref: {
33 nir_deref_instr *deref = nir_instr_as_deref(instr);
34 if (!nir_deref_mode_is_in_set(deref, modes))
35 return false;
36
37 const struct glsl_type *vec4_type =
38 glsl_type_replace_vec3_with_vec4(deref->type);
39 if (deref->type != vec4_type) {
40 deref->type = vec4_type;
41 return true;
42 }
43 break;
44 }
45
46 case nir_instr_type_intrinsic: {
47 nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr);
48 switch (intrin->intrinsic) {
49 case nir_intrinsic_load_deref: {
50 if (intrin->num_components != 3)
51 break;
52
53 nir_deref_instr *deref = nir_src_as_deref(intrin->src[0]);
54 if (!nir_deref_mode_is_in_set(deref, modes))
55 break;
56
57 intrin->num_components = 4;
58 intrin->def.num_components = 4;
59
60 b->cursor = nir_after_instr(&intrin->instr);
61 nir_def *vec3 = nir_trim_vector(b, &intrin->def, 3);
62 nir_def_rewrite_uses_after(&intrin->def,
63 vec3,
64 vec3->parent_instr);
65 return true;
66 }
67
68 case nir_intrinsic_store_deref: {
69 if (intrin->num_components != 3)
70 break;
71
72 nir_deref_instr *deref = nir_src_as_deref(intrin->src[0]);
73 if (!nir_deref_mode_is_in_set(deref, modes))
74 break;
75
76 nir_def *data = intrin->src[1].ssa;
77
78 b->cursor = nir_before_instr(&intrin->instr);
79 unsigned swiz[] = { 0, 1, 2, 2 };
80 data = nir_swizzle(b, data, swiz, 4);
81
82 intrin->num_components = 4;
83 nir_src_rewrite(&intrin->src[1], data);
84 return true;
85 }
86
87 case nir_intrinsic_copy_deref: {
88 nir_deref_instr *dst = nir_src_as_deref(intrin->src[0]);
89 nir_deref_instr *src = nir_src_as_deref(intrin->src[0]);
90 /* If we convert once side of a copy and not the other, that
91 * would be very bad.
92 */
93 if (nir_deref_mode_may_be(dst, modes) ||
94 nir_deref_mode_may_be(src, modes)) {
95 assert(nir_deref_mode_must_be(dst, modes));
96 assert(nir_deref_mode_must_be(src, modes));
97 }
98 break;
99 }
100
101 default:
102 break;
103 }
104 break;
105 }
106
107 default:
108 break;
109 }
110
111 return false;
112 }
113
114 bool
nir_lower_vec3_to_vec4(nir_shader * shader,nir_variable_mode modes)115 nir_lower_vec3_to_vec4(nir_shader *shader, nir_variable_mode modes)
116 {
117 bool progress = false;
118
119 if (modes & ~nir_var_function_temp) {
120 nir_foreach_variable_in_shader(var, shader) {
121 if (!(var->data.mode & modes))
122 continue;
123
124 const struct glsl_type *vec4_type =
125 glsl_type_replace_vec3_with_vec4(var->type);
126 if (var->type != vec4_type) {
127 var->type = vec4_type;
128 progress = true;
129 }
130 }
131 }
132
133 if (modes & nir_var_function_temp) {
134 nir_foreach_function_impl(impl, shader) {
135 nir_foreach_function_temp_variable(var, impl) {
136 const struct glsl_type *vec4_type =
137 glsl_type_replace_vec3_with_vec4(var->type);
138 if (var->type != vec4_type) {
139 var->type = vec4_type;
140 progress = true;
141 }
142 }
143 }
144 }
145
146 progress |= nir_shader_instructions_pass(shader,
147 lower_vec3_to_vec4_instr,
148 nir_metadata_control_flow,
149 &modes);
150
151 return progress;
152 }
153