bearch: Disallow passing Projs to get_irn_ops().
[libfirm] / ir / ir / irprofile.c
index 472598f..8888ce9 100644 (file)
 /*
- * Copyright (C) 1995-2008 University of Karlsruhe.  All right reserved.
- *
  * 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.
+ * Copyright (C) 2012 University of Karlsruhe.
  */
 
 /**
  * @file
  * @brief       Code instrumentation and execution count profiling.
- * @author      Adam M. Szalkowski
- * @date        06.04.2006
- * @version     $Id$
+ * @author      Adam M. Szalkowski, Steven Schaefer
+ * @date        06.04.2006, 11.11.2010
  */
 #include "config.h"
 
 #include <math.h>
+#include <stdio.h>
 
 #include "hashptr.h"
 #include "debug.h"
 #include "obst.h"
+#include "xmalloc.h"
 #include "set.h"
-#include "list.h"
-#include "pmap.h"
-#include "array_t.h"
+#include "irtools.h"
 
-#include "irprintf.h"
 #include "irgwalk.h"
 #include "irdump_t.h"
 #include "irnode_t.h"
 #include "ircons_t.h"
-#include "execfreq.h"
+#include "execfreq_t.h"
+#include "irprofile.h"
 #include "typerep.h"
 
-#include "dbginfo.h"
-#include "irhooks.h"
-#include "iredges.h"
+/* Instrument blocks walker. */
+typedef struct block_id_walker_data_t {
+       unsigned int id;   /**< current block id number */
+       ir_node *symconst; /**< the SymConst representing the counter array */
+} block_id_walker_data_t;
 
-#include "irprofile.h"
+/* 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;
 
-/** An entry in the id-to-location map */
-typedef struct loc_entry {
-       ir_entity    *fname;   /**< the entity holding the file name */
-       unsigned int lineno;   /**< line number */
-} loc_entry;
-
-typedef struct _block_id_walker_data_t {
-       tarval         **array;    /**< the entity the holds the block counts */
-       unsigned int   id;         /**< current block id number */
-       ir_node        *symconst;  /**< the SymConst representing array */
-       pmap           *fname_map; /**< set containing all found filenames */
-       loc_entry      *locs;      /**< locations */
-       ir_type        *tp_char;   /**< the character type */
-       unsigned       flags;      /**< profile flags */
-} block_id_walker_data_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;
 
