bearch: Disallow passing Projs to get_irn_ops().
[libfirm] / ir / ir / irprofile.c
index 45218f2..8888ce9 100644 (file)
@@ -1,20 +1,6 @@
 /*
- * Copyright (C) 1995-2011 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.
  */
 
 /**
@@ -22,7 +8,6 @@
  * @brief       Code instrumentation and execution count profiling.
  * @author      Adam M. Szalkowski, Steven Schaefer
  * @date        06.04.2006, 11.11.2010
- * @version     $Id$
  */
 #include "config.h"
 
 #include "irdump_t.h"
 #include "irnode_t.h"
 #include "ircons_t.h"
-#include "execfreq.h"
-#include "typerep.h"
-
+#include "execfreq_t.h"
 #include "irprofile.h"
+#include "typerep.h"
 
 /* Instrument blocks walker. */
 typedef struct block_id_walker_data_t {
@@ -57,15 +41,6 @@ typedef struct block_assoc_t {
        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
 
@@ -73,7 +48,7 @@ typedef struct intialize_execfreq_env_t {
 static set *profile = NULL;
 
 /* Hook for vcg output. */
-DEBUG_ONLY(static void *hook;)
+static void *hook;
 
 /* The debug module handle. */
 DEBUG_ONLY(static firm_dbg_module_t *dbg;)
@@ -84,7 +59,7 @@ DEBUG_ONLY(static firm_dbg_module_t *dbg;)
  */
 typedef struct execcount_t {
        unsigned long block; /**< block id */
-       unsigned int  count; /**< execution count */
+       uint32_t      count; /**< execution count */
 } execcount_t;
 
 /**
@@ -98,6 +73,22 @@ static int cmp_execcount(const void *a, const void *b, size_t 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.
  */
@@ -153,8 +144,6 @@ static void add_constructor(ir_entity *method)
     ir_type   *ptr_type     = new_type_pointer(method_type);
 
     ir_type   *constructors = get_segment_type(IR_SEGMENT_CONSTRUCTORS);
-       /* 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();
@@ -270,7 +259,7 @@ static void instrument_block(ir_node *bb, ir_node *address, unsigned int id)
        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);
+       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);
@@ -469,14 +458,6 @@ static ir_entity *new_static_string_entity(ident *name, const char *string)
        return result;
 }
 
-/**
- * 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;
@@ -512,13 +493,8 @@ ir_graph *ir_profile_instrument(const char *filename)
        return gen_initializer_irg(ent_filename, bblock_counts, n_blocks);
 }
 
-static unsigned int *
-parse_profile(const char *filename, unsigned int num_blocks)
+static unsigned int *parse_profile(const char *filename, unsigned int num_blocks)
 {
-       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));
@@ -526,16 +502,31 @@ parse_profile(const char *filename, unsigned int num_blocks)
        }
 
        /* check header */
-       ret = fread(buf, 8, 1, f);
+       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;
        }
 
        result = XMALLOCN(unsigned int, num_blocks);
-       if (fread(result, sizeof(unsigned int) * num_blocks, 1, f) < 1) {
+
+       /* 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 = fread(bytes, 1, 4, f)) < 1)
+                       break;
+
+               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));
+                       sizeof(unsigned int) * num_blocks));
                xfree(result);
                result = NULL;
        }
@@ -548,7 +539,6 @@ end:
 /**
  * Reads the corresponding profile info file if it exists.
  */
-
 static void block_associate_walker(ir_node *bb, void *env)
 {
        block_assoc_t *b = (block_assoc_t*) env;
@@ -558,43 +548,17 @@ static void block_associate_walker(ir_node *bb, void *env)
        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);
+       (void)set_insert(execcount_t, profile, &query, sizeof(query), query.block);
 }
 
 static void irp_associate_blocks(block_assoc_t *env)
 {
-       int n;
-       for (n = get_irp_n_irgs() - 1; n >= 0; --n) {
+       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);
        }
 }
 
-bool ir_profile_read(const char *filename)
-{
-       block_assoc_t env;
-       FIRM_DBG_REGISTER(dbg, "firm.ir.profile");
-
-       env.i = 0;
-       env.counters = parse_profile(filename, get_irp_n_blocks());
-       if (!env.counters)
-               return false;
-
-       if (profile)
-               ir_profile_free();
-       profile = new_set(cmp_execcount, 16);
-
-       irp_associate_blocks(&env);
-       xfree(env.counters);
-
-       /* register the vcg hook */
-       hook = dump_add_node_info_callback(dump_profile_node_info, NULL);
-       return true;
-}
-
-/**
- * Frees the profile info
- */
 void ir_profile_free(void)
 {
        if (profile) {
@@ -608,43 +572,40 @@ void ir_profile_free(void)
        }
 }
 
-/**
- * Tells whether profile module has acquired data
- */
-bool ir_profile_has_data(void)
+bool ir_profile_read(const char *filename)
 {
-       return profile != NULL;
-}
+       block_assoc_t env;
+       FIRM_DBG_REGISTER(dbg, "firm.ir.profile");
 
-/**
- * Get block execution count as determined by profiling
- */
-unsigned int ir_profile_get_block_execcount(const ir_node *block)
-{
-       execcount_t *ec, query;
+       unsigned n_blocks = get_irp_n_blocks();
+       env.i        = 0;
+       env.counters = parse_profile(filename, n_blocks);
+       if (!env.counters)
+               return false;
 
-       if (!ir_profile_has_data())
-               return 1;
+       ir_profile_free();
+       profile = new_set(cmp_execcount, 16);
 
-       query.block = get_irn_node_nr(block);
-       ec = (execcount_t*)set_find(profile, &query, sizeof(query), query.block);
+       irp_associate_blocks(&env);
+       xfree(env.counters);
 
-       if (ec != NULL) {
-               return ec->count;
-       } else {
-               DBG((dbg, LEVEL_3,
-                       "Warning: Profile contains no data for %+F\n", block));
-               return 1;
-       }
+       /* register the vcg hook */
+       hook = dump_add_node_info_callback(dump_profile_node_info, NULL);
+       return 1;
 }
 
+typedef struct initialize_execfreq_env_t {
+       double freq_factor;
+} initialize_execfreq_env_t;
+
 static void initialize_execfreq(ir_node *block, void *data)
 {
-       initialize_execfreq_env_t *env = (initialize_execfreq_env_t*)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);
@@ -653,29 +614,29 @@ static void initialize_execfreq(ir_node *block, void *data)
                        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);
-
        /* Find the first block containing instructions */
-       start_block = get_irg_start_block(irg);
-       count = ir_profile_get_block_execcount(start_block);
+       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 */
-               free_execfreq(env.execfreqs);
-               return compute_execfreq(irg, 10);
+               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);
+       }
 }