irprofile.c 17.1 KB
Newer Older
Christian Würdig's avatar
Christian Würdig committed
1
2
/*
 * This file is part of libFirm.
3
 * Copyright (C) 2012 University of Karlsruhe.
Christian Würdig's avatar
Christian Würdig committed
4
5
 */

Christian Würdig's avatar
Christian Würdig committed
6
7
8
/**
 * @file
 * @brief       Code instrumentation and execution count profiling.
9
10
 * @author      Adam M. Szalkowski, Steven Schaefer
 * @date        06.04.2006, 11.11.2010
11
12
 */

Christoph Mallon's avatar
Christoph Mallon committed
13
#include "../adt/util.h"
14
#include "debug.h"
Christoph Mallon's avatar
Christoph Mallon committed
15
16
17
#include "execfreq_t.h"
#include "hashptr.h"
#include "ircons_t.h"
18
#include "irdump_t.h"
Christoph Mallon's avatar
Christoph Mallon committed
19
#include "irgwalk.h"
20
#include "irnode_t.h"
Michael Beck's avatar
Michael Beck committed
21
#include "irprofile.h"
Christoph Mallon's avatar
Christoph Mallon committed
22
23
24
#include "irprog_t.h"
#include "obst.h"
#include "set.h"
25
#include "typerep.h"
Christoph Mallon's avatar
Christoph Mallon committed
26
#include "xmalloc.h"
27

28
/* Instrument blocks walker. */
29
typedef struct block_id_walker_data_t {
30
31
	unsigned int  id;       /**< current block id number */
	ir_node      *counters; /**< the node representing the counter array */
32
33
} block_id_walker_data_t;

34
35
36
37
38
39
40
41
42
43
44
45
46
/* 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. */
47
static hook_entry_t *hook;
48
49
50
51

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

Christoph Mallon's avatar
Christoph Mallon committed
52
53
/**
 * Since the backend creates a new firm graph we cannot associate counts with
54
55
56
 * blocks directly. Instead we associate them with the block ids, which are
 * maintained.
 */
57
typedef struct execcount_t {
58
	unsigned long block; /**< block id */
59
	uint32_t      count; /**< execution count */
60
61
} execcount_t;

Michael Beck's avatar
Michael Beck committed
62
63
64
/**
 * Compare two execcount_t entries.
 */
65
66
static int cmp_execcount(const void *a, const void *b, size_t size)
{
67
68
	const execcount_t *ea = (const execcount_t*)a;
	const execcount_t *eb = (const execcount_t*)b;
Christoph Mallon's avatar
Christoph Mallon committed
69
	(void)size;
Michael Beck's avatar
Michael Beck committed
70
	return ea->block != eb->block;
71
}
72

73
74
uint32_t ir_profile_get_block_execcount(const ir_node *block)
{
Christoph Mallon's avatar
Christoph Mallon committed
75
76
	execcount_t  const query = { .block = get_irn_node_nr(block), .count = 0 };
	execcount_t *const ec    = set_find(execcount_t, profile, &query, sizeof(query), query.block);
77
78
79
80

	if (ec != NULL) {
		return ec->count;
	} else {
Christoph Mallon's avatar
Christoph Mallon committed
81
		DBG((dbg, LEVEL_3, "Warning: Profile contains no data for %+F\n", block));
82
83
84
85
		return 0;
	}
}

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

Michael Beck's avatar
Michael Beck committed
96
/**
97
 * Returns the number of blocks the given graph.
Michael Beck's avatar
Michael Beck committed
98
 */
99
static unsigned int get_irg_n_blocks(ir_graph *irg)
100
{
101
102
103
104
105
106
	unsigned int count = 0;
	irg_block_walk_graph(irg, block_counter, NULL, &count);
	return count;
}

/**
107
 * Returns the number of basic blocks in the current ir program.
108
 */
109
static unsigned int get_irp_n_blocks(void)
110
{
111
	unsigned int count = 0;
112
	foreach_irp_irg(i, irg) {
113
114
115
		count += get_irg_n_blocks(irg);
	}
	return count;
116
117
}