-typedef struct _execcount_t {
-       unsigned long block;
-       unsigned int count;
+/* Hook for vcg output. */
+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.
+ */
+typedef struct execcount_t {
+       unsigned long block; /**< block id */
+       uint32_t      count; /**< execution count */
 } execcount_t;
 
 /**
  * Compare two execcount_t entries.
  */
-static int cmp_execcount(const void *a, const void *b, size_t size) {
-       const execcount_t *ea = a;
-       const execcount_t *eb = b;
+static int cmp_execcount(const void *a, const void *b, size_t size)
+{
+       const execcount_t *ea = (const execcount_t*)a;
+       const execcount_t *eb = (const execcount_t*)b;
        (void) size;
        return ea->block != eb->block;
 }
 
+uint32_t ir_profile_get_block_execcount(const ir_node *block)
+{
+       execcount_t *ec, query;
+
+       query.block = get_irn_node_nr(block);
+       ec = set_find(execcount_t, profile, &query, sizeof(query), query.block);
+
+       if (ec != NULL) {
+               return ec->count;
+       } else {
+               DBG((dbg, LEVEL_3,
+                       "Warning: Profile contains no data for %+F\n", block));
+               return 0;
+       }
+}
+
 /**
  * Block walker, count number of blocks.
  */
-static void block_counter(ir_node * bb, void * data) {
-       unsigned int *count = data;
+static void block_counter(ir_node *bb, void *data)
+{
+       unsigned *count = (unsigned*) data;
        (void) bb;
-       *count = *count + 1;
+       ++(*count);
 }
 
 /**
- * Return the number of blocks the given graph.
+ * Returns the number of blocks the given graph.
  */
-static unsigned int count_blocks(ir_graph *irg) {
+static unsigned int get_irg_n_blocks(ir_graph *irg)
+{
        unsigned int count = 0;
-
        irg_block_walk_graph(irg, block_counter, NULL, &count);
        return count;
 }
 
-/* keep the execcounts here because they are only read once per compiler run */
-static set * profile = NULL;
-static hook_entry_t hook;
-
 /**
- * Instrument a block with code needed for profiling
+ * Returns the number of basic blocks in the current ir program.
  */
-static void
-instrument_block(ir_node *bb, ir_node *address, unsigned int id)
+static unsigned int get_irp_n_blocks(void)
 {
-       ir_graph *irg = get_irn_irg(bb);
-       ir_node  *start_block = get_irg_start_block(irg);
-       ir_node  *load, *store, *offset, *add, *projm, *proji, *unknown;
-       ir_node  *cnst;
-
-       /**
-        * We can't instrument the end block as there are no real instructions there
-        */
-       if(bb == get_irg_end_block(irg))
-               return;
+       int i, n = get_irp_n_irgs();
+       unsigned int count = 0;
 
-       unknown = new_r_Unknown(irg, mode_M);
-       cnst    = new_r_Const_long(irg, start_block, mode_Iu, get_mode_size_bytes(mode_Iu) * id);
-       offset  = new_r_Add(irg, bb, address, cnst, mode_P);
-       load    = new_r_Load(irg, bb, unknown, offset, mode_Iu);
-       projm   = new_r_Proj(irg, bb, load, mode_M, pn_Load_M);
-       proji   = new_r_Proj(irg, bb, load, mode_Iu, pn_Load_res);
-       cnst    = new_r_Const_long(irg, start_block, mode_Iu, 1);
-       add     = new_r_Add(irg, bb, proji, cnst, mode_Iu);
-       store   = new_r_Store(irg, bb, projm, offset, add);
-       projm   = new_r_Proj(irg, bb, store, mode_M, pn_Store_M);
-       set_irn_link(bb, projm);
-       set_irn_link(projm, load);
-}
+       for (i = 0; i < n; i++) {
+               ir_graph *irg = get_irp_irg(i);
+               count += get_irg_n_blocks(irg);
+       }
 
-typedef struct fix_env {
-       ir_node *end_block;
-} fix_env;
+       return count;
+}
 
-/**
- * SSA Construction for instrumentation code memory
- */
-static void
-fix_ssa(ir_node * bb, void * data)
+/* vcg helper */
+static void dump_profile_node_info(void *ctx, FILE *f, const ir_node *irn)
 {
-       fix_env *env = data;
-       ir_node *mem;
-       int     arity = get_Block_n_cfgpreds(bb);
-
-       /* start and end block are not instrumented, skip! */
-       if (bb == env->end_block)
-               return;
-
-       if (bb == get_irg_start_block(get_irn_irg(bb))) {
-               mem = new_NoMem();
-       } else if (arity == 1) {
-               mem = get_irn_link(get_Block_cfgpred_block(bb, 0));
-       } else {
-               int n;
-               ir_node **ins;
-               ir_graph *irg = current_ir_graph;
-
-               NEW_ARR_A(ir_node*, ins, arity);
-               for (n = arity - 1; n >= 0; --n) {
-                       ins[n] = get_irn_link(get_Block_cfgpred_block(bb, n));
-               }
-               mem = new_r_Phi(irg, bb, arity, ins, mode_M);
+       (void) ctx;
+       if (is_Block(irn)) {
+               unsigned int execcount = ir_profile_get_block_execcount(irn);
+               fprintf(f, "profiled execution count: %u\n", execcount);
        }
-       set_Load_mem(get_irn_link(get_irn_link(bb)), mem);
 }
 
+/**
+ * Add the given method entity as a constructor.
+ */
 static void add_constructor(ir_entity *method)
 {
     ir_type   *method_type  = get_entity_type(method);
-    ident     *id           = id_unique("constructor_ptrt.%u");
-    ir_type   *ptr_type     = new_type_pointer(id, method_type, mode_P_code);
+    ir_type   *ptr_type     = new_type_pointer(method_type);
 
     ir_type   *constructors = get_segment_type(IR_SEGMENT_CONSTRUCTORS);
-    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, NULL);
+       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));
     set_entity_compiler_generated(ptr, 1);
-    set_entity_variability(ptr, variability_constant);
+    set_entity_linkage(ptr, IR_LINKAGE_CONSTANT | IR_LINKAGE_HIDDEN_USER);
+    set_entity_visibility(ptr, ir_visibility_private);
     set_atomic_ent_value(ptr, val);
 }
 
+/**
+ * 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;
+}
+
 /**
  * Generates a new irg which calls the initializer
  *
  * Pseudocode:
- *      void __firmprof_initializer(void) { __init_firmprof(ent_filename, bblock_id, bblock_counts, n_blocks); }
+ *    static void __firmprof_initializer(void) __attribute__ ((constructor))
+ *    {
+ *        __init_firmprof(ent_filename, bblock_counts, n_blocks);
+ *    }
  */
-static ir_graph *
-gen_initializer_irg(ir_entity * ent_filename, ir_entity * bblock_id, ir_entity * bblock_counts, int n_blocks)
+static ir_graph *gen_initializer_irg(ir_entity *ent_filename,
+                                     ir_entity *bblock_counts, int n_blocks)
 {
-       ir_node *start_block;
-
-       ir_node   *ins[4];
-       ident     *name = new_id_from_str("__firmprof_initializer");
-       ir_entity *ent  = new_entity(get_glob_type(), name, new_type_method(name, 0, 0));
-       ir_node   *ret, *call, *symconst;
+       ir_graph *irg;
+       ir_node  *ins[3];
+       ir_node  *bb, *ret, *call, *symconst;
+       ir_type  *empty_frame_type;
        symconst_symbol sym;
 
-       ident     *init_name = new_id_from_str("__init_firmprof");
-       ir_type   *init_type = new_type_method(init_name, 4, 0);
-       ir_type   *uint, *uintptr, *string;
-       ir_entity *init_ent;
-       ir_graph  *irg;
-       ir_node   *bb;
-       ir_type   *empty_frame_type;
+       ir_entity *init_ent = get_init_firmprof_ref();
 
+       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);
        set_entity_ld_ident(ent, name);
 
-       uint    = new_type_primitive(new_id_from_str("__uint"), mode_Iu);
-       uintptr = new_type_pointer(new_id_from_str("__uintptr"), uint, mode_P);
-       string  = new_type_pointer(new_id_from_str("__charptr"), new_type_primitive(new_id_from_str("__char"), mode_Bs), mode_P);
-
-       set_method_param_type(init_type, 0, string);
-       set_method_param_type(init_type, 1, uintptr);
-       set_method_param_type(init_type, 2, uintptr);
-       set_method_param_type(init_type, 3, uint);
-       init_ent = new_entity(get_glob_type(), init_name, init_type);
-       set_entity_ld_ident(init_ent, init_name);
-
+       /* create the new ir_graph */
        irg = new_ir_graph(ent, 0);
+       set_current_ir_graph(irg);
        empty_frame_type = get_irg_frame_type(irg);
        set_type_size_bytes(empty_frame_type, 0);
+       set_type_state(empty_frame_type, layout_fixed);
 
-       bb = get_cur_block();
-
-       start_block = get_irg_start_block(irg);
+       bb = get_r_cur_block(irg);
 
        sym.entity_p = init_ent;
-       symconst     = new_r_SymConst(irg, start_block, mode_P_data, sym, symconst_addr_ent);
+       symconst     = new_r_SymConst(irg, mode_P_data, sym, symconst_addr_ent);
 
        sym.entity_p = ent_filename;
-       ins[0] = new_r_SymConst(irg, start_block, mode_P_data, sym, symconst_addr_ent);
-       sym.entity_p = bblock_id;
-       ins[1] = new_r_SymConst(irg, start_block, mode_P_data, sym, symconst_addr_ent);
+       ins[0] = new_r_SymConst(irg, mode_P_data, sym, symconst_addr_ent);
        sym.entity_p = bblock_counts;
-       ins[2] = new_r_SymConst(irg, start_block, mode_P_data, sym, symconst_addr_ent);
-       ins[3] = new_r_Const_long(irg, start_block, mode_Iu, n_blocks);
+       ins[1] = new_r_SymConst(irg, mode_P_data, sym, symconst_addr_ent);
+       ins[2] = new_r_Const_long(irg, mode_Iu, n_blocks);
 
-       call = new_r_Call(irg, bb, get_irg_initial_mem(irg), symconst, 4, ins, init_type);
-       ret = new_r_Return(irg, bb, new_r_Proj(irg, bb, call, mode_M, pn_Call_M_regular), 0, NULL);
+       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);
        mature_immBlock(bb);
 
        add_immBlock_pred(get_irg_end_block(irg), ret);
