* @author Sebastian Hack
* @cvs-id $Id$
*
- * Copyright (C) 2005 Universitaet Karlsruhe
+ * Copyright (C) 2005-2006 Universitaet Karlsruhe
* Released under the GPL
*
* Driver for the chordal register allocator.
#include "config.h"
#endif
+#include <time.h>
+
#include "obst.h"
#include "pset.h"
#include "list.h"
#include <libcore/lc_timing.h>
#endif /* WITH_LIBCORE */
+#include "ircons_t.h"
#include "irmode_t.h"
#include "irgraph_t.h"
#include "irprintf_t.h"
#include "beifg_t.h"
#include "beifg_impl.h"
#include "benode_t.h"
+#include "bestatevent.h"
#include "bespillbelady.h"
#include "bespillmorgan.h"
#include "bespillslots.h"
+#include "bespilloptions.h"
#include "belower.h"
#ifdef WITH_ILP
BE_CH_VRFY_WARN,
};
+/** The name of the file where the statistics are put to. */
+static char stat_file_name[2048];
+
+/** Enable extreme live range splitting. */
+static int be_elr_split = 0;
+
+/** Assumed loop iteration count for execution frequency estimation. */
+static int be_loop_weight = 9;
+
+#ifdef WITH_LIBCORE
static be_ra_timer_t ra_timer = {
NULL,
NULL,
NULL,
NULL,
NULL,
+ NULL,
};
-#ifdef WITH_LIBCORE
static const lc_opt_enum_int_items_t spill_items[] = {
{ "morgan", BE_CH_SPILL_MORGAN },
{ "belady", BE_CH_SPILL_BELADY },
};
static const lc_opt_enum_int_items_t dump_items[] = {
- { "spill", BE_CH_DUMP_SPILL },
- { "live", BE_CH_DUMP_LIVE },
- { "color", BE_CH_DUMP_COLOR },
- { "copymin", BE_CH_DUMP_COPYMIN },
- { "ssadestr", BE_CH_DUMP_SSADESTR },
- { "tree", BE_CH_DUMP_TREE_INTV },
- { "constr", BE_CH_DUMP_CONSTR },
- { "lower", BE_CH_DUMP_LOWER },
- { "appel", BE_CH_DUMP_APPEL },
- { "all", BE_CH_DUMP_ALL },
+ { "spill", BE_CH_DUMP_SPILL },
+ { "live", BE_CH_DUMP_LIVE },
+ { "color", BE_CH_DUMP_COLOR },
+ { "copymin", BE_CH_DUMP_COPYMIN },
+ { "ssadestr", BE_CH_DUMP_SSADESTR },
+ { "tree", BE_CH_DUMP_TREE_INTV },
+ { "constr", BE_CH_DUMP_CONSTR },
+ { "lower", BE_CH_DUMP_LOWER },
+ { "spillslots", BE_CH_DUMP_SPILLSLOTS },
+ { "appel", BE_CH_DUMP_APPEL },
+ { "all", BE_CH_DUMP_ALL },
{ NULL, 0 }
};
&options.vrfy_option, be_ch_vrfy_items
};
-/** Enable extreme live range splitting. */
-static int be_elr_split = 0;
-
-/** Assumed loop iteration count for execution frequency estimation. */
-static int be_loop_weight = 9;
-
static const lc_opt_table_entry_t be_chordal_options[] = {
- LC_OPT_ENT_ENUM_INT ("spill", "spill method (belady, morgan or remat)", &spill_var),
- LC_OPT_ENT_ENUM_PTR ("ifg", "interference graph flavour (std, fast, clique, pointer, list, check)", &ifg_flavor_var),
- LC_OPT_ENT_ENUM_PTR ("perm", "perm lowering options (copy or swap)", &lower_perm_var),
+ LC_OPT_ENT_STR ("statfile", "the name of the statisctics file", stat_file_name, sizeof(stat_file_name)),
+ LC_OPT_ENT_ENUM_INT ("spill", "spill method", &spill_var),
+ LC_OPT_ENT_ENUM_PTR ("ifg", "interference graph flavour", &ifg_flavor_var),
+ LC_OPT_ENT_ENUM_PTR ("perm", "perm lowering options", &lower_perm_var),
LC_OPT_ENT_ENUM_MASK("dump", "select dump phases", &dump_var),
- LC_OPT_ENT_ENUM_PTR ("vrfy", "verify options (off, warn, assert)", &be_ch_vrfy_var),
+ LC_OPT_ENT_ENUM_PTR ("vrfy", "verify options", &be_ch_vrfy_var),
LC_OPT_ENT_BOOL ("elrsplit", "enable extreme live range splitting", &be_elr_split),
LC_OPT_ENT_INT ("loop_weight", "assumed amount of loop iterations for guessing the execution frequency", &be_loop_weight),
{ NULL }
};
+extern void be_spill_remat_register_options(lc_opt_entry_t *ent);
+
+
static void be_ra_chordal_register_options(lc_opt_entry_t *grp)
{
static int run_once = 0;
chordal_grp = lc_opt_get_grp(grp, "chordal");
lc_opt_add_table(chordal_grp, be_chordal_options);
- }
- co_register_options(chordal_grp);
- be_java_coal_register_options(chordal_grp);
+ co_register_options(chordal_grp);
+ be_java_coal_register_options(chordal_grp);
+#ifdef WITH_ILP
+ be_spill_remat_register_options(chordal_grp);
+#endif
+ be_spill_register_options(chordal_grp);
+ }
}
#endif /* WITH_LIBCORE */
const arch_env_t *aenv = cenv->birg->main_env->arch_env;
const ir_edge_t *edge, *ne;
ir_node *block;
+ ir_node *spill;
if (! be_is_Reload(irn))
return;
+ /* always use addressmode, it's good for x86 */
+#if 0
+ /* only use memory operands, if the reload is only used by 1 node */
+ if(get_irn_n_edges(irn) > 1)
+ return;
+#endif
+
+ spill = be_get_Reload_mem(irn);
block = get_nodes_block(irn);
foreach_out_edge_safe(irn, edge, ne) {
if (get_nodes_block(src) == block && arch_possible_memory_operand(aenv, src, pos)) {
DBG((cenv->dbg, LEVEL_3, "performing memory operand %+F at %+F\n", irn, src));
- arch_perform_memory_operand(aenv, src, irn, pos);
+ arch_perform_memory_operand(aenv, src, spill, pos);
}
}
}
/**
- * Performs chordal register allocation for each register class on given irg.
- *
- * @param bi Backend irg object
- * @return Structure containing timer for the single phases or NULL if no timing requested.
+ * Sorry for doing stats again...
*/
-static be_ra_timer_t *be_ra_chordal_main(const be_irg_t *bi)
+typedef struct _node_stat_t {
+ unsigned int n_phis; /**< Phis of the current register class. */
+ unsigned int n_mem_phis; /**< Memory Phis (Phis with spill operands). */
+ unsigned int n_copies; /**< Copies */
+ unsigned int n_perms; /**< Perms */
+ unsigned int n_spills; /**< Spill nodes */
+ unsigned int n_reloads; /**< Reloads */
+} node_stat_t;
+
+struct node_stat_walker {
+ node_stat_t *stat;
+ const be_chordal_env_t *cenv;
+ bitset_t *mem_phis;
+};
+
+static void node_stat_walker(ir_node *irn, void *data)
{
- const be_main_env_t *main_env = bi->main_env;
- const arch_isa_t *isa = arch_env_get_isa(main_env->arch_env);
- ir_graph *irg = bi->irg;
- be_options_t *main_opts = main_env->options;
- int splitted = 0;
+ struct node_stat_walker *env = data;
+ const arch_env_t *aenv = env->cenv->birg->main_env->arch_env;
- int j, m;
- be_chordal_env_t chordal_env;
+ if(arch_irn_consider_in_reg_alloc(aenv, env->cenv->cls, irn)) {
+
+ /* if the node is a normal phi */
+ if(is_Phi(irn))
+ env->stat->n_phis++;
+
+ else if(arch_irn_classify(aenv, irn) & arch_irn_class_spill)
+ ++env->stat->n_spills;
+
+ else if(arch_irn_classify(aenv, irn) & arch_irn_class_reload)
+ ++env->stat->n_reloads;
+
+ else if(arch_irn_classify(aenv, irn) & arch_irn_class_copy)
+ ++env->stat->n_copies;
+
+ else if(arch_irn_classify(aenv, irn) & arch_irn_class_perm)
+ ++env->stat->n_perms;
+ }
+
+ /* a mem phi is a PhiM with a mem phi operand or a Spill operand */
+ else if(is_Phi(irn) && get_irn_mode(irn) == mode_M) {
+ int i;
+
+ for(i = get_irn_arity(irn) - 1; i >= 0; --i) {
+ ir_node *op = get_irn_n(irn, i);
+
+ if((is_Phi(op) && bitset_contains_irn(env->mem_phis, op)) || (arch_irn_classify(aenv, op) & arch_irn_class_spill)) {
+ bitset_add_irn(env->mem_phis, irn);
+ env->stat->n_mem_phis++;
+ break;
+ }
+ }
+ }
+}
+
+static void node_stats(const be_chordal_env_t *cenv, node_stat_t *stat)
+{
+ struct node_stat_walker env;
+
+ memset(stat, 0, sizeof(stat[0]));
+ env.cenv = cenv;
+ env.mem_phis = bitset_irg_malloc(cenv->irg);
+ env.stat = stat;
+ irg_walk_graph(cenv->irg, NULL, node_stat_walker, &env);
+ bitset_free(env.mem_phis);
+}
+
+static void insn_count_walker(ir_node *irn, void *data)
+{
+ int *cnt = data;
+
+ switch(get_irn_opcode(irn)) {
+ case iro_Proj:
+ case iro_Phi:
+ case iro_Start:
+ case iro_End:
+ break;
+ default:
+ (*cnt)++;
+ }
+}
+
+static unsigned int count_insns(ir_graph *irg)
+{
+ int cnt = 0;
+ irg_walk_graph(irg, insn_count_walker, NULL, &cnt);
+ return cnt;
+}
+#ifdef WITH_LIBCORE
+/**
+ * Initialize all timers.
+ */
+static void be_init_timer(be_options_t *main_opts)
+{
if (main_opts->timing == BE_TIME_ON) {
- ra_timer.t_prolog = lc_timer_register("ra_prolog", "regalloc prolog");
- ra_timer.t_epilog = lc_timer_register("ra_epilog", "regalloc epilog");
- ra_timer.t_live = lc_timer_register("ra_liveness", "be liveness");
- ra_timer.t_spill = lc_timer_register("ra_spill", "spiller");
- ra_timer.t_color = lc_timer_register("ra_color", "graph coloring");
- ra_timer.t_ifg = lc_timer_register("ra_ifg", "interference graph");
- ra_timer.t_copymin = lc_timer_register("ra_copymin", "copy minimization");
- ra_timer.t_ssa = lc_timer_register("ra_ssadestr", "ssa destruction");
- ra_timer.t_verify = lc_timer_register("ra_verify", "graph verification");
- ra_timer.t_other = lc_timer_register("ra_other", "other time");
+ ra_timer.t_prolog = lc_timer_register("ra_prolog", "regalloc prolog");
+ ra_timer.t_epilog = lc_timer_register("ra_epilog", "regalloc epilog");
+ ra_timer.t_live = lc_timer_register("ra_liveness", "be liveness");
+ ra_timer.t_spill = lc_timer_register("ra_spill", "spiller");
+ ra_timer.t_spillslots = lc_timer_register("ra_spillslots", "spillslots");
+ ra_timer.t_color = lc_timer_register("ra_color", "graph coloring");
+ ra_timer.t_ifg = lc_timer_register("ra_ifg", "interference graph");
+ ra_timer.t_copymin = lc_timer_register("ra_copymin", "copy minimization");
+ ra_timer.t_ssa = lc_timer_register("ra_ssadestr", "ssa destruction");
+ ra_timer.t_verify = lc_timer_register("ra_verify", "graph verification");
+ ra_timer.t_other = lc_timer_register("ra_other", "other time");
LC_STOP_AND_RESET_TIMER(ra_timer.t_prolog);
LC_STOP_AND_RESET_TIMER(ra_timer.t_epilog);
LC_STOP_AND_RESET_TIMER(ra_timer.t_live);
LC_STOP_AND_RESET_TIMER(ra_timer.t_spill);
+ LC_STOP_AND_RESET_TIMER(ra_timer.t_spillslots);
LC_STOP_AND_RESET_TIMER(ra_timer.t_color);
LC_STOP_AND_RESET_TIMER(ra_timer.t_ifg);
LC_STOP_AND_RESET_TIMER(ra_timer.t_copymin);
LC_STOP_AND_RESET_TIMER(ra_timer.t_verify);
LC_STOP_AND_RESET_TIMER(ra_timer.t_other);
}
+}
-#define BE_TIMER_PUSH(timer) \
- if (main_opts->timing == BE_TIME_ON) { \
- int res = lc_timer_push(timer); \
- if (options.vrfy_option == BE_CH_VRFY_ASSERT) \
- assert(res && "Timer already on stack, cannot be pushed twice."); \
- else if (options.vrfy_option == BE_CH_VRFY_WARN && ! res) \
- fprintf(stderr, "Timer %s already on stack, cannot be pushed twice.\n", \
- lc_timer_get_name(timer)); \
+#define BE_TIMER_INIT(main_opts) be_init_timer(main_opts)
+
+#define BE_TIMER_PUSH(timer) \
+ if (main_opts->timing == BE_TIME_ON) { \
+ if (! lc_timer_push(timer)) { \
+ if (options.vrfy_option == BE_CH_VRFY_ASSERT) \
+ assert(!"Timer already on stack, cannot be pushed twice."); \
+ else if (options.vrfy_option == BE_CH_VRFY_WARN) \
+ fprintf(stderr, "Timer %s already on stack, cannot be pushed twice.\n", \
+ lc_timer_get_name(timer)); \
+ } \
}
#define BE_TIMER_POP(timer) \
if (main_opts->timing == BE_TIME_ON) { \
lc_timer_get_name(tmp), lc_timer_get_name(timer)); \
timer = tmp; \
}
+#else
+
+#define BE_TIMER_INIT(main_opts)
+#define BE_TIMER_PUSH(timer)
+#define BE_TIMER_POP(timer)
+
+#endif /* WITH_LIBCORE */
+enum {
+ STAT_TAG_FILE = 0,
+ STAT_TAG_TIME = 1,
+ STAT_TAG_IRG = 2,
+ STAT_TAG_CLS = 3,
+ STAT_TAG_LAST
+};
+
+/**
+ * Performs chordal register allocation for each register class on given irg.
+ *
+ * @param bi Backend irg object
+ * @return Structure containing timer for the single phases or NULL if no timing requested.
+ */
+static be_ra_timer_t *be_ra_chordal_main(const be_irg_t *bi)
+{
+ const be_main_env_t *main_env = bi->main_env;
+ const arch_isa_t *isa = arch_env_get_isa(main_env->arch_env);
+ ir_graph *irg = bi->irg;
+ be_options_t *main_opts = main_env->options;
+ int splitted = 0;
+ FILE *stat_file = NULL;
+
+ char time_str[32];
+ char irg_name[128];
+ int j, m, line;
+ be_chordal_env_t chordal_env;
+ const char *stat_tags[STAT_TAG_LAST];
+
+ /* if we want to do some statistics, push the environment. */
+ if(strlen(stat_file_name) > 0 && (stat_file = fopen(stat_file_name, "at")) != NULL) {
+
+ /* initialize the statistics tags */
+ ir_snprintf(time_str, sizeof(time_str),"%u", time(NULL));
+ ir_snprintf(irg_name, sizeof(irg_name), "%F", irg);
+
+ stat_tags[STAT_TAG_FILE] = be_retrieve_dbg_info(get_entity_dbg_info(get_irg_entity(irg)), &line);
+ stat_tags[STAT_TAG_TIME] = time_str;
+ stat_tags[STAT_TAG_IRG] = irg_name;
+ stat_tags[STAT_TAG_CLS] = "<all>";
+
+ be_stat_ev_push(stat_tags, STAT_TAG_LAST, stat_file);
+ }
+
+ BE_TIMER_INIT(main_opts);
BE_TIMER_PUSH(ra_timer.t_other);
BE_TIMER_PUSH(ra_timer.t_prolog);
chordal_env.irg = irg;
chordal_env.birg = bi;
chordal_env.dom_front = be_compute_dominance_frontiers(irg);
- chordal_env.exec_freq = compute_execfreq(irg, be_loop_weight);
+ chordal_env.exec_freq = bi->execfreqs;
+ /*compute_execfreq(irg, be_loop_weight);*/
chordal_env.lv = be_liveness(irg);
FIRM_DBG_REGISTER(chordal_env.dbg, "firm.be.chordal");
BE_TIMER_POP(ra_timer.t_prolog);
+ be_stat_ev("insns_before", count_insns(irg));
+
/* Perform the following for each register class. */
for (j = 0, m = arch_isa_get_n_reg_class(isa); j < m; ++j) {
+ node_stat_t node_stat;
+
chordal_env.cls = arch_isa_get_reg_class(isa, j);
chordal_env.border_heads = pmap_create();
chordal_env.ignore_colors = bitset_malloc(chordal_env.cls->n_regs);
+ stat_tags[STAT_TAG_CLS] = chordal_env.cls->name;
+
+ if(stat_file) {
+ be_stat_ev_push(stat_tags, STAT_TAG_LAST, stat_file);
+
+ /* perform some node statistics. */
+ node_stats(&chordal_env, &node_stat);
+ be_stat_ev("phis_before_spill", node_stat.n_phis);
+ }
+
/* put all ignore registers into the ignore register set. */
put_ignore_colors(&chordal_env);
BE_TIMER_POP(ra_timer.t_spill);
- DBG((chordal_env.dbg, LEVEL_1, "spill costs for %+F in regclass %s: %g\n",
- irg,
- chordal_env.cls->name,
- get_irg_spill_cost(&chordal_env))
- );
+ if(stat_file) {
+ node_stats(&chordal_env, &node_stat);
+ be_stat_ev("phis_after_spill", node_stat.n_phis);
+ be_stat_ev("mem_phis", node_stat.n_mem_phis);
+ be_stat_ev("reloads", node_stat.n_reloads);
+ be_stat_ev("spills", node_stat.n_spills);
+ }
+
+ DBG((chordal_env.dbg, LEVEL_1, "spill costs for %+F in regclass %s: %g\n",irg, chordal_env.cls->name, get_irg_spill_cost(&chordal_env)));
dump(BE_CH_DUMP_SPILL, irg, chordal_env.cls, "-spill", dump_ir_block_graph_sched);
+
check_for_memory_operands(&chordal_env);
+
be_abi_fix_stack_nodes(bi->abi, chordal_env.lv);
BE_TIMER_PUSH(ra_timer.t_verify);
/* verify schedule and register pressure */
if (options.vrfy_option == BE_CH_VRFY_WARN) {
be_verify_schedule(irg);
- be_verify_register_pressure(chordal_env.birg->main_env->arch_env, chordal_env.cls, irg);
+ be_verify_register_pressure(chordal_env.birg, chordal_env.cls, irg);
}
else if (options.vrfy_option == BE_CH_VRFY_ASSERT) {
assert(be_verify_schedule(irg) && "Schedule verification failed");
- assert(be_verify_register_pressure(chordal_env.birg->main_env->arch_env, chordal_env.cls, irg)
+ assert(be_verify_register_pressure(chordal_env.birg, chordal_env.cls, irg)
&& "Register pressure verification failed");
}
BE_TIMER_POP(ra_timer.t_verify);
}
BE_TIMER_POP(ra_timer.t_ifg);
+ if(stat_file) {
+ be_ifg_stat_t stat;
+ be_ifg_stat(&chordal_env, &stat);
+ be_stat_ev("ifg_nodes", stat.n_nodes);
+ be_stat_ev("ifg_edges", stat.n_edges);
+ be_stat_ev("ifg_comps", stat.n_comps);
+ }
+
BE_TIMER_PUSH(ra_timer.t_verify);
- if (options.vrfy_option != BE_CH_VRFY_OFF)
- be_ra_chordal_check(&chordal_env);
+ if (options.vrfy_option != BE_CH_VRFY_OFF) {
+ //be_ra_chordal_check(&chordal_env);
+ }
BE_TIMER_POP(ra_timer.t_verify);
+ if(stat_file) {
+ node_stats(&chordal_env, &node_stat);
+ be_stat_ev("perms_before_coal", node_stat.n_perms);
+ be_stat_ev("copies_before_coal", node_stat.n_copies);
+ }
+
/* copy minimization */
BE_TIMER_PUSH(ra_timer.t_copymin);
co_driver(&chordal_env);
BE_TIMER_POP(ra_timer.t_copymin);
+
dump(BE_CH_DUMP_COPYMIN, irg, chordal_env.cls, "-copymin", dump_ir_block_graph_sched);
BE_TIMER_PUSH(ra_timer.t_verify);
- if (options.vrfy_option != BE_CH_VRFY_OFF)
- be_ra_chordal_check(&chordal_env);
+ if (options.vrfy_option != BE_CH_VRFY_OFF) {
+ //be_ra_chordal_check(&chordal_env);
+ }
BE_TIMER_POP(ra_timer.t_verify);
BE_TIMER_PUSH(ra_timer.t_ssa);
BE_TIMER_PUSH(ra_timer.t_verify);
if (options.vrfy_option != BE_CH_VRFY_OFF) {
be_ssa_destruction_check(&chordal_env);
- be_ra_chordal_check(&chordal_env);
+ //be_ra_chordal_check(&chordal_env);
}
BE_TIMER_POP(ra_timer.t_verify);
be_ifg_free(chordal_env.ifg);
pmap_destroy(chordal_env.border_heads);
bitset_free(chordal_env.ignore_colors);
+
+ if(stat_file) {
+ node_stats(&chordal_env, &node_stat);
+ be_stat_ev("perms_after_coal", node_stat.n_perms);
+ be_stat_ev("copies_after_coal", node_stat.n_copies);
+ }
+
+ be_stat_ev_pop();
}
+ BE_TIMER_PUSH(ra_timer.t_spillslots);
+
be_coalesce_spillslots(&chordal_env);
+ dump(BE_CH_DUMP_SPILLSLOTS, irg, NULL, "-spillslots", dump_ir_block_graph_sched);
+
+ BE_TIMER_POP(ra_timer.t_spillslots);
+
+ BE_TIMER_PUSH(ra_timer.t_verify);
+
+ /* verify spillslots */
+ if (options.vrfy_option == BE_CH_VRFY_WARN) {
+ be_verify_spillslots(main_env->arch_env, irg);
+ }
+ else if (options.vrfy_option == BE_CH_VRFY_ASSERT) {
+ assert(be_verify_spillslots(main_env->arch_env, irg) && "Spillslot verification failed");
+ }
+ BE_TIMER_POP(ra_timer.t_verify);
BE_TIMER_PUSH(ra_timer.t_epilog);
obstack_free(&chordal_env.obst, NULL);
be_free_dominance_frontiers(chordal_env.dom_front);
be_liveness_free(chordal_env.lv);
- free_execfreq(chordal_env.exec_freq);
+ //free_execfreq(chordal_env.exec_freq);
BE_TIMER_POP(ra_timer.t_epilog);
BE_TIMER_POP(ra_timer.t_other);
-#undef BE_TIMER_PUSH
-#undef BE_TIMER_POP
+ be_stat_ev("insns_after", count_insns(irg));
+ be_stat_ev_pop();
+
+ if(stat_file)
+ fclose(stat_file);
+#ifdef WITH_LIBCORE
return main_opts->timing == BE_TIME_ON ? &ra_timer : NULL;
+#endif /* WITH_LIBCORE */
+ return NULL;
}
const be_ra_t be_ra_chordal_allocator = {
#ifdef WITH_LIBCORE
be_ra_chordal_register_options,
+#else
+ NULL,
#endif
- be_ra_chordal_main
+ be_ra_chordal_main,
};