extended lpp-matrix statistics
[libfirm] / ir / be / beilpsched.c
index 08ddd95..35ea3a1 100644 (file)
 #include "benode_t.h"
 #include "besched_t.h"
 #include "beilpsched.h"
+#include "beutil.h"
 
 typedef struct _ilpsched_options_t {
+       unsigned regpress;
        unsigned limit_dead;
        unsigned time_limit;
        char     log_file[1024];
@@ -71,6 +73,7 @@ typedef struct _ilp_var_types_t {
 typedef struct _ilpsched_node_attr_t {
        unsigned asap;                     /**< The ASAP scheduling control step */
        unsigned alap;                     /**< The ALAP scheduling control step */
+       unsigned latency;                  /**< Latency of this node (needed for sorting) */
        unsigned sched_point;              /**< the step in which the node is finally scheduled */
        unsigned visit_idx;                /**< Index of the node having visited this node last */
        unsigned consumer_idx;             /**< Index of the node having counted this node as consumer last */
@@ -129,16 +132,13 @@ typedef struct {
 #define get_ilpsched_block_attr(block)      (&(block)->attr.block_attr)
 #define get_ilpsched_node_attr(node)        (&(node)->attr.node_attr)
 
-/* iterate over a list of ir_nodes linked by link field */
-#define foreach_linked_irns(head, iter) for ((iter) = (head); (iter); (iter) = get_irn_link((iter)))
-
 /* check if node is considered for ILP scheduling */
 #define consider_for_sched(isa, irn) \
        (! (is_Block(irn)            ||  \
                is_normal_Proj(isa, irn) ||  \
                is_Phi(irn)              ||  \
                is_NoMem(irn)            ||  \
-               is_Jmp(irn)              ||  \
+               is_Unknown(irn)          ||  \
                is_End(irn)                  \
                ))
 
@@ -171,6 +171,7 @@ typedef struct {
 
 /* option variable */
 static ilpsched_options_t ilp_opts = {
+       1,     /* default is with register pressure constraints */
        70,    /* if we have more than 70 nodes: use alive nodes constraint */
        300,   /* 300 sec per block time limit */
        ""     /* no log file */
@@ -179,6 +180,7 @@ static ilpsched_options_t ilp_opts = {
 #ifdef WITH_LIBCORE
 /* ILP options */
 static const lc_opt_table_entry_t ilpsched_option_table[] = {
+       LC_OPT_ENT_BOOL("regpress",  "Use register pressure constraints", &ilp_opts.regpress),
        LC_OPT_ENT_INT("limit_dead", "Upto how many nodes the dead node constraint should be used", &ilp_opts.limit_dead),
        LC_OPT_ENT_INT("time_limit", "ILP time limit per block", &ilp_opts.time_limit),
        LC_OPT_ENT_STR("lpp_log",    "LPP logfile (stderr and stdout are supported)", ilp_opts.log_file, sizeof(ilp_opts.log_file)),
@@ -235,7 +237,12 @@ static int cmp_ilpsched_irn(const void *a, const void *b) {
                        return 1;
                if (heights_reachable_in_block(glob_heights, irn_b, irn_a))
                        return -1;
-               return 0;
+
+               /*
+                       Ok, timestep is equal and the nodes are parallel,
+                       so check latency and schedule high latency first.
+               */
+               return QSORT_CMP(n2_a->latency, n1_a->latency);
        }
        else
                return QSORT_CMP(n1_a->sched_point, n2_a->sched_point);
@@ -471,8 +478,9 @@ static void calculate_irn_asap(ir_node *irn, void *walk_env) {
                        ilpsched_node_attr_t *pna       = get_ilpsched_node_attr(pred_node);
                        unsigned             lat;
 
-                       lat      = fixed_latency(env->sel, pred, env->block_env);
-                       na->asap = MAX(na->asap, pna->asap + lat);
+                       lat         = fixed_latency(env->sel, pred, env->block_env);
+                       na->latency = lat;
+                       na->asap    = MAX(na->asap, pna->asap + lat);
                }
        }
 
@@ -482,7 +490,7 @@ static void calculate_irn_asap(ir_node *irn, void *walk_env) {
 
        set_irn_link(irn, ba->head_ilp_nodes);
        ba->head_ilp_nodes = irn;
-       ba->max_steps      = fixed_latency(env->sel, irn, env->block_env);
+       ba->max_steps     += fixed_latency(env->sel, irn, env->block_env);
 
        DB((env->dbg, LEVEL_2, "%u\n", na->asap));
 }
@@ -752,7 +760,7 @@ static void apply_solution(be_ilpsched_env_t *env, lpp_t *lpp, ir_node *block) {
                                        if (! LPP_VALUE_IS_0(val)) {
                                                na->sched_point = t;
                                                ARR_APP1(be_ilpsched_irn_t *, sched_nodes, node);
-                                               DBG((env->dbg, LEVEL_1, "Schedpoint of %+F is %u at unit type %s\n",
+                                               DBG((env->dbg, LEVEL_2, "Schedpoint of %+F is %u at unit type %s\n",
                                                        irn, t, na->type_info[tp_idx].tp->name));
                                                found = 1;
                                        }
@@ -760,10 +768,9 @@ static void apply_solution(be_ilpsched_env_t *env, lpp_t *lpp, ir_node *block) {
                        }
                }
 
-               glob_heights = heights_new(env->irg);
+               glob_heights = env->height;
                /* sort nodes ascending by scheduling time step */
                qsort(sched_nodes, ARR_LEN(sched_nodes), sizeof(sched_nodes[0]), cmp_ilpsched_irn);
-               heights_free(glob_heights);
        }
 
        /* make all Phis ready and remember the single cf op */
@@ -779,6 +786,7 @@ static void apply_solution(be_ilpsched_env_t *env, lpp_t *lpp, ir_node *block) {
                        case iro_End:
                        case iro_Proj:
                        case iro_Bad:
+                       case iro_Unknown:
                                break;
                        default:
                                if (is_cfop(irn)) {
@@ -792,7 +800,8 @@ static void apply_solution(be_ilpsched_env_t *env, lpp_t *lpp, ir_node *block) {
        /* add all nodes from list */
        for (i = 0, l = ARR_LEN(sched_nodes); i < l; ++i) {
                ilpsched_node_attr_t *na = get_ilpsched_node_attr(sched_nodes[i]);
-               add_to_sched(env, block, sched_nodes[i]->irn, na->sched_point);
+               if (sched_nodes[i]->irn != cfop)
+                       add_to_sched(env, block, sched_nodes[i]->irn, na->sched_point);
        }
 
        /* schedule control flow node if not already done */
@@ -1603,6 +1612,7 @@ static void create_pressure_alive_constraint(be_ilpsched_env_t *env, lpp_t *lpp,
                num_cst, ilp_timer_elapsed_usec(t_cst) / 1000000.0));
 }
 
+#if 0
 static void create_proj_keep_constraints(be_ilpsched_env_t *env, lpp_t *lpp, be_ilpsched_irn_t *block_node) {
        char                  buf[1024];
        ir_node               *irn;
@@ -1676,6 +1686,7 @@ static void create_proj_keep_constraints(be_ilpsched_env_t *env, lpp_t *lpp, be_
        DBG((env->dbg, LEVEL_1, "\t%u Proj and Keep constraints (%g sec)\n",
                num_cst, ilp_timer_elapsed_usec(t_cst) / 1000000.0));
 }
+#endif
 
 /***************************************************
  *  _____ _      _____                    _
@@ -1697,6 +1708,7 @@ static void create_ilp(ir_node *block, void *walk_env) {
        FILE                  *logfile       = NULL;
        lpp_t                 *lpp           = NULL;
        struct obstack        var_obst;
+       char                  name[1024];
 
        DBG((env->dbg, 255, "\n\n\n=========================================\n"));
        DBG((env->dbg, 255, "  ILP Scheduling for %+F\n", block));
@@ -1710,22 +1722,24 @@ static void create_ilp(ir_node *block, void *walk_env) {
 
        /* if we have less than two interesting nodes, there is no need to create the ILP */
        if (ba->n_interesting_nodes > 1) {
-               double fact_var        = ba->n_interesting_nodes > 25 ? 1.1 : 1.2;
-               double fact_cst        = ba->n_interesting_nodes > 25 ? 0.7 : 1.5;
+               double fact_var        = ba->n_interesting_nodes > 25 ? 2.3 : 3;
+               double fact_cst        = ba->n_interesting_nodes > 25 ? 3   : 4.5;
                int    base_num        = ba->n_interesting_nodes * ba->n_interesting_nodes;
                int    estimated_n_var = (int)((double)base_num * fact_var);
                int    estimated_n_cst = (int)((double)base_num * fact_cst);
 
-               DBG((env->dbg, LEVEL_1, "Creating LPP with estimed numbers: %d vars, %d cst\n",
+               DBG((env->dbg, LEVEL_1, "Creating LPP with estimated numbers: %d vars, %d cst\n",
                        estimated_n_var, estimated_n_cst));
 
                /* set up the LPP object */
+               snprintf(name, sizeof(name), "ilp scheduling IRG %s", get_entity_ld_name(get_irg_entity(env->irg)));
+
                lpp = new_lpp_userdef(
-                       "be ilp scheduling",
+                       (const char *)name,
                        lpp_minimize,
-                       estimated_n_cst + 1,  /* num vars */
-                       estimated_n_cst + 20, /* num cst */
-                       1.2);                 /* grow factor */
+                       estimated_n_cst,     /* num vars */
+                       estimated_n_cst + 1, /* num cst */
+                       1.3);                /* grow factor */
                obstack_init(&var_obst);
 
                /* create ILP variables */
@@ -1737,19 +1751,22 @@ static void create_ilp(ir_node *block, void *walk_env) {
                create_ressource_constraints(env, lpp, block_node);
                create_bundle_constraints(env, lpp, block_node);
                //create_proj_keep_constraints(env, lpp, block_node);
-               if (ba->n_interesting_nodes > env->opts->limit_dead) {
-                       create_alive_nodes_constraint(env, lpp, block_node);
-                       create_pressure_alive_constraint(env, lpp, block_node);
-               } else {
-                       create_dying_nodes_constraint(env, lpp, block_node);
-                       create_pressure_dead_constraint(env, lpp, block_node);
+
+               if (env->opts->regpress) {
+                       if (ba->n_interesting_nodes > env->opts->limit_dead) {
+                               create_alive_nodes_constraint(env, lpp, block_node);
+                               create_pressure_alive_constraint(env, lpp, block_node);
+                       } else {
+                               create_dying_nodes_constraint(env, lpp, block_node);
+                               create_pressure_dead_constraint(env, lpp, block_node);
+                       }
                }
 
                DBG((env->dbg, LEVEL_1, "ILP to solve: %u variables, %u constraints\n", lpp->var_next, lpp->cst_next));
 
                /* debug stuff, dump lpp when debugging is on  */
                DEBUG_ONLY(
-                       if (firm_dbg_get_mask(env->dbg) > 0) {
+                       if (firm_dbg_get_mask(env->dbg) > 1) {
                                char buf[1024];
                                FILE *f;
 
@@ -1805,6 +1822,7 @@ static void create_ilp(ir_node *block, void *walk_env) {
                DBG((env->dbg, LEVEL_1, "\nSolution:\n"));
                DBG((env->dbg, LEVEL_1, "\tsend time: %g sec\n", lpp->send_time / 1000000.0));
                DBG((env->dbg, LEVEL_1, "\treceive time: %g sec\n", lpp->recv_time / 1000000.0));
+               DBG((env->dbg, LEVEL_1, "\tmatrix: %u elements, density %.2f%%, size %.2fMB\n", lpp->n_elems, lpp->density, (double)lpp->matrix_mem / 1024.0 / 1024.0));
                DBG((env->dbg, LEVEL_1, "\titerations: %d\n", lpp->iterations));
                DBG((env->dbg, LEVEL_1, "\tsolution time: %g\n", lpp->sol_time));
                DBG((env->dbg, LEVEL_1, "\tobjective function: %g\n", LPP_VALUE_IS_0(lpp->objval) ? 0.0 : lpp->objval));
@@ -1834,7 +1852,7 @@ void be_ilp_sched(const be_irg_t *birg) {
 
        FIRM_DBG_REGISTER(env.dbg, "firm.be.sched.ilp");
 
-       //firm_dbg_set_mask(env.dbg, 31);
+//     firm_dbg_set_mask(env.dbg, 1);
 
        env.irg_env    = be_ilp_sched_init_irg_ilp_schedule(sel, birg->irg);
        env.sel        = sel;
@@ -1865,9 +1883,6 @@ void be_ilp_sched(const be_irg_t *birg) {
        /* We refine the {ASAP(n), ALAP(n)} interval and fix the time steps for Projs and Keeps */
        irg_walk_in_or_dep_blkwise_graph(env.irg, NULL, refine_asap_alap_times, &env);
 
-       /* we don't need this information any longer */
-       heights_free(env.height);
-
        /* perform ILP scheduling */
        irg_block_walk_graph(env.irg, clear_unwanted_data, create_ilp, &env);
 
@@ -1882,6 +1897,7 @@ void be_ilp_sched(const be_irg_t *birg) {
 
        /* free all allocated object */
        phase_free(&env.ph);
+       heights_free(env.height);
 
        /* notify backend */
        be_ilp_sched_finish_irg_ilp_schedule(sel, birg->irg, env.irg_env);
@@ -1891,21 +1907,18 @@ void be_ilp_sched(const be_irg_t *birg) {
 /**
  * Register ILP scheduler options.
  */
-void ilpsched_register_options(lc_opt_entry_t *grp) {
-       static int     run_once = 0;
-       lc_opt_entry_t *sched_grp;
-
-       if (! run_once) {
-               run_once  = 1;
-               sched_grp = lc_opt_get_grp(grp, "ilpsched");
+void be_init_ilpsched(void)
+{
+       lc_opt_entry_t *be_grp = lc_opt_get_grp(firm_opt_get_root(), "be");
+       lc_opt_entry_t *sched_grp = lc_opt_get_grp(be_grp, "ilpsched");
 
-               lc_opt_add_table(sched_grp, ilpsched_option_table);
-       }
+       lc_opt_add_table(sched_grp, ilpsched_option_table);
 }
 #endif /* WITH_LIBCORE */
 
 #else /* WITH_ILP */
 
-static int some_picky_compiler_do_not_allow_empty_files;
+static INLINE void some_picky_compiler_do_not_allow_empty_files(void)
+{}
 
 #endif /* WITH_ILP */