irprofile.c 16.5 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
 */

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

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

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

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

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

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

74
75
uint32_t ir_profile_get_block_execcount(const ir_node *block)
{
Christoph Mallon's avatar
Christoph Mallon committed
76
77
	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);
78
79
80
81

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

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

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

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

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

129
130
131
/**
 * Add the given method entity as a constructor.
 */
132
133
static void add_constructor(ir_entity *method)
{
Christoph Mallon's avatar
Christoph Mallon committed
134
135
136
	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);
137
	ident     *const ide          = id_unique("constructor_ptr");
138
	ir_entity *const ptr          = new_global_entity(constructors, ide, ptr_type, ir_visibility_private, IR_LINKAGE_CONSTANT | IR_LINKAGE_HIDDEN_USER);
Christoph Mallon's avatar
Christoph Mallon committed
139
140
	ir_graph  *const irg          = get_const_code_irg();
	ir_node   *const val          = new_r_Address(irg, method);
141

142
	set_entity_ld_ident(ptr, NEW_IDENT(""));
Christoph Mallon's avatar
Christoph Mallon committed
143
	set_atomic_ent_value(ptr, val);
144
}
145

146
147
148
149
150
151
152
/**
 * 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
153
	ident   *const init_name = new_id_from_str("__init_firmprof");
154
	ir_type *const init_type = new_type_method(3, 0, false);
Christoph Mallon's avatar
Christoph Mallon committed
155
156
157
	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));
158
159
160
161
162

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

163
	return new_entity(get_glob_type(), init_name, init_type);
164
165
}

166
167
/**
 * Generates a new irg which calls the initializer
Michael Beck's avatar
BugFix:    
Michael Beck committed
168
169
 *
 * Pseudocode:
170
171
172
173
 *    static void __firmprof_initializer(void) __attribute__ ((constructor))
 *    {
 *        __init_firmprof(ent_filename, bblock_counts, n_blocks);
 *    }
174
 */
Christoph Mallon's avatar
Christoph Mallon committed
175
static ir_graph *gen_initializer_irg(ir_entity *ent_filename, ir_entity *bblock_counts, int n_blocks)
176
{
177
178
	ident     *const name  = new_id_from_str("__firmprof_initializer");
	ir_type   *const owner = get_glob_type();
179
	ir_type   *const type  = new_type_method(0, 0, false);
180
	ir_entity *const ent   = new_global_entity(owner, name, type, ir_visibility_local, IR_LINKAGE_DEFAULT);
Christian Würdig's avatar
Christian Würdig committed
181

Christoph Mallon's avatar
Christoph Mallon committed
182
183
	ir_graph *const irg              = new_ir_graph(ent, 0);
	ir_type  *const empty_frame_type = get_irg_frame_type(irg);
184
	set_type_size(empty_frame_type, 0);
185
	set_type_state(empty_frame_type, layout_fixed);
186

Christoph Mallon's avatar
Christoph Mallon committed
187
188
189
190
191
192
193
194
195
196
197
198
	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);
199
200

	add_immBlock_pred(get_irg_end_block(irg), ret);
Matthias Braun's avatar
fixes    
Matthias Braun committed
201
	irg_finalize_cons(irg);
202
203
	add_constructor(ent);

204
205
206
	return irg;
}

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

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

220
	ir_type *const type_Iu = get_entity_type(get_irn_entity_attr(address));
Christoph Mallon's avatar
Christoph Mallon committed
221
222
	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);
223
	ir_node *const offset  = new_r_Add(bb, address, cnst);
224
	ir_node *const load    = new_r_Load(bb, unknown, offset, mode_Iu, type_Iu, cons_none);
Christoph Mallon's avatar
Christoph Mallon committed
225
226
227
	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);
228
	ir_node *const add     = new_r_Add(bb, proji, one);
229
	ir_node *const store   = new_r_Store(bb, lmem, offset, add, type_Iu, cons_none);
Christoph Mallon's avatar
Christoph Mallon committed
230
231
232
233
	ir_node *const smem    = new_r_Proj(store, mode_M, pn_Store_M);

	set_irn_link(bb, smem);
	set_irn_link(smem, load);
234
235
236
237
238
239
240
241
242
}

