0ff7e7eabc24786dae00ec66ef1c5cfbfed77c13
[mesa.git] / src / gallium / drivers / lima / ir / gp / 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 <string.h>
26
27 #include "util/ralloc.h"
28
29 #include "gpir.h"
30
31 gpir_instr *gpir_instr_create(gpir_block *block)
32 {
33 gpir_instr *instr = rzalloc(block, gpir_instr);
34 if (unlikely(!instr))
35 return NULL;
36
37 instr->index = block->sched.instr_index++;
38 instr->alu_num_slot_free = 6;
39
40 list_add(&instr->list, &block->instr_list);
41 return instr;
42 }
43
44 static gpir_node *gpir_instr_get_the_other_acc_node(gpir_instr *instr, int slot)
45 {
46 if (slot == GPIR_INSTR_SLOT_ADD0)
47 return instr->slots[GPIR_INSTR_SLOT_ADD1];
48 else if (slot == GPIR_INSTR_SLOT_ADD1)
49 return instr->slots[GPIR_INSTR_SLOT_ADD0];
50
51 return NULL;
52 }
53
54 static bool gpir_instr_check_acc_same_op(gpir_instr *instr, gpir_node *node, int slot)
55 {
56 /* two ACC slots must share the same op code */
57 gpir_node *acc_node = gpir_instr_get_the_other_acc_node(instr, slot);
58
59 /* spill move case may get acc_node == node */
60 if (acc_node && acc_node != node &&
61 !gpir_codegen_acc_same_op(node->op, acc_node->op))
62 return false;
63
64 return true;
65 }
66
67 static int gpir_instr_get_consume_slot(gpir_instr *instr, gpir_node *node)
68 {
69 if (gpir_op_infos[node->op].may_consume_two_slots) {
70 gpir_node *acc_node = gpir_instr_get_the_other_acc_node(instr, node->sched.pos);
71 if (acc_node)
72 /* at this point node must have the same acc op with acc_node,
73 * so it just consumes the extra slot acc_node consumed */
74 return 0;
75 else
76 return 2;
77 }
78 else
79 return 1;
80 }
81
82 static bool gpir_instr_insert_alu_check(gpir_instr *instr, gpir_node *node)
83 {
84 if (!gpir_instr_check_acc_same_op(instr, node, node->sched.pos))
85 return false;
86
87 int consume_slot = gpir_instr_get_consume_slot(instr, node);
88
89 /* check if this node is child of one store node.
90 * complex1 won't be any of this instr's store node's child,
91 * because it has two instr latency before store can use it.
92 */
93 for (int i = GPIR_INSTR_SLOT_STORE0; i < GPIR_INSTR_SLOT_STORE3; i++) {
94 gpir_store_node *s = gpir_node_to_store(instr->slots[i]);
95 if (s && s->child == node) {
96 /* acc node may consume 2 slots, so even it's the child of a
97 * store node, it may not be inserted successfully, in which
98 * case we need a move node for it */
99 if (instr->alu_num_slot_free - consume_slot <
100 instr->alu_num_slot_needed_by_store - 1)
101 return false;
102
103 instr->alu_num_slot_needed_by_store--;
104 instr->alu_num_slot_free -= consume_slot;
105 return true;
106 }
107 }
108
109 /* not a child of any store node, so must reserve alu slot for store node */
110 if (instr->alu_num_slot_free - consume_slot <
111 instr->alu_num_slot_needed_by_store)
112 return false;
113
114 instr->alu_num_slot_free -= consume_slot;
115 return true;
116 }
117
118 static void gpir_instr_remove_alu(gpir_instr *instr, gpir_node *node)
119 {
120 int consume_slot = gpir_instr_get_consume_slot(instr, node);
121
122 for (int i = GPIR_INSTR_SLOT_STORE0; i < GPIR_INSTR_SLOT_STORE3; i++) {
123 gpir_store_node *s = gpir_node_to_store(instr->slots[i]);
124 if (s && s->child == node) {
125 instr->alu_num_slot_needed_by_store++;
126 instr->alu_num_slot_free += consume_slot;
127 return;
128 }
129 }
130
131 instr->alu_num_slot_free += consume_slot;
132 }
133
134 static bool gpir_instr_insert_reg0_check(gpir_instr *instr, gpir_node *node)
135 {
136 gpir_load_node *load = gpir_node_to_load(node);
137 int i = node->sched.pos - GPIR_INSTR_SLOT_REG0_LOAD0;
138
139 if (load->component != i)
140 return false;
141
142 if (instr->reg0_is_attr && node->op != gpir_op_load_attribute)
143 return false;
144
145 if (instr->reg0_use_count) {
146 if (instr->reg0_index != load->index)
147 return false;
148 }
149 else {
150 instr->reg0_is_attr = node->op == gpir_op_load_attribute;
151 instr->reg0_index = load->index;
152 }
153
154 instr->reg0_use_count++;
155 return true;
156 }
157
158 static void gpir_instr_remove_reg0(gpir_instr *instr, gpir_node *node)
159 {
160 instr->reg0_use_count--;
161 if (!instr->reg0_use_count)
162 instr->reg0_is_attr = false;
163 }
164
165 static bool gpir_instr_insert_reg1_check(gpir_instr *instr, gpir_node *node)
166 {
167 gpir_load_node *load = gpir_node_to_load(node);
168 int i = node->sched.pos - GPIR_INSTR_SLOT_REG1_LOAD0;
169
170 if (load->component != i)
171 return false;
172
173 if (instr->reg1_use_count) {
174 if (instr->reg1_index != load->index)
175 return false;
176 }
177 else
178 instr->reg1_index = load->index;
179
180 instr->reg1_use_count++;
181 return true;
182 }
183
184 static void gpir_instr_remove_reg1(gpir_instr *instr, gpir_node *node)
185 {
186 instr->reg1_use_count--;
187 }
188
189 static bool gpir_instr_insert_mem_check(gpir_instr *instr, gpir_node *node)
190 {
191 gpir_load_node *load = gpir_node_to_load(node);
192 int i = node->sched.pos - GPIR_INSTR_SLOT_MEM_LOAD0;
193
194 if (load->component != i)
195 return false;
196
197 if (instr->mem_is_temp && node->op != gpir_op_load_temp)
198 return false;
199
200 if (instr->mem_use_count) {
201 if (instr->mem_index != load->index)
202 return false;
203 }
204 else {
205 instr->mem_is_temp = node->op == gpir_op_load_temp;
206 instr->mem_index = load->index;
207 }
208
209 instr->mem_use_count++;
210 return true;
211 }
212
213 static void gpir_instr_remove_mem(gpir_instr *instr, gpir_node *node)
214 {
215 instr->mem_use_count--;
216 if (!instr->mem_use_count)
217 instr->mem_is_temp = false;
218 }
219
220 static bool gpir_instr_insert_store_check(gpir_instr *instr, gpir_node *node)
221 {
222 gpir_store_node *store = gpir_node_to_store(node);
223 int i = node->sched.pos - GPIR_INSTR_SLOT_STORE0;
224
225 if (store->component != i)
226 return false;
227
228 i >>= 1;
229 switch (instr->store_content[i]) {
230 case GPIR_INSTR_STORE_NONE:
231 /* store temp has only one address reg for two store unit */
232 if (node->op == gpir_op_store_temp &&
233 instr->store_content[!i] == GPIR_INSTR_STORE_TEMP &&
234 instr->store_index[!i] != store->index)
235 return false;
236 break;
237
238 case GPIR_INSTR_STORE_VARYING:
239 if (node->op != gpir_op_store_varying ||
240 instr->store_index[i] != store->index)
241 return false;
242 break;
243
244 case GPIR_INSTR_STORE_REG:
245 if (node->op != gpir_op_store_reg ||
246 instr->store_index[i] != store->index)
247 return false;
248 break;
249
250 case GPIR_INSTR_STORE_TEMP:
251 if (node->op != gpir_op_store_temp ||
252 instr->store_index[i] != store->index)
253 return false;
254 break;
255 }
256
257 /* check if any store node has the same child as this node */
258 for (int j = GPIR_INSTR_SLOT_STORE0; j <= GPIR_INSTR_SLOT_STORE3; j++) {
259 gpir_store_node *s = gpir_node_to_store(instr->slots[j]);
260 if (s && s->child == store->child)
261 goto out;
262 }
263
264 /* check if the child is alrady in this instr's alu slot,
265 * this may happen when store an scheduled alu node to reg
266 */
267 for (int j = GPIR_INSTR_SLOT_ALU_BEGIN; j <= GPIR_INSTR_SLOT_ALU_END; j++) {
268 if (store->child == instr->slots[j])
269 goto out;
270 }
271
272 /* no store node has the same child as this node, and child is not
273 * already in this instr's alu slot, so instr must have some free
274 * alu slot to insert this node's child
275 */
276 if (gpir_instr_alu_slot_is_full(instr))
277 return false;
278
279 instr->alu_num_slot_needed_by_store++;
280
281 out:
282 if (instr->store_content[i] == GPIR_INSTR_STORE_NONE) {
283 if (node->op == gpir_op_store_varying)
284 instr->store_content[i] = GPIR_INSTR_STORE_VARYING;
285 else if (node->op == gpir_op_store_reg)
286 instr->store_content[i] = GPIR_INSTR_STORE_REG;
287 else
288 instr->store_content[i] = GPIR_INSTR_STORE_TEMP;
289
290 instr->store_index[i] = store->index;
291 }
292 return true;
293 }
294
295 static void gpir_instr_remove_store(gpir_instr *instr, gpir_node *node)
296 {
297 gpir_store_node *store = gpir_node_to_store(node);
298 int component = node->sched.pos - GPIR_INSTR_SLOT_STORE0;
299 int other_slot = GPIR_INSTR_SLOT_STORE0 + (component ^ 1);
300
301 for (int j = GPIR_INSTR_SLOT_STORE0; j <= GPIR_INSTR_SLOT_STORE3; j++) {
302 gpir_store_node *s = gpir_node_to_store(instr->slots[j]);
303 if (s && s->child == store->child)
304 goto out;
305 }
306
307 for (int j = GPIR_INSTR_SLOT_ALU_BEGIN; j <= GPIR_INSTR_SLOT_ALU_END; j++) {
308 if (store->child == instr->slots[j])
309 goto out;
310 }
311
312 instr->alu_num_slot_needed_by_store--;
313
314 out:
315 if (!instr->slots[other_slot])
316 instr->store_content[component >> 1] = GPIR_INSTR_STORE_NONE;
317 }
318
319 static bool gpir_instr_spill_move(gpir_instr *instr, int slot, int spill_to_start)
320 {
321 gpir_node *node = instr->slots[slot];
322 if (!node)
323 return true;
324
325 if (node->op != gpir_op_mov)
326 return false;
327
328 for (int i = spill_to_start; i <= GPIR_INSTR_SLOT_DIST_TWO_END; i++) {
329 if (i != slot && !instr->slots[i] &&
330 gpir_instr_check_acc_same_op(instr, node, i)) {
331 instr->slots[i] = node;
332 instr->slots[slot] = NULL;
333 node->sched.pos = i;
334
335 gpir_debug("instr %d spill move %d from slot %d to %d\n",
336 instr->index, node->index, slot, i);
337 return true;
338 }
339 }
340
341 return false;
342 }
343
344 static bool gpir_instr_slot_free(gpir_instr *instr, gpir_node *node)
345 {
346 if (node->op == gpir_op_mov ||
347 node->sched.pos > GPIR_INSTR_SLOT_DIST_TWO_END) {
348 if (instr->slots[node->sched.pos])
349 return false;
350 }
351 else {
352 /* for node needs dist two slot, if the slot has a move, we can
353 * spill it to other dist two slot without any side effect */
354 int spill_to_start = GPIR_INSTR_SLOT_MUL0;
355 if (node->op == gpir_op_complex1 || node->op == gpir_op_select)
356 spill_to_start = GPIR_INSTR_SLOT_ADD0;
357
358 if (!gpir_instr_spill_move(instr, node->sched.pos, spill_to_start))
359 return false;
360
361 if (node->op == gpir_op_complex1 || node->op == gpir_op_select) {
362 if (!gpir_instr_spill_move(instr, GPIR_INSTR_SLOT_MUL1, spill_to_start))
363 return false;
364 }
365 }
366
367 return true;
368 }
369
370 bool gpir_instr_try_insert_node(gpir_instr *instr, gpir_node *node)
371 {
372 if (!gpir_instr_slot_free(instr, node))
373 return false;
374
375 if (node->sched.pos >= GPIR_INSTR_SLOT_ALU_BEGIN &&
376 node->sched.pos <= GPIR_INSTR_SLOT_ALU_END) {
377 if (!gpir_instr_insert_alu_check(instr, node))
378 return false;
379 }
380 else if (node->sched.pos >= GPIR_INSTR_SLOT_REG0_LOAD0 &&
381 node->sched.pos <= GPIR_INSTR_SLOT_REG0_LOAD3) {
382 if (!gpir_instr_insert_reg0_check(instr, node))
383 return false;
384 }
385 else if (node->sched.pos >= GPIR_INSTR_SLOT_REG1_LOAD0 &&
386 node->sched.pos <= GPIR_INSTR_SLOT_REG1_LOAD3) {
387 if (!gpir_instr_insert_reg1_check(instr, node))
388 return false;
389 }
390 else if (node->sched.pos >= GPIR_INSTR_SLOT_MEM_LOAD0 &&
391 node->sched.pos <= GPIR_INSTR_SLOT_MEM_LOAD3) {
392 if (!gpir_instr_insert_mem_check(instr, node))
393 return false;
394 }
395 else if (node->sched.pos >= GPIR_INSTR_SLOT_STORE0 &&
396 node->sched.pos <= GPIR_INSTR_SLOT_STORE3) {
397 if (!gpir_instr_insert_store_check(instr, node))
398 return false;
399 }
400
401 instr->slots[node->sched.pos] = node;
402
403 if (node->op == gpir_op_complex1 || node->op == gpir_op_select)
404 instr->slots[GPIR_INSTR_SLOT_MUL1] = node;
405
406 return true;
407 }
408
409 void gpir_instr_remove_node(gpir_instr *instr, gpir_node *node)
410 {
411 if (node->sched.pos >= GPIR_INSTR_SLOT_ALU_BEGIN &&
412 node->sched.pos <= GPIR_INSTR_SLOT_ALU_END)
413 gpir_instr_remove_alu(instr, node);
414 else if (node->sched.pos >= GPIR_INSTR_SLOT_REG0_LOAD0 &&
415 node->sched.pos <= GPIR_INSTR_SLOT_REG0_LOAD3)
416 gpir_instr_remove_reg0(instr, node);
417 else if (node->sched.pos >= GPIR_INSTR_SLOT_REG1_LOAD0 &&
418 node->sched.pos <= GPIR_INSTR_SLOT_REG1_LOAD3)
419 gpir_instr_remove_reg1(instr, node);
420 else if (node->sched.pos >= GPIR_INSTR_SLOT_MEM_LOAD0 &&
421 node->sched.pos <= GPIR_INSTR_SLOT_MEM_LOAD3)
422 gpir_instr_remove_mem(instr, node);
423 else if (node->sched.pos >= GPIR_INSTR_SLOT_STORE0 &&
424 node->sched.pos <= GPIR_INSTR_SLOT_STORE3)
425 gpir_instr_remove_store(instr, node);
426
427 instr->slots[node->sched.pos] = NULL;
428
429 if (node->op == gpir_op_complex1 || node->op == gpir_op_select)
430 instr->slots[GPIR_INSTR_SLOT_MUL1] = NULL;
431 }
432
433 void gpir_instr_print_prog(gpir_compiler *comp)
434 {
435 struct {
436 int len;
437 char *name;
438 } fields[] = {
439 [GPIR_INSTR_SLOT_MUL0] = { 4, "mul0" },
440 [GPIR_INSTR_SLOT_MUL1] = { 4, "mul1" },
441 [GPIR_INSTR_SLOT_ADD0] = { 4, "add0" },
442 [GPIR_INSTR_SLOT_ADD1] = { 4, "add1" },
443 [GPIR_INSTR_SLOT_REG0_LOAD3] = { 15, "load0" },
444 [GPIR_INSTR_SLOT_REG1_LOAD3] = { 15, "load1" },
445 [GPIR_INSTR_SLOT_MEM_LOAD3] = { 15, "load2" },
446 [GPIR_INSTR_SLOT_BRANCH] = { 4, "bnch" },
447 [GPIR_INSTR_SLOT_STORE3] = { 15, "store" },
448 [GPIR_INSTR_SLOT_COMPLEX] = { 4, "cmpl" },
449 [GPIR_INSTR_SLOT_PASS] = { 4, "pass" },
450 };
451
452 printf("========prog instr========\n");
453 printf(" ");
454 for (int i = 0; i < GPIR_INSTR_SLOT_NUM; i++) {
455 if (fields[i].len)
456 printf("%-*s ", fields[i].len, fields[i].name);
457 }
458 printf("\n");
459
460 int index = 0;
461 list_for_each_entry(gpir_block, block, &comp->block_list, list) {
462 list_for_each_entry(gpir_instr, instr, &block->instr_list, list) {
463 printf("%03d: ", index++);
464
465 char buff[16] = "null";
466 int start = 0;
467 for (int j = 0; j < GPIR_INSTR_SLOT_NUM; j++) {
468 gpir_node *node = instr->slots[j];
469 if (fields[j].len) {
470 if (node)
471 snprintf(buff + start, sizeof(buff) - start, "%d", node->index);
472 printf("%-*s ", fields[j].len, buff);
473
474 strcpy(buff, "null");
475 start = 0;
476 }
477 else {
478 if (node)
479 start += snprintf(buff + start, sizeof(buff) - start, "%d", node->index);
480 start += snprintf(buff + start, sizeof(buff) - start, "|");
481 }
482 }
483 printf("\n");
484 }
485 printf("-----------------------\n");
486 }
487 printf("==========================\n");
488 }