@@ -255,441 +233,410 @@ gen_initializer_irg(ir_entity * ent_filename, ir_entity * bblock_id, ir_entity *
 
        irg_finalize_cons(irg);
 
+       /* add a pointer to the new function in the constructor section */
        add_constructor(ent);
 
        return irg;
 }
 
 /**
- * Create the location data for the given debug info.
+ * 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.
  */
-static void create_location_data(dbg_info *dbg, block_id_walker_data_t *wd)
+static void instrument_block(ir_node *bb, ir_node *address, unsigned int id)
 {
-       unsigned lineno;
-       const char *fname = ir_retrieve_dbg_info(dbg, &lineno);
-
-       if (fname) {
-               pmap_entry *entry = pmap_find(wd->fname_map, (void *)fname);
-               ir_entity  *ent;
-
-               if (! entry) {
-                       static unsigned nr = 0;
-                       ident   *id;
-                       char    buf[128];
-                       ir_type *arr;
-                       int     i, len = strlen(fname) + 1;
-                       tarval  **tarval_string;
-
-                       snprintf(buf, sizeof(buf), "firm_name_arr.%d", nr);
-                       arr = new_type_array(new_id_from_str(buf), 1, wd->tp_char);
-                       set_array_bounds_int(arr, 0, 0, len);
-
-                       snprintf(buf, sizeof(buf), "__firm_name.%d", nr++);
-                       id = new_id_from_str(buf);
-                       ent = new_entity(get_glob_type(), id, arr);
-                       set_entity_ld_ident(ent, id);
-
-                       pmap_insert(wd->fname_map, (void *)fname, ent);
-
-                       /* initialize file name string constant */
-                       tarval_string = alloca(sizeof(*tarval_string) * (len));
-                       for (i = 0; i < len; ++i) {
-                               tarval_string[i] = new_tarval_from_long(fname[i], mode_Bs);
-                       }
-                       set_entity_variability(ent, variability_constant);
-                       set_array_entity_values(ent, tarval_string, len);
-               } else {
-                       ent = entry->value;
-               }
-               wd->locs[wd->id].fname  = ent;
-               wd->locs[wd->id].lineno = lineno;
-       } else {
-               wd->locs[wd->id].fname  = NULL;
-               wd->locs[wd->id].lineno = 0;
-       }
+       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(irg, get_mode_one(mode_Iu));
+       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);
 }
 
 /**
- * Walker: assigns an ID to every block.
- * Builds the string table
+ * 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
-block_id_walker(ir_node * bb, void * data)
+static void fix_ssa(ir_node *bb, void *data)
 {
-       block_id_walker_data_t *wd = data;
+       ir_graph *irg = get_irn_irg(bb);
+       ir_node *mem, *proj, *load;
+       int n, arity = get_Block_n_cfgpreds(bb);
 
-       wd->array[wd->id] = new_tarval_from_long(get_irn_node_nr(bb), mode_Iu);
-       instrument_block(bb, wd->symconst, wd->id);
+       (void) data;
+
+       /* end blocks are not instrumented, skip! */
+       if (bb == get_irg_end_block(irg))
+               return;
 
