it compiles
[libfirm] / ir / be / beprofile.c
1 /** vim: set sw=4 ts=4:
2  * @file   beprofile.c
3  * @date   2006-04-06
4  * @author Adam M. Szalkowski
5  *
6  * Code instrumentation and execution count profiling
7  *
8  * Copyright (C) 2006 Universitaet Karlsruhe
9  * Released under the GPL
10  */
11 #ifdef HAVE_CONFIG_H
12 #include "config.h"
13 #endif
14
15 #include <math.h>
16
17 #include "hashptr.h"
18 #include "debug.h"
19 #include "obst.h"
20 #include "set.h"
21 #include "list.h"
22 #include "pmap.h"
23
24 #include "entity.h"
25 #include "irprintf.h"
26 #include "irgwalk.h"
27 #include "irdump_t.h"
28 #include "irnode_t.h"
29 #include "ircons_t.h"
30 #include "irloop_t.h"
31 #include "iredges.h"
32 #include "execfreq.h"
33 #include "irvrfy.h"
34 #include "type.h"
35 #include "entity.h"
36
37 #include "be_t.h"
38 #include "belive_t.h"
39 #include "besched_t.h"
40 #include "beirgmod.h"
41 #include "bearch.h"
42 #include "beabi.h"
43 #include "benode_t.h"
44 #include "beutil.h"
45
46 #include "bechordal_t.h"
47
48 #ifdef WITH_LIBCORE
49 #include <libcore/lc_opts.h>
50 #include <libcore/lc_opts_enum.h>
51 #endif /* WITH_LIBCORE */
52
53 typedef struct _block_id_walker_data {
54         tarval        **array;
55         unsigned int    id;
56         ir_node  *symconst;
57 } block_id_walker_data;
58
59 static void
60 block_counter(ir_node * bb, void * data)
61 {
62         unsigned int  *count = data;
63         *count = *count + 1;
64 }
65
66 static unsigned int
67 count_blocks(ir_graph * irg)
68 {
69         unsigned int count = 0;
70
71         irg_block_walk_graph(irg, block_counter, NULL, &count);
72         return count;
73 }
74
75 /**
76  * Instrument a block with code needed for profiling
77  */
78 static void
79 instrument_block(ir_node * bb, ir_node * address, unsigned int id)
80 {
81         ir_node  *load, *store, *offset, *add, *projm, *proji;
82
83         offset = new_r_Add(get_irn_irg(bb), bb, address, new_Const_long(mode_Is, get_mode_size_bytes(mode_Iu)*id), mode_P);
84         load = new_r_Load(get_irn_irg(bb), bb, new_NoMem(), offset, mode_Iu);
85         projm = new_r_Proj(get_irn_irg(bb), bb, load, mode_M, 0);
86         proji = new_r_Proj(get_irn_irg(bb), bb, load, mode_Iu, 2);
87         add = new_r_Add(get_irn_irg(bb), bb, proji, new_Const_long(mode_Iu, 1), mode_Iu);
88         store = new_r_Store(get_irn_irg(bb), bb, projm, offset, add);
89         keep_alive(new_r_Proj(get_irn_irg(bb), bb, load, mode_M, 0));
90 }
91
92 /**
93  * Generates a new irg which calls the initializer
94  */
95 static ir_graph *
96 gen_initializer_irg(entity * bblock_id, entity * bblock_counts, entity * bblock_count)
97 {
98         ir_node   *ins[3];
99         ident     *name = new_id_from_str("__firmprof_initializer");
100         entity    *ent = new_entity(get_glob_type(), name, new_type_method(name, 0, 0));
101         ir_node   *ret, *call, *symconst;
102         symconst_symbol sym;
103
104         ident     *init_name = new_id_from_str("__init_firmprof");
105         ir_type   *init_type = new_type_method(init_name, 3, 0);
106         ir_type   *uint, *uintptr;
107
108         uint = new_type_primitive(new_id_from_str("__uint"), mode_Iu);
109         uintptr = new_type_pointer(new_id_from_str("__uintptr"), uint, mode_P);
110
111         set_method_param_type(init_type, 0, uintptr);
112         set_method_param_type(init_type, 1, uintptr);
113         set_method_param_type(init_type, 2, uint);
114         entity    *init_ent = new_entity(get_glob_type(), init_name, init_type);
115
116         ir_graph *irg = new_ir_graph(ent, 0);
117         set_current_ir_graph(irg);
118
119         ir_node *bb = get_cur_block();
120
121         sym.entity_p = init_ent;
122         symconst = new_SymConst(sym, symconst_addr_ent);
123
124         sym.entity_p = bblock_id;
125         ins[0] = new_SymConst(sym, symconst_addr_ent);
126         sym.entity_p = bblock_counts;
127         ins[1] = new_SymConst(sym, symconst_addr_ent);
128         sym.entity_p = bblock_count;
129         ins[2] = new_SymConst(sym, symconst_addr_ent);
130
131         call = new_r_Call( irg,
132                         bb,                                                     //ir_node *     block,
133                         get_irg_initial_mem(irg),       //ir_node *     store,
134                         symconst,                                       //ir_node *     callee,
135                         3,                                                      //int   arity,
136                         ins,                                            //ir_node **    in,
137                         init_type                                       //ir_type *     tp
138                         );
139
140         ret = new_r_Return ( irg,
141                         bb,                                                                             //ir_node *     block,
142                         new_r_Proj(irg, bb, call, mode_M, 0),   //ir_node *     store,
143                         0,                                                                              //int   arity,
144                         NULL                                                                    //ir_node **    in
145                         );
146
147         mature_immBlock(bb);
148
149         add_immBlock_pred(get_irg_end_block(irg), ret);
150         mature_immBlock(get_irg_end_block(irg));
151
152         return irg;
153 }
154
155 static void
156 block_id_walker(ir_node * bb, void * data)
157 {
158         block_id_walker_data *wd = data;
159
160         wd->array[wd->id] = new_tarval_from_long(get_irn_node_nr(bb), mode_Iu);
161         instrument_block(bb, wd->symconst, wd->id);
162         ++wd->id;
163 }
164
165 void
166 be_profile_instrument(void)
167 {
168         int            n, i;
169         unsigned int   n_blocks = 0;
170         entity     *bblock_id, *bblock_counts, *bblock_count;
171         ir_type       *array_type, *integer_type;
172         tarval       **tarval_array;
173
174         block_id_walker_data  wd;
175         symconst_symbol       sym;
176
177         integer_type = new_type_primitive(new_id_from_str("__uint"), mode_Iu);
178         array_type = new_type_array(new_id_from_str("__block_info_array"), 1, integer_type);
179         set_array_bounds_int(array_type, 0, 0, n_blocks);
180         bblock_id = new_entity(get_glob_type(), new_id_from_str("__BLOCK_IDS"), array_type);
181         bblock_counts = new_entity(get_glob_type(), new_id_from_str("__BLOCK_COUNTS"), array_type);
182         bblock_count = new_entity(get_glob_type(), new_id_from_str("__N_BLOCKS"), integer_type);
183
184         for (n = get_irp_n_irgs()-1; n>=0; --n) {
185                 ir_graph      *irg = get_irp_irg(n);
186
187                 n_blocks += count_blocks(irg);
188         }
189
190         /* initialize count array */
191         tarval_array = alloca(sizeof(tarval_array[0]) * n_blocks);
192         for(i = 0; i < n_blocks; ++i) {
193                 tarval_array[i] = get_tarval_null(mode_Iu);
194         }
195         set_array_entity_values(bblock_counts, tarval_array, n_blocks);
196
197         /* initialize the block count entity */
198         set_atomic_ent_value(bblock_count, new_Const_long(mode_Iu, n_blocks));
199
200         /* generate a symbolic constant pointing to the count array */
201         sym.entity_p = bblock_count;
202         wd.symconst = new_SymConst(sym, symconst_addr_ent);
203
204         /* initialize block id array and instrument blocks */
205         wd.array = tarval_array;
206         wd.id = 0;
207         for (n = get_irp_n_irgs()-1; n>=0; --n) {
208                 ir_graph      *irg = get_irp_irg(n);
209
210                 irg_block_walk_graph(irg, block_id_walker, NULL, &wd);
211         }
212         set_array_entity_values(bblock_id, tarval_array, n_blocks);
213
214         gen_initializer_irg(bblock_id, bblock_counts, bblock_count);
215 }
216
217
218 void
219 be_profile_read(void)
220 {
221
222 }