fixed config.h include
[libfirm] / ir / ana / interval_analysis.c
1 #ifdef HAVE_CONFIG_H
2 #include "config.h"
3 #endif
4
5 #ifdef HAVE_STRING_H
6 #include <string.h>
7 #endif
8
9 #include "interval_analysis.h"
10
11 #include "firm_common_t.h"
12 #include "set.h"
13 #include "array.h"
14
15 #include "irloop.h"
16 #include "irnode.h"
17 #include "irdump_t.h"
18 #include "irdom.h"
19 #include "irflag.h"
20
21 /*------------------------------------------------------------------*/
22 /* A new in array via a hashmap. */
23 /* The in array refers to the loop the block is contained in if the */
24 /* block is not in blocks loop. */
25 /*------------------------------------------------------------------*/
26
27 typedef struct {
28   void *reg;
29   void **in_array;
30   void **op_array;
31   int n_outs;
32   int n_exc_outs;
33 } region_attr;
34
35 static set *region_attr_set = NULL;
36
37 int region_attr_cmp(const void *e1, const void *e2, size_t size) {
38   region_attr *ra1 = (region_attr *)e1;
39   region_attr *ra2 = (region_attr *)e2;
40   return (ra1->reg != ra2->reg);
41 }
42
43 static INLINE int attr_set_hash (region_attr *a) {
44   unsigned int v = (unsigned int) a->reg;
45   return v ^ (v>>8);
46 }
47
48 static INLINE region_attr *get_region_attr(void *region) {
49   region_attr r_attr, *res;
50   r_attr.reg = region;
51
52   res = set_find(region_attr_set, &r_attr, sizeof(r_attr), attr_set_hash(&r_attr));
53
54   if (!res) {
55     r_attr.in_array = NEW_ARR_F(void *, 0);
56     if (is_ir_loop(region))
57       r_attr.op_array = NEW_ARR_F(void *, 0);
58     else
59       r_attr.op_array = NULL;
60     r_attr.n_outs = 0;
61     r_attr.n_exc_outs = 0;
62     res = set_insert(region_attr_set, &r_attr, sizeof(r_attr), attr_set_hash(&r_attr));
63   }
64
65   return res;
66 }
67
68 int get_region_n_ins(void *region) {
69   return ARR_LEN(get_region_attr(region)->in_array);
70 }
71
72 void *get_region_in(void *region, int pos) {
73   assert(0 <= pos && pos < get_region_n_ins(region));
74   return (get_region_attr(region)->in_array)[pos];
75 }
76
77 void add_region_in (void *region, void *in) {
78   ARR_APP1(void *, get_region_attr(region)->in_array, in);
79   get_region_attr(in)->n_outs++;
80 }
81
82 int get_region_n_outs(void *region) {
83   return get_region_attr(region)->n_outs;
84 }
85
86 int get_region_n_exc_outs(void *region) {
87   return get_region_attr(region)->n_exc_outs;
88 }
89
90 void inc_region_n_exc_outs(void *region) {
91   (get_region_attr(region)->n_exc_outs)++;
92 }
93
94 void *get_loop_cfop(void *region, int pos) {
95   assert(0 <= pos && pos < get_region_n_ins(region));
96   return (get_region_attr(region)->op_array)[pos];
97 }
98
99 void add_loop_cfop (void *region, void *cfop) {
100   assert(cfop);
101   ARR_APP1(void *, get_region_attr(region)->op_array, cfop);
102 }
103
104 static INLINE void exc_outs(void *reg, ir_node *cfop) {
105   if (is_fragile_op(cfop)) inc_region_n_exc_outs(reg);
106 }
107
108 /*------------------------------------------------------------------*/
109 /* Algorithm to construct the interval edges based on a loop tree. */
110 /* Walk a loop and add all edges.  Walk inner loops by recursion. */
111 /*------------------------------------------------------------------*/
112
113 /* return true if outer can be reached from inner via the outer loop relation */
114 static int find_outer_loop(ir_loop *inner, ir_loop *outer, ir_node *b, ir_node *cfop) {
115   if (get_loop_outer_loop(inner) == outer) {
116     add_region_in(inner, b);
117     add_loop_cfop(inner, cfop);
118     exc_outs(b, cfop);
119     return true;
120   }
121   return false;
122 }
123
124 static int test_loop_nest(ir_node *pred_b, ir_loop *nest) {
125   int i, n_elems = get_loop_n_elements(nest);
126
127   for (i = 0; (i < n_elems); ++i) {
128     loop_element e = get_loop_element(nest, i);
129     switch (*e.kind) {
130     case k_ir_node: {
131       if (e.node == pred_b) return true;
132     } break;
133     case k_ir_loop: {
134       if (test_loop_nest(pred_b, e.son)) return true;
135     } break;
136     default: break;
137     }
138   }
139   return false;
140 }
141
142 static int find_inner_loop(ir_node *b, ir_loop *l, ir_node *pred, ir_node *cfop) {
143   int i, n_elems = get_loop_n_elements(l);
144   int found = false;
145
146   for (i = 0; (i < n_elems) && !found; ++i) {
147     loop_element e = get_loop_element(l, i);
148     switch (*e.kind) {
149     case k_ir_node: {
150       if (e.node == b) return false;
151     } break;
152     case k_ir_loop: {
153       found = test_loop_nest(pred, e.son);
154       if (found) {
155         add_region_in(b, e.son);
156         exc_outs(e.son, cfop);
157         //if (is_fragile_op(cfop)) inc_region_n_exc_outs(b);
158         return found;
159       }
160     } break;
161     default: break;
162     }
163   }
164   return found;
165 }
166
167
168 static int find_previous_loop(ir_loop *l, ir_loop *pred_l, ir_node *b, ir_node *pred_b, ir_node *cfop) {
169   ir_loop *outer = get_loop_outer_loop(l);
170   int found, i;
171   int l_pos = get_loop_element_pos(outer, l);
172   assert(l_pos > -1);
173   assert(l_pos > 0 && "Is this a necessary condition?  There could be a perfect nest ...");
174
175   for (i = l_pos -1, found = false; i > -1 && !found; --i) {
176     ir_loop *k = get_loop_element(outer, i).son;
177     if (is_ir_loop(k)) {
178       found = test_loop_nest(pred_b, k);
179       if (found) {
180         add_region_in(l, k);
181         //if (is_fragile_op(cfop)) inc_region_n_exc_outs(k);
182         exc_outs(k, cfop);
183         add_loop_cfop(l, cfop);
184         add_region_in(b, NULL);
185       }
186     }
187   }
188
189   if (!found) {
190     DDMG(current_ir_graph);
191     DDML(l);
192     DDML(pred_l);
193     DDMN(b);
194     DDMN(pred_b);
195   }
196
197   return found;
198 }
199
200
201 /* Compute the edges for the interval graph.
202  *
203  * @param b The block for which to constuct the edges.
204  * @param l The loop of b.
205  *
206  * There are four cases:
207  * - The pred block is in the same loop.  Add a normal block-block edge.
208  * - The pred block is in a loop contained in this loop, somewhere down in
209  *   the nesting. The predecessor of this block is the outermost loop of the nest
210  *   directly contained in l.
211  * - The pred block is in the outer loop of l.  l gets an edge to the pred block.
212  * - The outer loop of l contains another loop k just before l.  The control flow
213  *   branches directly from loop k to loop l.  Add an edge l->k.  Watch it: k must
214  *   not be a direct predecessor of l in the loop tree!
215  */
216 static void construct_interval_block(ir_node *b, ir_loop *l) {
217   int i, n_cfgpreds = get_Block_n_cfgpreds(b);
218
219   if (b == get_irg_start_block(current_ir_graph)) return;
220   /* We want nice blocks. */
221   assert(n_cfgpreds > 0);
222
223   for (i = 0; i < n_cfgpreds; ++i) {
224     if (is_backedge(b, i)) {
225       if (b != get_loop_element(l, 0).node) {
226         if (get_firm_verbosity()) {
227           printf("Loophead not at loop position 0. "); DDMN(b);
228         }
229       }
230       /* There are no backedges in the interval decomposition. */
231       add_region_in(b, NULL);
232       continue;
233     }
234
235     ir_node *cfop = skip_Proj(get_Block_cfgpred(b, i));
236     ir_node *pred = get_nodes_block(cfop);
237     /* We want nice blocks. */
238     assert(   get_irn_op(pred) != op_Bad
239            && get_irn_op(skip_Proj(get_Block_cfgpred(b, i))) != op_Bad);
240     ir_loop *pred_l = get_irn_loop(pred);
241     if (pred_l == l) {
242       add_region_in(b, pred);
243       //if (is_fragile_op(cfop)) inc_region_n_exc_outs(b);
244       exc_outs(pred, cfop);
245     } else {
246       int found = find_inner_loop(b, l, pred, cfop);
247       if (!found) {
248         if (b != get_loop_element(l, 0).node) {
249           if (get_firm_verbosity()) {
250             printf("Loop entry not at loop position 0. "); DDMN(b);
251           }
252         }
253         found = find_outer_loop(l, pred_l, pred, cfop);
254         if (found) add_region_in(b, NULL);  /* placeholder */
255       }
256       if (!found) {
257         found = find_previous_loop(l, pred_l, b, pred, cfop);
258       }
259       if (!found) {
260         DDMG(current_ir_graph);
261         DDMN(b);
262         DDMN(pred);
263         assert(is_backedge(b, i));
264         assert(found && "backedge from inner loop");
265       }
266     }
267
268     if (b != get_loop_element(l, 0).node) {
269       /* Check for improper region */
270       if (has_backedges(b)) {
271         printf("Improper Region!!!!!!\n");
272         DDMG(current_ir_graph);
273         DDMN(b);
274         DDML(l);
275       }
276     }
277   }
278 }
279
280 static void construct_interval_edges(ir_loop *l) {
281   int i, n_elems = get_loop_n_elements(l);
282   for (i = 0; i < n_elems; ++i) {
283     loop_element e = get_loop_element(l, i);
284     switch (*e.kind) {
285     case k_ir_node: {
286       construct_interval_block(e.node, l);
287     } break;
288     case k_ir_loop: {
289       construct_interval_edges(e.son);
290     } break;
291     default: break;
292     }
293   }
294 }
295
296 void construct_intervals(ir_graph *irg) {
297   ir_loop *l;
298   ir_graph *rem = current_ir_graph;
299   current_ir_graph = irg;
300
301   if (!region_attr_set)
302     region_attr_set = new_set(region_attr_cmp, 256);
303
304   construct_cf_backedges(current_ir_graph);
305
306
307   l = get_irg_loop(current_ir_graph);
308
309   construct_interval_edges(l);
310
311   current_ir_graph = rem;
312 }
313
314 void free_intervals(void) {
315   //void **ins;
316   if (!region_attr_set) return;
317   /* @@@ mem leak
318   for (ins = (void **)pmap_first(region_in_map);
319        ins;
320        ins = (void **)pmap_next(region_in_map)) {
321     //DEL_ARR_F(ins);
322   }
323   */
324   del_set(region_attr_set);
325   region_attr_set = NULL;
326 }
327
328 /*------------------------------------------------------------------*/
329 /* A vcg dumper showing an interval decomposition of a cfg.         */
330 /*                                                                  */
331 /*------------------------------------------------------------------*/
332
333 void dump_region_edges(FILE *F, void *reg) {
334   int i, n_ins = get_region_n_ins(reg);
335
336   if (is_ir_node(reg) && get_Block_n_cfgpreds((ir_node *)reg) > get_region_n_ins(reg)) {
337     for (i = n_ins; i < get_Block_n_cfgpreds((ir_node *)reg); ++i) {
338       if (is_backedge((ir_node *)reg, i))
339         fprintf (F, "backedge: { sourcename: \"");
340       else
341         fprintf (F, "edge: { sourcename: \"");
342       PRINT_NODEID(((ir_node *)reg));
343       fprintf (F, "\" targetname: \"");
344       PRINT_NODEID(get_nodes_block(skip_Proj(get_Block_cfgpred((ir_node *)reg, i))));
345       fprintf (F, "\" " BLOCK_EDGE_ATTR "}\n");
346     }
347   }
348
349   for (i = 0; i < n_ins; ++i) {
350     void *target = get_region_in(reg, i);
351
352     if (is_ir_node(reg)) {
353       if (get_Block_n_cfgpreds((ir_node *)reg) != get_region_n_ins(reg)) {
354         printf("n_cfgpreds = %d, n_ins = %d\n", get_Block_n_cfgpreds((ir_node *)reg), get_region_n_ins(reg));
355         DDMN((ir_node *)reg);
356       }
357     }
358
359     if ((!target || (is_ir_node(reg) && !is_ir_node(target))) && i < get_Block_n_cfgpreds((ir_node *)reg)) {
360       assert(is_ir_node(reg));
361       if (is_backedge((ir_node *)reg, i))
362         fprintf (F, "backedge: { sourcename: \"");
363       else
364         fprintf (F, "edge: { sourcename: \"");
365       PRINT_NODEID(((ir_node *)reg));
366       fprintf (F, "\" targetname: \"");
367       PRINT_NODEID(get_nodes_block(skip_Proj(get_Block_cfgpred((ir_node *)reg, i))));
368       fprintf (F, "\" " BLOCK_EDGE_ATTR "}\n");
369
370       if (!target) continue;
371     }
372
373     fprintf (F, "edge: { sourcename: \"");
374     if (is_ir_node(reg)) {
375       PRINT_NODEID(((ir_node *)reg));
376     } else {
377       PRINT_LOOPID(((ir_loop *)reg));
378     }
379     fprintf (F, "\" targetname: \"");
380     if (is_ir_node(target)) {
381       PRINT_NODEID(((ir_node *)target));
382     } else {
383       PRINT_LOOPID(((ir_loop *)target));
384     }
385     fprintf (F, "\"");
386     if (is_ir_node(reg) && is_fragile_op(skip_Proj(get_Block_cfgpred(reg, i))))
387       fprintf(F, EXC_CF_EDGE_ATTR);
388     fprintf (F, "}\n");
389   }
390 }
391
392 #include "execution_frequency.h"
393
394 void dump_interval_block(FILE *F, ir_node *block) {
395   int i, fl;
396   /* This is a block. Dump a node for the block. */
397   fprintf (F, "node: {title: \""); PRINT_NODEID(block);
398   fprintf (F, "\" label: \"");
399   if (block == get_irg_start_block(get_irn_irg(block)))
400     fprintf(F, "Start ");
401   if (block == get_irg_end_block(get_irn_irg(block)))
402     fprintf(F, "End ");
403
404   fprintf (F, "%s ", get_op_name(get_irn_op(block)));
405   PRINT_NODEID(block);
406   fprintf(F, " freq: %9.4lf", get_region_exec_freq(block));
407   fprintf(F, " n_outs: %d", get_region_n_outs(block));
408   fprintf(F, " n_exc_outs: %d", get_region_n_exc_outs(block));
409   fprintf (F, "\" ");
410   fprintf(F, "info1:\"");
411   if (dump_dominator_information_flag)
412     fprintf(F, "dom depth %d\n", get_Block_dom_depth(block));
413
414   /* show arity and possible Bad predecessors of the block */
415   fprintf(F, "arity: %d\n", get_Block_n_cfgpreds(block));
416   for (fl = i = 0; i < get_Block_n_cfgpreds(block); ++i) {
417     ir_node *pred = get_Block_cfgpred(block, i);
418     if (is_Bad(pred)) {
419       if (! fl)
420         fprintf(F, "Bad pred at pos: ");
421       fprintf(F, "%d ", i);
422       fl = 1;
423     }
424   }
425   if (fl)
426     fprintf(F, "\n");
427
428   fprintf (F, "\"");  /* closing quote of info */
429
430   if ((block == get_irg_start_block(get_irn_irg(block))) ||
431       (block == get_irg_end_block(get_irn_irg(block)))     )
432     fprintf(F, " color:blue ");
433   else if (fl)
434     fprintf(F, " color:yellow ");
435
436   fprintf (F, "}\n");
437 }
438
439 void dump_interval_loop(FILE *F, ir_loop *l) {
440   int i, n_elems = get_loop_n_elements(l);
441
442   fprintf(F, "graph: { title: \"");
443   PRINT_LOOPID(l);
444   fprintf(F, "\" label: \"loop %d", get_loop_loop_nr(l));
445   fprintf(F, " freq: %9.4lf", get_region_exec_freq(l));
446   fprintf(F, " n_outs: %d", get_region_n_outs(l));
447   fprintf(F, " n_exc_outs: %d", get_region_n_exc_outs(l));
448   fprintf(F, "\" status:clustered color:white \n");
449
450   for (i = 0; i < n_elems; ++i) {
451     loop_element e = get_loop_element(l, i);
452     dump_region_edges(F, e.node);
453     switch (*e.kind) {
454     case k_ir_node: {
455       dump_interval_block(F, e.node);
456     } break;
457     case k_ir_loop: {
458       dump_interval_loop(F, e.son);
459     } break;
460     default: break;
461     }
462   }
463
464   fprintf(F, "}\n\n");
465 }
466
467
468 void dump_interval_graph(ir_graph *irg, const char *suffix) {
469   FILE *f;
470
471   if (strncmp(get_entity_name(get_irg_entity(irg)), dump_file_filter, strlen(dump_file_filter)) != 0)
472     return;
473
474   f = vcg_open(irg, suffix, "-intervals");
475   dump_vcg_header(f, get_irg_dump_name(irg), NULL);
476
477   current_ir_graph = irg;
478
479   dump_interval_loop(f, get_irg_loop(current_ir_graph));
480
481   vcg_close(f);
482 }