irprofile.c 19.5 KB
Newer Older
Christian Würdig's avatar
Christian Würdig committed
1
/*
Michael Beck's avatar
Michael Beck committed
2
 * Copyright (C) 1995-2008 University of Karlsruhe.  All right reserved.
Christian Würdig's avatar
Christian Würdig committed
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 *
 * This file is part of libFirm.
 *
 * This file may be distributed and/or modified under the terms of the
 * GNU General Public License version 2 as published by the Free Software
 * Foundation and appearing in the file LICENSE.GPL included in the
 * packaging of this file.
 *
 * Licensees holding valid libFirm Professional Edition licenses may use
 * this file in accordance with the libFirm Commercial License.
 * Agreement provided with the Software.
 *
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE.
 */

Christian Würdig's avatar
Christian Würdig committed
20
21
22
23
24
25
/**
 * @file
 * @brief       Code instrumentation and execution count profiling.
 * @author      Adam M. Szalkowski
 * @date        06.04.2006
 * @version     $Id$
26
27
28
29
30
31
32
33
34
35
36
37
38
 */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <math.h>

#include "hashptr.h"
#include "debug.h"
#include "obst.h"
#include "set.h"
#include "list.h"
#include "pmap.h"
39
#include "array_t.h"
40
41
42
43
44
45
46

#include "irprintf.h"
#include "irgwalk.h"
#include "irdump_t.h"
#include "irnode_t.h"
#include "ircons_t.h"
#include "execfreq.h"
47
#include "typerep.h"
48

Michael Beck's avatar
Michael Beck committed
49
#include "dbginfo.h"
50
#include "irhooks.h"
51
#include "iredges.h"
52

Michael Beck's avatar
Michael Beck committed
53
#include "irprofile.h"
54

55
56
/** An entry in the id-to-location map */
typedef struct loc_entry {
57
	ir_entity    *fname;   /**< the entity holding the file name */
58
59
60
	unsigned int lineno;   /**< line number */
} loc_entry;

61
typedef struct _block_id_walker_data_t {
62
63
64
65
66
67
68
	tarval         **array;    /**< the entity the holds the block counts */
	unsigned int   id;         /**< current block id number */
	ir_node        *symconst;  /**< the SymConst representing array */
	pmap           *fname_map; /**< set containing all found filenames */
	loc_entry      *locs;      /**< locations */
	ir_type        *tp_char;   /**< the character type */
	unsigned       flags;      /**< profile flags */
69
70
71
} block_id_walker_data_t;

typedef struct _execcount_t {
Michael Beck's avatar
Michael Beck committed
72
	unsigned long block;
73
74
75
	unsigned int count;
} execcount_t;

Michael Beck's avatar
Michael Beck committed
76
77
78
79
80
81
/**
 * Compare two execcount_t entries.
 */
static int cmp_execcount(const void *a, const void *b, size_t size) {
	const execcount_t *ea = a;
	const execcount_t *eb = b;
82
	(void) size;
Michael Beck's avatar
Michael Beck committed
83
	return ea->block != eb->block;
84
}
85

Michael Beck's avatar
Michael Beck committed
86
87
88
89
90
/**
 * Block walker, count number of blocks.
 */
static void block_counter(ir_node * bb, void * data) {
	unsigned int *count = data;
91
	(void) bb;
92
93
94
	*count = *count + 1;
}

Michael Beck's avatar
Michael Beck committed
95
96
97
98
/**
 * Return the number of blocks the given graph.
 */
static unsigned int count_blocks(ir_graph *irg) {
99
100
101
102
103
104
	unsigned int count = 0;

	irg_block_walk_graph(irg, block_counter, NULL, &count);
	return count;
}

105
106
/* keep the execcounts here because they are only read once per compiler run */
static set * profile = NULL;
107
static hook_entry_t hook;
108

109
110
111
112
/**
 * Instrument a block with code needed for profiling
 */
