etnaviv: move liveness related stuff into own file
[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
32 #define compile_error(ctx, args...) ({ \
33 printf(args); \
34 ctx->error = true; \
35 assert(0); \
36 })
37
38 enum {
39 BYPASS_DST = 1,
40 BYPASS_SRC = 2,
41 };
42
43 static inline bool is_sysval(nir_instr *instr)
44 {
45 if (instr->type != nir_instr_type_intrinsic)
46 return false;
47
48 nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
49 return intr->intrinsic == nir_intrinsic_load_front_face ||
50 intr->intrinsic == nir_intrinsic_load_frag_coord;
51 }
52
53 /* get unique ssa/reg index for nir_src */
54 static inline unsigned
55 src_index(nir_function_impl *impl, nir_src *src)
56 {
57 return src->is_ssa ? src->ssa->index : (src->reg.reg->index + impl->ssa_alloc);
58 }
59
60 /* get unique ssa/reg index for nir_dest */
61 static inline unsigned
62 dest_index(nir_function_impl *impl, nir_dest *dest)
63 {
64 return dest->is_ssa ? dest->ssa.index : (dest->reg.reg->index + impl->ssa_alloc);
65 }
66
67 static inline void
68 update_swiz_mask(nir_alu_instr *alu, nir_dest *dest, unsigned *swiz, unsigned *mask)
69 {
70 if (!swiz)
71 return;
72
73 bool is_vec = dest != NULL;
74 unsigned swizzle = 0, write_mask = 0;
75 for (unsigned i = 0; i < 4; i++) {
76 /* channel not written */
77 if (!(alu->dest.write_mask & (1 << i)))
78 continue;
79 /* src is different (only check for vecN) */
80 if (is_vec && alu->src[i].src.ssa != &dest->ssa)
81 continue;
82
83 unsigned src_swiz = is_vec ? alu->src[i].swizzle[0] : alu->src[0].swizzle[i];
84 swizzle |= (*swiz >> src_swiz * 2 & 3) << i * 2;
85 /* this channel isn't written through this chain */
86 if (*mask & (1 << src_swiz))
87 write_mask |= 1 << i;
88 }
89 *swiz = swizzle;
90 *mask = write_mask;
91 }
92
93 static nir_dest *
94 real_dest(nir_dest *dest, unsigned *swiz, unsigned *mask)
95 {
96 if (!dest || !dest->is_ssa)
97 return dest;
98
99 bool can_bypass_src = !list_length(&dest->ssa.if_uses);
100 nir_instr *p_instr = dest->ssa.parent_instr;
101
102 /* if used by a vecN, the "real" destination becomes the vecN destination
103 * lower_alu guarantees that values used by a vecN are only used by that vecN
104 * we can apply the same logic to movs in a some cases too
105 */
106 nir_foreach_use(use_src, &dest->ssa) {
107 nir_instr *instr = use_src->parent_instr;
108
109 /* src bypass check: for now only deal with tex src mov case
110 * note: for alu don't bypass mov for multiple uniform sources
111 */
112 switch (instr->type) {
113 case nir_instr_type_tex:
114 if (p_instr->type == nir_instr_type_alu &&
115 nir_instr_as_alu(p_instr)->op == nir_op_mov) {
116 break;
117 }
118 default:
119 can_bypass_src = false;
120 break;
121 }
122
123 if (instr->type != nir_instr_type_alu)
124 continue;
125
126 nir_alu_instr *alu = nir_instr_as_alu(instr);
127
128 switch (alu->op) {
129 case nir_op_vec2:
130 case nir_op_vec3:
131 case nir_op_vec4:
132 assert(list_length(&dest->ssa.if_uses) == 0);
133 nir_foreach_use(use_src, &dest->ssa)
134 assert(use_src->parent_instr == instr);
135
136 update_swiz_mask(alu, dest, swiz, mask);
137 break;
138 case nir_op_mov: {
139 switch (dest->ssa.parent_instr->type) {
140 case nir_instr_type_alu:
141 case nir_instr_type_tex:
142 break;
143 default:
144 continue;
145 }
146 if (list_length(&dest->ssa.if_uses) || list_length(&dest->ssa.uses) > 1)
147 continue;
148
149 update_swiz_mask(alu, NULL, swiz, mask);
150 break;
151 };
152 default:
153 continue;
154 }
155
156 assert(!(instr->pass_flags & BYPASS_SRC));
157 instr->pass_flags |= BYPASS_DST;
158 return real_dest(&alu->dest.dest, swiz, mask);
159 }
160
161 if (can_bypass_src && !(p_instr->pass_flags & BYPASS_DST)) {
162 p_instr->pass_flags |= BYPASS_SRC;
163 return NULL;
164 }
165
166 return dest;
167 }
168
169 /* if instruction dest needs a register, return nir_dest for it */
170 static inline nir_dest *
171 dest_for_instr(nir_instr *instr)
172 {
173 nir_dest *dest = NULL;
174
175 switch (instr->type) {
176 case nir_instr_type_alu:
177 dest = &nir_instr_as_alu(instr)->dest.dest;
178 break;
179 case nir_instr_type_tex:
180 dest = &nir_instr_as_tex(instr)->dest;
181 break;
182 case nir_instr_type_intrinsic: {
183 nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
184 if (intr->intrinsic == nir_intrinsic_load_uniform ||
185 intr->intrinsic == nir_intrinsic_load_ubo ||
186 intr->intrinsic == nir_intrinsic_load_input ||
187 intr->intrinsic == nir_intrinsic_load_instance_id)
188 dest = &intr->dest;
189 } break;
190 case nir_instr_type_deref:
191 return NULL;
192 default:
193 break;
194 }
195 return real_dest(dest, NULL, NULL);
196 }
197
198 struct live_def {
199 nir_instr *instr;
200 nir_dest *dest; /* cached dest_for_instr */
201 unsigned live_start, live_end; /* live range */
202 };
203
204 unsigned
205 etna_live_defs(nir_function_impl *impl, struct live_def *defs, unsigned *live_map);
206
207 #endif