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