irprofile.c 18 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

#include "irgwalk.h"
#include "irdump_t.h"
#include "irnode_t.h"
#include "ircons_t.h"
42
#include "execfreq_t.h"
Michael Beck's avatar
Michael Beck committed
43
#include "irprofile.h"
44
#include "typerep.h"
45

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

52
53
54
55
56
57
58
59
60
61
62
63
64
/* 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;

/* 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. */
65
static void *hook;
66
67
68
69
70
71
72
73

/* 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.
 */
74
typedef struct execcount_t {
75
	unsigned long block; /**< block id */
76
	uint32_t      count; /**< execution count */
77
78
} execcount_t;

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

90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
uint32_t ir_profile_get_block_execcount(const ir_node *block)
{
	execcount_t *ec, query;

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

	if (ec != NULL) {
		return ec->count;
	} else {
		DBG((dbg, LEVEL_3,
			"Warning: Profile contains no data for %+F\n", block));
		return 0;
	}
}

Michael Beck's avatar
Michael Beck committed
106
107
108
/**
 * Block walker, count number of blocks.
 */
109
static void block_counter(ir_node *bb, void *data)
110
{
111
	unsigned *count = (unsigned*) data;
Michael Beck's avatar
Michael Beck committed
112
113
	(void) bb;
	++(*count);
114
115
}

Michael Beck's avatar
Michael Beck committed
116
/**
117
 * Returns the number of blocks the given graph.
Michael Beck's avatar
Michael Beck committed
118
 */
119
static unsigned int get_irg_n_blocks(ir_graph *irg)
120
{
121
122
123
124
125
126
	unsigned int count = 0;
	irg_block_walk_graph(irg, block_counter, NULL, &count);
	return count;
}

/**
127
 * Returns the number of basic blocks in the current ir program.
128
 */
129
static unsigned int get_irp_n_blocks(void)
130
{
131
132
	int i, n = get_irp_n_irgs();
	unsigned int count = 0;
Matthias Braun's avatar
fixes    
Matthias Braun committed
133

134
135
136
137
	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
138

139
	return count;
140
141
}

142
143
/* vcg helper */
static void dump_profile_node_info(void *ctx, FILE *f, const ir_node *irn)
144
{
145
146
147
148
	(void) ctx;
	if (is_Block(irn)) {
		unsigned int execcount = ir_profile_get_block_execcount(irn);
		fprintf(f, "profiled execution count: %u\n", execcount);
149
150
151
	}
}

152
153
154
/**
 * Add the given method entity as a constructor.
 */
155
156
157
static void add_constructor(ir_entity *method)
{
    ir_type   *method_type  = get_entity_type(method);
158
    ir_type   *ptr_type     = new_type_pointer(method_type);
159

160
    ir_type   *constructors = get_segment_type(IR_SEGMENT_CONSTRUCTORS);
161
162
163
164
165
166
	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));
167
    set_entity_compiler_generated(ptr, 1);
168
169
    set_entity_linkage(ptr, IR_LINKAGE_CONSTANT | IR_LINKAGE_HIDDEN_USER);
    set_entity_visibility(ptr, ir_visibility_private);
170
171
    set_atomic_ent_value(ptr, val);
}
172

173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
/**
 * 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;
}

197
198
/**
 * Generates a new irg which calls the initializer
Michael Beck's avatar
BugFix:    
Michael Beck committed
199
200
 *
 * Pseudocode:
201
202
203
204
 *    static void __firmprof_initializer(void) __attribute__ ((constructor))
 *    {
 *        __init_firmprof(ent_filename, bblock_counts, n_blocks);
 *    }
205
 */
206
207
static ir_graph *gen_initializer_irg(ir_entity *ent_filename,
                                     ir_entity *bblock_counts, int n_blocks)