static void
Michael Beck's avatar
Michael Beck committed
113
instrument_block(ir_node *bb, ir_node *address, unsigned int id)
114
{
Matthias Braun's avatar
fixes    
Matthias Braun committed
115
	ir_graph *irg = get_irn_irg(bb);
116
117
118
	ir_node  *start_block = get_irg_start_block(irg);
	ir_node  *load, *store, *offset, *add, *projm, *proji, *unknown;
	ir_node  *cnst;
Matthias Braun's avatar
fixes    
Matthias Braun committed
119

120
	/**
121
	 * We can't instrument the end block as there are no real instructions there
122
	 */
123
	if(bb == get_irg_end_block(irg))
Matthias Braun's avatar
fixes    
Matthias Braun committed
124
125
		return;

126
127
128
129
130
131
132
133
134
135
136
137
	unknown = new_r_Unknown(irg, mode_M);
	cnst    = new_r_Const_long(irg, start_block, mode_Iu, get_mode_size_bytes(mode_Iu) * id);
	offset  = new_r_Add(irg, bb, address, cnst, mode_P);
	load    = new_r_Load(irg, bb, unknown, offset, mode_Iu);
	projm   = new_r_Proj(irg, bb, load, mode_M, pn_Load_M);
	proji   = new_r_Proj(irg, bb, load, mode_Iu, pn_Load_res);
	cnst    = new_r_Const_long(irg, start_block, mode_Iu, 1);
	add     = new_r_Add(irg, bb, proji, cnst, mode_Iu);
	store   = new_r_Store(irg, bb, projm, offset, add);
	projm   = new_r_Proj(irg, bb, store, mode_M, pn_Store_M);
	set_irn_link(bb, projm);
	set_irn_link(projm, load);
138
139
}

Michael Beck's avatar
BugFix:    
Michael Beck committed
140
141
142
143
typedef struct fix_env {
	ir_node *end_block;
} fix_env;

144
/**
Michael Beck's avatar
BugFix:    
Michael Beck committed
145
 * SSA Construction for instrumentation code memory
146
147
148
149
 */
static void
fix_ssa(ir_node * bb, void * data)
{
Michael Beck's avatar
BugFix:    
Michael Beck committed
150
151
152
	fix_env *env = data;
	ir_node *mem;
	int     arity = get_Block_n_cfgpreds(bb);
153
154

	/* start and end block are not instrumented, skip! */
155
	if (bb == env->end_block)
156
157
		return;

158
159
160
	if (bb == get_irg_start_block(get_irn_irg(bb))) {
		mem = new_NoMem();
	} else if (arity == 1) {
Michael Beck's avatar
BugFix:    
Michael Beck committed
161
		mem = get_irn_link(get_Block_cfgpred_block(bb, 0));
162
	} else {
Michael Beck's avatar
BugFix:    
Michael Beck committed
163
164
165
166
167
168
169
		int n;
		ir_node **ins;
		ir_graph *irg = current_ir_graph;

		NEW_ARR_A(ir_node*, ins, arity);
		for (n = arity - 1; n >= 0; --n) {
			ins[n] = get_irn_link(get_Block_cfgpred_block(bb, n));
170
		}
Michael Beck's avatar
BugFix:    
Michael Beck committed
171
		mem = new_r_Phi(irg, bb, arity, ins, mode_M);
172
173
174
175
	}
	set_Load_mem(get_irn_link(get_irn_link(bb)), mem);
}

176
177
178
179
180
181
static void add_constructor(ir_entity *method)
{
    ir_type   *method_type  = get_entity_type(method);
    ident     *id           = id_unique("constructor_ptrt.%u");
    ir_type   *ptr_type     = new_type_pointer(id, method_type, mode_P_code);

182
    ir_type   *constructors = get_segment_type(IR_SEGMENT_CONSTRUCTORS);
183
184
185
186
187
188
189
    ident     *ide          = id_unique("constructor_ptr.%u");
    ir_entity *ptr          = new_entity(constructors, ide, ptr_type);
	ir_graph  *irg          = get_const_code_irg();
    ir_node   *val          = new_rd_SymConst_addr_ent(NULL, irg, mode_P_code,
	                                                   method, NULL);

    set_entity_compiler_generated(ptr, 1);
Matthias Braun's avatar
Matthias Braun committed
190
    set_entity_variability(ptr, variability_constant);
191
192
    set_atomic_ent_value(ptr, val);
}
193