-       if (wd->flags & profile_with_locations) {
-               dbg_info *dbg = get_irn_dbg_info(bb);
-               create_location_data(dbg, wd);
+       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);
+       } else {
+               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);
        }
+
+       /* 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);
+}
+
+/**
+ * Instrument a single block.
+ */
+static void block_instrument_walker(ir_node *bb, void *data)
+{
+       block_id_walker_data_t *wd = (block_id_walker_data_t*)data;
+       instrument_block(bb, wd->symconst, wd->id);
        ++wd->id;
 }
 
-#define IDENT(x)       new_id_from_chars(x, sizeof(x) - 1)
+/**
+ * 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);
+}
 
-ir_graph *
-ir_profile_instrument(const char *filename, unsigned flags)
+/**
+ * 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)
 {
-       int n, i;
-       int n_blocks = 0;
-       ir_entity *bblock_id;
-       ir_entity *bblock_counts;
-       ir_entity *ent_filename;
-       ir_entity *ent_locations = NULL;
-       ir_entity *loc_lineno = NULL;
-       ir_entity *loc_name = NULL;
-       ir_entity *ent;
-       ir_type *array_type;
-       ir_type *uint_type;
-       ir_type *string_type;
-       ir_type *character_type;
-       ir_type *loc_type = NULL;
-       ir_type *charptr_type;
-       ir_type *gtp;
-       ir_node *start_block;
-       tarval **tarval_array;
-       tarval **tarval_string;
-       tarval *tv;
-       int filename_len = strlen(filename)+1;
-       ident *cur_ident;
-       unsigned align_l, align_n, size;
-       ir_graph *rem;
-       block_id_walker_data_t  wd;
-       symconst_symbol sym;
+       ir_node *end   = get_irg_end(irg);
+       ir_node *endbb = get_irg_end_block(irg);
+       int i;
 
-       /* count the number of block first */
-       for (n = get_irp_n_irgs() - 1; n >= 0; --n) {
-               ir_graph *irg = get_irp_irg(n);
+       /* 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");
+               }
+       }
 
-               n_blocks += count_blocks(irg);
+       /* 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));
+               }
        }
+}
 
-       /* create all the necessary types and entities. Note that the
-          types must have a fixed layout, because we already running in the
-          backend */
-       uint_type      = new_type_primitive(IDENT("__uint"), mode_Iu);
+/**
+ * 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);
        set_type_alignment_bytes(uint_type, get_type_size_bytes(uint_type));
 
-       array_type     = new_type_array(IDENT("__block_info_array"), 1, uint_type);
-       set_array_bounds_int(array_type, 0, 0, n_blocks);
-       set_type_size_bytes(array_type, n_blocks * get_mode_size_bytes(mode_Iu));
+       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));
        set_type_alignment_bytes(array_type, get_mode_size_bytes(mode_Iu));
        set_type_state(array_type, layout_fixed);
 
-       character_type = new_type_primitive(IDENT("__char"), mode_Bs);
-       string_type    = new_type_array(IDENT("__filename"), 1, character_type);
-       set_array_bounds_int(string_type, 0, 0, filename_len);
-       set_type_size_bytes(string_type, filename_len);
-       set_type_alignment_bytes(string_type, 1);
-       set_type_state(string_type, layout_fixed);
+       result = new_entity(get_glob_type(), name, array_type);
+       set_entity_visibility(result, ir_visibility_local);
+       set_entity_compiler_generated(result, 1);
 
-       gtp            = get_glob_type();
-
-       cur_ident      = IDENT("__FIRMPROF__BLOCK_IDS");
-       bblock_id      = new_entity(gtp, cur_ident, array_type);
-       set_entity_ld_ident(bblock_id, cur_ident);
-       set_entity_variability(bblock_id, variability_initialized);
-
-       cur_ident      = IDENT("__FIRMPROF__BLOCK_COUNTS");
-       bblock_counts  = new_entity(gtp, cur_ident, array_type);
-       set_entity_ld_ident(bblock_counts, cur_ident);
-       set_entity_variability(bblock_counts, variability_initialized);
-
-       cur_ident      = IDENT("__FIRMPROF__FILE_NAME");
-       ent_filename   = new_entity(gtp, cur_ident, string_type);
-       set_entity_ld_ident(ent_filename, cur_ident);
-
-       if (flags & profile_with_locations) {
-               loc_type       = new_type_struct(IDENT("__location"));
-               loc_lineno     = new_entity(loc_type, IDENT("lineno"), uint_type);
-               align_l        = get_type_alignment_bytes(uint_type);
-               size           = get_type_size_bytes(uint_type);
-               set_entity_offset(loc_lineno, 0);
-
-               charptr_type   = new_type_pointer(IDENT("__charptr"), character_type, mode_P_data);
-               align_n        = get_type_size_bytes(charptr_type);
-               set_type_alignment_bytes(charptr_type, align_n);
-               loc_name       = new_entity(loc_type, IDENT("name"), charptr_type);
-               size           = (size + align_n - 1) & ~(align_n - 1);
-               set_entity_offset(loc_name, size);
-               size          += align_n;
-
-               if (align_n > align_l)
-                       align_l = align_n;
-               size = (size + align_l - 1) & ~(align_l - 1);
-               set_type_size_bytes(loc_type, size);
-               set_type_state(loc_type, layout_fixed);
-
-               loc_type = new_type_array(IDENT("__locarray"), 1, loc_type);
-               set_array_bounds_int(string_type, 0, 0, n_blocks);
-
-               cur_ident      = IDENT("__FIRMPROF__LOCATIONS");
-               ent_locations   = new_entity(gtp, cur_ident, loc_type);
-               set_entity_ld_ident(ent_locations, cur_ident);
-       }
+       return result;
+}
 
-       /* initialize count array */
-       NEW_ARR_A(tarval *, tarval_array, n_blocks);
-       tv = get_tarval_null(mode_Iu);
-       for (i = 0; i < n_blocks; ++i) {
-               tarval_array[i] = tv;
-       }
-       set_array_entity_values(bblock_counts, tarval_array, n_blocks);
+/**
+ * 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;
 
-       /* initialize function name string constant */
-       tarval_string = alloca(sizeof(*tarval_string) * (filename_len));
-       for (i = 0; i < filename_len; ++i) {
-               tarval_string[i] = new_tarval_from_long(filename[i], mode_Bs);
-       }
-       set_entity_variability(ent_filename, variability_constant);
-       set_array_entity_values(ent_filename, tarval_string, filename_len);
+       ir_type *char_type   = new_type_primitive(mode_Bs);
+       ir_type *string_type = new_type_array(1, char_type);
 
-       /* initialize block id array and instrument blocks */
-       wd.array     = tarval_array;
-       wd.id        = 0;
-       wd.tp_char   = character_type;
-       wd.flags     = flags;
-       if (flags & profile_with_locations) {
-               wd.fname_map = pmap_create();
-               NEW_ARR_A(loc_entry, wd.locs, n_blocks);
-       }
+       ir_initializer_t *contents;
 
-       for (n = get_irp_n_irgs() - 1; n >= 0; --n) {
-               ir_graph      *irg = get_irp_irg(n);
-               int            i;
-               ir_node       *endbb = get_irg_end_block(irg);
-               fix_env       env;
-
-               set_current_ir_graph(irg);
-
-               /* generate a symbolic constant pointing to the count array */
-               sym.entity_p = bblock_counts;
-               wd.symconst  = new_r_SymConst(irg, get_irg_start_block(irg), mode_P_data, sym, symconst_addr_ent);
-
-               irg_block_walk_graph(irg, block_id_walker, NULL, &wd);
-               start_block = get_irg_start_block(irg);
-               env.end_block   = get_irg_end_block(irg);
-               irg_block_walk_graph(irg, fix_ssa, NULL, &env);
-               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 *sync;
-                       ir_node *ins[2];
-
-                       switch (get_irn_opcode(node)) {
-                       case iro_Return:
-                               ins[0] = get_irn_link(bb);
-                               ins[1] = get_Return_mem(node);
-                               sync   = new_r_Sync(irg, bb, 2, ins);
-                               set_Return_mem(node, sync);
-                               break;
-                       case iro_Raise:
-                               ins[0] = get_irn_link(bb);
-                               ins[1] = get_Raise_mem(node);
-                               sync   = new_r_Sync(irg, bb, 2, ins);
-                               set_Raise_mem(node, sync);
-                               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");
-                       }
-               }
-       }
-       set_array_entity_values(bblock_id, tarval_array, n_blocks);
-
-       if (flags & profile_with_locations) {
-               /* build the initializer for the locations */
-               rem = current_ir_graph;
-               current_ir_graph = get_const_code_irg();
-               ent = get_array_element_entity(loc_type);
-               set_entity_variability(ent_locations, variability_constant);
-               for (i = 0; i < n_blocks; ++i) {
-                       compound_graph_path *path;
-                       tarval *tv;
-                       ir_node *n;
-
-                       /* lineno */
-                       path = new_compound_graph_path(loc_type, 2);
-                       set_compound_graph_path_array_index(path, 0, i);
-                       set_compound_graph_path_node(path, 0, ent);
-                       set_compound_graph_path_node(path, 1, loc_lineno);
-                       tv = new_tarval_from_long(wd.locs[i].lineno, mode_Iu);
-                       add_compound_ent_value_w_path(ent_locations, new_Const(mode_Iu, tv), path);
-
-                       /* name */
-                       path = new_compound_graph_path(loc_type, 2);
-                       set_compound_graph_path_array_index(path, 0, i);
-                       set_compound_graph_path_node(path, 0, ent);
-                       set_compound_graph_path_node(path, 1, loc_name);
-                       if (wd.locs[i].fname) {
-                               sym.entity_p = wd.locs[i].fname;
-                               n = new_SymConst(mode_P_data, sym, symconst_addr_ent);
-                       } else {
-                               n = new_Const(mode_P_data, get_mode_null(mode_P_data));
-                       }
-                       add_compound_ent_value_w_path(ent_locations, n, path);
-               }
-               pmap_destroy(wd.fname_map);
-       }
-       return gen_initializer_irg(ent_filename, bblock_id, bblock_counts, n_blocks);
-}
+       size_t i, length = strlen(string)+1;
 
