irprofile.c 16.7 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);
139
	set_entity_ld_ident(ptr, NEW_IDENT(""));
140
141
142
143
144

	ir_graph         *const irg  = get_const_code_irg();
	ir_node          *const val  = new_r_Address(irg, method);
	ir_initializer_t *const init = create_initializer_const(val);
	set_entity_initializer(ptr, init);
145
}
146

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

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

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

167
168
/**
 * Generates a new irg which calls the initializer
Michael Beck's avatar
BugFix:    
Michael Beck committed
169
170
 *
 * Pseudocode:
171
172
173
174
 *    static void __firmprof_initializer(void) __attribute__ ((constructor))
 *    {
 *        __init_firmprof(ent_filename, bblock_counts, n_blocks);
 *    }
175
 */
Christoph Mallon's avatar
Christoph Mallon committed
176
static ir_graph *gen_initializer_irg(ir_entity *ent_filename, ir_entity *bblock_counts, int n_blocks)
177
{
178
179
	ident     *const name  = new_id_from_str("__firmprof_initializer");
	ir_type   *const owner = get_glob_type();
180
	ir_type   *const type  = new_type_method(0, 0, false, cc_cdecl_set, mtp_no_property);
181
	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
182

183
	ir_graph  *const irg       = new_ir_graph(ent, 0);
Christoph Mallon's avatar
Christoph Mallon committed
184
185
186
187
188
189
190
191
192
193
194
195
	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);
196
197

	add_immBlock_pred(get_irg_end_block(irg), ret);
Matthias Braun's avatar
fixes    
Matthias Braun committed
198
	irg_finalize_cons(irg);
199
200
	add_constructor(ent);

201
202
203
	return irg;
}

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

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

217
218
	ir_type *const type_arr = get_entity_type(get_irn_entity_attr(address));
	ir_type *const type_ctr = get_array_element_type(type_arr);
219
	ir_mode *const mode_ctr = get_type_mode(type_ctr);
220
221
	ir_node *const unknown  = new_r_Unknown(irg, mode_M);
	ir_mode *const mode_off = get_reference_offset_mode(get_irn_mode(address));
222
	ir_node *const cnst     = new_r_Const_long(irg, mode_off, get_mode_size_bytes(mode_ctr) * id);
223
	ir_node *const offset   = new_r_Add(bb, address, cnst);
224
	ir_node *const load     = new_r_Load(bb, unknown, offset, mode_ctr, type_arr, cons_none);
225
	ir_node *const lmem     = new_r_Proj(load, mode_M, pn_Load_M);
226
227
	ir_node *const proji    = new_r_Proj(load, mode_ctr, pn_Load_res);
	ir_node *const one      = new_r_Const_one(irg, mode_ctr);
228
	ir_node *const add      = new_r_Add(bb, proji, one);
229
	ir_node *const store    = new_r_Store(bb, lmem, offset, add, type_arr, cons_none);
230
	ir_node *const smem     = new_r_Proj(store, mode_M, pn_Store_M);
Christoph Mallon's avatar
Christoph Mallon committed
231
232
233

	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
	ir_reserve_resources(irg, IR_RESOURCE_IRN_LINK);

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

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

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

	ir_free_resources(irg, IR_RESOURCE_IRN_LINK);
351
}
352

353
354
/**
 * Creates a new entity representing the equivalent of
355
 * static <element_mode> <name>[<length>];
356
 */
357
static ir_entity *new_array_entity(ident *const name, ir_mode *const element_mode, unsigned const length, ir_linkage const linkage)
358
{
359
360
361
362
363
	ir_type *const element_type = get_type_for_mode(element_mode);
	ir_type *const array_type   = new_type_array(element_type, length);
	ident   *const id           = new_id_from_str(name);
	ir_type *const owner        = get_glob_type();
	return new_global_entity(owner, id, array_type, ir_visibility_private, linkage);
364
365
366
367
368
369
}

/**
 * Creates a new entity representing the equivalent of
 * static const char name[strlen(string)+1] = string
 */
370
static ir_entity *new_static_string_entity(char const *const name, char const *const string)
371
{
Christoph Mallon's avatar
Christoph Mallon committed
372
	/* Create the type for a fixed-length string */
373
374
375
	ir_mode   *const mode   = mode_Bs;
	size_t     const length = strlen(string) + 1;
	ir_entity *const result = new_array_entity(name, mode, length, IR_LINKAGE_CONSTANT);
376
377
378

	/* 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
379
380
	ir_initializer_t *const contents = create_initializer_compound(length);
	for (size_t i = 0; i < length; i++) {
381
		ir_tarval        *const c    = new_tarval_from_long(string[i], mode);
Christoph Mallon's avatar
Christoph Mallon committed
382
		ir_initializer_t *const init = create_initializer_tarval(c);
383
		set_initializer_compound_value(contents, i, init);
384
	}
385
	set_entity_initializer(result, contents);
386

387
388
	return result;
}
389

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

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

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

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

407
	ir_entity *const ent_filename = new_static_string_entity("__FIRMPROF__FILE_NAME", filename);
408
409

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

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

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

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

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

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

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

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

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

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

	query.block = get_irn_node_nr(bb);
Christoph Mallon's avatar
Christoph Mallon committed
469
470
	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
471
	(void)set_insert(execcount_t, profile, &query, sizeof(query), query.block);
472
}
473

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

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

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

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

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

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

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

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

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

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

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

536
	set_block_execfreq(block, freq);
537
538
}

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

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

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