7276b0a39566728d6524aa158847e1b2962e3ce9
[libfirm] / ir / ana / execfreq.c
1 /*
2  * Project:     libFIRM
3  * File name:   ir/ana/execfreq.c
4  * Purpose:     Compute an estimate of basic block executions.
5  * Author:      Adam M. Szalkowski
6  * Modified by:
7  * Created:     28.05.2006
8  * CVS-ID:      $Id$
9  * Copyright:   (c) 2006 Universität Karlsruhe
10  * Licence:     This file protected by GPL -  GNU GENERAL PUBLIC LICENSE.
11  */
12
13 #ifdef HAVE_CONFIG_H
14 #include "config.h"
15 #endif
16
17 //#define USE_GSL
18
19 #include <stdio.h>
20 #include <string.h>
21
22 #ifdef USE_GSL
23 #include <gsl/gsl_linalg.h>
24 #include <gsl/gsl_vector.h>
25 #else
26 #include "gaussjordan.h"
27 #endif
28
29 #include "execfreq.h"
30
31 #include "firm_common_t.h"
32 #include "set.h"
33 #include "hashptr.h"
34
35 #include "irprog_t.h"
36 #include "irgraph_t.h"
37 #include "irnode_t.h"
38 #include "irloop.h"
39 #include "irgwalk.h"
40 #include "irouts.h"
41 #include "irprintf.h"
42
43 #include "execfreq.h"
44
45 #define set_foreach(s,i) for((i)=set_first((s)); (i); (i)=set_next((s)))
46
47 typedef struct _walkerdata_t {
48   set    *set;
49   size_t  idx;
50 } walkerdata_t;
51
52 static int
53 cmp_freq(const void *a, const void *b, size_t size)
54 {
55   const freq_t *p = a;
56   const freq_t *q = b;
57
58   return !(p->irn == q->irn);
59 }
60
61 static freq_t *
62 set_find_freq(set * set, const ir_node * irn)
63 {
64   freq_t     query;
65
66   query.irn = irn;
67   return set_find(set, &query, sizeof(query), HASH_PTR(irn));
68 }
69
70 static freq_t *
71 set_insert_freq(set * set, const ir_node * irn)
72 {
73   freq_t     query;
74
75   query.irn = irn;
76   query.freq = 0.0;
77   return set_insert(set, &query, sizeof(query), HASH_PTR(irn));
78 }
79
80 double
81 get_block_execfreq(set * freqs, const ir_node * irn)
82 {
83   assert(is_Block(irn));
84
85   freq_t *freq = set_find_freq(freqs, irn);
86   assert(freq);
87
88   return freq->freq;
89 }
90
91 #define ZERO(x)   (((x) > 0) ? ((x) < 0.0001) : ((x) > -0.0001))
92
93 static void
94 block_walker(ir_node * bb, void * data)
95 {
96   walkerdata_t  *wd = data;
97
98   set_insert_freq(wd->set, bb);
99   set_irn_link(bb, (void*)wd->idx++);
100 }
101
102 #ifdef USE_GSL
103 static gsl_vector *
104 solve_lgs(double * a_data, double * b_data, size_t size)
105 {
106   gsl_matrix_view m
107     = gsl_matrix_view_array (a_data, size, size);
108
109   gsl_vector_view b
110     = gsl_vector_view_array (b_data, size);
111
112   gsl_vector *x = gsl_vector_alloc (size);
113
114   int s;
115
116   gsl_permutation * p = gsl_permutation_alloc (size);
117
118   gsl_linalg_LU_decomp (&m.matrix, p, &s);
119
120   gsl_linalg_LU_solve (&m.matrix, p, &b.vector, x);
121
122   gsl_permutation_free (p);
123
124   return x;
125 }
126 #else
127 static double *
128 solve_lgs(double * A, double * b, size_t size)
129 {
130   if(firm_gaussjordansolve(A,b,size) == 0) {
131     return b;
132   } else {
133     return NULL;
134   }
135 }
136 #endif
137
138 static double
139 get_cf_probability(const ir_node * bb, int pos)
140 {
141 #define LOOP_WEIGHT 9.0
142
143   double    sum = 0.0;
144   double    cur = 0.0;
145   int       i,
146             n;
147   ir_node  *pred = get_Block_cfgpred_block(bb, pos);
148
149   if(get_loop_depth(get_irn_loop(bb)) < get_loop_depth(get_irn_loop(pred))) {
150     cur = 1.0;
151   } else {
152     cur = LOOP_WEIGHT;
153   }
154
155   for(i = 0, n = get_Block_n_cfg_outs(pred); i < n; ++i) {
156     ir_node *succ = get_Block_cfg_out(pred, i);
157
158     if(get_loop_depth(get_irn_loop(succ)) < get_loop_depth(get_irn_loop(pred))) {
159       sum += 1.0;
160     } else {
161       sum += LOOP_WEIGHT;
162     }
163   }
164
165   return cur/sum;
166 }
167
168 set *
169 compute_execfreq(ir_graph * irg)
170 {
171   set          *freqs = new_set(cmp_freq, 32);
172   size_t        size;
173   double       *matrix;
174   double       *rhs;
175   size_t        i = 0;
176   freq_t       *freq;
177   walkerdata_t  wd;
178 #ifdef USE_GSL
179   gsl_vector   *x;
180 #else
181   double       *x;
182 #endif
183
184   construct_cf_backedges(irg);
185
186   wd.idx = 0;
187   wd.set = freqs;
188
189   irg_block_walk_graph(irg, block_walker, NULL, &wd);
190
191   size = set_count(freqs);
192   matrix = malloc(size*size*sizeof(*matrix));
193   memset(matrix, 0, size*size*sizeof(*matrix));
194   rhs = malloc(size*sizeof(*rhs));
195   memset(rhs, 0, size*sizeof(*rhs));
196
197   set_foreach(freqs, freq) {
198     const ir_node  *bb = freq->irn;
199     size_t    idx = (int)get_irn_link(bb);
200
201     matrix[idx*(size+1)] = -1.0;
202
203     if(bb == get_irg_start_block(irg)) {
204       rhs[(int)get_irn_link(bb)] = -1.0;
205       continue;
206     }
207
208     for(i = 0; i < get_Block_n_cfgpreds(bb); ++i) {
209       ir_node   *pred = get_Block_cfgpred_block(bb, i);
210       size_t     pred_idx = (int)get_irn_link(pred);
211
212 //      matrix[pred_idx + idx*size] += 1.0/(double)get_Block_n_cfg_outs(pred);
213       matrix[pred_idx + idx*size] += get_cf_probability(bb, i);
214     }
215   }
216
217   x = solve_lgs(matrix, rhs, size);
218   if(x == NULL) {
219     del_set(freqs);
220     return NULL;
221   }
222
223   set_foreach(freqs, freq) {
224     const ir_node  *bb = freq->irn;
225     size_t          idx = PTR_TO_INT(get_irn_link(bb));
226
227 #ifdef USE_GSL
228     freq->freq = ZERO(gsl_vector_get(x, idx)) ? 0.0 : gsl_vector_get(x, idx);
229 #else
230     freq->freq = ZERO(x[idx]) ? 0.0 : x[idx];
231 #endif
232 //    ir_fprintf(stderr, "execfreq %+F: %f\n", bb, freq->freq);
233   }
234
235 #ifdef USE_GSL
236   gsl_vector_free(x);
237 #endif
238   free(matrix);
239
240   return freqs;
241 }
242
243 void
244 free_execfreq(set * freqs)
245 {
246   if(freqs) del_set(freqs);
247 }
248
249 #undef ELEM