/**
 * 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
243
static void fix_ssa(ir_node *const bb, void *const data)
244
{
Christoph Mallon's avatar
Christoph Mallon committed
245
	(void)data;
246

Christoph Mallon's avatar
Christoph Mallon committed
247
	ir_graph *const irg = get_irn_irg(bb);
248
249
250
251
252

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

Christoph Mallon's avatar
Christoph Mallon committed
253
254
	ir_node  *mem;
	int const arity = get_Block_n_cfgpreds(bb);
255
256
257
	if (bb == get_irg_start_block(irg)) {
		mem = get_irg_initial_mem(irg);
	} else if (arity == 1) {
Christoph Mallon's avatar
Christoph Mallon committed
258
259
		ir_node *const pred = get_Block_cfgpred_block(bb, 0);
		mem = pred ? (ir_node*)get_irn_link(pred) : new_r_NoMem(irg);
260
	} else {
261
		ir_node **ins = ALLOCAN(ir_node*, arity);
Christoph Mallon's avatar
Christoph Mallon committed
262
263
264
		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);
265
266
		}
		mem = new_r_Phi(bb, arity, ins, mode_M);
267
	}
268
269
270
271

	/* 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
272
273
	ir_node *const proj = (ir_node*)get_irn_link(bb);
	ir_node *const load = (ir_node*)get_irn_link(proj);
274
	set_Load_mem(load, mem);
275
276
277
}

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

287
288
289
290
291
292
/**
 * 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
293
294
	ir_node *const ins[] = { (ir_node*)get_irn_link(bb), mem };
	return new_r_Sync(bb, ARRAY_SIZE(ins), ins);
295
}
296

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

	/* 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
311
	ir_node *const endbb = get_irg_end_block(irg);
Matthias Braun's avatar
Matthias Braun committed
312
	for (unsigned i = get_Block_n_cfgpreds(endbb); i-- > 0;) {
Christoph Mallon's avatar
Christoph Mallon committed
313
314
		ir_node *const node = skip_Proj(get_Block_cfgpred(endbb, i));
		ir_node *const bb   = get_Block_cfgpred_block(endbb, i);
315
316
		if (bb == NULL)
			continue;
317

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

337
	/* as well as calls with attribute noreturn */
Christoph Mallon's avatar
Christoph Mallon committed
338
	ir_node *const end = get_irg_end(irg);
Matthias Braun's avatar
Matthias Braun committed
339
	for (unsigned i = get_End_n_keepalives(end); i-- > 0;) {
340
341
		ir_node *node = get_End_keepalive(end, i);
		if (is_Call(node)) {
Christoph Mallon's avatar
Christoph Mallon committed
342
343
			ir_node *const bb  = get_nodes_block(node);
			ir_node *const mem = get_Call_mem(node);
344
345
			set_Call_mem(node, sync_mem(bb, mem));
		}
346
	}
347
}
348

349
350
351
352
353
354
/**
 * 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
355
356
	ir_type *const uint_type  = new_type_primitive(mode_Iu);
	ir_type *const array_type = new_type_array(uint_type, size);
Christian Würdig's avatar
Christian Würdig committed
357

358
359
	ir_type *const owner = get_glob_type();
	return new_global_entity(owner, name, array_type, ir_visibility_private, IR_LINKAGE_DEFAULT);
360
361
362
363
364
365
366
367
}

/**
 * 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
368
	/* Create the type for a fixed-length string */
Christoph Mallon's avatar
Christoph Mallon committed
369
370
	ir_type *const char_type   = new_type_primitive(mode_Bs);
	size_t   const length      = strlen(string) + 1;
Christoph Mallon's avatar
Christoph Mallon committed
371
	ir_type *const string_type = new_type_array(char_type, length);
Christian Würdig's avatar
Christian Würdig committed
372

373
374
	ir_type   *const owner  = get_glob_type();
	ir_entity *const result = new_global_entity(owner, name, string_type, ir_visibility_private, IR_LINKAGE_CONSTANT);
375
376
377

	/* 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
378
379
380
381
	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);
382
		set_initializer_compound_value(contents, i, init);
383
	}
384
	set_entity_initializer(result, contents);
385

386
387
	return result;
}
388

389
ir_graph *ir_profile_instrument(const char *filename)
390
391
{
	FIRM_DBG_REGISTER(dbg, "firm.ir.profile");
392

393
394
395
	/* Don't do anything for modules without code. Else the linker will
	 * complain. */
	if (get_irp_n_irgs() == 0)
396
		return NULL;
397

398
	/* count the number of block first */
399
	unsigned const n_blocks = get_irp_n_blocks();
400
401
402
403

	/* 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
404
405
	ident     *const counter_id    = new_id_from_str("__FIRMPROF__BLOCK_COUNTS");
	ir_entity *const bblock_counts = new_array_entity(counter_id, n_blocks);
406

Christoph Mallon's avatar
Christoph Mallon committed
407
408
	ident     *const filename_id  = new_id_from_str("__FIRMPROF__FILE_NAME");
	ir_entity *const ent_filename = new_static_string_entity(filename_id, filename);
409
410

	/* initialize block id array and instrument blocks */
Christoph Mallon's avatar
Christoph Mallon committed
411
	block_id_walker_data_t wd = { .id = 0 };
412
	foreach_irp_irg_r(i, irg) {
413
		instrument_irg(irg, bblock_counts, &wd);
414
	}
415

416
	return gen_initializer_irg(ent_filename, bblock_counts, n_blocks);
417
418
}