118
119
/* vcg helper */
static void dump_profile_node_info(void *ctx, FILE *f, const ir_node *irn)
120
{
121
122
123
124
	(void) ctx;
	if (is_Block(irn)) {
		unsigned int execcount = ir_profile_get_block_execcount(irn);
		fprintf(f, "profiled execution count: %u\n", execcount);
125
126
127
	}
}

128
129
130
/**
 * Add the given method entity as a constructor.
 */
131
132
static void add_constructor(ir_entity *method)
{
Christoph Mallon's avatar
Christoph Mallon committed
133
134
135
136
137
138
139
	ir_type   *const method_type  = get_entity_type(method);
	ir_type   *const ptr_type     = new_type_pointer(method_type);
	ir_type   *const constructors = get_segment_type(IR_SEGMENT_CONSTRUCTORS);
	ident     *const ide          = id_unique("constructor_ptr.%u");
	ir_entity *const ptr          = new_entity(constructors, ide, ptr_type);
	ir_graph  *const irg          = get_const_code_irg();
	ir_node   *const val          = new_r_Address(irg, method);
140
141

	set_entity_ld_ident(ptr, new_id_from_chars("", 0));
Christoph Mallon's avatar
Christoph Mallon committed
142
143
144
145
	set_entity_compiler_generated(ptr, 1);
	set_entity_linkage(ptr, IR_LINKAGE_CONSTANT | IR_LINKAGE_HIDDEN_USER);
	set_entity_visibility(ptr, ir_visibility_private);
	set_atomic_ent_value(ptr, val);
146
}
147

148
149
150
151
152
153
154
/**
 * 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)
{
Christoph Mallon's avatar
Christoph Mallon committed
155
156
157
158
159
	ident   *const init_name = new_id_from_str("__init_firmprof");
	ir_type *const init_type = new_type_method(3, 0);
	ir_type *const uint      = new_type_primitive(mode_Iu);
	ir_type *const uintptr   = new_type_pointer(uint);
	ir_type *const string    = new_type_pointer(new_type_primitive(mode_Bs));
160
161
162
163
164

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

Christoph Mallon's avatar
Christoph Mallon committed
165
	ir_entity *const result = new_entity(get_glob_type(), init_name, init_type);
166
167
168
169
170
	set_entity_visibility(result, ir_visibility_external);

	return result;
}

171
172
/**
 * Generates a new irg which calls the initializer
Michael Beck's avatar
BugFix:    
Michael Beck committed
173
174
 *
 * Pseudocode:
175
176
177
178
 *    static void __firmprof_initializer(void) __attribute__ ((constructor))
 *    {
 *        __init_firmprof(ent_filename, bblock_counts, n_blocks);
 *    }
179
 */
Christoph Mallon's avatar
Christoph Mallon committed
180
static ir_graph *gen_initializer_irg(ir_entity *ent_filename, ir_entity *bblock_counts, int n_blocks)
181
{
Christoph Mallon's avatar
Christoph Mallon committed
182
183
	ident     *const name = new_id_from_str("__firmprof_initializer");
	ir_entity *const ent  = new_entity(get_glob_type(), name, new_type_method(0, 0));
184
	set_entity_visibility(ent, ir_visibility_local);
Christian Würdig's avatar
Christian Würdig committed
185
186
	set_entity_ld_ident(ent, name);

Christoph Mallon's avatar
Christoph Mallon committed
187
188
	ir_graph *const irg              = new_ir_graph(ent, 0);
	ir_type  *const empty_frame_type = get_irg_frame_type(irg);
Christian Würdig's avatar
Christian Würdig committed
189
	set_type_size_bytes(empty_frame_type, 0);
190
	set_type_state(empty_frame_type, layout_fixed);
191

Christoph Mallon's avatar
Christoph Mallon committed
192
193
194
195
196
197
198
199
200
201
202
203
	ir_node   *const bb        = get_r_cur_block(irg);
	ir_node   *const init_mem  = get_irg_initial_mem(irg);
	ir_entity *const init_ent  = get_init_firmprof_ref();
	ir_node   *const callee    = new_r_Address(irg, init_ent);
	ir_node   *const filename  = new_r_Address(irg, ent_filename);
	ir_node   *const counters  = new_r_Address(irg, bblock_counts);
	ir_node   *const size      = new_r_Const_long(irg, mode_Iu, n_blocks);
	ir_node   *const ins[]     = { filename, counters, size };
	ir_type   *const call_type = get_entity_type(init_ent);
	ir_node   *const call      = new_r_Call(bb, init_mem, callee, ARRAY_SIZE(ins), ins, call_type);
	ir_node   *const call_mem  = new_r_Proj(call, mode_M, pn_Call_M);
	ir_node   *const ret       = new_r_Return(bb, call_mem, 0, NULL);
204
205

	add_immBlock_pred(get_irg_end_block(irg), ret);
Matthias Braun's avatar
fixes    
Matthias Braun committed
206
	irg_finalize_cons(irg);
207
208
	add_constructor(ent);

209
210
211
	return irg;
}

