Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/gallium/drivers/lima/ir/gp/instr.c
4574 views
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
block->comp->num_instr++;
38
if (block->comp->num_instr > 512) {
39
gpir_error("shader exceeds limit of 512 instructions\n");
40
return NULL;
41
}
42
43
instr->index = block->sched.instr_index++;
44
instr->alu_num_slot_free = 6;
45
instr->alu_non_cplx_slot_free = 5;
46
instr->alu_max_allowed_next_max = 5;
47
48
list_add(&instr->list, &block->instr_list);
49
return instr;
50
}
51
52
static gpir_node *gpir_instr_get_the_other_acc_node(gpir_instr *instr, int slot)
53
{
54
if (slot == GPIR_INSTR_SLOT_ADD0)
55
return instr->slots[GPIR_INSTR_SLOT_ADD1];
56
else if (slot == GPIR_INSTR_SLOT_ADD1)
57
return instr->slots[GPIR_INSTR_SLOT_ADD0];
58
59
return NULL;
60
}
61
62
static bool gpir_instr_check_acc_same_op(gpir_instr *instr, gpir_node *node, int slot)
63
{
64
/* two ACC slots must share the same op code */
65
gpir_node *acc_node = gpir_instr_get_the_other_acc_node(instr, slot);
66
67
/* spill move case may get acc_node == node */
68
if (acc_node && acc_node != node &&
69
!gpir_codegen_acc_same_op(node->op, acc_node->op))
70
return false;
71
72
return true;
73
}
74
75
static int gpir_instr_get_consume_slot(gpir_instr *instr, gpir_node *node)
76
{
77
if (gpir_op_infos[node->op].may_consume_two_slots) {
78
gpir_node *acc_node = gpir_instr_get_the_other_acc_node(instr, node->sched.pos);
79
if (acc_node)
80
/* at this point node must have the same acc op with acc_node,
81
* so it just consumes the extra slot acc_node consumed */
82
return 0;
83
else
84
return 2;
85
}
86
else
87
return 1;
88
}
89
90
static bool gpir_instr_insert_alu_check(gpir_instr *instr, gpir_node *node)
91
{
92
if (!gpir_instr_check_acc_same_op(instr, node, node->sched.pos))
93
return false;
94
95
if (node->sched.next_max_node && !node->sched.complex_allowed &&
96
node->sched.pos == GPIR_INSTR_SLOT_COMPLEX)
97
return false;
98
99
int consume_slot = gpir_instr_get_consume_slot(instr, node);
100
int non_cplx_consume_slot =
101
node->sched.pos == GPIR_INSTR_SLOT_COMPLEX ? 0 : consume_slot;
102
int store_reduce_slot = 0;
103
int non_cplx_store_reduce_slot = 0;
104
int max_reduce_slot = node->sched.max_node ? 1 : 0;
105
int next_max_reduce_slot = node->sched.next_max_node ? 1 : 0;
106
int alu_new_max_allowed_next_max =
107
node->op == gpir_op_complex1 ? 4 : instr->alu_max_allowed_next_max;
108
109
/* check if this node is child of one store node.
110
* complex1 won't be any of this instr's store node's child,
111
* because it has two instr latency before store can use it.
112
*/
113
for (int i = GPIR_INSTR_SLOT_STORE0; i <= GPIR_INSTR_SLOT_STORE3; i++) {
114
gpir_store_node *s = gpir_node_to_store(instr->slots[i]);
115
if (s && s->child == node) {
116
store_reduce_slot = 1;
117
if (node->sched.next_max_node && !node->sched.complex_allowed)
118
non_cplx_store_reduce_slot = 1;
119
break;
120
}
121
}
122
123
/* Check that the invariants will be maintained after we adjust everything
124
*/
125
126
int slot_difference =
127
instr->alu_num_slot_needed_by_store - store_reduce_slot +
128
instr->alu_num_slot_needed_by_max - max_reduce_slot +
129
MAX2(instr->alu_num_unscheduled_next_max - next_max_reduce_slot -
130
alu_new_max_allowed_next_max, 0) -
131
(instr->alu_num_slot_free - consume_slot);
132
if (slot_difference > 0) {
133
gpir_debug("failed %d because of alu slot\n", node->index);
134
instr->slot_difference = slot_difference;
135
}
136
137
int non_cplx_slot_difference =
138
instr->alu_num_slot_needed_by_max - max_reduce_slot +
139
instr->alu_num_slot_needed_by_non_cplx_store - non_cplx_store_reduce_slot -
140
(instr->alu_non_cplx_slot_free - non_cplx_consume_slot);
141
if (non_cplx_slot_difference > 0) {
142
gpir_debug("failed %d because of alu slot\n", node->index);
143
instr->non_cplx_slot_difference = non_cplx_slot_difference;
144
}
145
146
if (slot_difference > 0 || non_cplx_slot_difference > 0)
147
return false;
148
149
instr->alu_num_slot_free -= consume_slot;
150
instr->alu_non_cplx_slot_free -= non_cplx_consume_slot;
151
instr->alu_num_slot_needed_by_store -= store_reduce_slot;
152
instr->alu_num_slot_needed_by_non_cplx_store -= non_cplx_store_reduce_slot;
153
instr->alu_num_slot_needed_by_max -= max_reduce_slot;
154
instr->alu_num_unscheduled_next_max -= next_max_reduce_slot;
155
instr->alu_max_allowed_next_max = alu_new_max_allowed_next_max;
156
return true;
157
}
158
159
static void gpir_instr_remove_alu(gpir_instr *instr, gpir_node *node)
160
{
161
int consume_slot = gpir_instr_get_consume_slot(instr, node);
162
163
for (int i = GPIR_INSTR_SLOT_STORE0; i <= GPIR_INSTR_SLOT_STORE3; i++) {
164
gpir_store_node *s = gpir_node_to_store(instr->slots[i]);
165
if (s && s->child == node) {
166
instr->alu_num_slot_needed_by_store++;
167
if (node->sched.next_max_node && !node->sched.complex_allowed)
168
instr->alu_num_slot_needed_by_non_cplx_store++;
169
break;
170
}
171
}
172
173
instr->alu_num_slot_free += consume_slot;
174
if (node->sched.pos != GPIR_INSTR_SLOT_COMPLEX)
175
instr->alu_non_cplx_slot_free += consume_slot;
176
if (node->sched.max_node)
177
instr->alu_num_slot_needed_by_max++;
178
if (node->sched.next_max_node)
179
instr->alu_num_unscheduled_next_max++;
180
if (node->op == gpir_op_complex1)
181
instr->alu_max_allowed_next_max = 5;
182
}
183
184
static bool gpir_instr_insert_reg0_check(gpir_instr *instr, gpir_node *node)
185
{
186
gpir_load_node *load = gpir_node_to_load(node);
187
int i = node->sched.pos - GPIR_INSTR_SLOT_REG0_LOAD0;
188
189
if (load->component != i)
190
return false;
191
192
if (instr->reg0_is_attr && node->op != gpir_op_load_attribute)
193
return false;
194
195
if (instr->reg0_use_count) {
196
if (instr->reg0_index != load->index)
197
return false;
198
}
199
else {
200
instr->reg0_is_attr = node->op == gpir_op_load_attribute;
201
instr->reg0_index = load->index;
202
}
203
204
instr->reg0_use_count++;
205
return true;
206
}
207
208
static void gpir_instr_remove_reg0(gpir_instr *instr, gpir_node *node)
209
{
210
instr->reg0_use_count--;
211
if (!instr->reg0_use_count)
212
instr->reg0_is_attr = false;
213
}
214
215
static bool gpir_instr_insert_reg1_check(gpir_instr *instr, gpir_node *node)
216
{
217
gpir_load_node *load = gpir_node_to_load(node);
218
int i = node->sched.pos - GPIR_INSTR_SLOT_REG1_LOAD0;
219
220
if (load->component != i)
221
return false;
222
223
if (instr->reg1_use_count) {
224
if (instr->reg1_index != load->index)
225
return false;
226
}
227
else
228
instr->reg1_index = load->index;
229
230
instr->reg1_use_count++;
231
return true;
232
}
233
234
static void gpir_instr_remove_reg1(gpir_instr *instr, gpir_node *node)
235
{
236
instr->reg1_use_count--;
237
}
238
239
static bool gpir_instr_insert_mem_check(gpir_instr *instr, gpir_node *node)
240
{
241
gpir_load_node *load = gpir_node_to_load(node);
242
int i = node->sched.pos - GPIR_INSTR_SLOT_MEM_LOAD0;
243
244
if (load->component != i)
245
return false;
246
247
if (instr->mem_is_temp && node->op != gpir_op_load_temp)
248
return false;
249
250
if (instr->mem_use_count) {
251
if (instr->mem_index != load->index)
252
return false;
253
}
254
else {
255
instr->mem_is_temp = node->op == gpir_op_load_temp;
256
instr->mem_index = load->index;
257
}
258
259
instr->mem_use_count++;
260
return true;
261
}
262
263
static void gpir_instr_remove_mem(gpir_instr *instr, gpir_node *node)
264
{
265
instr->mem_use_count--;
266
if (!instr->mem_use_count)
267
instr->mem_is_temp = false;
268
}
269
270
static bool gpir_instr_insert_store_check(gpir_instr *instr, gpir_node *node)
271
{
272
gpir_store_node *store = gpir_node_to_store(node);
273
int i = node->sched.pos - GPIR_INSTR_SLOT_STORE0;
274
275
if (store->component != i)
276
return false;
277
278
i >>= 1;
279
switch (instr->store_content[i]) {
280
case GPIR_INSTR_STORE_NONE:
281
/* store temp has only one address reg for two store unit */
282
if (node->op == gpir_op_store_temp &&
283
instr->store_content[!i] == GPIR_INSTR_STORE_TEMP &&
284
instr->store_index[!i] != store->index)
285
return false;
286
break;
287
288
case GPIR_INSTR_STORE_VARYING:
289
if (node->op != gpir_op_store_varying ||
290
instr->store_index[i] != store->index)
291
return false;
292
break;
293
294
case GPIR_INSTR_STORE_REG:
295
if (node->op != gpir_op_store_reg ||
296
instr->store_index[i] != store->index)
297
return false;
298
break;
299
300
case GPIR_INSTR_STORE_TEMP:
301
if (node->op != gpir_op_store_temp ||
302
instr->store_index[i] != store->index)
303
return false;
304
break;
305
}
306
307
/* check if any store node has the same child as this node */
308
for (int j = GPIR_INSTR_SLOT_STORE0; j <= GPIR_INSTR_SLOT_STORE3; j++) {
309
gpir_store_node *s = gpir_node_to_store(instr->slots[j]);
310
if (s && s->child == store->child)
311
goto out;
312
}
313
314
/* check if the child is already in this instr's alu slot,
315
* this may happen when store an scheduled alu node to reg
316
*/
317
for (int j = GPIR_INSTR_SLOT_ALU_BEGIN; j <= GPIR_INSTR_SLOT_ALU_END; j++) {
318
if (store->child == instr->slots[j])
319
goto out;
320
}
321
322
/* Check the invariants documented in gpir.h, similar to the ALU case.
323
* When the only thing that changes is alu_num_slot_needed_by_store, we
324
* can get away with just checking the first one.
325
*/
326
int slot_difference = instr->alu_num_slot_needed_by_store + 1
327
+ instr->alu_num_slot_needed_by_max +
328
MAX2(instr->alu_num_unscheduled_next_max - instr->alu_max_allowed_next_max, 0) -
329
instr->alu_num_slot_free;
330
if (slot_difference > 0) {
331
instr->slot_difference = slot_difference;
332
return false;
333
}
334
335
if (store->child->sched.next_max_node &&
336
!store->child->sched.complex_allowed) {
337
/* The child of the store is already partially ready, and has a use one
338
* cycle ago that disqualifies it (or a move replacing it) from being
339
* put in the complex slot. Therefore we have to check the non-complex
340
* invariant.
341
*/
342
int non_cplx_slot_difference =
343
instr->alu_num_slot_needed_by_max +
344
instr->alu_num_slot_needed_by_non_cplx_store + 1 -
345
instr->alu_non_cplx_slot_free;
346
if (non_cplx_slot_difference > 0) {
347
instr->non_cplx_slot_difference = non_cplx_slot_difference;
348
return false;
349
}
350
351
instr->alu_num_slot_needed_by_non_cplx_store++;
352
}
353
354
instr->alu_num_slot_needed_by_store++;
355
356
out:
357
if (instr->store_content[i] == GPIR_INSTR_STORE_NONE) {
358
if (node->op == gpir_op_store_varying)
359
instr->store_content[i] = GPIR_INSTR_STORE_VARYING;
360
else if (node->op == gpir_op_store_reg)
361
instr->store_content[i] = GPIR_INSTR_STORE_REG;
362
else
363
instr->store_content[i] = GPIR_INSTR_STORE_TEMP;
364
365
instr->store_index[i] = store->index;
366
}
367
return true;
368
}
369
370
static void gpir_instr_remove_store(gpir_instr *instr, gpir_node *node)
371
{
372
gpir_store_node *store = gpir_node_to_store(node);
373
int component = node->sched.pos - GPIR_INSTR_SLOT_STORE0;
374
int other_slot = GPIR_INSTR_SLOT_STORE0 + (component ^ 1);
375
376
for (int j = GPIR_INSTR_SLOT_STORE0; j <= GPIR_INSTR_SLOT_STORE3; j++) {
377
if (j == node->sched.pos)
378
continue;
379
380
gpir_store_node *s = gpir_node_to_store(instr->slots[j]);
381
if (s && s->child == store->child)
382
goto out;
383
}
384
385
for (int j = GPIR_INSTR_SLOT_ALU_BEGIN; j <= GPIR_INSTR_SLOT_ALU_END; j++) {
386
if (store->child == instr->slots[j])
387
goto out;
388
}
389
390
instr->alu_num_slot_needed_by_store--;
391
392
if (store->child->sched.next_max_node &&
393
!store->child->sched.complex_allowed) {
394
instr->alu_num_slot_needed_by_non_cplx_store--;
395
}
396
397
out:
398
if (!instr->slots[other_slot])
399
instr->store_content[component >> 1] = GPIR_INSTR_STORE_NONE;
400
}
401
402
static bool gpir_instr_spill_move(gpir_instr *instr, int slot, int spill_to_start)
403
{
404
gpir_node *node = instr->slots[slot];
405
if (!node)
406
return true;
407
408
if (node->op != gpir_op_mov)
409
return false;
410
411
for (int i = spill_to_start; i <= GPIR_INSTR_SLOT_DIST_TWO_END; i++) {
412
if (i != slot && !instr->slots[i] &&
413
gpir_instr_check_acc_same_op(instr, node, i)) {
414
instr->slots[i] = node;
415
instr->slots[slot] = NULL;
416
node->sched.pos = i;
417
418
gpir_debug("instr %d spill move %d from slot %d to %d\n",
419
instr->index, node->index, slot, i);
420
return true;
421
}
422
}
423
424
return false;
425
}
426
427
static bool gpir_instr_slot_free(gpir_instr *instr, gpir_node *node)
428
{
429
if (node->op == gpir_op_mov ||
430
node->sched.pos > GPIR_INSTR_SLOT_DIST_TWO_END) {
431
if (instr->slots[node->sched.pos])
432
return false;
433
}
434
else {
435
/* for node needs dist two slot, if the slot has a move, we can
436
* spill it to other dist two slot without any side effect */
437
int spill_to_start = GPIR_INSTR_SLOT_MUL0;
438
if (node->op == gpir_op_complex1 || node->op == gpir_op_select)
439
spill_to_start = GPIR_INSTR_SLOT_ADD0;
440
441
if (!gpir_instr_spill_move(instr, node->sched.pos, spill_to_start))
442
return false;
443
444
if (node->op == gpir_op_complex1 || node->op == gpir_op_select) {
445
if (!gpir_instr_spill_move(instr, GPIR_INSTR_SLOT_MUL1, spill_to_start))
446
return false;
447
}
448
}
449
450
return true;
451
}
452
453
bool gpir_instr_try_insert_node(gpir_instr *instr, gpir_node *node)
454
{
455
instr->slot_difference = 0;
456
instr->non_cplx_slot_difference = 0;
457
458
if (!gpir_instr_slot_free(instr, node))
459
return false;
460
461
if (node->sched.pos >= GPIR_INSTR_SLOT_ALU_BEGIN &&
462
node->sched.pos <= GPIR_INSTR_SLOT_ALU_END) {
463
if (!gpir_instr_insert_alu_check(instr, node))
464
return false;
465
}
466
else if (node->sched.pos >= GPIR_INSTR_SLOT_REG0_LOAD0 &&
467
node->sched.pos <= GPIR_INSTR_SLOT_REG0_LOAD3) {
468
if (!gpir_instr_insert_reg0_check(instr, node))
469
return false;
470
}
471
else if (node->sched.pos >= GPIR_INSTR_SLOT_REG1_LOAD0 &&
472
node->sched.pos <= GPIR_INSTR_SLOT_REG1_LOAD3) {
473
if (!gpir_instr_insert_reg1_check(instr, node))
474
return false;
475
}
476
else if (node->sched.pos >= GPIR_INSTR_SLOT_MEM_LOAD0 &&
477
node->sched.pos <= GPIR_INSTR_SLOT_MEM_LOAD3) {
478
if (!gpir_instr_insert_mem_check(instr, node))
479
return false;
480
}
481
else if (node->sched.pos >= GPIR_INSTR_SLOT_STORE0 &&
482
node->sched.pos <= GPIR_INSTR_SLOT_STORE3) {
483
if (!gpir_instr_insert_store_check(instr, node))
484
return false;
485
}
486
487
instr->slots[node->sched.pos] = node;
488
489
if (node->op == gpir_op_complex1 || node->op == gpir_op_select)
490
instr->slots[GPIR_INSTR_SLOT_MUL1] = node;
491
492
return true;
493
}
494
495
void gpir_instr_remove_node(gpir_instr *instr, gpir_node *node)
496
{
497
assert(node->sched.pos >= 0);
498
499
/* This can happen if we merge duplicate loads in the scheduler. */
500
if (instr->slots[node->sched.pos] != node) {
501
node->sched.pos = -1;
502
node->sched.instr = NULL;
503
return;
504
}
505
506
if (node->sched.pos >= GPIR_INSTR_SLOT_ALU_BEGIN &&
507
node->sched.pos <= GPIR_INSTR_SLOT_ALU_END)
508
gpir_instr_remove_alu(instr, node);
509
else if (node->sched.pos >= GPIR_INSTR_SLOT_REG0_LOAD0 &&
510
node->sched.pos <= GPIR_INSTR_SLOT_REG0_LOAD3)
511
gpir_instr_remove_reg0(instr, node);
512
else if (node->sched.pos >= GPIR_INSTR_SLOT_REG1_LOAD0 &&
513
node->sched.pos <= GPIR_INSTR_SLOT_REG1_LOAD3)
514
gpir_instr_remove_reg1(instr, node);
515
else if (node->sched.pos >= GPIR_INSTR_SLOT_MEM_LOAD0 &&
516
node->sched.pos <= GPIR_INSTR_SLOT_MEM_LOAD3)
517
gpir_instr_remove_mem(instr, node);
518
else if (node->sched.pos >= GPIR_INSTR_SLOT_STORE0 &&
519
node->sched.pos <= GPIR_INSTR_SLOT_STORE3)
520
gpir_instr_remove_store(instr, node);
521
522
instr->slots[node->sched.pos] = NULL;
523
524
if (node->op == gpir_op_complex1 || node->op == gpir_op_select)
525
instr->slots[GPIR_INSTR_SLOT_MUL1] = NULL;
526
527
node->sched.pos = -1;
528
node->sched.instr = NULL;
529
}
530
531
void gpir_instr_print_prog(gpir_compiler *comp)
532
{
533
struct {
534
int len;
535
char *name;
536
} fields[] = {
537
[GPIR_INSTR_SLOT_MUL0] = { 4, "mul0" },
538
[GPIR_INSTR_SLOT_MUL1] = { 4, "mul1" },
539
[GPIR_INSTR_SLOT_ADD0] = { 4, "add0" },
540
[GPIR_INSTR_SLOT_ADD1] = { 4, "add1" },
541
[GPIR_INSTR_SLOT_REG0_LOAD3] = { 15, "load0" },
542
[GPIR_INSTR_SLOT_REG1_LOAD3] = { 15, "load1" },
543
[GPIR_INSTR_SLOT_MEM_LOAD3] = { 15, "load2" },
544
[GPIR_INSTR_SLOT_STORE3] = { 15, "store" },
545
[GPIR_INSTR_SLOT_COMPLEX] = { 4, "cmpl" },
546
[GPIR_INSTR_SLOT_PASS] = { 4, "pass" },
547
};
548
549
printf("========prog instr========\n");
550
printf(" ");
551
for (int i = 0; i < GPIR_INSTR_SLOT_NUM; i++) {
552
if (fields[i].len)
553
printf("%-*s ", fields[i].len, fields[i].name);
554
}
555
printf("\n");
556
557
int index = 0;
558
list_for_each_entry(gpir_block, block, &comp->block_list, list) {
559
list_for_each_entry(gpir_instr, instr, &block->instr_list, list) {
560
printf("%03d: ", index++);
561
562
char buff[16] = "null";
563
int start = 0;
564
for (int j = 0; j < GPIR_INSTR_SLOT_NUM; j++) {
565
gpir_node *node = instr->slots[j];
566
if (fields[j].len) {
567
if (node)
568
snprintf(buff + start, sizeof(buff) - start, "%d", node->index);
569
printf("%-*s ", fields[j].len, buff);
570
571
strcpy(buff, "null");
572
start = 0;
573
}
574
else {
575
if (node)
576
start += snprintf(buff + start, sizeof(buff) - start, "%d", node->index);
577
start += snprintf(buff + start, sizeof(buff) - start, "|");
578
}
579
}
580
printf("\n");
581
}
582
printf("-----------------------\n");
583
}
584
printf("==========================\n");
585
}
586
587