execfreq stroes set internally now
[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 static set   *freqs = NULL;
46
47 #define set_foreach(s,i) for((i)=set_first((s)); (i); (i)=set_next((s)))
48
49 typedef struct _walkerdata_t {
50   set    *set;
51   size_t  idx;
52 } walkerdata_t;
53
54 static int
55 cmp_freq(const void *a, const void *b, size_t size)
56 {
57   const freq_t *p = a;
58   const freq_t *q = b;
59
60   return !(p->irn == q->irn);
61 }
62
63 static freq_t *
64 set_find_freq(set * set, const ir_node * irn)
65 {
66   freq_t     query;
67
68   query.irn = irn;
69   return set_find(set, &query, sizeof(query), HASH_PTR(irn));
70 }
71
72 static freq_t *
73 set_insert_freq(set * set, const ir_node * irn)
74 {
75   freq_t     query;
76
77   query.irn = irn;
78   query.freq = 0.0;
79   return set_insert(set, &query, sizeof(query), HASH_PTR(irn));
80 }
81
82 double
83 get_block_execfreq(const ir_node * irn)
84 {
85   freq_t *freq;
86
87   assert(is_Block(irn));
88
89   freq = set_find_freq(freqs, irn);
90
91   assert(freq);
92
93   return freq->freq;
94 }
95
96 #define ZERO(x)   (((x) > 0) ? ((x) < 0.0001) : ((x) > -0.0001))
97
98 static void
99 block_walker(ir_node * bb, void * data)
100 {
101   walkerdata_t  *wd = data;
102
103   set_insert_freq(wd->set, bb);
104   set_irn_link(bb, (void*)wd->idx++);
105 }
106
107 #ifdef USE_GSL
108 static gsl_vector *
109 solve_lgs(double * a_data, double * b_data, size_t size)
110 {
111   gsl_matrix_view m
112     = gsl_matrix_view_array (a_data, size, size);
113
114   gsl_vector_view b
115     = gsl_vector_view_array (b_data, size);
116
117   gsl_vector *x = gsl_vector_alloc (size);
118
119   int s;
120
121   gsl_permutation * p = gsl_permutation_alloc (size);
122
123   gsl_linalg_LU_decomp (&m.matrix, p, &s);
124
125   gsl_linalg_LU_solve (&m.matrix, p, &b.vector, x);
126
127   gsl_permutation_free (p);
128
129   return x;
130 }
131 #else
132 static double *
133 solve_lgs(double * A, double * b, size_t size)
134 {
135   if(firm_gaussjordansolve(A,b,size) == 0) {
136     return b;
137   } else {
138     return NULL;
139   }
140 }
141 #endif
142
143 static double
144 get_cf_probability(ir_node *bb, int pos, double loop_weight)
145 {
146   double  sum = 0.0;
147   double  cur = 0.0;
148   int     i;
149   ir_node *pred = get_Block_cfgpred_block(bb, pos);
150
151   cur = get_loop_depth(get_irn_loop(bb)) < get_loop_depth(get_irn_loop(pred)) ? 1.0 : loop_weight;
152
153   for(i = get_Block_n_cfg_outs(pred) - 1; i >= 0; --i) {
154     ir_node *succ = get_Block_cfg_out(pred, i);
155
156     sum += get_loop_depth(get_irn_loop(succ)) < get_loop_depth(get_irn_loop(pred)) ? 1.0 : loop_weight;
157   }
158
159   return cur/sum;
160 }
161
162 void
163 compute_execfreq(ir_graph * irg, double loop_weight)
164 {
165   size_t        size;
166   double       *matrix;
167   double       *rhs;
168   int           i;
169   freq_t       *freq;
170   walkerdata_t  wd;
171 #ifdef USE_GSL
172   gsl_vector   *x;
173 #else
174   double       *x;
175 #endif
176
177   free_execfreq();
178   freqs = new_set(cmp_freq, 32);
179
180   construct_cf_backedges(irg);
181
182   wd.idx = 0;
183   wd.set = freqs;
184
185   irg_block_walk_graph(irg, block_walker, NULL, &wd);
186
187   size = set_count(freqs);
188   matrix = xmalloc(size*size*sizeof(*matrix));
189   memset(matrix, 0, size*size*sizeof(*matrix));
190   rhs = xmalloc(size*sizeof(*rhs));
191   memset(rhs, 0, size*sizeof(*rhs));
192
193   set_foreach(freqs, freq) {
194     ir_node *bb = (ir_node *)freq->irn;
195     size_t  idx = (int)get_irn_link(bb);
196
197     matrix[idx * (size + 1)] = -1.0;
198
199     if (bb == get_irg_start_block(irg)) {
200       rhs[(int)get_irn_link(bb)] = -1.0;
201       continue;
202     }
203
204     for(i = get_Block_n_cfgpreds(bb) - 1; i >= 0; --i) {
205       ir_node *pred    = get_Block_cfgpred_block(bb, i);
206       size_t  pred_idx = (int)get_irn_link(pred);
207
208 //      matrix[pred_idx + idx*size] += 1.0/(double)get_Block_n_cfg_outs(pred);
209       matrix[pred_idx + idx * size] += get_cf_probability(bb, i, loop_weight);
210     }
211   }
212
213   x = solve_lgs(matrix, rhs, size);
214   if(x == NULL) {
215     del_set(freqs);
216     return;
217   }
218
219   set_foreach(freqs, freq) {
220     const ir_node *bb = freq->irn;
221     size_t        idx = PTR_TO_INT(get_irn_link(bb));
222
223 #ifdef USE_GSL
224     freq->freq = ZERO(gsl_vector_get(x, idx)) ? 0.0 : gsl_vector_get(x, idx);
225 #else
226     freq->freq = ZERO(x[idx]) ? 0.0 : x[idx];
227 #endif
228 //    ir_fprintf(stderr, "execfreq %+F: %f\n", bb, freq->freq);
229   }
230
231 #ifdef USE_GSL
232   gsl_vector_free(x);
233 #endif
234   free(matrix);
235
236   return;
237 }
238
239 void
240 free_execfreq()
241 {
242   if(freqs) del_set(freqs);
243 }
244
245 #undef ELEM