2 * Implements a list scheduler for the MRIS algorithm in:
3 * Govindarajan, Yang, Amaral, Zhang, Gao
4 * Minimum Register Instruction Sequencing to Reduce Register Spills
5 * in out-of-order issue superscalar architectures
6 * @author Sebastian Hack
15 #include "irgraph_t.h"
17 #include "iredges_t.h"
23 #include "besched_t.h"
24 #include "beschedmris.h"
27 firm_dbg_module_t *dbg;
28 const arch_env_t *aenv;
33 struct list_head lineage_head;
37 typedef struct _mris_irn_t {
40 ir_node *lineage_start;
41 ir_node *lineage_next;
43 struct list_head lineage_list;
46 #define to_appear(env, irn) (to_appear_in_schedule(irn) && get_nodes_block(irn) == env->bl)
48 #define get_irn_height(env, irn) (get_mris_irn(env, irn)->height)
49 #define foreach_lineage(env, pos, tmp) list_for_each_entry_safe(mris_irn_t, pos, tmp, &(env)->lineage_head, lineage_list)
51 static mris_irn_t *get_mris_irn(mris_env_t *env, ir_node *irn)
53 mris_irn_t *mi = get_irn_link(irn);
56 mi = obstack_alloc(&env->obst, sizeof(mi[0]));
57 memset(mi, 0, sizeof(mi[0]));
58 set_irn_link(irn, mi);
59 INIT_LIST_HEAD(&mi->lineage_list);
65 static int compute_height(mris_env_t *env, ir_node *irn, unsigned long visited)
67 mris_irn_t *mi = get_mris_irn(env, irn);
69 if(get_irn_visited(irn) >= visited) {
70 DBG((env->dbg, LEVEL_3, "\theight of %+F = %d\n", irn, mi->height));
75 const ir_edge_t *edge;
77 set_irn_visited(irn, visited);
80 foreach_out_edge(irn, edge) {
81 ir_node *dep = get_edge_src_irn(edge);
83 if(!is_Block(dep) && get_nodes_block(dep) == env->bl) {
84 int dep_height = compute_height(env, dep, visited);
85 mi->height = MAX(mi->height, dep_height);
90 DBG((env->dbg, LEVEL_3, "\tsetting height of %+F = %d\n", irn, mi->height));
96 static void compute_heights(mris_env_t *env)
98 const ir_edge_t *edge;
99 unsigned long visited;
101 visited = get_irg_visited(env->irg) + 1;
102 set_irg_visited(env->irg, visited);
104 foreach_out_edge(env->bl, edge) {
105 ir_node *dep = get_edge_src_irn(edge);
106 if(to_appear(env, dep))
107 compute_height(env, dep, visited);
111 #define valid_node(env, dep) (to_appear(env, dep) && !nodeset_find(env->inserted, dep) && !be_is_Keep(dep))
113 static void grow_all_descendands(mris_env_t *env, ir_node *irn, unsigned long visited)
115 const ir_edge_t *edge;
117 assert(get_irn_mode(irn) != mode_T);
119 foreach_out_edge(irn, edge) {
120 ir_node *desc = get_edge_src_irn(edge);
121 if(valid_node(env, desc) && get_irn_visited(desc) < visited) {
122 obstack_ptr_grow(&env->obst, desc);
123 set_irn_visited(desc, visited);
128 static ir_node **all_descendants(mris_env_t *env, ir_node *irn)
130 unsigned long visited;
131 const ir_edge_t *edge;
133 visited = get_irg_visited(env->irg) + 1;
134 set_irg_visited(env->irg, visited);
136 if(get_irn_mode(irn) == mode_T) {
137 foreach_out_edge(irn, edge) {
138 ir_node *desc = get_edge_src_irn(edge);
139 assert(is_Proj(desc) && get_irn_mode(desc) != mode_T);
140 grow_all_descendands(env, desc, visited);
145 grow_all_descendands(env, irn, visited);
147 obstack_ptr_grow(&env->obst, NULL);
148 return obstack_finish(&env->obst);
151 static ir_node *put_lowest_in_front(mris_env_t *env, ir_node **in)
153 int lowest_index = 0;
154 int lowest_height = INT_MAX;
157 for(i = 0; in[i]; ++i) {
158 mris_irn_t *mi = get_mris_irn(env, in[i]);
159 if(mi->height < lowest_height) {
160 lowest_height = mi->height;
166 ir_node *tmp = in[0];
167 in[0] = in[lowest_index];
168 in[lowest_index] = tmp;
174 static void reaches_walker(mris_env_t *env, ir_node *irn, ir_node *tgt, int *found, unsigned long visited)
176 if(get_irn_visited(irn) < visited && get_nodes_block(irn) == env->bl) {
178 set_irn_visited(irn, visited);
185 for(i = 0, n = get_irn_arity(irn); i < n; ++i) {
186 ir_node *op = get_irn_n(irn, i);
188 reaches_walker(env, op, tgt, found, visited);
194 static int reaches(mris_env_t *env, ir_node *src, ir_node *tgt)
197 unsigned long visited = get_irg_visited(env->irg) + 1;
199 set_irg_visited(env->irg, visited);
200 reaches_walker(env, src, tgt, &found, visited);
204 static INLINE ir_node *skip_Projs(ir_node *irn)
206 return is_Proj(irn) ? skip_Projs(get_Proj_pred(irn)) : irn;
209 static void replace_tuple_by_repr_proj(mris_env_t *env, ir_node **in)
213 for(i = 0; in[i]; ++i) {
214 if(get_irn_mode(in[i]) == mode_T) {
215 const ir_edge_t *edge;
216 ir_node *proj = NULL;
217 ir_node *first = NULL;
219 foreach_out_edge(in[i], edge) {
220 ir_node *desc = get_edge_src_irn(edge);
222 first = first ? first : desc;
223 if(get_irn_mode(desc) == mode_M) {
229 proj = proj ? proj : first;
236 static void lineage_formation(mris_env_t *env)
238 firm_dbg_module_t *dbg = env->dbg;
239 nodeset *nodes = new_nodeset(128);
241 const ir_edge_t *edge;
243 foreach_out_edge(env->bl, edge) {
244 ir_node *irn = get_edge_src_irn(edge);
245 if(to_appear(env, irn))
246 nodeset_insert(nodes, irn);
249 compute_heights(env);
251 while(nodeset_count(nodes) > 0) {
254 ir_node *highest_node = NULL;
255 ir_node *lowest_desc = NULL;
258 int recompute_height = 0;
261 /* search the highest node which is not yet in a lineage. */
262 for(irn = nodeset_first(nodes); irn; irn = nodeset_next(nodes)) {
263 mris_irn_t *inf = get_mris_irn(env, irn);
264 if(inf->height > curr_height) {
266 curr_height = inf->height;
270 assert(highest_node);
271 DBG((dbg, LEVEL_2, "highest node is %+F height %d\n", highest_node, get_irn_height(env, highest_node)));
273 /* start a lineage beginning with highest_node. */
274 mi = get_mris_irn(env, highest_node);
275 mi->lineage_start = highest_node;
276 mi->lineage_next = NULL;
277 mi->lineage_end = NULL;
278 list_add(&mi->lineage_list, &env->lineage_head);
279 nodeset_remove(nodes, highest_node);
282 put all descendants in an array.
283 we also move the lowest descendant in front, so that the other nodes
284 are easily accessible as an array, too.
286 in = all_descendants(env, highest_node);
287 lowest_desc = put_lowest_in_front(env, in);
289 /* as long as the current highest node has still descendants */
291 mris_irn_t *lowest_mi = get_mris_irn(env, lowest_desc);
292 mris_irn_t *highest_mi = get_mris_irn(env, highest_node);
293 mris_irn_t *start_mi = get_mris_irn(env, highest_mi->lineage_start);
294 int highest_is_tuple = get_irn_mode(highest_node) == mode_T;
298 DBG((dbg, LEVEL_2, "\tlowest descendant %+F height %d\n", lowest_desc, mi->height));
300 /* count the number of all descendants which are not the lowest descendant */
301 for(n_desc = 0; in[n_desc + 1]; ++n_desc);
304 we insert a CopyKeep node to express the artificial dependencies from the lowest
305 descendant to all other descendants.
307 if(n_desc > 1 && !be_is_Keep(lowest_desc)) {
308 const arch_register_class_t *cls;
309 ir_node *copy_keep, *op;
312 for(i = 0, n = get_irn_arity(lowest_desc); i < n; ++i) {
315 op = get_irn_n(lowest_desc, i);
316 cmp = highest_is_tuple ? skip_Projs(op) : op;
318 if(cmp == highest_node)
322 assert(i < n && "could not find operand");
324 cls = arch_get_irn_reg_class(env->aenv, op, BE_OUT_POS(0));
325 replace_tuple_by_repr_proj(env, &in[1]);
326 copy_keep = be_new_CopyKeep(cls, env->irg, env->bl, op, n_desc, &in[1], get_irn_mode(op));
327 set_irn_n(lowest_desc, i, copy_keep);
328 nodeset_insert(env->inserted, copy_keep);
330 obstack_free(&env->obst, in);
332 /* mark the current lowest node as the last one in the lineage. */
333 highest_mi->lineage_next = lowest_desc;
334 start_mi->lineage_end = lowest_desc;
336 /* if the current lowest node is not yet in a lineage, add it to the current one. */
337 if(!lowest_mi->lineage_start) {
338 lowest_mi->lineage_start = highest_mi->lineage_start;
339 nodeset_remove(nodes, lowest_desc);
342 /* else we cannot extend this lineage, so break. */
346 highest_node = lowest_desc;
347 highest_mi = lowest_mi;
349 /* recompute the descendants array and the new lowest descendant. */
350 in = all_descendants(env, highest_node);
351 lowest_desc = put_lowest_in_front(env, in);
354 /* recompute the heights if desired. */
356 compute_heights(env);
360 static int fuse_two_lineages(mris_env_t *env, mris_irn_t *u, mris_irn_t *v)
364 ir_node *irn, *last, *copy;
365 ir_node *u_end = u->lineage_end;
366 ir_node *v_start = v->lineage_start;
367 ir_node *start = skip_Projs(v_start);
369 if(be_is_Keep(start))
372 /* set lineage end of nodes in u to end of v. */
373 irn = last = u->lineage_start;
374 mi = get_mris_irn(env, irn);
375 while(irn != u_end) {
376 mi = get_mris_irn(env, irn);
377 mi->lineage_end = v->lineage_end;
379 irn = mi->lineage_next;
382 /* insert a CopyKeep to make lineage v dependent on u. */
384 const arch_register_class_t *cls;
387 if(get_irn_arity(start) == 0)
390 op = get_irn_n(start, 0);
392 cls = arch_get_irn_reg_class(env->aenv, op, BE_OUT_POS(0));
393 if(get_irn_mode(last) == mode_T) {
394 const ir_edge_t *edge;
395 foreach_out_edge(last, edge) {
396 last = get_edge_src_irn(edge);
400 copy = be_new_CopyKeep_single(cls, env->irg, env->bl, op, last, get_irn_mode(op));
401 set_irn_n(start, 0, copy);
402 copy_mi = get_mris_irn(env, copy);
403 nodeset_insert(env->inserted, copy);
406 /* irn now points to the last node in lineage u; mi has the info for the node _before_ the terminator of the lineage. */
407 mi->lineage_next = copy;
408 copy_mi->lineage_start = u->lineage_start;
409 copy_mi->lineage_end = v->lineage_end;
410 copy_mi->lineage_next = v_start;
412 /* set lineage start of nodes in v to start of u. */
413 irn = v->lineage_start;
414 while(irn != v->lineage_end) {
415 mris_irn_t *mi = get_mris_irn(env, irn);
416 mi->lineage_start = u->lineage_start;
417 irn = mi->lineage_next;
420 mi = get_mris_irn(env, v_start);
421 list_del(&mi->lineage_list);
426 static void fuse_lineages(mris_env_t *env)
429 mris_irn_t *u, *v, *tmp1, *tmp2;
432 foreach_lineage(env, u, tmp1) {
433 foreach_lineage(env, v, tmp2) {
437 if(!reaches(env, u->lineage_start, v->lineage_end) && reaches(env, v->lineage_start, u->lineage_end)) {
438 if(fuse_two_lineages(env, u, v))
445 static void block_walker(ir_node *bl, void *data)
447 mris_env_t *env = data;
449 lineage_formation(env);
454 mris_env_t *be_sched_mris_preprocess(const be_irg_t *birg)
456 mris_env_t *env = xmalloc(sizeof(env[0]));
458 env->aenv = birg->main_env->arch_env;
459 env->irg = birg->irg;
461 env->inserted = new_nodeset(128);
462 INIT_LIST_HEAD(&env->lineage_head);
463 FIRM_DBG_REGISTER(env->dbg, "firm.be.sched.mris");
464 obstack_init(&env->obst);
465 irg_walk_graph(env->irg, firm_clear_link, NULL, NULL);
466 irg_block_walk_graph(birg->irg, block_walker, NULL, env);
467 obstack_free(&env->obst, NULL);
471 static void cleanup_inserted(mris_env_t *env)
475 foreach_nodeset(env->inserted, irn) {
479 assert(be_is_CopyKeep(irn));
480 tgt = get_irn_n(irn, be_pos_CopyKeep_op);
482 /* reroute the edges, remove from schedule and make it invisible. */
483 edges_reroute(irn, tgt, env->irg);
484 if (sched_is_scheduled(irn))
486 for(i = -1, n = get_irn_arity(irn); i < n; ++i)
487 set_irn_n(irn, i, new_r_Bad(env->irg));
491 void be_sched_mris_free(mris_env_t *env)
493 cleanup_inserted(env);
494 del_nodeset(env->inserted);