added option to select between schedulers (list or ilp)
[libfirm] / ir / be / bespill.c
index 40339e8..154a3a1 100644 (file)
 #include "bechordal_t.h"
 #include "bejavacoal.h"
 #include "benodesets.h"
+#include "bespilloptions.h"
+#include "bestatevent.h"
 
 // only rematerialise when costs are less than REMAT_COST_LIMIT
 // TODO determine a good value here...
-#define REMAT_COST_LIMIT       20
+#define REMAT_COST_LIMIT       10
 
 typedef struct _reloader_t reloader_t;
 
@@ -64,8 +66,10 @@ struct _spill_env_t {
        const arch_env_t *arch_env;
        const be_chordal_env_t *chordal_env;
        struct obstack obst;
-       set *spills;                            /**< all spill_info_t's, which must be placed */
-       pset *mem_phis;                         /**< set of all special spilled phis. allocated and freed separately */
+       int spill_cost;     /**< the cost of a single spill node */
+       int reload_cost;    /**< the cost of a reload node */
+       set *spills;        /**< all spill_info_t's, which must be placed */
+       pset *mem_phis;     /**< set of all special spilled phis. allocated and freed separately */
 
        DEBUG_ONLY(firm_dbg_module_t *dbg;)
 };
@@ -79,6 +83,19 @@ static int cmp_spillinfo(const void *x, const void *y, size_t size) {
        return xx->spilled_node != yy->spilled_node;
 }
 
+/**
+ * Returns spill info for a specific value (returns NULL if the info doesn't
+ * exist yet)
+ */
+static spill_info_t *find_spillinfo(const spill_env_t *env, ir_node *value) {
+       spill_info_t info;
+       int hash = nodeset_hash(value);
+
+       info.spilled_node = value;
+
+       return set_find(env->spills, &info, sizeof(info), hash);
+}
+
 /**
  * Returns spill info for a specific value (the value that is to be spilled)
  */
@@ -114,6 +131,9 @@ spill_env_t *be_new_spill_env(const be_chordal_env_t *chordal_env) {
        env->chordal_env        = chordal_env;
        env->arch_env       = env->chordal_env->birg->main_env->arch_env;
        env->mem_phis           = pset_new_ptr_default();
+       // TODO, ask backend about costs...
+       env->spill_cost     = 8;
+       env->reload_cost    = 5;
        obstack_init(&env->obst);
        return env;
 }
@@ -126,7 +146,7 @@ void be_delete_spill_env(spill_env_t *env) {
        free(env);
 }
 
-/**
+/*
  *  ____  _                  ____      _                 _
  * |  _ \| | __ _  ___ ___  |  _ \ ___| | ___   __ _  __| |___
  * | |_) | |/ _` |/ __/ _ \ | |_) / _ \ |/ _ \ / _` |/ _` / __|
@@ -159,7 +179,7 @@ void be_add_reload(spill_env_t *env, ir_node *to_spill, ir_node *before) {
        info->reloaders = rel;
 }
 
-void be_add_reload_on_edge(spill_env_t *env, ir_node *to_spill, ir_node *block, int pos) {
+static ir_node *get_reload_insertion_point(ir_node *block, int pos) {
        ir_node *predblock, *last;
 
        /* simply add the reload to the beginning of the block if we only have 1 predecessor
@@ -167,8 +187,7 @@ void be_add_reload_on_edge(spill_env_t *env, ir_node *to_spill, ir_node *block,
         */
        if(get_Block_n_cfgpreds(block) == 1) {
                assert(!is_Phi(sched_first(block)));
-               be_add_reload(env, to_spill, sched_first(block));
-               return;
+               return sched_first(block);
        }
 
        /* We have to reload the value in pred-block */
@@ -180,10 +199,22 @@ void be_add_reload_on_edge(spill_env_t *env, ir_node *to_spill, ir_node *block,
                last = sched_prev(last);
                assert(!sched_is_end(last));
        }
-       assert(is_cfop(last));
+
+       if(!is_cfop(last)) {
+               ir_graph *irg = get_irn_irg(block);
+               ir_node *startblock = get_irg_start_block(irg);
+
+               // last node must be a cfop, only exception is the start block
+               assert(last     == startblock);
+       }
 
        // add the reload before the (cond-)jump