194
195
/**
 * Generates a new irg which calls the initializer
Michael Beck's avatar
BugFix:    
Michael Beck committed
196
197
198
 *
 * Pseudocode:
 *	 void __firmprof_initializer(void) { __init_firmprof(ent_filename, bblock_id, bblock_counts, n_blocks); }
199
200
 */
static ir_graph *
201
gen_initializer_irg(ir_entity * ent_filename, ir_entity * bblock_id, ir_entity * bblock_counts, int n_blocks)
202
{
Matthias Braun's avatar
fixes    
Matthias Braun committed
203
204
	ir_node *start_block;

205
	ir_node   *ins[4];
206
	ident     *name = new_id_from_str("__firmprof_initializer");
207
	ir_entity *ent  = new_entity(get_glob_type(), name, new_type_method(name, 0, 0));
Adam Szalkowski's avatar
Adam Szalkowski committed
208
209
	ir_node   *ret, *call, *symconst;
	symconst_symbol sym;
210
211

	ident     *init_name = new_id_from_str("__init_firmprof");
212
213
	ir_type   *init_type = new_type_method(init_name, 4, 0);
	ir_type   *uint, *uintptr, *string;
214
	ir_entity *init_ent;
Christian Würdig's avatar
Christian Würdig committed
215
216
	ir_graph  *irg;
	ir_node   *bb;
Christian Würdig's avatar
Christian Würdig committed
217
	ir_type   *empty_frame_type;
Adam Szalkowski's avatar
Adam Szalkowski committed
218

Christian Würdig's avatar
Christian Würdig committed
219
220
	set_entity_ld_ident(ent, name);

Christian Würdig's avatar
Christian Würdig committed
221
	uint    = new_type_primitive(new_id_from_str("__uint"), mode_Iu);
Adam Szalkowski's avatar
Adam Szalkowski committed
222
	uintptr = new_type_pointer(new_id_from_str("__uintptr"), uint, mode_P);
Christian Würdig's avatar
Christian Würdig committed
223
	string  = new_type_pointer(new_id_from_str("__charptr"), new_type_primitive(new_id_from_str("__char"), mode_Bs), mode_P);
Adam Szalkowski's avatar
Adam Szalkowski committed
224

225
	set_method_param_type(init_type, 0, string);
Adam Szalkowski's avatar
Adam Szalkowski committed
226
	set_method_param_type(init_type, 1, uintptr);
227
228
	set_method_param_type(init_type, 2, uintptr);
	set_method_param_type(init_type, 3, uint);
Christian Würdig's avatar
Christian Würdig committed
229
	init_ent = new_entity(get_glob_type(), init_name, init_type);
Christian Würdig's avatar
Christian Würdig committed
230
	set_entity_ld_ident(init_ent, init_name);
Adam Szalkowski's avatar
Adam Szalkowski committed
231

Christian Würdig's avatar
Christian Würdig committed
232
	irg = new_ir_graph(ent, 0);
Christian Würdig's avatar
Christian Würdig committed
233
234
	empty_frame_type = get_irg_frame_type(irg);
	set_type_size_bytes(empty_frame_type, 0);
235

Christian Würdig's avatar
Christian Würdig committed
236
	bb = get_cur_block();
Adam Szalkowski's avatar
Adam Szalkowski committed
237

Matthias Braun's avatar
fixes    
Matthias Braun committed
238
239
	start_block = get_irg_start_block(irg);

Adam Szalkowski's avatar
Adam Szalkowski committed
240
	sym.entity_p = init_ent;
241
	symconst     = new_r_SymConst(irg, start_block, mode_P_data, sym, symconst_addr_ent);
Adam Szalkowski's avatar
Adam Szalkowski committed
242

243
	sym.entity_p = ent_filename;
244
	ins[0] = new_r_SymConst(irg, start_block, mode_P_data, sym, symconst_addr_ent);
245
	sym.entity_p = bblock_id;
246
	ins[1] = new_r_SymConst(irg, start_block, mode_P_data, sym, symconst_addr_ent);
247
	sym.entity_p = bblock_counts;
248
	ins[2] = new_r_SymConst(irg, start_block, mode_P_data, sym, symconst_addr_ent);
249
	ins[3] = new_r_Const_long(irg, start_block, mode_Iu, n_blocks);
250

251
252
	call = new_r_Call(irg, bb, get_irg_initial_mem(irg), symconst, 4, ins, init_type);
	ret = new_r_Return(irg, bb, new_r_Proj(irg, bb, call, mode_M, pn_Call_M_regular), 0, NULL);
253
254
255
256
257
	mature_immBlock(bb);

	add_immBlock_pred(get_irg_end_block(irg), ret);
	mature_immBlock(get_irg_end_block(irg));

Matthias Braun's avatar
fixes    
Matthias Braun committed
258
259
	irg_finalize_cons(irg);

260
261
	add_constructor(ent);

262
263
264
	return irg;
}

