irprofile.c 18.1 KB
Newer Older
Christian Würdig's avatar
Christian Würdig committed
1
/*
Michael Beck's avatar
Michael Beck committed
2
 * Copyright (C) 1995-2011 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
/**
 * @file
 * @brief       Code instrumentation and execution count profiling.
23
24
 * @author      Adam M. Szalkowski, Steven Schaefer
 * @date        06.04.2006, 11.11.2010
25
26
27
28
 */
#include "config.h"

#include <math.h>
29
#include <stdio.h>
30
31
32
33

#include "hashptr.h"
#include "debug.h"
#include "obst.h"
34
#include "xmalloc.h"
35
#include "set.h"
36
#include "irtools.h"
37
38
39
40
41
42

#include "irgwalk.h"
#include "irdump_t.h"
#include "irnode_t.h"
#include "ircons_t.h"
#include "execfreq.h"
43
#include "typerep.h"
44

Michael Beck's avatar
Michael Beck committed
45
#include "irprofile.h"
46

47
/* Instrument blocks walker. */
48
typedef struct block_id_walker_data_t {
49
50
	unsigned int id;   /**< current block id number */
	ir_node *symconst; /**< the SymConst representing the counter array */
51
52
} block_id_walker_data_t;

53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
/* Associate counters with blocks. */
typedef struct block_assoc_t {
	unsigned int i;          /**< current block id number */
	unsigned int *counters;  /**< block execution counts */
} block_assoc_t;

typedef struct intialize_execfreq_env_t {
	ir_graph *irg;
	ir_exec_freq *execfreqs;
	double freq_factor;
} initialize_execfreq_env_t;

/* minimal execution frequency (an execfreq of 0 confuses algos) */
#define MIN_EXECFREQ 0.00001

/* keep the execcounts here because they are only read once per compiler run */
static set *profile = NULL;

/* Hook for vcg output. */
72
static void *hook;
73
74
75
76
77
78
79
80

/* The debug module handle. */
DEBUG_ONLY(static firm_dbg_module_t *dbg;)

/* Since the backend creates a new firm graph we cannot associate counts with
 * blocks directly. Instead we associate them with the block ids, which are
 * maintained.
 */
81
typedef struct execcount_t {
82
83
	unsigned long block; /**< block id */
	unsigned int  count; /**< execution count */
84
85
} execcount_t;

Michael Beck's avatar
Michael Beck committed
86
87
88
/**
 * Compare two execcount_t entries.
 */
89
90
static int cmp_execcount(const void *a, const void *b, size_t size)
{
91
92
	const execcount_t *ea = (const execcount_t*)a;
	const execcount_t *eb = (const execcount_t*)b;
93
	(void) size;
Michael Beck's avatar
Michael Beck committed
94
	return ea->block != eb->block;
95
}
96

Michael Beck's avatar
Michael Beck committed
97
98
99
/**
 * Block walker, count number of blocks.
 */
100
static void block_counter(ir_node *bb, void *data)
101
{
102
	unsigned *count = (unsigned*) data;
Michael Beck's avatar
Michael Beck committed
103
104
	(void) bb;
	++(*count);
105
106
}

Michael Beck's avatar
Michael Beck committed
107
/**
108
 * Returns the number of blocks the given graph.
Michael Beck's avatar
Michael Beck committed
109
 */
110
static unsigned int get_irg_n_blocks(ir_graph *irg)
111
{
112
113
114
115
116
117
	unsigned int count = 0;
	irg_block_walk_graph(irg, block_counter, NULL, &count);
	return count;
}

/**
118
 * Returns the number of basic blocks in the current ir program.
119
 */
120
static unsigned int get_irp_n_blocks(void)
121
{
122
123
	int i, n = get_irp_n_irgs();
	unsigned int count = 0;
Matthias Braun's avatar
fixes    
Matthias Braun committed
124

125
126
127
128
	for (i = 0; i < n; i++) {
		ir_graph *irg = get_irp_irg(i);
		count += get_irg_n_blocks(irg);
	}
Matthias Braun's avatar
fixes    
Matthias Braun committed
129

130
	return count;
131
132
}