212
/**
213
214
215
 * 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.
216
 */
Christoph Mallon's avatar
Christoph Mallon committed
217
static void instrument_block(ir_node *const bb, ir_node *const address, unsigned int const id)
218
{
Christoph Mallon's avatar
Christoph Mallon committed
219
	ir_graph *const irg = get_irn_irg(bb);
220
221
222
223
224

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

Christoph Mallon's avatar
Christoph Mallon committed
225
226
227
228
229
230
231
232
233
234
235
236
237
	ir_node *const unknown = new_r_Unknown(irg, mode_M);
	ir_node *const cnst    = new_r_Const_long(irg, mode_Iu, get_mode_size_bytes(mode_Iu) * id);
	ir_node *const offset  = new_r_Add(bb, address, cnst, get_modeP_data());
	ir_node *const load    = new_r_Load(bb, unknown, offset, mode_Iu, cons_none);
	ir_node *const lmem    = new_r_Proj(load, mode_M, pn_Load_M);
	ir_node *const proji   = new_r_Proj(load, mode_Iu, pn_Load_res);
	ir_node *const one     = new_r_Const_one(irg, mode_Iu);
	ir_node *const add     = new_r_Add(bb, proji, one, mode_Iu);
	ir_node *const store   = new_r_Store(bb, lmem, offset, add, cons_none);
	ir_node *const smem    = new_r_Proj(store, mode_M, pn_Store_M);

	set_irn_link(bb, smem);
	set_irn_link(smem, load);
238
239
240
241
242
243
244
245
246
}

/**
 * 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.
 */
Christoph Mallon's avatar
Christoph Mallon committed
247
static void fix_ssa(ir_node *const bb, void *const data)
248
{
Christoph Mallon's avatar
Christoph Mallon committed
249
	(void)data;
250

Christoph Mallon's avatar
Christoph Mallon committed
251
	ir_graph *const irg = get_irn_irg(bb);
252
253
254
255
256

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

Christoph Mallon's avatar
Christoph Mallon committed
257
258
	ir_node  *mem;
	int const arity = get_Block_n_cfgpreds(bb);
259
260
261
	if (bb == get_irg_start_block(irg)) {
		mem = get_irg_initial_mem(irg);
	} else if (arity == 1) {
Christoph Mallon's avatar
Christoph Mallon committed
262
263
		ir_node *const pred = get_Block_cfgpred_block(bb, 0);
		mem = pred ? (ir_node*)get_irn_link(pred) : new_r_NoMem(irg);
264
	} else {
265
		ir_node **ins = ALLOCAN(ir_node*, arity);
Christoph Mallon's avatar
Christoph Mallon committed
266
267
268
		for (int n = arity; n-- != 0;) {
			ir_node *const pred = get_Block_cfgpred_block(bb, n);
			ins[n] = pred ? (ir_node*)get_irn_link(pred) : new_r_NoMem(irg);
269
270
		}
		mem = new_r_Phi(bb, arity, ins, mode_M);
271
	}
272
273
274
275

	/* 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. */
Christoph Mallon's avatar
Christoph Mallon committed
276
277
	ir_node *const proj = (ir_node*)get_irn_link(bb);
	ir_node *const load = (ir_node*)get_irn_link(proj);
278
	set_Load_mem(load, mem);
279
280
281
}