265
266
267
268
269
270
/**
 * Create the location data for the given debug info.
 */
static void create_location_data(dbg_info *dbg, block_id_walker_data_t *wd)
{
	unsigned lineno;
Michael Beck's avatar
Michael Beck committed
271
	const char *fname = ir_retrieve_dbg_info(dbg, &lineno);
272
273
274

	if (fname) {
		pmap_entry *entry = pmap_find(wd->fname_map, (void *)fname);
275
		ir_entity  *ent;
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317

		if (! entry) {
			static unsigned nr = 0;
			ident   *id;
			char    buf[128];
			ir_type *arr;
			int     i, len = strlen(fname) + 1;
			tarval  **tarval_string;

			snprintf(buf, sizeof(buf), "firm_name_arr.%d", nr);
			arr = new_type_array(new_id_from_str(buf), 1, wd->tp_char);
			set_array_bounds_int(arr, 0, 0, len);

			snprintf(buf, sizeof(buf), "__firm_name.%d", nr++);
			id = new_id_from_str(buf);
			ent = new_entity(get_glob_type(), id, arr);
			set_entity_ld_ident(ent, id);

			pmap_insert(wd->fname_map, (void *)fname, ent);

			/* initialize file name string constant */
			tarval_string = alloca(sizeof(*tarval_string) * (len));
			for (i = 0; i < len; ++i) {
				tarval_string[i] = new_tarval_from_long(fname[i], mode_Bs);
			}
			set_entity_variability(ent, variability_constant);
			set_array_entity_values(ent, tarval_string, len);
		} else {
			ent = entry->value;
		}
		wd->locs[wd->id].fname  = ent;
		wd->locs[wd->id].lineno = lineno;
	} else {
		wd->locs[wd->id].fname  = NULL;
		wd->locs[wd->id].lineno = 0;
	}
}

/**
 * Walker: assigns an ID to every block.
 * Builds the string table
 */
318
319
320
static void
block_id_walker(ir_node * bb, void * data)
{
321
	block_id_walker_data_t *wd = data;
322

323
	wd->array[wd->id] = new_tarval_from_long(get_irn_node_nr(bb), mode_Iu);
324
	instrument_block(bb, wd->symconst, wd->id);
325
326
327
328
329

	if (wd->flags & profile_with_locations) {
		dbg_info *dbg = get_irn_dbg_info(bb);
		create_location_data(dbg, wd);
	}
330
331
332
	++wd->id;
}

333
334
#define IDENT(x)	new_id_from_chars(x, sizeof(x) - 1)