133
134
/* vcg helper */
static void dump_profile_node_info(void *ctx, FILE *f, const ir_node *irn)
135
{
136
137
138
139
	(void) ctx;
	if (is_Block(irn)) {
		unsigned int execcount = ir_profile_get_block_execcount(irn);
		fprintf(f, "profiled execution count: %u\n", execcount);
140
141
142
	}
}

143
144
145
/**
 * Add the given method entity as a constructor.
 */
146
147
148
static void add_constructor(ir_entity *method)
{
    ir_type   *method_type  = get_entity_type(method);
149
    ir_type   *ptr_type     = new_type_pointer(method_type);
150

151
    ir_type   *constructors = get_segment_type(IR_SEGMENT_CONSTRUCTORS);
152
153
154
155
156
157
	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);

	set_entity_ld_ident(ptr, new_id_from_chars("", 0));
158
    set_entity_compiler_generated(ptr, 1);
159
160
    set_entity_linkage(ptr, IR_LINKAGE_CONSTANT | IR_LINKAGE_HIDDEN_USER);
    set_entity_visibility(ptr, ir_visibility_private);
161
162
    set_atomic_ent_value(ptr, val);
}
163

164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
/**
 * Returns an entity representing the __init_firmprof function from libfirmprof
 * This is the equivalent of:
 * extern void __init_firmprof(char *filename, uint *counters, uint size)
 */
static ir_entity *get_init_firmprof_ref(void)
{
	ident   *init_name = new_id_from_str("__init_firmprof");
	ir_type *init_type = new_type_method(3, 0);
	ir_type *uint      = new_type_primitive(mode_Iu);
	ir_type *uintptr   = new_type_pointer(uint);
	ir_type *string    = new_type_pointer(new_type_primitive(mode_Bs));
	ir_entity *result;

	set_method_param_type(init_type, 0, string);
	set_method_param_type(init_type, 1, uintptr);
	set_method_param_type(init_type, 2, uint);

	result = new_entity(get_glob_type(), init_name, init_type);
	set_entity_visibility(result, ir_visibility_external);

	return result;
}

188
189
/**
 * Generates a new irg which calls the initializer
Michael Beck's avatar
BugFix:    
Michael Beck committed
190
191
 *
 * Pseudocode:
192
193
194
195
 *    static void __firmprof_initializer(void) __attribute__ ((constructor))
 *    {
 *        __init_firmprof(ent_filename, bblock_counts, n_blocks);
 *    }
196
 */
197
198
static ir_graph *gen_initializer_irg(ir_entity *ent_filename,
                                     ir_entity *bblock_counts, int n_blocks)
199
{
200
201
202
203
	ir_graph *irg;
	ir_node  *ins[3];
	ir_node  *bb, *ret, *call, *symconst;
	ir_type  *empty_frame_type;
Adam Szalkowski's avatar
Adam Szalkowski committed
204
	symconst_symbol sym;
205

206
	ir_entity *init_ent = get_init_firmprof_ref();
Adam Szalkowski's avatar
Adam Szalkowski committed
207

208
209
210
	ident     *name = new_id_from_str("__firmprof_initializer");
	ir_entity *ent  = new_entity(get_glob_type(), name, new_type_method(0, 0));
	set_entity_visibility(ent, ir_visibility_local);
Christian Würdig's avatar
Christian Würdig committed
211
212
	set_entity_ld_ident(ent, name);

213
	/* create the new ir_graph */
Christian Würdig's avatar
Christian Würdig committed
214
	irg = new_ir_graph(ent, 0);
215
	set_current_ir_graph(irg);
Christian Würdig's avatar
Christian Würdig committed
216
217
	empty_frame_type = get_irg_frame_type(irg);
	set_type_size_bytes(empty_frame_type, 0);
218
	set_type_state(empty_frame_type, layout_fixed);
219

220
	bb = get_r_cur_block(irg);
Adam Szalkowski's avatar
Adam Szalkowski committed
221
222

	sym.entity_p = init_ent;
223
	symconst     = new_r_SymConst(irg, mode_P_data, sym, symconst_addr_ent);
Adam Szalkowski's avatar
Adam Szalkowski committed
224

225
	sym.entity_p = ent_filename;
226
	ins[0] = new_r_SymConst(irg, mode_P_data, sym, symconst_addr_ent);
227
	sym.entity_p = bblock_counts;
228
229
	ins[1] = new_r_SymConst(irg, mode_P_data, sym, symconst_addr_ent);
	ins[2] = new_r_Const_long(irg, mode_Iu, n_blocks);
230

231
232
233
	call = new_r_Call(bb, get_irg_initial_mem(irg), symconst, 3, ins,
	        get_entity_type(init_ent));
	ret  = new_r_Return(bb, new_r_Proj(call, mode_M, pn_Call_M), 0, NULL);
234
235
236
237
238
	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
239
240
	irg_finalize_cons(irg);

241
	/* add a pointer to the new function in the constructor section */
242
243
	add_constructor(ent);

244
245
246
	return irg;
}