-static void
-profile_node_info(void *ctx, FILE *f, const ir_node *irn)
-{
-       (void) ctx;
-       if(is_Block(irn)) {
-               fprintf(f, "profiled execution count: %u\n", ir_profile_get_block_execcount(irn));
+       /* Create the type for a fixed-length string */
+       set_array_bounds_int(string_type, 0, 0, length);
+       set_type_size_bytes(string_type, length);
+       set_type_alignment_bytes(string_type, 1);
+       set_type_state(string_type, layout_fixed);
+
+       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);
        }
-}
+       set_entity_initializer(result, contents);
 
-static void
-register_vcg_hook(void)
-{
-       memset(&hook, 0, sizeof(hook));
-       hook.hook._hook_node_info = profile_node_info;
-       register_hook(hook_node_info, &hook);
+       return result;
 }
 
-static void
-unregister_vcg_hook(void)
+ir_graph *ir_profile_instrument(const char *filename)
 {
-       unregister_hook(hook_node_info, &hook);
+       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");
+
+       /* Don't do anything for modules without code. Else the linker will
+        * complain. */
+       if (get_irp_n_irgs() == 0)
+               return NULL;
+
+       /* 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;
+       for (n = get_irp_n_irgs() - 1; n >= 0; --n) {
+               ir_graph *irg = get_irp_irg(n);
+               instrument_irg(irg, bblock_counts, &wd);
+       }
+
+       return gen_initializer_irg(ent_filename, bblock_counts, n_blocks);
 }
 
-/**
- * Reads the corresponding profile info file if it exists and returns a
- * profile info struct
- */
-void
-ir_profile_read(const char *filename)
+static unsigned int *parse_profile(const char *filename, unsigned int num_blocks)
 {
-       FILE   *f;
-       char    buf[8];
-       size_t  ret;
-
-       f = fopen(filename, "r");
-       if(f == NULL) {
-               return;
+       FILE *f = fopen(filename, "rb");
+       if (!f) {
+               DBG((dbg, LEVEL_2, "Failed to open profile file (%s)\n", filename));
+               return NULL;
        }
-       printf("found profile data '%s'.\n", filename);
 
-       /* check magic */
-       ret = fread(buf, 8, 1, f);
-       if(ret == 0 || strncmp(buf, "firmprof", 8) != 0) {
-               return;
+       /* check header */
+       uint32_t *result = NULL;
+       char      buf[8];
+       size_t    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;
        }
 
-       if(profile) ir_profile_free();
-       profile = new_set(cmp_execcount, 16);
+       result = XMALLOCN(unsigned int, num_blocks);
 
-       do {
-               execcount_t  query;
-               ret = fread(&query, sizeof(unsigned int), 2, f);
+       /* The profiling output format is defined to be a sequence of integer
+        * values stored little endian format. */
+       for (unsigned i = 0; i < num_blocks; ++i) {
+               unsigned char bytes[4];
 
-               if(ret != 2) break;
+               if ((ret = fread(bytes, 1, 4, f)) < 1)
+                       break;
 
-               set_insert(profile, &query, sizeof(query), query.block);
-       } while(1);
+               result[i] = (bytes[0] <<  0) | (bytes[1] <<  8)
+                         | (bytes[2] << 16) | (bytes[3] << 24);
+       }
+
+       if (ret < 1) {
+               DBG((dbg, LEVEL_4, "Failed to read counters... (size: %u)\n",
+                       sizeof(unsigned int) * num_blocks));
+               xfree(result);
+               result = NULL;
+       }
 
+end:
        fclose(f);
-       register_vcg_hook();
+       return result;
 }
 
 /**
- * Frees the profile info
+ * Reads the corresponding profile info file if it exists.
  */
-void
-ir_profile_free(void)
+static void block_associate_walker(ir_node *bb, void *env)
 {
-       if(profile) {
-               unregister_vcg_hook();
-               del_set(profile);
+       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));
+       (void)set_insert(execcount_t, profile, &query, sizeof(query), query.block);
+}
+
+static void irp_associate_blocks(block_assoc_t *env)
+{
+       for (int 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);
        }
 }
 
