96e2938465e9b1ebaa86a9f7ed5bc2c57c99251c
[libfirm] / ir / be / beschedmris.c
1 /**
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
7  * @date   04.04.2006
8  */
9
10 #include <limits.h>
11
12 #include "obst.h"
13 #include "debug.h"
14
15 #include "irgraph_t.h"
16 #include "irnode_t.h"
17 #include "iredges_t.h"
18 #include "ircons_t.h"
19 #include "irphase_t.h"
20 #include "irgwalk.h"
21 #include "irtools.h"
22
23 #include "height.h"
24
25 #include "benode_t.h"
26 #include "besched_t.h"
27 #include "beschedmris.h"
28
29 struct _mris_env_t {
30         phase_t            ph;
31         heights_t         *heights;
32         const arch_env_t  *aenv;
33         ir_graph          *irg;
34         ir_node           *bl;
35         nodeset           *inserted;
36         int               visited;
37         struct list_head  lineage_head;
38         struct obstack    obst;
39 DEBUG_ONLY(firm_dbg_module_t *dbg;)
40 };
41
42 typedef struct _mris_irn_t {
43         int visited;
44         ir_node *lineage_start;
45         ir_node *lineage_next;
46         ir_node *lineage_end;
47         struct list_head lineage_list;
48 } mris_irn_t;
49
50 #define to_appear(env, irn) (to_appear_in_schedule(irn) && get_nodes_block(irn) == env->bl)
51
52 #define get_mris_irn(env, irn)   ((mris_irn_t *) phase_get_or_set_irn_data(&env->ph, irn))
53 #define foreach_lineage(env, pos, tmp) list_for_each_entry_safe(mris_irn_t, pos, tmp, &(env)->lineage_head, lineage_list)
54
55 static void mris_irn_data_init(phase_t *ph, const ir_node *irn, void *data)
56 {
57         mris_irn_t *mi = data;
58         memset(data, 0, sizeof(mi[0]));
59         INIT_LIST_HEAD(&mi->lineage_list);
60 }
61
62 #if 0
63 static int compute_height(mris_env_t *env, ir_node *irn, unsigned long visited)
64 {
65         mris_irn_t *mi = get_mris_irn(env, irn);
66
67         if(get_irn_visited(irn) >= visited) {
68                 DBG((env->dbg, LEVEL_3, "\theight of %+F = %d\n", irn, mi->height));
69                 return mi->height;
70         }
71
72         else {
73                 const ir_edge_t *edge;
74
75                 set_irn_visited(irn, visited);
76                 mi->height  = 0;
77
78                 foreach_out_edge(irn, edge) {
79                         ir_node *dep = get_edge_src_irn(edge);
80
81                         if(!is_Block(dep) && get_nodes_block(dep) == env->bl) {
82                                 int dep_height = compute_height(env, dep, visited);
83                                 mi->height     = MAX(mi->height, dep_height);
84                         }
85                 }
86
87                 mi->height++;
88                 DBG((env->dbg, LEVEL_3, "\tsetting height of %+F = %d\n", irn, mi->height));
89         }
90
91         return mi->height;
92 }
93
94 static void compute_heights(mris_env_t *env)
95 {
96         const ir_edge_t *edge;
97         unsigned long visited;
98
99         visited = get_irg_visited(env->irg) + 1;
100         set_irg_visited(env->irg, visited);
101
102         foreach_out_edge(env->bl, edge) {
103                 ir_node *dep = get_edge_src_irn(edge);
104                 if(to_appear(env, dep))
105                         compute_height(env, dep, visited);
106         }
107 }
108 #endif
109
110 #define valid_node(env, dep) (to_appear(env, dep) && !nodeset_find(env->inserted, dep) && !be_is_Keep(dep))
111
112 static void grow_all_descendands(mris_env_t *env, ir_node *irn, unsigned long visited)
113 {
114         const ir_edge_t *edge;
115
116         assert(get_irn_mode(irn) != mode_T);
117
118         foreach_out_edge(irn, edge) {
119                 ir_node *desc = get_edge_src_irn(edge);
120                 if(valid_node(env, desc) && get_irn_visited(desc) < visited) {
121                         obstack_ptr_grow(&env->obst, desc);
122                         set_irn_visited(desc, visited);
123                 }
124         }
125 }
126
127 static ir_node **all_descendants(mris_env_t *env, ir_node *irn)
128 {
129         unsigned long visited;
130         const ir_edge_t *edge;
131
132         visited = get_irg_visited(env->irg) + 1;
133         set_irg_visited(env->irg, visited);
134
135         if(get_irn_mode(irn) == mode_T) {
136                 foreach_out_edge(irn, edge) {
137                         ir_node *desc = get_edge_src_irn(edge);
138                         assert(is_Proj(desc) && get_irn_mode(desc) != mode_T);
139                         grow_all_descendands(env, desc, visited);
140                 }
141         }
142
143         else
144                 grow_all_descendands(env, irn, visited);
145
146         obstack_ptr_grow(&env->obst, NULL);
147         return obstack_finish(&env->obst);
148 }
149
150 static ir_node *put_lowest_in_front(mris_env_t *env, ir_node **in)
151 {
152         int lowest_index       = 0;
153         unsigned lowest_height = INT_MAX;
154         int i;
155
156         for(i = 0; in[i]; ++i) {
157                 unsigned height = get_irn_height(env->heights, in[i]);
158                 if(height < lowest_height) {
159                         lowest_height = height;
160                         lowest_index  = i;
161                 }
162         }
163
164         if(i > 0) {
165                 ir_node *tmp     = in[0];
166                 in[0]            = in[lowest_index];
167                 in[lowest_index] = tmp;
168         }
169
170         return in[0];
171 }
172
173 #if 0
174 static void reaches_walker(mris_env_t *env, ir_node *irn, ir_node *tgt, int *found, unsigned long visited)
175 {
176         if(get_irn_visited(irn) < visited && get_nodes_block(irn) == env->bl) {
177
178                 set_irn_visited(irn, visited);
179
180                 if(irn == tgt)
181                         *found = 1;
182                 else {
183                         int i, n;
184
185                         for(i = 0, n = get_irn_arity(irn); i < n; ++i) {
186                                 ir_node *op = get_irn_n(irn, i);
187                                 if(!*found)
188                                         reaches_walker(env, op, tgt, found, visited);
189                         }
190                 }
191         }
192 }
193
194 static int reaches(mris_env_t *env, ir_node *src, ir_node *tgt)
195 {
196         int found = 0;
197         unsigned long visited = get_irg_visited(env->irg) + 1;
198
199         set_irg_visited(env->irg, visited);
200         reaches_walker(env, src, tgt, &found, visited);
201         return found;
202 }
203 #endif
204
205 static INLINE ir_node *skip_Projs(ir_node *irn)
206 {
207         return is_Proj(irn) ? skip_Projs(get_Proj_pred(irn)) : irn;
208 }
209
210 static void replace_tuple_by_repr_proj(mris_env_t *env, ir_node **in)
211 {
212         int i;
213
214         for(i = 0; in[i]; ++i) {
215                 if(get_irn_mode(in[i]) == mode_T) {
216                         const ir_edge_t *edge;
217                         ir_node *proj  = NULL;
218                         ir_node *first = NULL;
219
220                         foreach_out_edge(in[i], edge) {
221                                 ir_node *desc = get_edge_src_irn(edge);
222
223                                 first = first ? first : desc;
224                                 if(get_irn_mode(desc) == mode_M) {
225                                         proj = desc;
226                                         break;
227                                 }
228                         }
229
230                         proj = proj ? proj : first;
231                         assert(proj);
232                         in[i] = proj;
233                 }
234         }
235 }
236
237 static void lineage_formation(mris_env_t *env)
238 {
239         firm_dbg_module_t *dbg = env->dbg;
240         nodeset *nodes         = new_nodeset(128);
241
242         const ir_edge_t *edge;
243
244         foreach_out_edge(env->bl, edge) {
245                 ir_node *irn = get_edge_src_irn(edge);
246                 if(to_appear(env, irn))
247                         nodeset_insert(nodes, irn);
248         }
249
250         while(nodeset_count(nodes) > 0) {
251                 mris_irn_t *mi;
252                 ir_node *irn;
253                 ir_node *highest_node = NULL;
254                 ir_node *lowest_desc  = NULL;
255
256                 ir_node **in;
257                 int recompute_height  = 0;
258                 unsigned  curr_height = 0;
259
260                 /* search the highest node which is not yet in a lineage. */
261                 for(irn = nodeset_first(nodes); irn; irn = nodeset_next(nodes)) {
262                         unsigned height = get_irn_height(env->heights, irn);
263                         if(height > curr_height) {
264                                 highest_node = irn;
265                                 curr_height  = height;
266                         }
267                 }
268
269                 assert(highest_node);
270                 DBG((dbg, LEVEL_2, "highest node is %+F height %d\n", highest_node, get_irn_height(env->heights, highest_node)));
271
272                 /* start a lineage beginning with highest_node. */
273                 mi = get_mris_irn(env, highest_node);
274                 mi->lineage_start = highest_node;
275                 mi->lineage_next  = NULL;
276                 mi->lineage_end   = NULL;
277                 list_add(&mi->lineage_list, &env->lineage_head);
278                 nodeset_remove(nodes, highest_node);
279
280                 /*
281                         put all descendants in an array.
282                         we also move the lowest descendant in front, so that the other nodes
283                         are easily accessible as an array, too.
284                 */
285                 in          = all_descendants(env, highest_node);
286                 lowest_desc = put_lowest_in_front(env, in);
287
288                 /* as long as the current highest node has still descendants */
289                 while(lowest_desc) {
290                         mris_irn_t *lowest_mi  = get_mris_irn(env, lowest_desc);
291                         mris_irn_t *highest_mi = get_mris_irn(env, highest_node);
292                         mris_irn_t *start_mi   = get_mris_irn(env, highest_mi->lineage_start);
293                         int highest_is_tuple   = get_irn_mode(highest_node) == mode_T;
294
295                         int n_desc;
296
297                         DBG((dbg, LEVEL_2, "\tlowest descendant %+F height %d\n", lowest_desc, get_irn_height(env->heights, lowest_desc)));
298
299                         /* count the number of all descendants which are not the lowest descendant */
300                         for(n_desc = 0; in[n_desc + 1]; ++n_desc);
301
302                         /*
303                         we insert a CopyKeep node to express the artificial dependencies from the lowest
304                         descendant to all other descendants.
305                         */
306                         if(n_desc > 1 && !be_is_Keep(lowest_desc)) {
307                                 const arch_register_class_t *cls;
308                                 ir_node *copy_keep, *op;
309                                 int i, n;
310
311                                 for(i = 0, n = get_irn_arity(lowest_desc); i < n; ++i) {
312                                         ir_node *cmp;
313
314                                         op  = get_irn_n(lowest_desc, i);
315                                         cmp = highest_is_tuple ? skip_Projs(op) : op;
316
317                                         if(cmp == highest_node)
318                                                 break;
319                                 }
320
321                                 assert(i < n && "could not find operand");
322
323                                 cls = arch_get_irn_reg_class(env->aenv, op, BE_OUT_POS(0));
324                                 replace_tuple_by_repr_proj(env, &in[1]);
325                                 copy_keep = be_new_CopyKeep(cls, env->irg, env->bl, op, n_desc, &in[1], get_irn_mode(op));
326                                 set_irn_n(lowest_desc, i, copy_keep);
327                                 nodeset_insert(env->inserted, copy_keep);
328                         }
329                         obstack_free(&env->obst, in);
330
331                         /* mark the current lowest node as the last one in the lineage. */
332                         highest_mi->lineage_next = lowest_desc;
333                         start_mi->lineage_end    = lowest_desc;
334
335                         /* if the current lowest node is not yet in a lineage, add it to the current one. */
336                         if(!lowest_mi->lineage_start) {
337                                 lowest_mi->lineage_start = highest_mi->lineage_start;
338                                 nodeset_remove(nodes, lowest_desc);
339                         }
340
341                         /* else we cannot extend this lineage, so break. */
342                         else
343                                 break;
344
345                         highest_node = lowest_desc;
346                         highest_mi   = lowest_mi;
347
348                         /* recompute the descendants array and the new lowest descendant. */
349                         in          = all_descendants(env, highest_node);
350                         lowest_desc = put_lowest_in_front(env, in);
351                 }
352
353                 /* recompute the heights if desired. */
354                 if(recompute_height)
355                         heights_recompute(env->heights);
356         }
357 }
358
359 static int fuse_two_lineages(mris_env_t *env, mris_irn_t *u, mris_irn_t *v)
360 {
361         mris_irn_t *mi;
362         mris_irn_t *copy_mi;
363         ir_node *irn, *last, *copy;
364         ir_node *u_end   = u->lineage_end;
365         ir_node *v_start = v->lineage_start;
366         ir_node *start   = skip_Projs(v_start);
367
368         if(be_is_Keep(start))
369                 return 0;
370
371         /* set lineage end of nodes in u to end of v. */
372         irn = last = u->lineage_start;
373         mi         = get_mris_irn(env, irn);
374         while(irn && irn != u_end) {
375                 mi = get_mris_irn(env, irn);
376                 mi->lineage_end = v->lineage_end;
377                 last = irn;
378                 irn = mi->lineage_next;
379         }
380
381         /* insert a CopyKeep to make lineage v dependent on u. */
382         {
383                 const arch_register_class_t *cls;
384                 ir_node *op    = NULL;
385
386                 if(get_irn_arity(start) == 0)
387                         return 0;
388
389                 op = get_irn_n(start, 0);
390
391                 cls  = arch_get_irn_reg_class(env->aenv, op, BE_OUT_POS(0));
392                 if(get_irn_mode(last) == mode_T) {
393                         const ir_edge_t *edge;
394                         foreach_out_edge(last, edge) {
395                                 last = get_edge_src_irn(edge);
396                                 break;
397                         }
398                 }
399                 copy = be_new_CopyKeep_single(cls, env->irg, env->bl, op, last, get_irn_mode(op));
400                 set_irn_n(start, 0, copy);
401                 copy_mi = get_mris_irn(env, copy);
402                 nodeset_insert(env->inserted, copy);
403         }
404
405         /* irn now points to the last node in lineage u; mi has the info for the node _before_ the terminator of the lineage. */
406         mi->lineage_next       = copy;
407         copy_mi->lineage_start = u->lineage_start;
408         copy_mi->lineage_end   = v->lineage_end;
409         copy_mi->lineage_next  = v_start;
410
411         /* set lineage start of nodes in v to start of u. */
412         irn = v->lineage_start;
413         while(irn && irn != v->lineage_end) {
414                 mris_irn_t *mi = get_mris_irn(env, irn);
415                 mi->lineage_start = u->lineage_start;
416                 irn = mi->lineage_next;
417         }
418
419         heights_recompute(env->heights);
420
421         mi = get_mris_irn(env, v_start);
422         list_del(&mi->lineage_list);
423
424         return 1;
425 }
426
427 static void fuse_lineages(mris_env_t *env)
428 {
429         int fused = 1;
430         mris_irn_t *u, *v, *tmp1, *tmp2;
431
432 again:
433         foreach_lineage(env, u, tmp1) {
434                 foreach_lineage(env, v, tmp2) {
435                         if(u != v && u->lineage_start && v->lineage_start && u->lineage_end && v->lineage_end
436                                 && get_nodes_block(u->lineage_start) == get_nodes_block(v->lineage_start)) {
437                                 int uv = heights_reachable_in_block(env->heights, u->lineage_start, v->lineage_end);
438                                 int vu = heights_reachable_in_block(env->heights, v->lineage_start, u->lineage_end);
439
440                                 if(uv && !vu) {
441                                         if(fuse_two_lineages(env, u, v))
442                                                 goto again;
443                                 }
444                         }
445                 }
446         }
447 }
448
449 static void block_walker(ir_node *bl, void *data)
450 {
451         mris_env_t *env = data;
452         env->bl = bl;
453         lineage_formation(env);
454         fuse_lineages(env);
455 }
456
457
458 mris_env_t *be_sched_mris_preprocess(const be_irg_t *birg)
459 {
460         mris_env_t *env = xmalloc(sizeof(env[0]));
461
462         phase_init(&env->ph, "mris", birg->irg, sizeof(mris_irn_t), 2 * PHASE_DEFAULT_GROWTH, mris_irn_data_init);
463         env->aenv     = birg->main_env->arch_env;
464         env->irg      = birg->irg;
465         env->visited  = 0;
466         env->inserted = new_nodeset(128);
467         env->heights  = heights_new(birg->irg);
468         INIT_LIST_HEAD(&env->lineage_head);
469         FIRM_DBG_REGISTER(env->dbg, "firm.be.sched.mris");
470         obstack_init(&env->obst);
471         irg_walk_graph(env->irg, firm_clear_link, NULL, NULL);
472         irg_block_walk_graph(birg->irg, block_walker, NULL, env);
473         obstack_free(&env->obst, NULL);
474         return env;
475 }
476
477 static void cleanup_inserted(mris_env_t *env)
478 {
479         ir_node *irn;
480
481         foreach_nodeset(env->inserted, irn) {
482                 int i, n;
483                 ir_node *tgt;
484
485                 assert(be_is_CopyKeep(irn));
486                 tgt = get_irn_n(irn, be_pos_CopyKeep_op);
487
488                 /* reroute the edges, remove from schedule and make it invisible. */
489                 edges_reroute(irn, tgt, env->irg);
490                 if (sched_is_scheduled(irn))
491                         sched_remove(irn);
492                 for(i = -1, n = get_irn_arity(irn); i < n; ++i)
493                         set_irn_n(irn, i, new_r_Bad(env->irg));
494         }
495 }
496
497 void be_sched_mris_free(mris_env_t *env)
498 {
499         cleanup_inserted(env);
500         phase_free(&env->ph);
501         del_nodeset(env->inserted);
502         heights_free(env->heights);
503         free(env);
504 }