Christian Würdig's avatar
Christian Würdig committed
335
ir_graph *
Michael Beck's avatar
Michael Beck committed
336
ir_profile_instrument(const char *filename, unsigned flags)
337
{
Matthias Braun's avatar
Matthias Braun committed
338
	int n, i;
339
	int n_blocks = 0;
340
341
342
343
344
345
346
	ir_entity *bblock_id;
	ir_entity *bblock_counts;
	ir_entity *ent_filename;
	ir_entity *ent_locations = NULL;
	ir_entity *loc_lineno = NULL;
	ir_entity *loc_name = NULL;
	ir_entity *ent;
Matthias Braun's avatar
Matthias Braun committed
347
348
349
350
351
352
353
	ir_type *array_type;
	ir_type *uint_type;
	ir_type *string_type;
	ir_type *character_type;
	ir_type *loc_type = NULL;
	ir_type *charptr_type;
	ir_type *gtp;
354
	ir_node *start_block;
Matthias Braun's avatar
Matthias Braun committed
355
356
357
358
359
	tarval **tarval_array;
	tarval **tarval_string;
	tarval *tv;
	int filename_len = strlen(filename)+1;
	ident *cur_ident;
360
	unsigned align_l, align_n, size;
Matthias Braun's avatar
Matthias Braun committed
361
	ir_graph *rem;
362
	block_id_walker_data_t  wd;
Matthias Braun's avatar
fixes    
Matthias Braun committed
363
	symconst_symbol sym;
364

365
366
367
368
369
370
371
372
373
374
375
376
	/* count the number of block first */
	for (n = get_irp_n_irgs() - 1; n >= 0; --n) {
		ir_graph *irg = get_irp_irg(n);

		n_blocks += count_blocks(irg);
	}

	/* create all the necessary types and entities. Note that the
	   types must have a fixed layout, because we already running in the
	   backend */
	uint_type      = new_type_primitive(IDENT("__uint"), mode_Iu);
	set_type_alignment_bytes(uint_type, get_type_size_bytes(uint_type));
377

378
	array_type     = new_type_array(IDENT("__block_info_array"), 1, uint_type);
379
	set_array_bounds_int(array_type, 0, 0, n_blocks);
380
381
382
	set_type_size_bytes(array_type, n_blocks * get_mode_size_bytes(mode_Iu));
	set_type_alignment_bytes(array_type, get_mode_size_bytes(mode_Iu));
	set_type_state(array_type, layout_fixed);
Christian Würdig's avatar
Christian Würdig committed
383

384
385
	character_type = new_type_primitive(IDENT("__char"), mode_Bs);
	string_type    = new_type_array(IDENT("__filename"), 1, character_type);
386
	set_array_bounds_int(string_type, 0, 0, filename_len);
387
388
389
	set_type_size_bytes(string_type, filename_len);
	set_type_alignment_bytes(string_type, 1);
	set_type_state(string_type, layout_fixed);
Christian Würdig's avatar
Christian Würdig committed
390

391
392
393
394
	gtp            = get_glob_type();

	cur_ident      = IDENT("__FIRMPROF__BLOCK_IDS");
	bblock_id      = new_entity(gtp, cur_ident, array_type);
Christian Würdig's avatar
Christian Würdig committed
395
	set_entity_ld_ident(bblock_id, cur_ident);
Matthias Braun's avatar
fixes    
Matthias Braun committed
396
	set_entity_variability(bblock_id, variability_initialized);
Christian Würdig's avatar
Christian Würdig committed
397

398
399
	cur_ident      = IDENT("__FIRMPROF__BLOCK_COUNTS");
	bblock_counts  = new_entity(gtp, cur_ident, array_type);
Christian Würdig's avatar
Christian Würdig committed
400
	set_entity_ld_ident(bblock_counts, cur_ident);
Matthias Braun's avatar
fixes    
Matthias Braun committed
401
	set_entity_variability(bblock_counts, variability_initialized);
Christian Würdig's avatar
Christian Würdig committed
402

403
404
	cur_ident      = IDENT("__FIRMPROF__FILE_NAME");
	ent_filename   = new_entity(gtp, cur_ident, string_type);
Christian Würdig's avatar
Christian Würdig committed
405
	set_entity_ld_ident(ent_filename, cur_ident);
406

407
408
409
410
411
	if (flags & profile_with_locations) {
		loc_type       = new_type_struct(IDENT("__location"));
		loc_lineno     = new_entity(loc_type, IDENT("lineno"), uint_type);
		align_l        = get_type_alignment_bytes(uint_type);
		size           = get_type_size_bytes(uint_type);
412
		set_entity_offset(loc_lineno, 0);
413
414
415
416
417

		charptr_type   = new_type_pointer(IDENT("__charptr"), character_type, mode_P_data);
		align_n        = get_type_size_bytes(charptr_type);
		set_type_alignment_bytes(charptr_type, align_n);
		loc_name       = new_entity(loc_type, IDENT("name"), charptr_type);
418
		size           = (size + align_n - 1) & ~(align_n - 1);
419
		set_entity_offset(loc_name, size);
420
421
422
423
		size          += align_n;

		if (align_n > align_l)
			align_l = align_n;
424
		size = (size + align_l - 1) & ~(align_l - 1);
425
426
427
428
429
430
431
432
433
		set_type_size_bytes(loc_type, size);
		set_type_state(loc_type, layout_fixed);

		loc_type = new_type_array(IDENT("__locarray"), 1, loc_type);
		set_array_bounds_int(string_type, 0, 0, n_blocks);

		cur_ident      = IDENT("__FIRMPROF__LOCATIONS");
		ent_locations   = new_entity(gtp, cur_ident, loc_type);
		set_entity_ld_ident(ent_locations, cur_ident);
434
435
436
	}

	/* initialize count array */
437
	NEW_ARR_A(tarval *, tarval_array, n_blocks);
Michael Beck's avatar
BugFix:    
Michael Beck committed
438
	tv = get_tarval_null(mode_Iu);
Christian Würdig's avatar
Christian Würdig committed
439
	for (i = 0; i < n_blocks; ++i) {
Michael Beck's avatar
BugFix:    
Michael Beck committed
440
		tarval_array[i] = tv;
441
	}
Adam Szalkowski's avatar
Adam Szalkowski committed
442
	set_array_entity_values(bblock_counts, tarval_array, n_blocks);
443

444
445
	/* initialize function name string constant */
	tarval_string = alloca(sizeof(*tarval_string) * (filename_len));
Christian Würdig's avatar
Christian Würdig committed
446
	for (i = 0; i < filename_len; ++i) {
447
448
		tarval_string[i] = new_tarval_from_long(filename[i], mode_Bs);
	}
Michael Beck's avatar
BugFix:    
Michael Beck committed
449
	set_entity_variability(ent_filename, variability_constant);
450
451
	set_array_entity_values(ent_filename, tarval_string, filename_len);

452
	/* initialize block id array and instrument blocks */
453
454
455
456
457
458
459
460
461
	wd.array     = tarval_array;
	wd.id        = 0;
	wd.tp_char   = character_type;
	wd.flags     = flags;
	if (flags & profile_with_locations) {
		wd.fname_map = pmap_create();
		NEW_ARR_A(loc_entry, wd.locs, n_blocks);
	}

Christian Würdig's avatar
Christian Würdig committed
462
	for (n = get_irp_n_irgs() - 1; n >= 0; --n) {
463
464
465
		ir_graph      *irg = get_irp_irg(n);
		int            i;
		ir_node       *endbb = get_irg_end_block(irg);
Michael Beck's avatar
BugFix:    
Michael Beck committed
466
		fix_env       env;
467
468

		set_current_ir_graph(irg);
469

470
		/* generate a symbolic constant pointing to the count array */
Christian Würdig's avatar
Christian Würdig committed
471
		sym.entity_p = bblock_counts;
472
		wd.symconst  = new_r_SymConst(irg, get_irg_start_block(irg), mode_P_data, sym, symconst_addr_ent);
Matthias Braun's avatar
fixes    
Matthias Braun committed
473

474
		irg_block_walk_graph(irg, block_id_walker, NULL, &wd);
475
		start_block = get_irg_start_block(irg);
Michael Beck's avatar
BugFix:    
Michael Beck committed
476
477
478
479
480
		env.end_block   = get_irg_end_block(irg);
		irg_block_walk_graph(irg, fix_ssa, NULL, &env);
		for (i = get_Block_n_cfgpreds(endbb) - 1; i >= 0; --i) {
			ir_node *node = skip_Proj(get_Block_cfgpred(endbb, i));
			ir_node *bb   = get_Block_cfgpred_block(endbb, i);
481
482
483
			ir_node *sync;
			ir_node *ins[2];

Michael Beck's avatar
BugFix:    
Michael Beck committed
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
			switch (get_irn_opcode(node)) {
			case iro_Return:
				ins[0] = get_irn_link(bb);
				ins[1] = get_Return_mem(node);
				sync   = new_r_Sync(irg, bb, 2, ins);
				set_Return_mem(node, sync);
				break;
			case iro_Raise:
				ins[0] = get_irn_link(bb);
				ins[1] = get_Raise_mem(node);
				sync   = new_r_Sync(irg, bb, 2, ins);
				set_Raise_mem(node, sync);
				break;
			default:
				/* a fragile's op exception. There should be another path to End,
				   so ignore it */
				assert(is_fragile_op(node) && "unexpected End control flow predecessor");
			}
502
		}
503
	}
Adam Szalkowski's avatar
Adam Szalkowski committed
504
	set_array_entity_values(bblock_id, tarval_array, n_blocks);
505

506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
	if (flags & profile_with_locations) {
		/* build the initializer for the locations */
		rem = current_ir_graph;
		current_ir_graph = get_const_code_irg();
		ent = get_array_element_entity(loc_type);
		set_entity_variability(ent_locations, variability_constant);
		for (i = 0; i < n_blocks; ++i) {
			compound_graph_path *path;
			tarval *tv;
			ir_node *n;

			/* lineno */
			path = new_compound_graph_path(loc_type, 2);
			set_compound_graph_path_array_index(path, 0, i);
			set_compound_graph_path_node(path, 0, ent);
			set_compound_graph_path_node(path, 1, loc_lineno);
			tv = new_tarval_from_long(wd.locs[i].lineno, mode_Iu);
			add_compound_ent_value_w_path(ent_locations, new_Const(mode_Iu, tv), path);

			/* name */
			path = new_compound_graph_path(loc_type, 2);
			set_compound_graph_path_array_index(path, 0, i);
			set_compound_graph_path_node(path, 0, ent);
			set_compound_graph_path_node(path, 1, loc_name);
			if (wd.locs[i].fname) {
				sym.entity_p = wd.locs[i].fname;
532
				n = new_SymConst(mode_P_data, sym, symconst_addr_ent);
533
534
535
536
537
538
539
			} else {
				n = new_Const(mode_P_data, get_mode_null(mode_P_data));
			}
			add_compound_ent_value_w_path(ent_locations, n, path);
		}
		pmap_destroy(wd.fname_map);
	}
540
	return gen_initializer_irg(ent_filename, bblock_id, bblock_counts, n_blocks);
541
542
}