247
/**
248
249
250
 * Instrument a block with code needed for profiling.
 * This just inserts the instruction nodes, it doesn't connect the memory
 * nodes in a meaningful way.
251
 */
252
static void instrument_block(ir_node *bb, ir_node *address, unsigned int id)
253
{
254
255
256
257
258
259
260
261
262
263
264
265
266
	ir_graph *irg = get_irn_irg(bb);
	ir_node  *load, *store, *offset, *add, *projm, *proji, *unknown, *cnst;

	/* We can't instrument the end block */
	if (bb == get_irg_end_block(irg))
		return;

	unknown = new_r_Unknown(irg, mode_M);
	cnst    = new_r_Const_long(irg, mode_Iu, get_mode_size_bytes(mode_Iu) * id);
	offset  = new_r_Add(bb, address, cnst, get_modeP_data());
	load    = new_r_Load(bb, unknown, offset, mode_Iu, cons_none);
	projm   = new_r_Proj(load, mode_M, pn_Load_M);
	proji   = new_r_Proj(load, mode_Iu, pn_Load_res);
267
	cnst    = new_r_Const(irg, get_mode_one(mode_Iu));
268
269
270
271
272
273
274
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
	add     = new_r_Add(bb, proji, cnst, mode_Iu);
	store   = new_r_Store(bb, projm, offset, add, cons_none);
	projm   = new_r_Proj(store, mode_M, pn_Store_M);

	set_irn_link(bb, projm);
	set_irn_link(projm, load);
}

/**
 * SSA Construction for instrumentation code memory.
 *
 * This introduces a new memory node and connects it to the instrumentation
 * codes, inserting phiM nodes as necessary. Note that afterwards, the new
 * memory is not connected to any return nodes and thus still dead.
 */
static void fix_ssa(ir_node *bb, void *data)
{
	ir_graph *irg = get_irn_irg(bb);
	ir_node *mem, *proj, *load;
	int n, arity = get_Block_n_cfgpreds(bb);

	(void) data;

	/* end blocks are not instrumented, skip! */
	if (bb == get_irg_end_block(irg))
		return;

	if (bb == get_irg_start_block(irg)) {
		mem = get_irg_initial_mem(irg);
	} else if (arity == 1) {
		ir_node *pred = get_Block_cfgpred_block(bb, 0);
		if (!is_Bad(pred))
			mem = (ir_node*) get_irn_link(pred);
		else
			mem = new_r_NoMem(irg);
303
	} else {
304
305
306
307
308
309
310
311
312
		ir_node **ins = ALLOCAN(ir_node*, arity);
		for (n = arity - 1; n >= 0; --n) {
			ir_node *pred = get_Block_cfgpred_block(bb, n);
			if (!is_Bad(pred))
				ins[n] = (ir_node*) get_irn_link(pred);
			else
				ins[n] = new_r_NoMem(irg);
		}
		mem = new_r_Phi(bb, arity, ins, mode_M);
313
	}
314
315
316
317
318
319
320

	/* The block link fields point to the projm from the instrumentation code,
	 * the projm in turn links to the initial load which lacks a memory
	 * argument at this point. */
	proj = (ir_node*) get_irn_link(bb);
	load = (ir_node*) get_irn_link(proj);
	set_Load_mem(load, mem);
321
322
323
}