419
static unsigned int *parse_profile(const char *filename, unsigned int num_blocks)
420
{
Christoph Mallon's avatar
Christoph Mallon committed
421
	FILE *const f = fopen(filename, "rb");
422
423
424
	if (!f) {
		DBG((dbg, LEVEL_2, "Failed to open profile file (%s)\n", filename));
		return NULL;
425
426
	}

427
	/* check header */
428
429
430
	uint32_t *result = NULL;
	char      buf[8];
	size_t    ret = fread(buf, 8, 1, f);
431
432
433
434
	if (ret == 0 || strncmp(buf, "firmprof", 8) != 0) {
		DBG((dbg, LEVEL_2, "Broken fileheader in profile\n"));
		goto end;
	}
435

436
	result = XMALLOCN(unsigned int, num_blocks);
437
438
439

	/* The profiling output format is defined to be a sequence of integer
	 * values stored little endian format. */
440
	for (unsigned i = 0; i < num_blocks; ++i) {
Manuel Mohr's avatar
Manuel Mohr committed
441
442
		unsigned char bytes[4];
		if ((ret = fread(bytes, 1, 4, f)) < 1)
443
444
445
446
447
448
449
			break;

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

	if (ret < 1) {
450
		DBG((dbg, LEVEL_4, "Failed to read counters... (size: %u)\n",
451
			sizeof(unsigned int) * num_blocks));
452
		free(result);
453
454
455
456
457
458
		result = NULL;
	}

end:
	fclose(f);
	return result;
459
}
460

461
/**
462
 * Reads the corresponding profile info file if it exists.
463
 */
464
465
static void block_associate_walker(ir_node *bb, void *env)
{
Christoph Mallon's avatar
Christoph Mallon committed
466
	block_assoc_t *b = (block_assoc_t*)env;
467
468
469
	execcount_t query;

	query.block = get_irn_node_nr(bb);
Christoph Mallon's avatar
Christoph Mallon committed
470
471
	query.count = b->counters[b->i++];
	DBG((dbg, LEVEL_4, "execcount(%+F, %u): %u\n", bb, query.block, query.count));
sebastian.buchwald1's avatar
sebastian.buchwald1 committed
472
	(void)set_insert(execcount_t, profile, &query, sizeof(query), query.block);
473
}
474

475
476
static void irp_associate_blocks(block_assoc_t *env)
{
477
	foreach_irp_irg_r(i, irg) {
478
		irg_block_walk_graph(irg, block_associate_walker, NULL, env);
479
	}
480
}
481

482
void ir_profile_free(void)
483
{
484
	if (profile) {
485
		del_set(profile);
486
487
488
489
490
491
		profile = NULL;
	}

	if (hook != NULL) {
		dump_remove_node_info_callback(hook);
		hook = NULL;
492
	}
493
494
}

495
bool ir_profile_read(const char *filename)
Adam Szalkowski's avatar
Adam Szalkowski committed
496
{
497
	FIRM_DBG_REGISTER(dbg, "firm.ir.profile");
Adam Szalkowski's avatar
Adam Szalkowski committed
498

499
	unsigned n_blocks = get_irp_n_blocks();
Christoph Mallon's avatar
Christoph Mallon committed
500
501
502
503
	block_assoc_t env = {
		.i        = 0,
		.counters = parse_profile(filename, n_blocks)
	};
504
505
	if (!env.counters)
		return false;
506

507
508
	ir_profile_free();
	profile = new_set(cmp_execcount, 16);
509

510
	irp_associate_blocks(&env);
511
	free(env.counters);
512

513
514
515
	/* register the vcg hook */
	hook = dump_add_node_info_callback(dump_profile_node_info, NULL);
	return 1;
516
}
517

518
519
520
521
typedef struct initialize_execfreq_env_t {
	double freq_factor;
} initialize_execfreq_env_t;

522
523
static void initialize_execfreq(ir_node *block, void *data)
{
Christoph Mallon's avatar
Christoph Mallon committed
524
	const initialize_execfreq_env_t *env = (const initialize_execfreq_env_t*)data;
525

Christoph Mallon's avatar
Christoph Mallon committed
526
527
	double          freq;
	ir_graph *const irg = get_irn_irg(block);
528
	if (block == get_irg_start_block(irg) || block == get_irg_end_block(irg)) {
529
530
		freq = 1.0;
	} else {
Michael Beck's avatar
Michael Beck committed
531
		freq = ir_profile_get_block_execcount(block);
532
		freq *= env->freq_factor;
533
		if (freq < MIN_EXECFREQ)
534
			freq = MIN_EXECFREQ;
535
536
	}

537
	set_block_execfreq(block, freq);
538
539
}

540
static void ir_set_execfreqs_from_profile(ir_graph *irg)
541
{
542
	/* Find the first block containing instructions */
Christoph Mallon's avatar
Christoph Mallon committed
543
544
	ir_node *const start_block = get_irg_start_block(irg);
	unsigned const count       = ir_profile_get_block_execcount(start_block);
545
	if (count == 0) {
546
		/* the function was never executed, so fallback to estimated freqs */
547
548
		ir_estimate_execfreq(irg);
		return;
549
550
	}

Christoph Mallon's avatar
Christoph Mallon committed
551
	initialize_execfreq_env_t env = { .freq_factor = 1.0 / count };
552
	irg_block_walk_graph(irg, initialize_execfreq, NULL, &env);
553
}
554

555
556
void ir_create_execfreqs_from_profile(void)
{
557
	foreach_irp_irg_r(i, irg) {
558
559
		ir_set_execfreqs_from_profile(irg);
	}
560
}