1 /*
2 * Copyright © 2022 Imagination Technologies Ltd.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * 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 THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 */
23
24 #include "nir/nir.h"
25 #include "nir/nir_builder.h"
26 #include "nir/nir_search_helpers.h"
27 #include "rogue.h"
28 #include "util/macros.h"
29
30 #include <assert.h>
31 #include <stdbool.h>
32 #include <stdint.h>
33
34 /**
35 * \file rogue_nir_lower_io.c
36 *
37 * \brief Contains the rogue_nir_lower_io pass.
38 */
39
lower_vulkan_resource_index(nir_builder * b,nir_intrinsic_instr * intr)40 static void lower_vulkan_resource_index(nir_builder *b,
41 nir_intrinsic_instr *intr)
42 {
43 /* Pass along the desc_set, binding, desc_type. */
44 unsigned desc_set = nir_intrinsic_desc_set(intr);
45 unsigned binding = nir_intrinsic_binding(intr);
46 unsigned desc_type = nir_intrinsic_desc_type(intr);
47
48 nir_def *def = nir_vec3(b,
49 nir_imm_int(b, desc_set),
50 nir_imm_int(b, binding),
51 nir_imm_int(b, desc_type));
52 nir_def_replace(&intr->def, def);
53 }
54
lower_load_global_constant_to_scalar(nir_builder * b,nir_intrinsic_instr * intr)55 static void lower_load_global_constant_to_scalar(nir_builder *b,
56 nir_intrinsic_instr *intr)
57 {
58 /* Scalarize the load_global_constant. */
59 b->cursor = nir_before_instr(&intr->instr);
60
61 assert(intr->num_components > 1);
62
63 nir_def *loads[NIR_MAX_VEC_COMPONENTS];
64
65 for (uint8_t i = 0; i < intr->num_components; i++) {
66 nir_intrinsic_instr *chan_intr =
67 nir_intrinsic_instr_create(b->shader, intr->intrinsic);
68 nir_def_init(&chan_intr->instr, &chan_intr->def, 1,
69 intr->def.bit_size);
70 chan_intr->num_components = 1;
71
72 nir_intrinsic_set_access(chan_intr, nir_intrinsic_access(intr));
73 nir_intrinsic_set_align_mul(chan_intr, nir_intrinsic_align_mul(intr));
74 nir_intrinsic_set_align_offset(chan_intr,
75 nir_intrinsic_align_offset(intr));
76
77 /* Address. */
78 chan_intr->src[0] =
79 nir_src_for_ssa(nir_iadd_imm(b, intr->src[0].ssa, i * 4));
80
81 nir_builder_instr_insert(b, &chan_intr->instr);
82
83 loads[i] = &chan_intr->def;
84 }
85
86 nir_def_replace(&intr->def, nir_vec(b, loads, intr->num_components));
87 }
88
lower_intrinsic(nir_builder * b,nir_intrinsic_instr * instr)89 static bool lower_intrinsic(nir_builder *b, nir_intrinsic_instr *instr)
90 {
91 switch (instr->intrinsic) {
92 case nir_intrinsic_vulkan_resource_index:
93 lower_vulkan_resource_index(b, instr);
94 return true;
95
96 case nir_intrinsic_load_global_constant:
97 lower_load_global_constant_to_scalar(b, instr);
98 return true;
99
100 default:
101 break;
102 }
103
104 return false;
105 }
106
lower_impl(nir_function_impl * impl)107 static bool lower_impl(nir_function_impl *impl)
108 {
109 bool progress = false;
110 nir_builder b = nir_builder_create(impl);
111
112 nir_foreach_block (block, impl) {
113 nir_foreach_instr_safe (instr, block) {
114 b.cursor = nir_before_instr(instr);
115 switch (instr->type) {
116 case nir_instr_type_intrinsic:
117 progress |= lower_intrinsic(&b, nir_instr_as_intrinsic(instr));
118 break;
119
120 default:
121 break;
122 }
123 }
124 }
125
126 if (progress)
127 nir_metadata_preserve(impl, nir_metadata_none);
128 else
129 nir_metadata_preserve(impl, nir_metadata_all);
130
131 return progress;
132 }
133
134 PUBLIC
rogue_nir_lower_io(nir_shader * shader)135 bool rogue_nir_lower_io(nir_shader *shader)
136 {
137 bool progress = false;
138
139 nir_foreach_function (function, shader) {
140 if (function->impl)
141 progress |= lower_impl(function->impl);
142 }
143
144 if (progress)
145 nir_opt_dce(shader);
146
147 return progress;
148 }
149