/**
324
 * Instrument a single block.
325
 */
326
static void block_instrument_walker(ir_node *bb, void *data)
327
{
328
	block_id_walker_data_t *wd = (block_id_walker_data_t*)data;
329
330
331
332
	instrument_block(bb, wd->symconst, wd->id);
	++wd->id;
}

333
334
335
336
337
338
339
340
341
342
343
/**
 * Synchronize the original memory input of node with the additional operand
 * from the profiling code.
 */
static ir_node *sync_mem(ir_node *bb, ir_node *mem)
{
	ir_node *ins[2];
	ins[0] = (ir_node*) get_irn_link(bb);
	ins[1] = mem;
	return new_r_Sync(bb, 2, ins);
}
344

345
346
347
348
349
350
/**
 * Instrument a single ir_graph, counters should point to the bblock
 * counters array.
 */
static void instrument_irg(ir_graph *irg, ir_entity *counters,
                           block_id_walker_data_t *wd)
351
{
352
353
354
	ir_node *end   = get_irg_end(irg);
	ir_node *endbb = get_irg_end_block(irg);
	int i;
355

356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
	/* generate a symbolic constant pointing to the count array */
	symconst_symbol sym;
	sym.entity_p = counters;
	wd->symconst = new_r_SymConst(irg, mode_P_data, sym, symconst_addr_ent);

	/* instrument each block in the current irg */
	irg_block_walk_graph(irg, block_instrument_walker, NULL, wd);
	irg_block_walk_graph(irg, fix_ssa, NULL, NULL);

	/* connect the new memory nodes to the return nodes */
	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);
		ir_node *mem;

		switch (get_irn_opcode(node)) {
		case iro_Return:
			mem = get_Return_mem(node);
			set_Return_mem(node, sync_mem(bb, mem));
			break;
		case iro_Raise:
			mem = get_Raise_mem(node);
			set_Raise_mem(node, sync_mem(bb, mem));
			break;
		case iro_Bad:
			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");
		}
	}
390

391
392
393
394
395
396
397
398
	/* as well as calls with attribute noreturn */
	for (i = get_End_n_keepalives(end) - 1; i >= 0; --i) {
		ir_node *node = get_End_keepalive(end, i);
		if (is_Call(node)) {
			ir_node *bb  = get_nodes_block(node);
			ir_node *mem = get_Call_mem(node);
			set_Call_mem(node, sync_mem(bb, mem));
		}
399
	}
400
}
401

402
403
404
405
406
407
408
409
410
411
/**
 * Creates a new entity representing the equivalent of
 * static unsigned int name[size]
 */
static ir_entity *new_array_entity(ident *name, int size)
{
	ir_entity *result;
	ir_type *uint_type, *array_type;

	uint_type = new_type_primitive(mode_Iu);
412
	set_type_alignment_bytes(uint_type, get_type_size_bytes(uint_type));
413

414
415
416
	array_type = new_type_array(1, uint_type);
	set_array_bounds_int(array_type, 0, 0, size);
	set_type_size_bytes(array_type, size * get_mode_size_bytes(mode_Iu));
417
418
	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
419

420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
	result = new_entity(get_glob_type(), name, array_type);
	set_entity_visibility(result, ir_visibility_local);
	set_entity_compiler_generated(result, 1);

	return result;
}

/**
 * Creates a new entity representing the equivalent of
 * static const char name[strlen(string)+1] = string
 */
