5c8bafde9b86063a663bd30e31d8a102cb161608
[mesa.git] / src / gallium / drivers / etnaviv / etnaviv_compiler_nir.h
1 /*
2 * Copyright (c) 2020 Etnaviv Project
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, sub license,
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
12 * next paragraph) shall be included in all copies or substantial portions
13 * of the 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 NON-INFRINGEMENT. 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.
22 *
23 * Authors:
24 * Jonathan Marek <jonathan@marek.ca>
25 */
26
27 #ifndef H_ETNAVIV_COMPILER_NIR
28 #define H_ETNAVIV_COMPILER_NIR
29
30 #include "compiler/nir/nir.h"
31 #include "etnaviv_asm.h"
32 #include "etnaviv_compiler.h"
33 #include "util/register_allocate.h"
34
35 struct etna_compile {
36 nir_shader *nir;
37 nir_function_impl *impl;
38 #define is_fs(c) ((c)->nir->info.stage == MESA_SHADER_FRAGMENT)
39 const struct etna_specs *specs;
40 struct etna_shader_variant *variant;
41
42 /* block # to instr index */
43 unsigned *block_ptr;
44
45 /* Code generation */
46 int inst_ptr; /* current instruction pointer */
47 struct etna_inst code[ETNA_MAX_INSTRUCTIONS * ETNA_INST_SIZE];
48
49 /* constants */
50 uint64_t consts[ETNA_MAX_IMM];
51 unsigned const_count;
52
53 /* ra state */
54 struct ra_graph *g;
55 struct ra_regs *regs;
56 unsigned *live_map;
57 unsigned num_nodes;
58
59 /* There was an error during compilation */
60 bool error;
61 };
62
63 #define compile_error(ctx, args...) ({ \
64 printf(args); \
65 ctx->error = true; \
66 assert(0); \
67 })
68
69 enum {
70 BYPASS_DST = 1,
71 BYPASS_SRC = 2,
72 };
73
74 static inline bool is_sysval(nir_instr *instr)
75 {
76 if (instr->type != nir_instr_type_intrinsic)
77 return false;
78
79 nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
80 return intr->intrinsic == nir_intrinsic_load_front_face ||
81 intr->intrinsic == nir_intrinsic_load_frag_coord;
82 }
83
84 /* get unique ssa/reg index for nir_src */
85 static inline unsigned
86 src_index(nir_function_impl *impl, nir_src *src)
87 {
88 return src->is_ssa ? src->ssa->index : (src->reg.reg->index + impl->ssa_alloc);
89 }
90
91 /* get unique ssa/reg index for nir_dest */
92 static inline unsigned
93 dest_index(nir_function_impl *impl, nir_dest *dest)
94 {
95 return dest->is_ssa ? dest->ssa.index : (dest->reg.reg->index + impl->ssa_alloc);
96 }
97
98 static inline void
99 update_swiz_mask(nir_alu_instr *alu, nir_dest *dest, unsigned *swiz, unsigned *mask)
100 {
101 if (!swiz)
102 return;
103
104 bool is_vec = dest != NULL;
105 unsigned swizzle = 0, write_mask = 0;
106 for (unsigned i = 0; i < 4; i++) {
107 /* channel not written */
108 if (!(alu->dest.write_mask & (1 << i)))
109 continue;
110 /* src is different (only check for vecN) */
111 if (is_vec && alu->src[i].src.ssa != &dest->ssa)
112 continue;
113
114 unsigned src_swiz = is_vec ? alu->src[i].swizzle[0] : alu->src[0].swizzle[i];
115 swizzle |= (*swiz >> src_swiz * 2 & 3) << i * 2;
116 /* this channel isn't written through this chain */
117 if (*mask & (1 << src_swiz))
118 write_mask |= 1 << i;
119 }
120 *swiz = swizzle;
121 *mask = write_mask;
122 }
123
124 static nir_dest *
125 real_dest(nir_dest *dest, unsigned *swiz, unsigned *mask)
126 {
127 if (!dest || !dest->is_ssa)
128 return dest;
129
130 bool can_bypass_src = !list_length(&dest->ssa.if_uses);
131 nir_instr *p_instr = dest->ssa.parent_instr;
132
133 /* if used by a vecN, the "real" destination becomes the vecN destination
134 * lower_alu guarantees that values used by a vecN are only used by that vecN
135 * we can apply the same logic to movs in a some cases too
136 */
137 nir_foreach_use(use_src, &dest->ssa) {
138 nir_instr *instr = use_src->parent_instr;
139
140 /* src bypass check: for now only deal with tex src mov case
141 * note: for alu don't bypass mov for multiple uniform sources
142 */
143 switch (instr->type) {
144 case nir_instr_type_tex:
145 if (p_instr->type == nir_instr_type_alu &&
146 nir_instr_as_alu(p_instr)->op == nir_op_mov) {
147 break;
148 }
149 default:
150 can_bypass_src = false;
151 break;
152 }
153
154 if (instr->type != nir_instr_type_alu)
155 continue;
156
157 nir_alu_instr *alu = nir_instr_as_alu(instr);
158
159 switch (alu->op) {
160 case nir_op_vec2:
161 case nir_op_vec3:
162 case nir_op_vec4:
163 assert(list_length(&dest->ssa.if_uses) == 0);
164 nir_foreach_use(use_src, &dest->ssa)
165 assert(use_src->parent_instr == instr);
166
167 update_swiz_mask(alu, dest, swiz, mask);
168 break;
169 case nir_op_mov: {
170 switch (dest->ssa.parent_instr->type) {
171 case nir_instr_type_alu:
172 case nir_instr_type_tex:
173 break;
174 default:
175 continue;
176 }
177 if (list_length(&dest->ssa.if_uses) || list_length(&dest->ssa.uses) > 1)
178 continue;
179
180 update_swiz_mask(alu, NULL, swiz, mask);
181 break;
182 };
183 default:
184 continue;
185 }
186
187 assert(!(instr->pass_flags & BYPASS_SRC));
188 instr->pass_flags |= BYPASS_DST;
189 return real_dest(&alu->dest.dest, swiz, mask);
190 }
191
192 if (can_bypass_src && !(p_instr->pass_flags & BYPASS_DST)) {
193 p_instr->pass_flags |= BYPASS_SRC;
194 return NULL;
195 }
196
197 return dest;
198 }
199
200 /* if instruction dest needs a register, return nir_dest for it */
201 static inline nir_dest *
202 dest_for_instr(nir_instr *instr)
203 {
204 nir_dest *dest = NULL;
205
206 switch (instr->type) {
207 case nir_instr_type_alu:
208 dest = &nir_instr_as_alu(instr)->dest.dest;
209 break;
210 case nir_instr_type_tex:
211 dest = &nir_instr_as_tex(instr)->dest;
212 break;
213 case nir_instr_type_intrinsic: {
214 nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
215 if (intr->intrinsic == nir_intrinsic_load_uniform ||
216 intr->intrinsic == nir_intrinsic_load_ubo ||
217 intr->intrinsic == nir_intrinsic_load_input ||
218 intr->intrinsic == nir_intrinsic_load_instance_id)
219 dest = &intr->dest;
220 } break;
221 case nir_instr_type_deref:
222 return NULL;
223 default:
224 break;
225 }
226 return real_dest(dest, NULL, NULL);
227 }
228
229 struct live_def {
230 nir_instr *instr;
231 nir_dest *dest; /* cached dest_for_instr */
232 unsigned live_start, live_end; /* live range */
233 };
234
235 unsigned
236 etna_live_defs(nir_function_impl *impl, struct live_def *defs, unsigned *live_map);
237
238 #endif