721504a810e264e810f5170f0860523d0cd88902
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.
30 static void ppir_schedule_calc_sched_info(ppir_instr
*instr
)
33 float extra_reg
= 1.0;
35 /* update all children's sched info */
36 ppir_instr_foreach_pred(instr
, dep
) {
37 ppir_instr
*pred
= dep
->pred
;
39 if (pred
->reg_pressure
< 0)
40 ppir_schedule_calc_sched_info(pred
);
42 if (instr
->est
< pred
->est
+ 1)
43 instr
->est
= pred
->est
+ 1;
45 float reg_weight
= 1.0 - 1.0 / list_length(&pred
->succ_list
);
46 if (extra_reg
> reg_weight
)
47 extra_reg
= reg_weight
;
54 instr
->reg_pressure
= 0;
59 ppir_instr_foreach_pred(instr
, dep
) {
60 ppir_instr
*pred
= dep
->pred
;
61 reg
[i
++] = pred
->reg_pressure
;
65 for (i
= 0; i
< n
- 1; i
++) {
66 for (int j
= 0; j
< n
- i
- 1; j
++) {
67 if (reg
[j
] > reg
[j
+ 1]) {
75 for (i
= 0; i
< n
; i
++) {
76 int pressure
= reg
[i
] + n
- (i
+ 1);
77 if (pressure
> instr
->reg_pressure
)
78 instr
->reg_pressure
= pressure
;
81 /* If all children of this instr have multi parents, then this
82 * instr need an extra reg to store its result. For example,
83 * it's not fair for parent has the same reg pressure as child
84 * if n==1 and child's successor>1, because we need 2 reg for
87 * But we can't add a full reg to the reg_pressure, because the
88 * last parent of a multi-successor child doesn't need an extra
89 * reg. For example, a single child (with multi successor) instr
90 * should has less reg pressure than a two children (with single
93 * extra reg = min(all child)(1.0 - 1.0 / num successor)
95 instr
->reg_pressure
+= extra_reg
;
98 static void ppir_insert_ready_list(struct list_head
*ready_list
,
99 ppir_instr
*insert_instr
)
101 struct list_head
*insert_pos
= ready_list
;
103 list_for_each_entry(ppir_instr
, instr
, ready_list
, list
) {
104 if (insert_instr
->parent_index
< instr
->parent_index
||
105 (insert_instr
->parent_index
== instr
->parent_index
&&
106 (insert_instr
->reg_pressure
< instr
->reg_pressure
||
107 (insert_instr
->reg_pressure
== instr
->reg_pressure
&&
108 (insert_instr
->est
>= instr
->est
))))) {
109 insert_pos
= &instr
->list
;
114 list_del(&insert_instr
->list
);
115 list_addtail(&insert_instr
->list
, insert_pos
);
118 static void ppir_schedule_ready_list(ppir_block
*block
,
119 struct list_head
*ready_list
)
121 if (list_empty(ready_list
))
124 ppir_instr
*instr
= list_first_entry(ready_list
, ppir_instr
, list
);
125 list_del(&instr
->list
);
127 /* schedule the instr to the block instr list */
128 list_add(&instr
->list
, &block
->instr_list
);
129 instr
->scheduled
= true;
130 block
->sched_instr_index
--;
131 instr
->seq
= block
->sched_instr_base
+ block
->sched_instr_index
;
133 ppir_instr_foreach_pred(instr
, dep
) {
134 ppir_instr
*pred
= dep
->pred
;
135 pred
->parent_index
= block
->sched_instr_index
;
138 ppir_instr_foreach_succ(pred
, dep
) {
139 ppir_instr
*succ
= dep
->succ
;
140 if (!succ
->scheduled
) {
145 /* all successor have been scheduled */
147 ppir_insert_ready_list(ready_list
, pred
);
150 ppir_schedule_ready_list(block
, ready_list
);
153 /* Register sensitive schedule algorithm from paper:
154 * "Register-Sensitive Selection, Duplication, and Sequencing of Instructions"
155 * Author: Vivek Sarkar, Mauricio J. Serrano, Barbara B. Simons
157 static void ppir_schedule_block(ppir_block
*block
)
159 /* move all instr to instr_list, block->instr_list will
160 * contain schedule result */
161 struct list_head instr_list
;
162 list_replace(&block
->instr_list
, &instr_list
);
163 list_inithead(&block
->instr_list
);
166 list_for_each_entry(ppir_instr
, instr
, &instr_list
, list
) {
167 if (ppir_instr_is_root(instr
))
168 ppir_schedule_calc_sched_info(instr
);
169 block
->sched_instr_index
++;
171 block
->sched_instr_base
= block
->comp
->sched_instr_base
;
172 block
->comp
->sched_instr_base
+= block
->sched_instr_index
;
175 struct list_head ready_list
;
176 list_inithead(&ready_list
);
179 list_for_each_entry_safe(ppir_instr
, instr
, &instr_list
, list
) {
180 if (ppir_instr_is_root(instr
)) {
181 instr
->parent_index
= INT_MAX
;
182 ppir_insert_ready_list(&ready_list
, instr
);
187 ppir_schedule_ready_list(block
, &ready_list
);
190 bool ppir_schedule_prog(ppir_compiler
*comp
)
192 list_for_each_entry(ppir_block
, block
, &comp
->block_list
, list
) {
193 ppir_schedule_block(block
);