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