543
544
545
static void
profile_node_info(void *ctx, FILE *f, const ir_node *irn)
{
546
	(void) ctx;
547
	if(is_Block(irn)) {
Michael Beck's avatar
Michael Beck committed
548
		fprintf(f, "profiled execution count: %u\n", ir_profile_get_block_execcount(irn));
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
	}
}

static void
register_vcg_hook(void)
{
	memset(&hook, 0, sizeof(hook));
	hook.hook._hook_node_info = profile_node_info;
	register_hook(hook_node_info, &hook);
}

static void
unregister_vcg_hook(void)
{
	unregister_hook(hook_node_info, &hook);
}
565

566
567
568
569
/**
 * Reads the corresponding profile info file if it exists and returns a
 * profile info struct
 */
570
void
Michael Beck's avatar
Michael Beck committed
571
ir_profile_read(const char *filename)
572
{
573
574
575
576
577
	FILE   *f;
	char    buf[8];
	size_t  ret;

	f = fopen(filename, "r");
Adam Szalkowski's avatar
oops    
Adam Szalkowski committed
578
579
580
	if(f == NULL) {
		return;
	}
581
	printf("found profile data '%s'.\n", filename);
582
583
584
585
586
587

	/* check magic */
	ret = fread(buf, 8, 1, f);
	if(ret == 0 || strncmp(buf, "firmprof", 8) != 0) {
		return;
	}
588

Michael Beck's avatar
Michael Beck committed
589
	if(profile) ir_profile_free();
590
591
592
593
594
595
596
597
598
599
	profile = new_set(cmp_execcount, 16);

	do {
		execcount_t  query;
		ret = fread(&query, sizeof(unsigned int), 2, f);

		if(ret != 2) break;

		set_insert(profile, &query, sizeof(query), query.block);
	} while(1);
Adam Szalkowski's avatar
Adam Szalkowski committed
600
601

	fclose(f);
602
	register_vcg_hook();
603
604
605
606
607
608
}