208
{
209
210
211
212
	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
213
	symconst_symbol sym;
214

215
	ir_entity *init_ent = get_init_firmprof_ref();
Adam Szalkowski's avatar
Adam Szalkowski committed
216

217
218
219
	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
220
221
	set_entity_ld_ident(ent, name);

222
	/* create the new ir_graph */
Christian Würdig's avatar
Christian Würdig committed
223
	irg = new_ir_graph(ent, 0);
224
	set_current_ir_graph(irg);
Christian Würdig's avatar
Christian Würdig committed
225
226
	empty_frame_type = get_irg_frame_type(irg);
	set_type_size_bytes(empty_frame_type, 0);
227
	set_type_state(empty_frame_type, layout_fixed);
228

229
	bb = get_r_cur_block(irg);
Adam Szalkowski's avatar
Adam Szalkowski committed
230
231

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

234
	sym.entity_p = ent_filename;
235
	ins[0] = new_r_SymConst(irg, mode_P_data, sym, symconst_addr_ent);
236
	sym.entity_p = bblock_counts;
237
238
	ins[1] = new_r_SymConst(irg, mode_P_data, sym, symconst_addr_ent);
	ins[2] = new_r_Const_long(irg, mode_Iu, n_blocks);
239

240
241
242
	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);
243
244
245
246
247
	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
248
249
	irg_finalize_cons(irg);

250
	/* add a pointer to the new function in the constructor section */
251
252
	add_constructor(ent);

253
254
255
	return irg;
}

256
/**
257
258
259
 * 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.
260
 */
261
static void instrument_block(ir_node *bb, ir_node *address, unsigned int id)
262
{
263
264
265
266
267
268
269
270
271
272
273
274
275
	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);
276
	cnst    = new_r_Const(irg, get_mode_one(mode_Iu));
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
	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);
312
	} else {
313
314
315
316
317
318
319
320
321
		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);
322
	}
323
324
325
326
327
328
329

	/* 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);
330
331
332
}

/**
333
 * Instrument a single block.
334
 */
335
static void block_instrument_walker(ir_node *bb, void *data)
336
{
337
	block_id_walker_data_t *wd = (block_id_walker_data_t*)data;
338
339
340
341
	instrument_block(bb, wd->symconst, wd->id);
	++wd->id;
}

342
343
344
345
346
347
348
349
350
351
352
/**
 * 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);
}
353

354
355
356
357
358
359
/**
 * 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)
360
{
361
362
363
	ir_node *end   = get_irg_end(irg);
	ir_node *endbb = get_irg_end_block(irg);
	int i;
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
390
391
392
393
394
395
396
397
398
	/* 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");
		}
	}
399

400
401
402
403
404
405
406
407
	/* 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));
		}
408
	}
409
}
410

411
412
413
414
415
416
417
418
419
420
/**
 * 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);
421
	set_type_alignment_bytes(uint_type, get_type_size_bytes(uint_type));
422

423
424
425
	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));
426
427
	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
428

429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
	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);
454
455
	set_type_alignment_bytes(string_type, 1);
	set_type_state(string_type, layout_fixed);
Christian Würdig's avatar
Christian Würdig committed
456

457
458
459
460
461
462
463
464
465
466
467
468
	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);
469
	}
470
	set_entity_initializer(result, contents);
471

472
473
	return result;
}
474

475
ir_graph *ir_profile_instrument(const char *filename)
476
477
478
479
480
481
{
	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");
482

483
484
485
	/* Don't do anything for modules without code. Else the linker will
	 * complain. */
	if (get_irp_n_irgs() == 0)
486
		return NULL;
487

488
489
490
491
492
493
494
495
496
497
498
499
500
501
	/* 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
502
	for (n = get_irp_n_irgs() - 1; n >= 0; --n) {
503
504
		ir_graph *irg = get_irp_irg(n);
		instrument_irg(irg, bblock_counts, &wd);
505
	}
506

507
	return gen_initializer_irg(ent_filename, bblock_counts, n_blocks);
508
509
}

510
static unsigned int *parse_profile(const char *filename, unsigned int num_blocks)
511
{
512
513
514
515
	FILE *f = fopen(filename, "rb");
	if (!f) {
		DBG((dbg, LEVEL_2, "Failed to open profile file (%s)\n", filename));
		return NULL;
516
517
	}

518
	/* check header */
519
520
521
	uint32_t *result = NULL;
	char      buf[8];
	size_t    ret = fread(buf, 8, 1, f);
522
523
524
525
	if (ret == 0 || strncmp(buf, "firmprof", 8) != 0) {
		DBG((dbg, LEVEL_2, "Broken fileheader in profile\n"));
		goto end;
	}