/**
282
 * Instrument a single block.
283
 */
284
static void block_instrument_walker(ir_node *bb, void *data)
285
{
286
	block_id_walker_data_t *wd = (block_id_walker_data_t*)data;
287
	instrument_block(bb, wd->counters, wd->id);
288
289
290
	++wd->id;
}

291
292
293
294
295
296
/**
 * 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)
{
Christoph Mallon's avatar
Christoph Mallon committed
297
298
	ir_node *const ins[] = { (ir_node*)get_irn_link(bb), mem };
	return new_r_Sync(bb, ARRAY_SIZE(ins), ins);
299
}
300

301
302
303
304
/**
 * Instrument a single ir_graph, counters should point to the bblock
 * counters array.
 */
Christoph Mallon's avatar
Christoph Mallon committed
305
static void instrument_irg(ir_graph *irg, ir_entity *counters, block_id_walker_data_t *wd)
306
{
307
	/* generate a node pointing to the count array */
308
	wd->counters = new_r_Address(irg, counters);
309
310
311
312
313
314

	/* 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 */
Christoph Mallon's avatar
Christoph Mallon committed
315
316
317
318
	ir_node *const endbb = get_irg_end_block(irg);
	for (int i = get_Block_n_cfgpreds(endbb); i != 0;) {
		ir_node *const node = skip_Proj(get_Block_cfgpred(endbb, i));
		ir_node *const bb   = get_Block_cfgpred_block(endbb, i);
319
320
		if (bb == NULL)
			continue;
321

Christoph Mallon's avatar
Christoph Mallon committed
322
		ir_node *mem;
323
324
325
326
327
328
329
330
331
332
333
334
335
		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,
Christoph Mallon's avatar
Christoph Mallon committed
336
337
			 * so ignore it. */
			assert(is_fragile_op(node) && "unexpected End control flow predecessor");
338
339
		}
	}
340

341
	/* as well as calls with attribute noreturn */
Christoph Mallon's avatar
Christoph Mallon committed
342
343
	ir_node *const end = get_irg_end(irg);
	for (int i = get_End_n_keepalives(end); i-- != 0;) {
344
345
		ir_node *node = get_End_keepalive(end, i);
		if (is_Call(node)) {
Christoph Mallon's avatar
Christoph Mallon committed
346
347
			ir_node *const bb  = get_nodes_block(node);
			ir_node *const mem = get_Call_mem(node);
348
349
			set_Call_mem(node, sync_mem(bb, mem));
		}
350
	}
351
}
352

353
354
355
356
357
358
/**
 * Creates a new entity representing the equivalent of
 * static unsigned int name[size]
 */
