irprofile.c 18.4 KB
Newer Older
Christian Würdig's avatar
Christian Würdig committed
1
/*
2
 * Copyright (C) 1995-2008 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
Christian Würdig's avatar
Christian Würdig committed
25
 * @version     $Id$
26
27
28
29
 */
#include "config.h"

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

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

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

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

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

54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
/* 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;

/* maximal filename size */
#define MAX_NAME_SIZE 0x100

/* 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. */
DEBUG_ONLY(static void *hook;)

/* 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.
 */
85
typedef struct execcount_t {
86
87
	unsigned long block; /**< block id */
	unsigned int  count; /**< execution count */
88
89
} execcount_t;

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

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

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

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

129
130
131
132
	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
133

134
	return count;
135
136
}

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

147
148
149
/**
 * Add the given method entity as a constructor.
 */
150
151
152
static void add_constructor(ir_entity *method)
{
    ir_type   *method_type  = get_entity_type(method);
153
    ir_type   *ptr_type     = new_type_pointer(method_type);
154

155
    ir_type   *constructors = get_segment_type(IR_SEGMENT_CONSTRUCTORS);
156
157
158
159
160
161
162
163
	/* Mach-O does not like labels in the constructor segment, but with ELF
	 * the linker dies horribly if there is no label. */
	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));
164
    set_entity_compiler_generated(ptr, 1);
165
166
    set_entity_linkage(ptr, IR_LINKAGE_CONSTANT | IR_LINKAGE_HIDDEN_USER);
    set_entity_visibility(ptr, ir_visibility_private);
167
168
    set_atomic_ent_value(ptr, val);
}
169

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

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

212
	ir_entity *init_ent = get_init_firmprof_ref();
Adam Szalkowski's avatar
Adam Szalkowski committed
213

214
215
216
	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
217
218
	set_entity_ld_ident(ent, name);

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

226
	bb = get_r_cur_block(irg);
Adam Szalkowski's avatar
Adam Szalkowski committed
227
228

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

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

237
238
239
	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);
240
241
242
243
244
	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
245
246
	irg_finalize_cons(irg);

247
	/* add a pointer to the new function in the constructor section */
248
249
	add_constructor(ent);

250
251
252
	return irg;
}

253
/**
254
255
256
 * 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.
257
 */
258
static void instrument_block(ir_node *bb, ir_node *address, unsigned int id)
259
{
260
261
262
263
264
265
266
267
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
303
304
305
306
307
308
	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);
	cnst    = new_r_Const_long(irg, mode_Iu, 1);
	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);
309
	} else {
310
311
312
313
314
315
316
317
318
		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);
319
	}
320
321
322
323
324
325
326

	/* 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);
327
328
329
}

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

339
340
341
342
343
344
345
346
347
348
349
/**
 * 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);
}
350

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

397
398
399
400
401
402
403
404
	/* 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));
		}
405
	}
406
}
407

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

420
421
422
	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));
423
424
	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
425

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

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

469
470
	return result;
}
471

472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
/**
 * Instrument all ir_graphs in the current ir_program. Currently this only
 * works for graphs in the backend. Additionally, the resulting program
 * has to be linked with libfirmprof.
 *
 * @param filename the name of the profile file (usually module_name.prof)
 * @returns the module initializer, may be NULL
 */
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");
487

488
489
490
491
	/* Don't do anything for modules without code. Else the linker will
	 * complain. */
	if (get_irp_n_irgs() == 0)
		return NULL;
492

493
494
495
496
497
498
499
500
501
502
503
504
505
506
	/* 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
507
	for (n = get_irp_n_irgs() - 1; n >= 0; --n) {
508
509
		ir_graph *irg = get_irp_irg(n);
		instrument_irg(irg, bblock_counts, &wd);
510
	}
511
512

	return gen_initializer_irg(ent_filename, bblock_counts, n_blocks);
513
514
}

515
516
static unsigned int *
parse_profile(const char *filename, unsigned int num_blocks)
517
{
518
519
520
521
522
523
524
525
	unsigned int *result = NULL;
	char buf[8];
	size_t ret;

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

528
529
530
531
532
533
	/* 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;
	}
534

535
536
537
538
539
540
541
542
543
544
545
	result = XMALLOCN(unsigned int, num_blocks);
	if (fread(result, sizeof(unsigned int) * num_blocks, 1, f) < 1) {
		DBG((dbg, LEVEL_4, "Failed to read counters... (size: %u)\n",
		    sizeof(unsigned int) * num_blocks));
		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
560
561
562
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));
	set_insert(profile, &query, sizeof(query), query.block);
}
563

564
565
566
567
568
569
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);
570
	}
571
}
572

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

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

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

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

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

/**
 * Frees the profile info
 */
598
void ir_profile_free(void)
599
{
600
	if (profile) {
601
		del_set(profile);
602
603
604
605
606
607
		profile = NULL;
	}

	if (hook != NULL) {
		dump_remove_node_info_callback(hook);
		hook = NULL;
608
	}
609
610
}

Adam Szalkowski's avatar
Adam Szalkowski committed
611
/**
Michael Beck's avatar
BugFix:    
Michael Beck committed
612
 * Tells whether profile module has acquired data
Adam Szalkowski's avatar
Adam Szalkowski committed
613
 */
614
bool ir_profile_has_data(void)
Adam Szalkowski's avatar
Adam Szalkowski committed
615
{
616
	return profile != NULL;
Adam Szalkowski's avatar
Adam Szalkowski committed
617
618
}

619
/**
620
 * Get block execution count as determined by profiling
621
 */
622
unsigned int ir_profile_get_block_execcount(const ir_node *block)
623
624
625
{
	execcount_t *ec, query;

626
	if (!ir_profile_has_data())
627
628
629
		return 1;

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

632
	if (ec != NULL) {
633
634
		return ec->count;
	} else {
635
636
		DBG((dbg, LEVEL_3,
			"Warning: Profile contains no data for %+F\n", block));
637
638
		return 1;
	}
639
}
640

641
642
static void initialize_execfreq(ir_node *block, void *data)
{
643
	initialize_execfreq_env_t *env = (initialize_execfreq_env_t*)data;
644
645
	double freq;

646
	if (block == get_irg_start_block(env->irg)
647
648
649
	   || block == get_irg_end_block(env->irg)) {
		freq = 1.0;
	} else {
Michael Beck's avatar
Michael Beck committed
650
		freq = ir_profile_get_block_execcount(block);
651
		freq *= env->freq_factor;
652
		if (freq < MIN_EXECFREQ)
653
			freq = MIN_EXECFREQ;
654
655
656
657
658
	}

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

Michael Beck's avatar
Michael Beck committed
659
ir_exec_freq *ir_create_execfreqs_from_profile(ir_graph *irg)
660
661
662
663
664
{
	ir_node *start_block;
	initialize_execfreq_env_t env;
	unsigned count;

665
	env.irg = irg;
666
667
	env.execfreqs = create_execfreq(irg);

668
669
	/* Find the first block containing instructions */
	start_block = get_irg_start_block(irg);
Michael Beck's avatar
Michael Beck committed
670
	count = ir_profile_get_block_execcount(start_block);
671
	if (count == 0) {
672
		/* the function was never executed, so fallback to estimated freqs */
673
674
675
676
		free_execfreq(env.execfreqs);
		return compute_execfreq(irg, 10);
	}

677
	env.freq_factor = 1.0 / count;
678
679
680
681
	irg_block_walk_graph(irg, initialize_execfreq, NULL, &env);

	return env.execfreqs;
}