-       be_add_reload(env, to_spill, last);
+       return last;
+}
+
+void be_add_reload_on_edge(spill_env_t *env, ir_node *to_spill, ir_node *block, int pos) {
+       ir_node *before = get_reload_insertion_point(block, pos);
+       be_add_reload(env, to_spill, before);
 }
 
 void be_spill_phi(spill_env_t *env, ir_node *node) {
@@ -467,7 +498,7 @@ static int check_remat_conditions_costs(spill_env_t *env, ir_node *spilled, ir_n
 }
 
 static int check_remat_conditions(spill_env_t *env, ir_node *spilled, ir_node *reloader) {
-       int costs = check_remat_conditions_costs(env, spilled, reloader, 1);
+       int costs = check_remat_conditions_costs(env, spilled, reloader, 0);
 
        return costs < REMAT_COST_LIMIT;
 }
@@ -514,6 +545,29 @@ static ir_node *do_remat(spill_env_t *env, ir_node *spilled, ir_node *reloader)
        return res;
 }
 
+int be_get_reload_costs(spill_env_t *env, ir_node *to_spill, ir_node *before) {
+       spill_info_t *spill_info;
+
+       if(be_do_remats) {
+               // is the node rematerializable?
+               int costs = check_remat_conditions_costs(env, to_spill, before, 0);
+               if(costs < REMAT_COST_LIMIT)
+                       return costs;
+       }
+
+       // do we already have a spill?
+       spill_info = find_spillinfo(env, to_spill);
+       if(spill_info != NULL && spill_info->spill != NULL)
+               return env->reload_cost;
+
+       return env->spill_cost + env->reload_cost;
+}
+
+int be_get_reload_costs_on_edge(spill_env_t *env, ir_node *to_spill, ir_node *block, int pos) {
+       ir_node *before = get_reload_insertion_point(block, pos);
+       return be_get_reload_costs(env, to_spill, before);
+}
+
 /*
  *  ___                     _     ____      _                 _
  * |_ _|_ __  ___  ___ _ __| |_  |  _ \ ___| | ___   __ _  __| |___
@@ -526,6 +580,9 @@ static ir_node *do_remat(spill_env_t *env, ir_node *spilled, ir_node *reloader)
 void be_insert_spills_reloads(spill_env_t *env) {
        const arch_env_t *arch_env = env->arch_env;
        spill_info_t *si;
+       int remats = 0;
+       int reloads = 0;
+       int spills = 0;
 
        /* process each spilled node */
        for(si = set_first(env->spills); si; si = set_next(env->spills)) {
@@ -537,14 +594,19 @@ void be_insert_spills_reloads(spill_env_t *env) {
                for(rld = si->reloaders; rld; rld = rld->next) {
                        ir_node *new_val;
 
-                       if (check_remat_conditions(env, si->spilled_node, rld->reloader)) {
+                       if (be_do_remats && check_remat_conditions(env, si->spilled_node, rld->reloader)) {
                                new_val = do_remat(env, si->spilled_node, rld->reloader);
+                               remats++;
                        } else {
                                /* make sure we have a spill */
-                               spill_node(env, si);
+                               if(si->spill == NULL) {
+                                       spill_node(env, si);
+                                       spills++;
+                               }
 
-                               /* do a reload */
+                               /* create a reload */
                                new_val = be_reload(arch_env, env->cls, rld->reloader, mode, si->spill);
+                               reloads++;
                        }
 
                        DBG((env->dbg, LEVEL_1, " %+F of %+F before %+F\n", new_val, si->spilled_node, rld->reloader));
@@ -562,6 +624,12 @@ void be_insert_spills_reloads(spill_env_t *env) {
                si->reloaders = NULL;
        }
 
+       if(be_stat_ev_is_active()) {
+               be_stat_ev("spill_spills", spills);
+               be_stat_ev("spill_reloads", reloads);
+               be_stat_ev("spill_remats", remats);
+       }
+
        be_remove_dead_nodes_from_schedule(env->chordal_env->irg);
        be_liveness_recompute(env->chordal_env->lv);
 }