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
39
40
41
42
43
44
45
 */
#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"

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

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

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

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

60
typedef struct _block_id_walker_data_t {
61
62
63
64
65
66
67
	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 */
68
69
70
} block_id_walker_data_t;

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

Michael Beck's avatar
Michael Beck committed
75
76
77
78
79
80
/**
 * 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;
81
	(void) size;
Michael Beck's avatar
Michael Beck committed
82
	return ea->block != eb->block;
83
}
84

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

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

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

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

108
109
110
111
/**
 * Instrument a block with code needed for profiling
 */
static void
Michael Beck's avatar
Michael Beck committed
112
instrument_block(ir_node *bb, ir_node *address, unsigned int id)
113
{
Matthias Braun's avatar
fixes    
Matthias Braun committed
114
	ir_graph *irg = get_irn_irg(bb);
115
116
117
	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
118

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

125
126
127
128
129
130
131
132
133
134
135
136
	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);
137
138
}

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

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

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

157
158
159
	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
160
		mem = get_irn_link(get_Block_cfgpred_block(bb, 0));
161
	} else {
Michael Beck's avatar
BugFix:    
Michael Beck committed
162
163
164
165
166
167
168
		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));
169
		}
Michael Beck's avatar
BugFix:    
Michael Beck committed
170
		mem = new_r_Phi(irg, bb, arity, ins, mode_M);
171
172
173
174
	}
	set_Load_mem(get_irn_link(get_irn_link(bb)), mem);
}

175
176
177
178
179
180
181
182
183
184
185
186
187
188
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);

    ir_type   *constructors = get_constructors_type();
    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
189
    set_entity_variability(ptr, variability_constant);
190
191
    set_atomic_ent_value(ptr, val);
}
192

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

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

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

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

Christian Würdig's avatar
Christian Würdig committed
220
	uint    = new_type_primitive(new_id_from_str("__uint"), mode_Iu);
Adam Szalkowski's avatar
Adam Szalkowski committed
221
	uintptr = new_type_pointer(new_id_from_str("__uintptr"), uint, mode_P);
Christian Würdig's avatar
Christian Würdig committed
222
	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
223

224
	set_method_param_type(init_type, 0, string);
Adam Szalkowski's avatar
Adam Szalkowski committed
225
	set_method_param_type(init_type, 1, uintptr);
226
227
	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
228
	init_ent = new_entity(get_glob_type(), init_name, init_type);
Christian Würdig's avatar
Christian Würdig committed
229
	set_entity_ld_ident(init_ent, init_name);
Adam Szalkowski's avatar
Adam Szalkowski committed
230

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

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

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

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

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

250
251
	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);
252
253
254
255
256
	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
257
258
	irg_finalize_cons(irg);

259
260
	add_constructor(ent);

261
262
263
	return irg;
}

264
265
266
267
268
269
/**
 * 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
270
	const char *fname = ir_retrieve_dbg_info(dbg, &lineno);
271
272
273

	if (fname) {
		pmap_entry *entry = pmap_find(wd->fname_map, (void *)fname);
274
		ir_entity  *ent;
275
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

		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
 */
