get_Proj_type() must return firm_unknown_type instead of NULL.
[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   freq_t *freq;
84
85   assert(is_Block(irn));
86
87   freq = set_find_freq(freqs, irn);
88
89   assert(freq);
90
91   return freq->freq;
92 }
93
94 #define ZERO(x)   (((x) > 0) ? ((x) < 0.0001) : ((x) > -0.0001))
95
96 static void
97 block_walker(ir_node * bb, void * data)
98 {
99   walkerdata_t  *wd = data;
100
101   set_insert_freq(wd->set, bb);
102   set_irn_link(bb, (void*)wd->idx++);
103 }
104
105 #ifdef USE_GSL
106 static gsl_vector *
107 solve_lgs(double * a_data, double * b_data, size_t size)
108 {
109   gsl_matrix_view m
110     = gsl_matrix_view_array (a_data, size, size);
111
112   gsl_vector_view b
113     = gsl_vector_view_array (b_data, size);
114
115   gsl_vector *x = gsl_vector_alloc (size);
116
117   int s;
118
119   gsl_permutation * p = gsl_permutation_alloc (size);
120
121   gsl_linalg_LU_decomp (&m.matrix, p, &s);
122
123   gsl_linalg_LU_solve (&m.matrix, p, &b.vector, x);
124
125   gsl_permutation_free (p);
126
127   return x;
128 }
129 #else
130 static double *
131 solve_lgs(double * A, double * b, size_t size)
132 {
133   if(firm_gaussjordansolve(A,b,size) == 0) {
134     return b;
135   } else {
136     return NULL;
137   }
138 }
139 #endif
140
141 static double
142 get_cf_probability(ir_node *bb, int pos)
143 {
144 #define LOOP_WEIGHT 9.0
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 set *
163 compute_execfreq(ir_graph * irg)
164 {
165   set          *freqs = new_set(cmp_freq, 32);
166   size_t        size;
167   double       *matrix;
168   double       *rhs;
169   int           i;
170   freq_t       *freq;
171   walkerdata_t  wd;
172 #ifdef USE_GSL
173   gsl_vector   *x;
174 #else
175   double       *x;
176 #endif
177
178   construct_cf_backedges(irg);
179
180   wd.idx = 0;
181   wd.set = freqs;
182
183   irg_block_walk_graph(irg, block_walker, NULL, &wd);
184
185   size = set_count(freqs);
186   matrix = xmalloc(size*size*sizeof(*matrix));
187   memset(matrix, 0, size*size*sizeof(*matrix));
188   rhs = xmalloc(size*sizeof(*rhs));
189   memset(rhs, 0, size*sizeof(*rhs));
190
191   set_foreach(freqs, freq) {
192     ir_node *bb = (ir_node *)freq->irn;
193     size_t  idx = (int)get_irn_link(bb);
194
195     matrix[idx * (size + 1)] = -1.0;
196
197     if (bb == get_irg_start_block(irg)) {
198       rhs[(int)get_irn_link(bb)] = -1.0;
199       continue;
200     }
201
202     for(i = get_Block_n_cfgpreds(bb) - 1; i >= 0; --i) {
203       ir_node *pred    = get_Block_cfgpred_block(bb, i);
204       size_t  pred_idx = (int)get_irn_link(pred);
205
206 //      matrix[pred_idx + idx*size] += 1.0/(double)get_Block_n_cfg_outs(pred);
207       matrix[pred_idx + idx * size] += get_cf_probability(bb, i);
208     }
209   }
210
211   x = solve_lgs(matrix, rhs, size);
212   if(x == NULL) {
213     del_set(freqs);
214     return NULL;
215   }
216
217   set_foreach(freqs, freq) {
218     const ir_node *bb = freq->irn;
219     size_t        idx = PTR_TO_INT(get_irn_link(bb));
220
221 #ifdef USE_GSL
222     freq->freq = ZERO(gsl_vector_get(x, idx)) ? 0.0 : gsl_vector_get(x, idx);
223 #else
224     freq->freq = ZERO(x[idx]) ? 0.0 : x[idx];
225 #endif
226 //    ir_fprintf(stderr, "execfreq %+F: %f\n", bb, freq->freq);
227   }
228
229 #ifdef USE_GSL
230   gsl_vector_free(x);
231 #endif
232   free(matrix);
233
234   return freqs;
235 }
236
237 void
238 free_execfreq(set * freqs)
239 {
240   if(freqs) del_set(freqs);
241 }
242
243 #undef ELEM