2 * Copyright (c) 2017 Lima Project
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:
11 * The above copyright notice and this permission notice (including the
12 * next paragraph) shall be included in all copies or substantial portions
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.
27 #include "util/ralloc.h"
31 gpir_instr
*gpir_instr_create(gpir_block
*block
)
33 gpir_instr
*instr
= rzalloc(block
, gpir_instr
);
37 instr
->index
= block
->sched
.instr_index
++;
38 instr
->alu_num_slot_free
= 6;
40 list_add(&instr
->list
, &block
->instr_list
);
44 static gpir_node
*gpir_instr_get_the_other_acc_node(gpir_instr
*instr
, int slot
)
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
];
54 static bool gpir_instr_check_acc_same_op(gpir_instr
*instr
, gpir_node
*node
, int slot
)
56 /* two ACC slots must share the same op code */
57 gpir_node
*acc_node
= gpir_instr_get_the_other_acc_node(instr
, slot
);
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
))
67 static int gpir_instr_get_consume_slot(gpir_instr
*instr
, gpir_node
*node
)
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
);
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 */
82 static bool gpir_instr_insert_alu_check(gpir_instr
*instr
, gpir_node
*node
)
84 if (!gpir_instr_check_acc_same_op(instr
, node
, node
->sched
.pos
))
87 int consume_slot
= gpir_instr_get_consume_slot(instr
, node
);
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.
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)
103 instr
->alu_num_slot_needed_by_store
--;
104 instr
->alu_num_slot_free
-= consume_slot
;
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
)
114 instr
->alu_num_slot_free
-= consume_slot
;
118 static void gpir_instr_remove_alu(gpir_instr
*instr
, gpir_node
*node
)
120 int consume_slot
= gpir_instr_get_consume_slot(instr
, node
);
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
;
131 instr
->alu_num_slot_free
+= consume_slot
;
134 static bool gpir_instr_insert_reg0_check(gpir_instr
*instr
, gpir_node
*node
)
136 gpir_load_node
*load
= gpir_node_to_load(node
);
137 int i
= node
->sched
.pos
- GPIR_INSTR_SLOT_REG0_LOAD0
;
139 if (load
->component
!= i
)
142 if (instr
->reg0_is_attr
&& node
->op
!= gpir_op_load_attribute
)
145 if (instr
->reg0_use_count
) {
146 if (instr
->reg0_index
!= load
->index
)
150 instr
->reg0_is_attr
= node
->op
== gpir_op_load_attribute
;
151 instr
->reg0_index
= load
->index
;
154 instr
->reg0_use_count
++;
158 static void gpir_instr_remove_reg0(gpir_instr
*instr
, gpir_node
*node
)
160 instr
->reg0_use_count
--;
161 if (!instr
->reg0_use_count
)
162 instr
->reg0_is_attr
= false;
165 static bool gpir_instr_insert_reg1_check(gpir_instr
*instr
, gpir_node
*node
)
167 gpir_load_node
*load
= gpir_node_to_load(node
);
168 int i
= node
->sched
.pos
- GPIR_INSTR_SLOT_REG1_LOAD0
;
170 if (load
->component
!= i
)
173 if (instr
->reg1_use_count
) {
174 if (instr
->reg1_index
!= load
->index
)
178 instr
->reg1_index
= load
->index
;
180 instr
->reg1_use_count
++;
184 static void gpir_instr_remove_reg1(gpir_instr
*instr
, gpir_node
*node
)
186 instr
->reg1_use_count
--;
189 static bool gpir_instr_insert_mem_check(gpir_instr
*instr
, gpir_node
*node
)
191 gpir_load_node
*load
= gpir_node_to_load(node
);
192 int i
= node
->sched
.pos
- GPIR_INSTR_SLOT_MEM_LOAD0
;
194 if (load
->component
!= i
)
197 if (instr
->mem_is_temp
&& node
->op
!= gpir_op_load_temp
)
200 if (instr
->mem_use_count
) {
201 if (instr
->mem_index
!= load
->index
)
205 instr
->mem_is_temp
= node
->op
== gpir_op_load_temp
;
206 instr
->mem_index
= load
->index
;
209 instr
->mem_use_count
++;
213 static void gpir_instr_remove_mem(gpir_instr
*instr
, gpir_node
*node
)
215 instr
->mem_use_count
--;
216 if (!instr
->mem_use_count
)
217 instr
->mem_is_temp
= false;
220 static bool gpir_instr_insert_store_check(gpir_instr
*instr
, gpir_node
*node
)
222 gpir_store_node
*store
= gpir_node_to_store(node
);
223 int i
= node
->sched
.pos
- GPIR_INSTR_SLOT_STORE0
;
225 if (store
->component
!= i
)
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
)
238 case GPIR_INSTR_STORE_VARYING
:
239 if (node
->op
!= gpir_op_store_varying
||
240 instr
->store_index
[i
] != store
->index
)
244 case GPIR_INSTR_STORE_REG
:
245 if (node
->op
!= gpir_op_store_reg
||
246 instr
->store_index
[i
] != store
->index
)
250 case GPIR_INSTR_STORE_TEMP
:
251 if (node
->op
!= gpir_op_store_temp
||
252 instr
->store_index
[i
] != store
->index
)
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
)
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
267 for (int j
= GPIR_INSTR_SLOT_ALU_BEGIN
; j
<= GPIR_INSTR_SLOT_ALU_END
; j
++) {
268 if (store
->child
== instr
->slots
[j
])
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
276 if (gpir_instr_alu_slot_is_full(instr
))
279 instr
->alu_num_slot_needed_by_store
++;
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
;
288 instr
->store_content
[i
] = GPIR_INSTR_STORE_TEMP
;
290 instr
->store_index
[i
] = store
->index
;
295 static void gpir_instr_remove_store(gpir_instr
*instr
, gpir_node
*node
)
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);
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
)
307 for (int j
= GPIR_INSTR_SLOT_ALU_BEGIN
; j
<= GPIR_INSTR_SLOT_ALU_END
; j
++) {
308 if (store
->child
== instr
->slots
[j
])
312 instr
->alu_num_slot_needed_by_store
--;
315 if (!instr
->slots
[other_slot
])
316 instr
->store_content
[component
>> 1] = GPIR_INSTR_STORE_NONE
;
319 static bool gpir_instr_spill_move(gpir_instr
*instr
, int slot
, int spill_to_start
)
321 gpir_node
*node
= instr
->slots
[slot
];
325 if (node
->op
!= gpir_op_mov
)
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
;
335 gpir_debug("instr %d spill move %d from slot %d to %d\n",
336 instr
->index
, node
->index
, slot
, i
);
344 static bool gpir_instr_slot_free(gpir_instr
*instr
, gpir_node
*node
)
346 if (node
->op
== gpir_op_mov
||
347 node
->sched
.pos
> GPIR_INSTR_SLOT_DIST_TWO_END
) {
348 if (instr
->slots
[node
->sched
.pos
])
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
;
358 if (!gpir_instr_spill_move(instr
, node
->sched
.pos
, spill_to_start
))
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
))
370 bool gpir_instr_try_insert_node(gpir_instr
*instr
, gpir_node
*node
)
372 if (!gpir_instr_slot_free(instr
, node
))
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
))
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
))
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
))
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
))
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
))
401 instr
->slots
[node
->sched
.pos
] = node
;
403 if (node
->op
== gpir_op_complex1
|| node
->op
== gpir_op_select
)
404 instr
->slots
[GPIR_INSTR_SLOT_MUL1
] = node
;
409 void gpir_instr_remove_node(gpir_instr
*instr
, gpir_node
*node
)
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
);
427 instr
->slots
[node
->sched
.pos
] = NULL
;
429 if (node
->op
== gpir_op_complex1
|| node
->op
== gpir_op_select
)
430 instr
->slots
[GPIR_INSTR_SLOT_MUL1
] = NULL
;
433 void gpir_instr_print_prog(gpir_compiler
*comp
)
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" },
452 printf("========prog instr========\n");
454 for (int i
= 0; i
< GPIR_INSTR_SLOT_NUM
; i
++) {
456 printf("%-*s ", fields
[i
].len
, fields
[i
].name
);
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
++);
465 char buff
[16] = "null";
467 for (int j
= 0; j
< GPIR_INSTR_SLOT_NUM
; j
++) {
468 gpir_node
*node
= instr
->slots
[j
];
471 snprintf(buff
+ start
, sizeof(buff
) - start
, "%d", node
->index
);
472 printf("%-*s ", fields
[j
].len
, buff
);
474 strcpy(buff
, "null");
479 start
+= snprintf(buff
+ start
, sizeof(buff
) - start
, "%d", node
->index
);
480 start
+= snprintf(buff
+ start
, sizeof(buff
) - start
, "|");
485 printf("-----------------------\n");
487 printf("==========================\n");