static ir_entity *new_array_entity(ident *name, int size)
{
Christoph Mallon's avatar
Christoph Mallon committed
359
	ir_type *const uint_type = new_type_primitive(mode_Iu);
360
	set_type_alignment_bytes(uint_type, get_type_size_bytes(uint_type));
361

Christoph Mallon's avatar
Christoph Mallon committed
362
	ir_type *const array_type = new_type_array(uint_type);
363
	set_array_size_int(array_type, size);
364
	set_type_size_bytes(array_type, size * get_mode_size_bytes(mode_Iu));
365
366
	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
367

Christoph Mallon's avatar
Christoph Mallon committed
368
	ir_entity *const result = new_entity(get_glob_type(), name, array_type);
369
370
371
372
373
374
375
376
377
378
379
380
	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)
{
Christoph Mallon's avatar
Christoph Mallon committed
381
382
383
	ir_type *const char_type   = new_type_primitive(mode_Bs);
	ir_type *const string_type = new_type_array(char_type);
	size_t   const length      = strlen(string) + 1;
384
385

	/* Create the type for a fixed-length string */
386
	set_array_size_int(string_type, length);
387
	set_type_size_bytes(string_type, length);
388
389
	set_type_alignment_bytes(string_type, 1);
	set_type_state(string_type, layout_fixed);
Christian Würdig's avatar
Christian Würdig committed
390

Christoph Mallon's avatar
Christoph Mallon committed
391
	ir_entity *const result = new_entity(get_glob_type(), name, string_type);
392
393
394
395
396
397
	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... */
Christoph Mallon's avatar
Christoph Mallon committed
398
399
400
401
	ir_initializer_t *const contents = create_initializer_compound(length);
	for (size_t i = 0; i < length; i++) {
		ir_tarval        *const c    = new_tarval_from_long(string[i], mode_Bs);
		ir_initializer_t *const init = create_initializer_tarval(c);
402
		set_initializer_compound_value(contents, i, init);
403
	}
404
	set_entity_initializer(result, contents);
405

406
407
	return result;
}
408

409
ir_graph *ir_profile_instrument(const char *filename)
410
411
{
	FIRM_DBG_REGISTER(dbg, "firm.ir.profile");
412

413
414
415
	/* Don't do anything for modules without code. Else the linker will
	 * complain. */
	if (get_irp_n_irgs() == 0)
416
		return NULL;
417

418
	/* count the number of block first */
419
	unsigned const n_blocks = get_irp_n_blocks();
420
421
422
423

	/* create all the necessary types and entities. Note that the
	 * types must have a fixed layout, because we are already running in the
	 * backend */
Christoph Mallon's avatar
Christoph Mallon committed
424
425
	ident     *const counter_id    = new_id_from_str("__FIRMPROF__BLOCK_COUNTS");
	ir_entity *const bblock_counts = new_array_entity(counter_id, n_blocks);
426

Christoph Mallon's avatar
Christoph Mallon committed
427
428
	ident     *const filename_id  = new_id_from_str("__FIRMPROF__FILE_NAME");
	ir_entity *const ent_filename = new_static_string_entity(filename_id, filename);
429
430

	/* initialize block id array and instrument blocks */
Christoph Mallon's avatar
Christoph Mallon committed
431
	block_id_walker_data_t wd = { .id = 0 };
432
	foreach_irp_irg_r(i, irg) {
433
		instrument_irg(irg, bblock_counts, &wd);
434
	}
435

436
	return gen_initializer_irg(ent_filename, bblock_counts, n_blocks);
437
438
}