317
318
319
static void
block_id_walker(ir_node * bb, void * data)
{
320
	block_id_walker_data_t *wd = data;
321

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

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

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

Christian Würdig's avatar
Christian Würdig committed
334
ir_graph *
Michael Beck's avatar
Michael Beck committed
335
ir_profile_instrument(const char *filename, unsigned flags)
336
{
Matthias Braun's avatar
Matthias Braun committed
337
	int n, i;
338
	int n_blocks = 0;
339
340
341
342
343
344
345
	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
346
347
348
349
350
351
352
	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;
353
	ir_node *start_block;
Matthias Braun's avatar
Matthias Braun committed
354
355
356
357
358
	tarval **tarval_array;
	tarval **tarval_string;
	tarval *tv;
	int filename_len = strlen(filename)+1;
	ident *cur_ident;
359
	unsigned align_l, align_n, size;
Matthias Braun's avatar
Matthias Braun committed
360
	ir_graph *rem;
361
	block_id_walker_data_t  wd;
Matthias Braun's avatar
fixes    
Matthias Braun committed
362
	symconst_symbol sym;
363

364
365
366
367
368
369
370
371
372
373
374
375
	/* 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));
376

377
	array_type     = new_type_array(IDENT("__block_info_array"), 1, uint_type);
378
	set_array_bounds_int(array_type, 0, 0, n_blocks);
379
380
381
	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
382

383
384
	character_type = new_type_primitive(IDENT("__char"), mode_Bs);
	string_type    = new_type_array(IDENT("__filename"), 1, character_type);
385
	set_array_bounds_int(string_type, 0, 0, filename_len);
386
387
388
	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
389

390
391
392
393
	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
394
	set_entity_ld_ident(bblock_id, cur_ident);
Matthias Braun's avatar
fixes    
Matthias Braun committed
395
	set_entity_variability(bblock_id, variability_initialized);
Christian Würdig's avatar
Christian Würdig committed
396

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

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

406
407
408
409
410
	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);
411
		set_entity_offset(loc_lineno, 0);
412
413
414
415
416

		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);
417
		size           = (size + align_n - 1) & ~(align_n - 1);
418
		set_entity_offset(loc_name, size);
419
420
421
422
		size          += align_n;

		if (align_n > align_l)
			align_l = align_n;
423
		size = (size + align_l - 1) & ~(align_l - 1);
424
425
426
427
428
429
430
431
432
		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);
433
434
435
	}

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

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

451
	/* initialize block id array and instrument blocks */
452
453
454
455
456
457
458
459
460
	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
461
	for (n = get_irp_n_irgs() - 1; n >= 0; --n) {
462
463
464
		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
465
		fix_env       env;
466
467

		set_current_ir_graph(irg);
468

469
		/* generate a symbolic constant pointing to the count array */
Christian Würdig's avatar
Christian Würdig committed
470
		sym.entity_p = bblock_counts;
471
		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
472

473
		irg_block_walk_graph(irg, block_id_walker, NULL, &wd);
474
		start_block = get_irg_start_block(irg);
Michael Beck's avatar
BugFix:    
Michael Beck committed
475
476
477
478
479
		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);
480
481
482
			ir_node *sync;
			ir_node *ins[2];

Michael Beck's avatar
BugFix:    
Michael Beck committed
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
			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");
			}
501
		}
502
	}
Adam Szalkowski's avatar
Adam Szalkowski committed
503
	set_array_entity_values(bblock_id, tarval_array, n_blocks);
504

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
	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;
531
				n = new_SymConst(mode_P_data, sym, symconst_addr_ent);
532
533
534
535
536
537
538
			} 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);
	}
539
	return gen_initializer_irg(ent_filename, bblock_id, bblock_counts, n_blocks);
540
541
}

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

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);
}
564

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

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

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

Michael Beck's avatar
Michael Beck committed
588
	if(profile) ir_profile_free();
589
590
591
592
593
594
595
596
597
598
	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
599
600

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

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

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

625
626
627
628
/**
 * Get block execution count as determined be profiling
 */
unsigned int
Michael Beck's avatar
Michael Beck committed
629
ir_profile_get_block_execcount(const ir_node *block)
630
631
632
633
634
635
636
637
638
{
	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));

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

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

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

657
658
659
660
661
662
663
664
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
665
		freq = ir_profile_get_block_execcount(block);
666
		freq *= env->freq_factor;
667
668
		if(freq < MIN_EXECFREQ)
			freq = MIN_EXECFREQ;
669
670
671
672
673
	}

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

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

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

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

		return compute_execfreq(irg, 10);
	}

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

	return env.execfreqs;
}