-/**
- * Tells whether profile module has acquired data
- */
-int
-ir_profile_has_data(void)
+void ir_profile_free(void)
 {
-       return (profile != NULL);
+       if (profile) {
+               del_set(profile);
+               profile = NULL;
+       }
+
+       if (hook != NULL) {
+               dump_remove_node_info_callback(hook);
+               hook = NULL;
+       }
 }
 
-/**
- * Get block execution count as determined be profiling
- */
-unsigned int
-ir_profile_get_block_execcount(const ir_node *block)
+bool ir_profile_read(const char *filename)
 {
-       execcount_t *ec, query;
+       block_assoc_t env;
+       FIRM_DBG_REGISTER(dbg, "firm.ir.profile");
 
-       if(!profile)
-               return 1;
+       unsigned n_blocks = get_irp_n_blocks();
+       env.i        = 0;
+       env.counters = parse_profile(filename, n_blocks);
+       if (!env.counters)
+               return false;
 
-       query.block = get_irn_node_nr(block);
-       ec = set_find(profile, &query, sizeof(query), get_irn_node_nr(block));
+       ir_profile_free();
+       profile = new_set(cmp_execcount, 16);
 
-       if(ec != NULL) {
-               return ec->count;
-       } else {
-               ir_fprintf(stderr, "Warning: Profile contains no data for %+F\n",
-                          block);
-               return 1;
-       }
+       irp_associate_blocks(&env);
+       xfree(env.counters);
+
+       /* register the vcg hook */
+       hook = dump_add_node_info_callback(dump_profile_node_info, NULL);
+       return 1;
 }
 
