irop: Constify get_op_ops().
[libfirm] / ir / ir / irprofile.c
1 /*
2  * This file is part of libFirm.
3  * Copyright (C) 2012 University of Karlsruhe.
4  */
5
6 /**
7  * @file
8  * @brief       Code instrumentation and execution count profiling.
9  * @author      Adam M. Szalkowski, Steven Schaefer
10  * @date        06.04.2006, 11.11.2010
11  */
12 #include "config.h"
13
14 #include <math.h>
15 #include <stdio.h>
16
17 #include "hashptr.h"
18 #include "debug.h"
19 #include "obst.h"
20 #include "xmalloc.h"
21 #include "set.h"
22 #include "irtools.h"
23
24 #include "irgwalk.h"
25 #include "irdump_t.h"
26 #include "irnode_t.h"
27 #include "ircons_t.h"
28 #include "execfreq_t.h"
29 #include "irprofile.h"
30 #include "typerep.h"
31
32 /* Instrument blocks walker. */
33 typedef struct block_id_walker_data_t {
34         unsigned int id;   /**< current block id number */
35         ir_node *symconst; /**< the SymConst representing the counter array */
36 } block_id_walker_data_t;
37
38 /* Associate counters with blocks. */
39 typedef struct block_assoc_t {
40         unsigned int i;          /**< current block id number */
41         unsigned int *counters;  /**< block execution counts */
42 } block_assoc_t;
43
44 /* minimal execution frequency (an execfreq of 0 confuses algos) */
45 #define MIN_EXECFREQ 0.00001
46
47 /* keep the execcounts here because they are only read once per compiler run */
48 static set *profile = NULL;
49
50 /* Hook for vcg output. */
51 static void *hook;
52
53 /* The debug module handle. */
54 DEBUG_ONLY(static firm_dbg_module_t *dbg;)
55
56 /* Since the backend creates a new firm graph we cannot associate counts with
57  * blocks directly. Instead we associate them with the block ids, which are
58  * maintained.
59  */
60 typedef struct execcount_t {
61         unsigned long block; /**< block id */
62         uint32_t      count; /**< execution count */
63 } execcount_t;
64
65 /**
66  * Compare two execcount_t entries.
67  */
68 static int cmp_execcount(const void *a, const void *b, size_t size)
69 {
70         const execcount_t *ea = (const execcount_t*)a;
71         const execcount_t *eb = (const execcount_t*)b;
72         (void) size;
73         return ea->block != eb->block;
74 }
75
76 uint32_t ir_profile_get_block_execcount(const ir_node *block)
77 {
78         execcount_t *ec, query;
79
80         query.block = get_irn_node_nr(block);
81         ec = set_find(execcount_t, profile, &query, sizeof(query), query.block);
82
83         if (ec != NULL) {
84                 return ec->count;
85         } else {
86                 DBG((dbg, LEVEL_3,
87                         "Warning: Profile contains no data for %+F\n", block));
88                 return 0;
89         }
90 }
91
92 /**
93  * Block walker, count number of blocks.
94  */
95 static void block_counter(ir_node *bb, void *data)
96 {
97         unsigned *count = (unsigned*) data;
98         (void) bb;
99         ++(*count);
100 }
101
102 /**
103  * Returns the number of blocks the given graph.
104  */
105 static unsigned int get_irg_n_blocks(ir_graph *irg)
106 {
107         unsigned int count = 0;
108         irg_block_walk_graph(irg, block_counter, NULL, &count);
109         return count;
110 }
111
112 /**
113  * Returns the number of basic blocks in the current ir program.
114  */
115 static unsigned int get_irp_n_blocks(void)
116 {
117         int i, n = get_irp_n_irgs();
118         unsigned int count = 0;
119
120         for (i = 0; i < n; i++) {
121                 ir_graph *irg = get_irp_irg(i);
122                 count += get_irg_n_blocks(irg);
123         }
124
125         return count;
126 }
127
128 /* vcg helper */
129 static void dump_profile_node_info(void *ctx, FILE *f, const ir_node *irn)
130 {
131         (void) ctx;
132         if (is_Block(irn)) {
133                 unsigned int execcount = ir_profile_get_block_execcount(irn);
134                 fprintf(f, "profiled execution count: %u\n", execcount);
135         }
136 }
137
138 /**
139  * Add the given method entity as a constructor.
140  */
141 static void add_constructor(ir_entity *method)
142 {
143     ir_type   *method_type  = get_entity_type(method);
144     ir_type   *ptr_type     = new_type_pointer(method_type);
145
146     ir_type   *constructors = get_segment_type(IR_SEGMENT_CONSTRUCTORS);
147         ident     *ide = id_unique("constructor_ptr.%u");
148     ir_entity *ptr = new_entity(constructors, ide, ptr_type);
149     ir_graph  *irg = get_const_code_irg();
150     ir_node   *val = new_rd_SymConst_addr_ent(NULL, irg, mode_P_code, method);
151
152         set_entity_ld_ident(ptr, new_id_from_chars("", 0));
153     set_entity_compiler_generated(ptr, 1);
154     set_entity_linkage(ptr, IR_LINKAGE_CONSTANT | IR_LINKAGE_HIDDEN_USER);
155     set_entity_visibility(ptr, ir_visibility_private);
156     set_atomic_ent_value(ptr, val);
157 }
158
159 /**
160  * Returns an entity representing the __init_firmprof function from libfirmprof
161  * This is the equivalent of:
162  * extern void __init_firmprof(char *filename, uint *counters, uint size)
163  */
164 static ir_entity *get_init_firmprof_ref(void)
165 {
166         ident   *init_name = new_id_from_str("__init_firmprof");
167         ir_type *init_type = new_type_method(3, 0);
168         ir_type *uint      = new_type_primitive(mode_Iu);
169         ir_type *uintptr   = new_type_pointer(uint);
170         ir_type *string    = new_type_pointer(new_type_primitive(mode_Bs));
171         ir_entity *result;
172
173         set_method_param_type(init_type, 0, string);
174         set_method_param_type(init_type, 1, uintptr);
175         set_method_param_type(init_type, 2, uint);
176
177         result = new_entity(get_glob_type(), init_name, init_type);
178         set_entity_visibility(result, ir_visibility_external);
179
180         return result;
181 }
182
183 /**
184  * Generates a new irg which calls the initializer
185  *
186  * Pseudocode:
187  *    static void __firmprof_initializer(void) __attribute__ ((constructor))
188  *    {
189  *        __init_firmprof(ent_filename, bblock_counts, n_blocks);
190  *    }
191  */
192 static ir_graph *gen_initializer_irg(ir_entity *ent_filename,
193                                      ir_entity *bblock_counts, int n_blocks)
194 {
195         ir_graph *irg;
196         ir_node  *ins[3];
197         ir_node  *bb, *ret, *call, *symconst;
198         ir_type  *empty_frame_type;
199         symconst_symbol sym;
200
201         ir_entity *init_ent = get_init_firmprof_ref();
202
203         ident     *name = new_id_from_str("__firmprof_initializer");
204         ir_entity *ent  = new_entity(get_glob_type(), name, new_type_method(0, 0));
205         set_entity_visibility(ent, ir_visibility_local);
206         set_entity_ld_ident(ent, name);
207
208         /* create the new ir_graph */
209         irg = new_ir_graph(ent, 0);
210         set_current_ir_graph(irg);
211         empty_frame_type = get_irg_frame_type(irg);
212         set_type_size_bytes(empty_frame_type, 0);
213         set_type_state(empty_frame_type, layout_fixed);
214
215         bb = get_r_cur_block(irg);
216
217         sym.entity_p = init_ent;
218         symconst     = new_r_SymConst(irg, mode_P_data, sym, symconst_addr_ent);
219
220         sym.entity_p = ent_filename;
221         ins[0] = new_r_SymConst(irg, mode_P_data, sym, symconst_addr_ent);
222         sym.entity_p = bblock_counts;
223         ins[1] = new_r_SymConst(irg, mode_P_data, sym, symconst_addr_ent);
224         ins[2] = new_r_Const_long(irg, mode_Iu, n_blocks);
225
226         call = new_r_Call(bb, get_irg_initial_mem(irg), symconst, 3, ins,
227                 get_entity_type(init_ent));
228         ret  = new_r_Return(bb, new_r_Proj(call, mode_M, pn_Call_M), 0, NULL);
229         mature_immBlock(bb);
230
231         add_immBlock_pred(get_irg_end_block(irg), ret);
232         mature_immBlock(get_irg_end_block(irg));
233
234         irg_finalize_cons(irg);
235
236         /* add a pointer to the new function in the constructor section */
237         add_constructor(ent);
238
239         return irg;
240 }
241
242 /**
243  * Instrument a block with code needed for profiling.
244  * This just inserts the instruction nodes, it doesn't connect the memory
245  * nodes in a meaningful way.
246  */
247 static void instrument_block(ir_node *bb, ir_node *address, unsigned int id)
248 {
249         ir_graph *irg = get_irn_irg(bb);
250         ir_node  *load, *store, *offset, *add, *projm, *proji, *unknown, *cnst;
251
252         /* We can't instrument the end block */
253         if (bb == get_irg_end_block(irg))
254                 return;
255
256         unknown = new_r_Unknown(irg, mode_M);
257         cnst    = new_r_Const_long(irg, mode_Iu, get_mode_size_bytes(mode_Iu) * id);
258         offset  = new_r_Add(bb, address, cnst, get_modeP_data());
259         load    = new_r_Load(bb, unknown, offset, mode_Iu, cons_none);
260         projm   = new_r_Proj(load, mode_M, pn_Load_M);
261         proji   = new_r_Proj(load, mode_Iu, pn_Load_res);
262         cnst    = new_r_Const(irg, get_mode_one(mode_Iu));
263         add     = new_r_Add(bb, proji, cnst, mode_Iu);
264         store   = new_r_Store(bb, projm, offset, add, cons_none);
265         projm   = new_r_Proj(store, mode_M, pn_Store_M);
266
267         set_irn_link(bb, projm);
268         set_irn_link(projm, load);
269 }
270
271 /**
272  * SSA Construction for instrumentation code memory.
273  *
274  * This introduces a new memory node and connects it to the instrumentation
275  * codes, inserting phiM nodes as necessary. Note that afterwards, the new
276  * memory is not connected to any return nodes and thus still dead.
277  */
278 static void fix_ssa(ir_node *bb, void *data)
279 {
280         ir_graph *irg = get_irn_irg(bb);
281         ir_node *mem, *proj, *load;
282         int n, arity = get_Block_n_cfgpreds(bb);
283
284         (void) data;
285
286         /* end blocks are not instrumented, skip! */
287         if (bb == get_irg_end_block(irg))
288                 return;
289
290         if (bb == get_irg_start_block(irg)) {
291                 mem = get_irg_initial_mem(irg);
292         } else if (arity == 1) {
293                 ir_node *pred = get_Block_cfgpred_block(bb, 0);
294                 if (!is_Bad(pred))
295                         mem = (ir_node*) get_irn_link(pred);
296                 else
297                         mem = new_r_NoMem(irg);
298         } else {
299                 ir_node **ins = ALLOCAN(ir_node*, arity);
300                 for (n = arity - 1; n >= 0; --n) {
301                         ir_node *pred = get_Block_cfgpred_block(bb, n);
302                         if (!is_Bad(pred))
303                                 ins[n] = (ir_node*) get_irn_link(pred);
304                         else
305                                 ins[n] = new_r_NoMem(irg);
306                 }
307                 mem = new_r_Phi(bb, arity, ins, mode_M);
308         }
309
310         /* The block link fields point to the projm from the instrumentation code,
311          * the projm in turn links to the initial load which lacks a memory
312          * argument at this point. */
313         proj = (ir_node*) get_irn_link(bb);
314         load = (ir_node*) get_irn_link(proj);
315         set_Load_mem(load, mem);
316 }
317
318 /**
319  * Instrument a single block.
320  */
321 static void block_instrument_walker(ir_node *bb, void *data)
322 {
323         block_id_walker_data_t *wd = (block_id_walker_data_t*)data;
324         instrument_block(bb, wd->symconst, wd->id);
325         ++wd->id;
326 }
327
328 /**
329  * Synchronize the original memory input of node with the additional operand
330  * from the profiling code.
331  */
332 static ir_node *sync_mem(ir_node *bb, ir_node *mem)
333 {
334         ir_node *ins[2];
335         ins[0] = (ir_node*) get_irn_link(bb);
336         ins[1] = mem;
337         return new_r_Sync(bb, 2, ins);
338 }
339
340 /**
341  * Instrument a single ir_graph, counters should point to the bblock
342  * counters array.
343  */
344 static void instrument_irg(ir_graph *irg, ir_entity *counters,
345                            block_id_walker_data_t *wd)
346 {
347         ir_node *end   = get_irg_end(irg);
348         ir_node *endbb = get_irg_end_block(irg);
349         int i;
350
351         /* generate a symbolic constant pointing to the count array */
352         symconst_symbol sym;
353         sym.entity_p = counters;
354         wd->symconst = new_r_SymConst(irg, mode_P_data, sym, symconst_addr_ent);
355
356         /* instrument each block in the current irg */
357         irg_block_walk_graph(irg, block_instrument_walker, NULL, wd);
358         irg_block_walk_graph(irg, fix_ssa, NULL, NULL);
359
360         /* connect the new memory nodes to the return nodes */
361         for (i = get_Block_n_cfgpreds(endbb) - 1; i >= 0; --i) {
362                 ir_node *node = skip_Proj(get_Block_cfgpred(endbb, i));
363                 ir_node *bb   = get_Block_cfgpred_block(endbb, i);
364                 ir_node *mem;
365
366                 switch (get_irn_opcode(node)) {
367                 case iro_Return:
368                         mem = get_Return_mem(node);
369                         set_Return_mem(node, sync_mem(bb, mem));
370                         break;
371                 case iro_Raise:
372                         mem = get_Raise_mem(node);
373                         set_Raise_mem(node, sync_mem(bb, mem));
374                         break;
375                 case iro_Bad:
376                         break;
377                 default:
378                         /* A fragile's op exception. There should be another path to End,
379                          * so ignore it.
380                          */
381                         assert(is_fragile_op(node) && \
382                                 "unexpected End control flow predecessor");
383                 }
384         }
385
386         /* as well as calls with attribute noreturn */
387         for (i = get_End_n_keepalives(end) - 1; i >= 0; --i) {
388                 ir_node *node = get_End_keepalive(end, i);
389                 if (is_Call(node)) {
390                         ir_node *bb  = get_nodes_block(node);
391                         ir_node *mem = get_Call_mem(node);
392                         set_Call_mem(node, sync_mem(bb, mem));
393                 }
394         }
395 }
396
397 /**
398  * Creates a new entity representing the equivalent of
399  * static unsigned int name[size]
400  */
401 static ir_entity *new_array_entity(ident *name, int size)
402 {
403         ir_entity *result;
404         ir_type *uint_type, *array_type;
405
406         uint_type = new_type_primitive(mode_Iu);
407         set_type_alignment_bytes(uint_type, get_type_size_bytes(uint_type));
408
409         array_type = new_type_array(1, uint_type);
410         set_array_bounds_int(array_type, 0, 0, size);
411         set_type_size_bytes(array_type, size * get_mode_size_bytes(mode_Iu));
412         set_type_alignment_bytes(array_type, get_mode_size_bytes(mode_Iu));
413         set_type_state(array_type, layout_fixed);
414
415         result = new_entity(get_glob_type(), name, array_type);
416         set_entity_visibility(result, ir_visibility_local);
417         set_entity_compiler_generated(result, 1);
418
419         return result;
420 }
421
422 /**
423  * Creates a new entity representing the equivalent of
424  * static const char name[strlen(string)+1] = string
425  */
426 static ir_entity *new_static_string_entity(ident *name, const char *string)
427 {
428         ir_entity *result;
429
430         ir_type *char_type   = new_type_primitive(mode_Bs);
431         ir_type *string_type = new_type_array(1, char_type);
432
433         ir_initializer_t *contents;
434
435         size_t i, length = strlen(string)+1;
436
437         /* Create the type for a fixed-length string */
438         set_array_bounds_int(string_type, 0, 0, length);
439         set_type_size_bytes(string_type, length);
440         set_type_alignment_bytes(string_type, 1);
441         set_type_state(string_type, layout_fixed);
442
443         result = new_entity(get_glob_type(), name, string_type);
444         set_entity_visibility(result, ir_visibility_local);
445         set_entity_linkage(result, IR_LINKAGE_CONSTANT);
446         set_entity_compiler_generated(result, 1);
447
448         /* There seems to be no simpler way to do this. Or at least, cparser
449          * does exactly the same thing... */
450         contents = create_initializer_compound(length);
451         for (i = 0; i < length; i++) {
452                 ir_tarval *c = new_tarval_from_long(string[i], mode_Bs);
453                 ir_initializer_t *init = create_initializer_tarval(c);
454                 set_initializer_compound_value(contents, i, init);
455         }
456         set_entity_initializer(result, contents);
457
458         return result;
459 }
460
461 ir_graph *ir_profile_instrument(const char *filename)
462 {
463         int n, n_blocks = 0;
464         ident *counter_id, *filename_id;
465         ir_entity *bblock_counts, *ent_filename;
466         block_id_walker_data_t wd;
467         FIRM_DBG_REGISTER(dbg, "firm.ir.profile");
468
469         /* Don't do anything for modules without code. Else the linker will
470          * complain. */
471         if (get_irp_n_irgs() == 0)
472                 return NULL;
473
474         /* count the number of block first */
475         n_blocks = get_irp_n_blocks();
476
477         /* create all the necessary types and entities. Note that the
478          * types must have a fixed layout, because we are already running in the
479          * backend */
480         counter_id    = new_id_from_str("__FIRMPROF__BLOCK_COUNTS");
481         bblock_counts = new_array_entity(counter_id, n_blocks);
482
483         filename_id  = new_id_from_str("__FIRMPROF__FILE_NAME");
484         ent_filename = new_static_string_entity(filename_id, filename);
485
486         /* initialize block id array and instrument blocks */
487         wd.id  = 0;
488         for (n = get_irp_n_irgs() - 1; n >= 0; --n) {
489                 ir_graph *irg = get_irp_irg(n);
490                 instrument_irg(irg, bblock_counts, &wd);
491         }
492
493         return gen_initializer_irg(ent_filename, bblock_counts, n_blocks);
494 }
495
496 static unsigned int *parse_profile(const char *filename, unsigned int num_blocks)
497 {
498         FILE *f = fopen(filename, "rb");
499         if (!f) {
500                 DBG((dbg, LEVEL_2, "Failed to open profile file (%s)\n", filename));
501                 return NULL;
502         }
503
504         /* check header */
505         uint32_t *result = NULL;
506         char      buf[8];
507         size_t    ret = fread(buf, 8, 1, f);
508         if (ret == 0 || strncmp(buf, "firmprof", 8) != 0) {
509                 DBG((dbg, LEVEL_2, "Broken fileheader in profile\n"));
510                 goto end;
511         }
512
513         result = XMALLOCN(unsigned int, num_blocks);
514
515         /* The profiling output format is defined to be a sequence of integer
516          * values stored little endian format. */
517         for (unsigned i = 0; i < num_blocks; ++i) {
518                 unsigned char bytes[4];
519
520                 if ((ret = fread(bytes, 1, 4, f)) < 1)
521                         break;
522
523                 result[i] = (bytes[0] <<  0) | (bytes[1] <<  8)
524                           | (bytes[2] << 16) | (bytes[3] << 24);
525         }
526
527         if (ret < 1) {
528                 DBG((dbg, LEVEL_4, "Failed to read counters... (size: %u)\n",
529                         sizeof(unsigned int) * num_blocks));
530                 xfree(result);
531                 result = NULL;
532         }
533
534 end:
535         fclose(f);
536         return result;
537 }
538
539 /**
540  * Reads the corresponding profile info file if it exists.
541  */
542 static void block_associate_walker(ir_node *bb, void *env)
543 {
544         block_assoc_t *b = (block_assoc_t*) env;
545         execcount_t query;
546
547         query.block = get_irn_node_nr(bb);
548         query.count = b->counters[(b->i)++];
549         DBG((dbg, LEVEL_4, "execcount(%+F, %u): %u\n", bb, query.block,
550             query.count));
551         (void)set_insert(execcount_t, profile, &query, sizeof(query), query.block);
552 }
553
554 static void irp_associate_blocks(block_assoc_t *env)
555 {
556         for (int n = get_irp_n_irgs() - 1; n >= 0; --n) {
557                 ir_graph *irg = get_irp_irg(n);
558                 irg_block_walk_graph(irg, block_associate_walker, NULL, env);
559         }
560 }
561
562 void ir_profile_free(void)
563 {
564         if (profile) {
565                 del_set(profile);
566                 profile = NULL;
567         }
568
569         if (hook != NULL) {
570                 dump_remove_node_info_callback(hook);
571                 hook = NULL;
572         }
573 }
574
575 bool ir_profile_read(const char *filename)
576 {
577         block_assoc_t env;
578         FIRM_DBG_REGISTER(dbg, "firm.ir.profile");
579
580         unsigned n_blocks = get_irp_n_blocks();
581         env.i        = 0;
582         env.counters = parse_profile(filename, n_blocks);
583         if (!env.counters)
584                 return false;
585
586         ir_profile_free();
587         profile = new_set(cmp_execcount, 16);
588
589         irp_associate_blocks(&env);
590         xfree(env.counters);
591
592         /* register the vcg hook */
593         hook = dump_add_node_info_callback(dump_profile_node_info, NULL);
594         return 1;
595 }
596
597 typedef struct initialize_execfreq_env_t {
598         double freq_factor;
599 } initialize_execfreq_env_t;
600
601 static void initialize_execfreq(ir_node *block, void *data)
602 {
603         const initialize_execfreq_env_t *env
604                 = (const initialize_execfreq_env_t*) data;
605         ir_graph *irg = get_irn_irg(block);
606         double freq;
607
608         if (block == get_irg_start_block(irg) || block == get_irg_end_block(irg)) {
609                 freq = 1.0;
610         } else {
611                 freq = ir_profile_get_block_execcount(block);
612                 freq *= env->freq_factor;
613                 if (freq < MIN_EXECFREQ)
614                         freq = MIN_EXECFREQ;
615         }
616
617         set_block_execfreq(block, freq);
618 }
619
620 static void ir_set_execfreqs_from_profile(ir_graph *irg)
621 {
622         /* Find the first block containing instructions */
623         ir_node *start_block = get_irg_start_block(irg);
624         unsigned count       = ir_profile_get_block_execcount(start_block);
625         if (count == 0) {
626                 /* the function was never executed, so fallback to estimated freqs */
627                 ir_estimate_execfreq(irg);
628                 return;
629         }
630
631         initialize_execfreq_env_t env;
632         env.freq_factor = 1.0 / count;
633         irg_block_walk_graph(irg, initialize_execfreq, NULL, &env);
634 }
635
636 void ir_create_execfreqs_from_profile(void)
637 {
638         for (int n = get_irp_n_irgs() - 1; n >= 0; --n) {
639                 ir_graph *irg = get_irp_irg(n);
640                 ir_set_execfreqs_from_profile(irg);
641         }
642 }