static ir_entity *new_static_string_entity(ident *name, const char *string)
{
	ir_entity *result;

	ir_type *char_type   = new_type_primitive(mode_Bs);
	ir_type *string_type = new_type_array(1, char_type);

	ir_initializer_t *contents;

	size_t i, length = strlen(string)+1;

	/* Create the type for a fixed-length string */
	set_array_bounds_int(string_type, 0, 0, length);
	set_type_size_bytes(string_type, length);
445
446
	set_type_alignment_bytes(string_type, 1);
	set_type_state(string_type, layout_fixed);
Christian Würdig's avatar
Christian Würdig committed
447

448
449
450
451
452
453
454
455
456
457
458
459
	result = new_entity(get_glob_type(), name, string_type);
	set_entity_visibility(result, ir_visibility_local);
	set_entity_linkage(result, IR_LINKAGE_CONSTANT);
	set_entity_compiler_generated(result, 1);

	/* There seems to be no simpler way to do this. Or at least, cparser
	 * does exactly the same thing... */
	contents = create_initializer_compound(length);
	for (i = 0; i < length; i++) {
		ir_tarval *c = new_tarval_from_long(string[i], mode_Bs);
		ir_initializer_t *init = create_initializer_tarval(c);
		set_initializer_compound_value(contents, i, init);
460
	}
461
	set_entity_initializer(result, contents);
462

463
464
	return result;
}
465

466
467
468
469
470
471
472
ir_graph *ir_profile_instrument(const char *filename)
{
	int n, n_blocks = 0;
	ident *counter_id, *filename_id;
	ir_entity *bblock_counts, *ent_filename;
	block_id_walker_data_t wd;
	FIRM_DBG_REGISTER(dbg, "firm.ir.profile");
473

474
475
476
477
	/* Don't do anything for modules without code. Else the linker will
	 * complain. */
	if (get_irp_n_irgs() == 0)
		return NULL;
478

479
480
481
482
483
484
485
486
487
488
489
490
491
492
	/* count the number of block first */
	n_blocks = get_irp_n_blocks();

	/* create all the necessary types and entities. Note that the
	 * types must have a fixed layout, because we are already running in the
	 * backend */
	counter_id    = new_id_from_str("__FIRMPROF__BLOCK_COUNTS");
	bblock_counts = new_array_entity(counter_id, n_blocks);

	filename_id  = new_id_from_str("__FIRMPROF__FILE_NAME");
	ent_filename = new_static_string_entity(filename_id, filename);

	/* initialize block id array and instrument blocks */
	wd.id  = 0;
Christian Würdig's avatar
Christian Würdig committed
493
	for (n = get_irp_n_irgs() - 1; n >= 0; --n) {
494
495
		ir_graph *irg = get_irp_irg(n);
		instrument_irg(irg, bblock_counts, &wd);
496
	}
497
498

	return gen_initializer_irg(ent_filename, bblock_counts, n_blocks);
499
500
}

501
502
static unsigned int *
parse_profile(const char *filename, unsigned int num_blocks)
503
{
504
	unsigned int *result = NULL;
505
506
507
	char          buf[8];
	size_t        ret;
	unsigned int  i;
508
509
510
511
512

	FILE *f = fopen(filename, "rb");
	if (!f) {
		DBG((dbg, LEVEL_2, "Failed to open profile file (%s)\n", filename));
		return NULL;
513
514
	}

515
516
517
518
519
520
	/* check header */
	ret = fread(buf, 8, 1, f);
	if (ret == 0 || strncmp(buf, "firmprof", 8) != 0) {
		DBG((dbg, LEVEL_2, "Broken fileheader in profile\n"));
		goto end;
	}
521

522
	result = XMALLOCN(unsigned int, num_blocks);
523
524
525
526

	/* The profiling output format is defined to be a sequence of integer
	 * values stored little endian format. */
	for (i = 0; i < num_blocks; ++i) {
Manuel Mohr's avatar
Manuel Mohr committed
527
		unsigned char bytes[4];
528

Manuel Mohr's avatar
Manuel Mohr committed
529
		if ((ret = fread(bytes, 1, 4, f)) < 1)
530
531
532
533
534
535
536
			break;

		result[i] = (bytes[0] <<  0) | (bytes[1] <<  8)
		          | (bytes[2] << 16) | (bytes[3] << 24);
	}

	if (ret < 1) {
537
		DBG((dbg, LEVEL_4, "Failed to read counters... (size: %u)\n",
538
			sizeof(unsigned int) * num_blocks));
539
540
541
542
543
544
545
		xfree(result);
		result = NULL;
	}

end:
	fclose(f);
	return result;
546
}
547

548
/**
549
 * Reads the corresponding profile info file if it exists.
550
 */