-typedef struct _intialize_execfreq_env_t {
-       ir_graph *irg;
-       ir_exec_freq *execfreqs;
+typedef struct initialize_execfreq_env_t {
        double freq_factor;
 } initialize_execfreq_env_t;
 
-// minimal execution frequency (an execfreq of 0 confuses algos)
-static const double MIN_EXECFREQ = 0.00001;
-
-static void initialize_execfreq(ir_node *block, void *data) {
-       initialize_execfreq_env_t *env = data;
+static void initialize_execfreq(ir_node *block, void *data)
+{
+       const initialize_execfreq_env_t *env
+               = (const initialize_execfreq_env_t*) data;
+       ir_graph *irg = get_irn_irg(block);
        double freq;
 
-       if(block == get_irg_start_block(env->irg)
-          || block == get_irg_end_block(env->irg)) {
+       if (block == get_irg_start_block(irg) || block == get_irg_end_block(irg)) {
                freq = 1.0;
        } else {
                freq = ir_profile_get_block_execcount(block);
                freq *= env->freq_factor;
-               if(freq < MIN_EXECFREQ)
+               if (freq < MIN_EXECFREQ)
                        freq = MIN_EXECFREQ;
        }
 
-       set_execfreq(env->execfreqs, block, freq);
+       set_block_execfreq(block, freq);
 }
 
-ir_exec_freq *ir_create_execfreqs_from_profile(ir_graph *irg)
+static void ir_set_execfreqs_from_profile(ir_graph *irg)
 {
-       ir_node *start_block;
-       initialize_execfreq_env_t env;
-       unsigned count;
-
-       env.irg = irg;
-       env.execfreqs = create_execfreq(irg);
-       start_block = get_irg_start_block(irg);
-
-       count = ir_profile_get_block_execcount(start_block);
-       if(count == 0) {
-               // the function was never executed, so fallback to estimated freqs
-               free_execfreq(env.execfreqs);
-
-               return compute_execfreq(irg, 10);
+       /* Find the first block containing instructions */
+       ir_node *start_block = get_irg_start_block(irg);
+       unsigned count       = ir_profile_get_block_execcount(start_block);
+       if (count == 0) {
+               /* the function was never executed, so fallback to estimated freqs */
+               ir_estimate_execfreq(irg);
+               return;
        }
 
+       initialize_execfreq_env_t env;
        env.freq_factor = 1.0 / count;
        irg_block_walk_graph(irg, initialize_execfreq, NULL, &env);
+}
 
-       return env.execfreqs;
+void ir_create_execfreqs_from_profile(void)
+{
+       for (int n = get_irp_n_irgs() - 1; n >= 0; --n) {
+               ir_graph *irg = get_irp_irg(n);
+               ir_set_execfreqs_from_profile(irg);
+       }
 }