/**
 * Frees the profile info
 */
void
Michael Beck's avatar
Michael Beck committed
609
ir_profile_free(void)
610
{
611
612
	if(profile) {
		unregister_vcg_hook();
613
		del_set(profile);
614
	}
615
616
}

Adam Szalkowski's avatar
Adam Szalkowski committed
617
/**
Michael Beck's avatar
BugFix:    
Michael Beck committed
618
 * Tells whether profile module has acquired data
Adam Szalkowski's avatar
Adam Szalkowski committed
619
620
 */
int
Michael Beck's avatar
Michael Beck committed
621
ir_profile_has_data(void)
Adam Szalkowski's avatar
Adam Szalkowski committed
622
623
624
625
{
	return (profile != NULL);
}

626
627
628
629
/**
 * Get block execution count as determined be profiling
 */
unsigned int
Michael Beck's avatar
Michael Beck committed
630
ir_profile_get_block_execcount(const ir_node *block)
631
632
633
634
635
636
637
638
639
{
	execcount_t *ec, query;

	if(!profile)
		return 1;

	query.block = get_irn_node_nr(block);
	ec = set_find(profile, &query, sizeof(query), get_irn_node_nr(block));

640
	if(ec != NULL) {
641
642
		return ec->count;
	} else {
643
644
		ir_fprintf(stderr, "Warning: Profile contains no data for %+F\n",
		           block);
645
646
		return 1;
	}
647
}
648
649
650