551
552
553
554
555
556
557
558
559
static void block_associate_walker(ir_node *bb, void *env)
{
	block_assoc_t *b = (block_assoc_t*) env;
	execcount_t query;

	query.block = get_irn_node_nr(bb);
	query.count = b->counters[(b->i)++];
	DBG((dbg, LEVEL_4, "execcount(%+F, %u): %u\n", bb, query.block,
	    query.count));
560
	set_insert(execcount_t, profile, &query, sizeof(query), query.block);
561
}
562

563
564
565
566
567
568
static void irp_associate_blocks(block_assoc_t *env)
{
	int n;
	for (n = get_irp_n_irgs() - 1; n >= 0; --n) {
		ir_graph *irg = get_irp_irg(n);
		irg_block_walk_graph(irg, block_associate_walker, NULL, env);
569
	}
570
}
571

572
573
574
575
bool ir_profile_read(const char *filename)
{
	block_assoc_t env;
	FIRM_DBG_REGISTER(dbg, "firm.ir.profile");
576

577
578
579
580
	env.i = 0;
	env.counters = parse_profile(filename, get_irp_n_blocks());
	if (!env.counters)
		return false;
581

582
583
584
	if (profile)
		ir_profile_free();
	profile = new_set(cmp_execcount, 16);
585

586
587
	irp_associate_blocks(&env);
	xfree(env.counters);
Adam Szalkowski's avatar
Adam Szalkowski committed
588

589
590
591
	/* register the vcg hook */
	hook = dump_add_node_info_callback(dump_profile_node_info, NULL);
	return true;
592
593
}

594
void ir_profile_free(void)
595
{
596
	if (profile) {
597
		del_set(profile);
598
599
600
601
602
603
		profile = NULL;
	}

	if (hook != NULL) {
		dump_remove_node_info_callback(hook);
		hook = NULL;
604
	}
605
606
}

607
bool ir_profile_has_data(void)
Adam Szalkowski's avatar
Adam Szalkowski committed
608
{
609
	return profile != NULL;
Adam Szalkowski's avatar
Adam Szalkowski committed
610
611
}

612
unsigned int ir_profile_get_block_execcount(const ir_node *block)
613
614
615
{
	execcount_t *ec, query;

616
	if (!ir_profile_has_data())
617
618
619
		return 1;

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

622
	if (ec != NULL) {
623
624
		return ec->count;
	} else {
625
626
		DBG((dbg, LEVEL_3,
			"Warning: Profile contains no data for %+F\n", block));
627
628
		return 1;
	}
629
}
630

631
632
static void initialize_execfreq(ir_node *block, void *data)
{
633
	initialize_execfreq_env_t *env = (initialize_execfreq_env_t*)data;
634
635
	double freq;

636
	if (block == get_irg_start_block(env->irg)
637
638
639
	   || block == get_irg_end_block(env->irg)) {
		freq = 1.0;
	} else {
Michael Beck's avatar
Michael Beck committed
640
		freq = ir_profile_get_block_execcount(block);
641
		freq *= env->freq_factor;
642
		if (freq < MIN_EXECFREQ)
643
			freq = MIN_EXECFREQ;
644
645
646
647
648
	}

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

Michael Beck's avatar
Michael Beck committed
649
ir_exec_freq *ir_create_execfreqs_from_profile(ir_graph *irg)
650
651
652
653
654
{
	ir_node *start_block;
	initialize_execfreq_env_t env;
	unsigned count;

655
	env.irg = irg;
656
657
	env.execfreqs = create_execfreq(irg);

658
659
	/* Find the first block containing instructions */
	start_block = get_irg_start_block(irg);
Michael Beck's avatar
Michael Beck committed
660
	count = ir_profile_get_block_execcount(start_block);
661
	if (count == 0) {
662
		/* the function was never executed, so fallback to estimated freqs */
663
664
665
666
		free_execfreq(env.execfreqs);
		return compute_execfreq(irg, 10);
	}

667
	env.freq_factor = 1.0 / count;
668
669
670
671
	irg_block_walk_graph(irg, initialize_execfreq, NULL, &env);

	return env.execfreqs;
}