439
static unsigned int *parse_profile(const char *filename, unsigned int num_blocks)
440
{
Christoph Mallon's avatar
Christoph Mallon committed
441
	FILE *const f = fopen(filename, "rb");
442
443
444
	if (!f) {
		DBG((dbg, LEVEL_2, "Failed to open profile file (%s)\n", filename));
		return NULL;
445
446
	}

447
	/* check header */
448
449
450
	uint32_t *result = NULL;
	char      buf[8];
	size_t    ret = fread(buf, 8, 1, f);
451
452
453
454
	if (ret == 0 || strncmp(buf, "firmprof", 8) != 0) {
		DBG((dbg, LEVEL_2, "Broken fileheader in profile\n"));
		goto end;
	}
455

456
	result = XMALLOCN(unsigned int, num_blocks);
457
458
459

	/* The profiling output format is defined to be a sequence of integer
	 * values stored little endian format. */
460
	for (unsigned i = 0; i < num_blocks; ++i) {
Manuel Mohr's avatar
Manuel Mohr committed
461
462
		unsigned char bytes[4];
		if ((ret = fread(bytes, 1, 4, f)) < 1)
463
464
465
466
467
468
469
			break;

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

	if (ret < 1) {
470
		DBG((dbg, LEVEL_4, "Failed to read counters... (size: %u)\n",
471
			sizeof(unsigned int) * num_blocks));
472
		free(result);
473
474
475
476
477
478
		result = NULL;
	}

end:
	fclose(f);
	return result;
479
}
480

481
/**
482
 * Reads the corresponding profile info file if it exists.
483
 */
484
485
static void block_associate_walker(ir_node *bb, void *env)
{
Christoph Mallon's avatar
Christoph Mallon committed
486
	block_assoc_t *b = (block_assoc_t*)env;
487
488
489
	execcount_t query;

	query.block = get_irn_node_nr(bb);
Christoph Mallon's avatar
Christoph Mallon committed
490
491
	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
492
	(void)set_insert(execcount_t, profile, &query, sizeof(query), query.block);
493
}
494

495
496
static void irp_associate_blocks(block_assoc_t *env)
{
497
	foreach_irp_irg_r(i, irg) {
498
		irg_block_walk_graph(irg, block_associate_walker, NULL, env);
499
	}
500
}
501

502
void ir_profile_free(void)
503
{
504
	if (profile) {
505
		del_set(profile);
506
507
508
509
510
511
		profile = NULL;
	}

	if (hook != NULL) {
		dump_remove_node_info_callback(hook);
		hook = NULL;
512
	}
513
514
}

515
bool ir_profile_read(const char *filename)
Adam Szalkowski's avatar
Adam Szalkowski committed
516
{
517
	FIRM_DBG_REGISTER(dbg, "firm.ir.profile");
Adam Szalkowski's avatar
Adam Szalkowski committed
518

519
	unsigned n_blocks = get_irp_n_blocks();
Christoph Mallon's avatar
Christoph Mallon committed
520
521
522
523
	block_assoc_t env = {
		.i        = 0,
		.counters = parse_profile(filename, n_blocks)
	};
524
525
	if (!env.counters)
		return false;
526

527
528
	ir_profile_free();
	profile = new_set(cmp_execcount, 16);
529

530
	irp_associate_blocks(&env);
531
	free(env.counters);
532

533
534
535
	/* register the vcg hook */
	hook = dump_add_node_info_callback(dump_profile_node_info, NULL);
	return 1;
536
}
537

538
539
540
541
typedef struct initialize_execfreq_env_t {
	double freq_factor;
} initialize_execfreq_env_t;

542
543
static void initialize_execfreq(ir_node *block, void *data)
{
Christoph Mallon's avatar
Christoph Mallon committed
544
	const initialize_execfreq_env_t *env = (const initialize_execfreq_env_t*)data;
545

Christoph Mallon's avatar
Christoph Mallon committed
546
547
	double          freq;
	ir_graph *const irg = get_irn_irg(block);
548
	if (block == get_irg_start_block(irg) || block == get_irg_end_block(irg)) {
549
550
		freq = 1.0;
	} else {
Michael Beck's avatar
Michael Beck committed
551
		freq = ir_profile_get_block_execcount(block);
552
		freq *= env->freq_factor;
553
		if (freq < MIN_EXECFREQ)
554
			freq = MIN_EXECFREQ;
555
556
	}

557
	set_block_execfreq(block, freq);
558
559
}

560
static void ir_set_execfreqs_from_profile(ir_graph *irg)
561
{
562
	/* Find the first block containing instructions */
Christoph Mallon's avatar
Christoph Mallon committed
563
564
	ir_node *const start_block = get_irg_start_block(irg);
	unsigned const count       = ir_profile_get_block_execcount(start_block);
565
	if (count == 0) {
566
		/* the function was never executed, so fallback to estimated freqs */
567
568
		ir_estimate_execfreq(irg);
		return;
569
570
	}

Christoph Mallon's avatar
Christoph Mallon committed
571
	initialize_execfreq_env_t env = { .freq_factor = 1.0 / count };
572
	irg_block_walk_graph(irg, initialize_execfreq, NULL, &env);
573
}
574

575
576
void ir_create_execfreqs_from_profile(void)
{
577
	foreach_irp_irg_r(i, irg) {
578
579
		ir_set_execfreqs_from_profile(irg);
	}
580
}