lima/ppir: implement discard and discard_if
[mesa.git] / src / gallium / drivers / lima / ir / pp / instr.c
1 /*
2 * Copyright (c) 2017 Lima 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 */
24
25 #include "util/ralloc.h"
26
27 #include "ppir.h"
28
29 ppir_instr *ppir_instr_create(ppir_block *block)
30 {
31 ppir_instr *instr = rzalloc(block, ppir_instr);
32 if (!instr)
33 return NULL;
34
35 list_inithead(&instr->succ_list);
36 list_inithead(&instr->pred_list);
37
38 instr->index = block->comp->cur_instr_index++;
39 instr->reg_pressure = -1;
40
41 list_addtail(&instr->list, &block->instr_list);
42 return instr;
43 }
44
45 void ppir_instr_add_dep(ppir_instr *succ, ppir_instr *pred)
46 {
47 /* don't add duplicated instr */
48 ppir_instr_foreach_pred(succ, dep) {
49 if (pred == dep->pred)
50 return;
51 }
52
53 ppir_dep *dep = ralloc(succ, ppir_dep);
54 dep->pred = pred;
55 dep->succ = succ;
56 list_addtail(&dep->pred_link, &succ->pred_list);
57 list_addtail(&dep->succ_link, &pred->succ_list);
58 }
59
60 void ppir_instr_insert_mul_node(ppir_node *add, ppir_node *mul)
61 {
62 ppir_instr *instr = add->instr;
63 int pos = mul->instr_pos;
64 int *slots = ppir_op_infos[mul->op].slots;
65
66 for (int i = 0; slots[i] != PPIR_INSTR_SLOT_END; i++) {
67 /* possible to insert at required place */
68 if (slots[i] == pos) {
69 if (!instr->slots[pos]) {
70 ppir_alu_node *add_alu = ppir_node_to_alu(add);
71 ppir_alu_node *mul_alu = ppir_node_to_alu(mul);
72 ppir_dest *dest = &mul_alu->dest;
73 int pipeline = pos == PPIR_INSTR_SLOT_ALU_VEC_MUL ?
74 ppir_pipeline_reg_vmul : ppir_pipeline_reg_fmul;
75
76 /* ^vmul/^fmul can't be used as last arg */
77 if (add_alu->num_src > 1) {
78 ppir_src *last_src = add_alu->src + add_alu->num_src - 1;
79 if (ppir_node_target_equal(last_src, dest))
80 return;
81 }
82
83 /* update add node src to use pipeline reg */
84 ppir_src *src = add_alu->src;
85 if (add_alu->num_src == 3) {
86 if (ppir_node_target_equal(src, dest)) {
87 src->type = ppir_target_pipeline;
88 src->pipeline = pipeline;
89 }
90
91 if (ppir_node_target_equal(++src, dest)) {
92 src->type = ppir_target_pipeline;
93 src->pipeline = pipeline;
94 }
95 }
96 else {
97 assert(ppir_node_target_equal(src, dest));
98 src->type = ppir_target_pipeline;
99 src->pipeline = pipeline;
100 }
101
102 /* update mul node dest to output to pipeline reg */
103 dest->type = ppir_target_pipeline;
104 dest->pipeline = pipeline;
105
106 instr->slots[pos] = mul;
107 mul->instr = instr;
108 }
109 return;
110 }
111 }
112 }
113
114 /* check whether a const slot fix into another const slot */
115 static bool ppir_instr_insert_const(ppir_const *dst, const ppir_const *src,
116 uint8_t *swizzle)
117 {
118 int i, j;
119
120 for (i = 0; i < src->num; i++) {
121 for (j = 0; j < dst->num; j++) {
122 if (src->value[i].ui == dst->value[j].ui)
123 break;
124 }
125
126 if (j == dst->num) {
127 if (dst->num == 4)
128 return false;
129 dst->value[dst->num++] = src->value[i];
130 }
131
132 swizzle[i] = j;
133 }
134
135 return true;
136 }
137
138 static void ppir_update_src_pipeline(ppir_pipeline pipeline, ppir_src *src,
139 ppir_dest *dest, uint8_t *swizzle)
140 {
141 if (ppir_node_target_equal(src, dest)) {
142 src->type = ppir_target_pipeline;
143 src->pipeline = pipeline;
144
145 if (swizzle) {
146 for (int k = 0; k < 4; k++)
147 src->swizzle[k] = swizzle[src->swizzle[k]];
148 }
149 }
150 }
151
152 /* make alu node src reflact the pipeline reg */
153 static void ppir_instr_update_src_pipeline(ppir_instr *instr, ppir_pipeline pipeline,
154 ppir_dest *dest, uint8_t *swizzle)
155 {
156 for (int i = PPIR_INSTR_SLOT_ALU_START; i <= PPIR_INSTR_SLOT_ALU_END; i++) {
157 if (!instr->slots[i])
158 continue;
159
160 ppir_alu_node *alu = ppir_node_to_alu(instr->slots[i]);
161 for (int j = 0; j < alu->num_src; j++) {
162 ppir_src *src = alu->src + j;
163 ppir_update_src_pipeline(pipeline, src, dest, swizzle);
164 }
165 }
166
167 ppir_node *branch_node = instr->slots[PPIR_INSTR_SLOT_BRANCH];
168 if (branch_node && (branch_node->type == ppir_node_type_branch)) {
169 ppir_branch_node *branch = ppir_node_to_branch(branch_node);
170 for (int j = 0; j < 2; j++) {
171 ppir_src *src = branch->src + j;
172 ppir_update_src_pipeline(pipeline, src, dest, swizzle);
173 }
174 }
175 }
176
177 bool ppir_instr_insert_node(ppir_instr *instr, ppir_node *node)
178 {
179 if (node->op == ppir_op_const) {
180 int i;
181 ppir_const_node *c = ppir_node_to_const(node);
182 const ppir_const *nc = &c->constant;
183
184 for (i = 0; i < 2; i++) {
185 ppir_const ic = instr->constant[i];
186 uint8_t swizzle[4] = {0};
187
188 if (ppir_instr_insert_const(&ic, nc, swizzle)) {
189 instr->constant[i] = ic;
190 ppir_instr_update_src_pipeline(
191 instr, ppir_pipeline_reg_const0 + i, &c->dest, swizzle);
192 break;
193 }
194 }
195
196 /* no const slot can insert */
197 if (i == 2)
198 return false;
199
200 return true;
201 }
202 else {
203 int *slots = ppir_op_infos[node->op].slots;
204 for (int i = 0; slots[i] != PPIR_INSTR_SLOT_END; i++) {
205 int pos = slots[i];
206
207 if (instr->slots[pos]) {
208 /* node already in this instr, i.e. load_uniform */
209 if (instr->slots[pos] == node)
210 return true;
211 else
212 continue;
213 }
214
215 if (pos == PPIR_INSTR_SLOT_ALU_SCL_MUL ||
216 pos == PPIR_INSTR_SLOT_ALU_SCL_ADD) {
217 ppir_dest *dest = ppir_node_get_dest(node);
218 if (!ppir_target_is_scaler(dest))
219 continue;
220 }
221
222 instr->slots[pos] = node;
223 node->instr = instr;
224 node->instr_pos = pos;
225
226 if ((node->op == ppir_op_load_uniform) || (node->op == ppir_op_load_temp)) {
227 ppir_load_node *l = ppir_node_to_load(node);
228 ppir_instr_update_src_pipeline(
229 instr, ppir_pipeline_reg_uniform, &l->dest, NULL);
230 }
231
232 return true;
233 }
234
235 return false;
236 }
237 }
238
239 static struct {
240 int len;
241 char *name;
242 } ppir_instr_fields[] = {
243 [PPIR_INSTR_SLOT_VARYING] = { 4, "vary" },
244 [PPIR_INSTR_SLOT_TEXLD] = { 4, "texl"},
245 [PPIR_INSTR_SLOT_UNIFORM] = { 4, "unif" },
246 [PPIR_INSTR_SLOT_ALU_VEC_MUL] = { 4, "vmul" },
247 [PPIR_INSTR_SLOT_ALU_SCL_MUL] = { 4, "smul" },
248 [PPIR_INSTR_SLOT_ALU_VEC_ADD] = { 4, "vadd" },
249 [PPIR_INSTR_SLOT_ALU_SCL_ADD] = { 4, "sadd" },
250 [PPIR_INSTR_SLOT_ALU_COMBINE] = { 4, "comb" },
251 [PPIR_INSTR_SLOT_STORE_TEMP] = { 4, "stor" },
252 [PPIR_INSTR_SLOT_BRANCH] = { 4, "brch" },
253 };
254
255 void ppir_instr_print_list(ppir_compiler *comp)
256 {
257 if (!(lima_debug & LIMA_DEBUG_PP))
258 return;
259
260 printf("======ppir instr list======\n");
261 printf(" ");
262 for (int i = 0; i < PPIR_INSTR_SLOT_NUM; i++)
263 printf("%-*s ", ppir_instr_fields[i].len, ppir_instr_fields[i].name);
264 printf("const0|1\n");
265
266 list_for_each_entry(ppir_block, block, &comp->block_list, list) {
267 list_for_each_entry(ppir_instr, instr, &block->instr_list, list) {
268 printf("%c%03d: ", instr->is_end ? '*' : ' ', instr->index);
269 for (int i = 0; i < PPIR_INSTR_SLOT_NUM; i++) {
270 ppir_node *node = instr->slots[i];
271 if (node)
272 printf("%-*d ", ppir_instr_fields[i].len, node->index);
273 else
274 printf("%-*s ", ppir_instr_fields[i].len, "null");
275 }
276 for (int i = 0; i < 2; i++) {
277 if (i)
278 printf("| ");
279
280 for (int j = 0; j < instr->constant[i].num; j++)
281 printf("%f ", instr->constant[i].value[j].f);
282 }
283 printf("\n");
284 }
285 printf("------------------------\n");
286 }
287 }
288
289 static void ppir_instr_print_sub(ppir_instr *instr)
290 {
291 printf("[%s%d",
292 instr->printed && !ppir_instr_is_leaf(instr) ? "+" : "",
293 instr->index);
294
295 if (!instr->printed) {
296 ppir_instr_foreach_pred(instr, dep) {
297 ppir_instr_print_sub(dep->pred);
298 }
299
300 instr->printed = true;
301 }
302
303 printf("]");
304 }
305
306 void ppir_instr_print_dep(ppir_compiler *comp)
307 {
308 if (!(lima_debug & LIMA_DEBUG_PP))
309 return;
310
311 list_for_each_entry(ppir_block, block, &comp->block_list, list) {
312 list_for_each_entry(ppir_instr, instr, &block->instr_list, list) {
313 instr->printed = false;
314 }
315 }
316
317 printf("======ppir instr depend======\n");
318 list_for_each_entry(ppir_block, block, &comp->block_list, list) {
319 list_for_each_entry(ppir_instr, instr, &block->instr_list, list) {
320 if (ppir_instr_is_root(instr)) {
321 ppir_instr_print_sub(instr);
322 printf("\n");
323 }
324 }
325 printf("------------------------\n");
326 }
327 }