526

527
	result = XMALLOCN(unsigned int, num_blocks);
528
529
530

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

Manuel Mohr's avatar
Manuel Mohr committed
534
		if ((ret = fread(bytes, 1, 4, f)) < 1)
535
536
537
538
539
540
541
			break;

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

	if (ret < 1) {
542
		DBG((dbg, LEVEL_4, "Failed to read counters... (size: %u)\n",
543
			sizeof(unsigned int) * num_blocks));
544
545
546
547
548
549
550
		xfree(result);
		result = NULL;
	}

end:
	fclose(f);
	return result;
551
}
552

553
/**
554
 * Reads the corresponding profile info file if it exists.
555
 */
556
557
558
559
560
561
562
563
564
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));
yb9976's avatar
yb9976 committed
565
	(void)set_insert(execcount_t, profile, &query, sizeof(query), query.block);
566
}
567

568
569
static void irp_associate_blocks(block_assoc_t *env)
{
570
	for (int n = get_irp_n_irgs() - 1; n >= 0; --n) {
571
572
		ir_graph *irg = get_irp_irg(n);
		irg_block_walk_graph(irg, block_associate_walker, NULL, env);
573
	}
574
}
575

576
void ir_profile_free(void)
577
{
578
	if (profile) {
579
		del_set(profile);
580
581
582
583
584
585
		profile = NULL;
	}

	if (hook != NULL) {
		dump_remove_node_info_callback(hook);
		hook = NULL;
586
	}
587
588
}

589
bool ir_profile_read(const char *filename)
Adam Szalkowski's avatar
Adam Szalkowski committed
590
{
591
592
	block_assoc_t env;
	FIRM_DBG_REGISTER(dbg, "firm.ir.profile");
Adam Szalkowski's avatar
Adam Szalkowski committed
593

594
595
596
597
598
	unsigned n_blocks = get_irp_n_blocks();
	env.i        = 0;
	env.counters = parse_profile(filename, n_blocks);
	if (!env.counters)
		return false;
599

600
601
	ir_profile_free();
	profile = new_set(cmp_execcount, 16);
602

603
604
	irp_associate_blocks(&env);
	xfree(env.counters);
605

606
607
608
	/* register the vcg hook */
	hook = dump_add_node_info_callback(dump_profile_node_info, NULL);
	return 1;
609
}
610

611
612
613
614
typedef struct initialize_execfreq_env_t {
	double freq_factor;
} initialize_execfreq_env_t;

615
616
static void initialize_execfreq(ir_node *block, void *data)
{
617
618
619
	const initialize_execfreq_env_t *env
		= (const initialize_execfreq_env_t*) data;
	ir_graph *irg = get_irn_irg(block);
620
621
	double freq;

622
	if (block == get_irg_start_block(irg) || block == get_irg_end_block(irg)) {
623
624
		freq = 1.0;
	} else {
Michael Beck's avatar
Michael Beck committed
625
		freq = ir_profile_get_block_execcount(block);
626
		freq *= env->freq_factor;
627
		if (freq < MIN_EXECFREQ)
628
			freq = MIN_EXECFREQ;
629
630
	}

631
	set_block_execfreq(block, freq);
632
633
}

634
static void ir_set_execfreqs_from_profile(ir_graph *irg)
635
{
636
	/* Find the first block containing instructions */
637
638
	ir_node *start_block = get_irg_start_block(irg);
	unsigned count       = ir_profile_get_block_execcount(start_block);
639
	if (count == 0) {
640
		/* the function was never executed, so fallback to estimated freqs */
641
642
		ir_estimate_execfreq(irg);
		return;
643
644
	}

645
	initialize_execfreq_env_t env;
646
	env.freq_factor = 1.0 / count;
647
	irg_block_walk_graph(irg, initialize_execfreq, NULL, &env);
648
}
649

650
651
652
653
654
655
void ir_create_execfreqs_from_profile(void)
{
	for (int n = get_irp_n_irgs() - 1; n >= 0; --n) {
		ir_graph *irg = get_irp_irg(n);
		ir_set_execfreqs_from_profile(irg);
	}
656
}