typedef struct _intialize_execfreq_env_t {
	ir_graph *irg;
651
	ir_exec_freq *execfreqs;
652
653
654
	double freq_factor;
} initialize_execfreq_env_t;

655
656
657
// minimal execution frequency (an execfreq of 0 confuses algos)
static const double MIN_EXECFREQ = 0.00001;

658
659
660
661
662
663
664
665
static void initialize_execfreq(ir_node *block, void *data) {
	initialize_execfreq_env_t *env = data;
	double freq;

	if(block == get_irg_start_block(env->irg)
	   || block == get_irg_end_block(env->irg)) {
		freq = 1.0;
	} else {
Michael Beck's avatar
Michael Beck committed
666
		freq = ir_profile_get_block_execcount(block);
667
		freq *= env->freq_factor;
668
669
		if(freq < MIN_EXECFREQ)
			freq = MIN_EXECFREQ;
670
671
672
673
674
	}

	set_execfreq(env->execfreqs, block, freq);
}

Michael Beck's avatar
Michael Beck committed
675
ir_exec_freq *ir_create_execfreqs_from_profile(ir_graph *irg)
676
677
678
679
680
{
	ir_node *start_block;
	initialize_execfreq_env_t env;
	unsigned count;

681
	env.irg = irg;
682
683
684
	env.execfreqs = create_execfreq(irg);
	start_block = get_irg_start_block(irg);

Michael Beck's avatar
Michael Beck committed
685
	count = ir_profile_get_block_execcount(start_block);
686
687
688
689
690
691
692
	if(count == 0) {
		// the function was never executed, so fallback to estimated freqs
		free_execfreq(env.execfreqs);

		return compute_execfreq(irg, 10);
	}

693
	env.freq_factor = 1.0 / count;
694
695
696
697
	irg_block_walk_graph(irg, initialize_execfreq, NULL, &env);

	return env.execfreqs;
}