remove morgan spiller, it's unused and the coming bespill changes won't support morga...
[libfirm] / ir / be / beilpsched.c
index b507a5a..bf508a3 100644 (file)
@@ -1,17 +1,40 @@
+/*
+ * Copyright (C) 1995-2007 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.
+ */
+
 /**
- * Scheduling algorithms.
+ * @file
+ * @brief       ILP based instruction scheduling.
+ * @author      Christian Wuerdig
+ * @date        22.10.2006
+ * @version     $Id$
+ *
  * An ILP scheduler based on
  * "ILP-based Instruction Scheduling for IA-64"
  * by Daniel Kaestner and Sebastian Winkel
- *
- * @date   22.10.2005
- * @author Christian Wuerdig
- * @cvs-id $Id$
+ * extended with register pressure constraints by Christian Wuerdig
  */
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
 
+#include "firm_config.h"
+
 #ifdef WITH_ILP
 
 #include <math.h>
@@ -30,6 +53,7 @@
 #include "debug.h"
 #include "irtools.h"
 #include "irdump.h"
+#include "irprintf.h"
 #include "plist.h"
 #include "irprintf.h"
 
@@ -46,6 +70,8 @@
 #include "beilpsched.h"
 #include "beutil.h"
 #include "bestat.h"
+#include "beirg_t.h"
+#include "benodesets.h"
 
 typedef struct _ilpsched_options_t {
        unsigned regpress;
@@ -120,7 +146,7 @@ typedef struct {
 
 /* The ILP scheduling environment */
 typedef struct {
-       phase_t              ph;            /**< The phase */
+       ir_phase             ph;            /**< The phase */
        ir_graph             *irg;          /**< The current irg */
        heights_t            *height;       /**< The heights object of the irg */
        void                 *irg_env;      /**< An environment for the irg scheduling, provided by the backend */
@@ -185,7 +211,7 @@ 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("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)),
-       { NULL }
+       LC_OPT_LAST
 };
 
 /*
@@ -257,7 +283,7 @@ static int cmp_ilpsched_irn(const void *a, const void *b) {
 /**
  * In case there is no phase information for irn, initialize it.
  */
-static void *init_ilpsched_irn(phase_t *ph, ir_node *irn, void *old) {
+static void *init_ilpsched_irn(ir_phase *ph, ir_node *irn, void *old) {
        be_ilpsched_irn_t *res = old ? old : phase_alloc(ph, sizeof(res[0]));
 
        if (res == old) {
@@ -352,7 +378,7 @@ static void collect_alap_root_nodes(ir_node *irn, void *walk_env) {
        unsigned              n_consumer     = 0;
        ir_edge_kind_t        ekind[2]       = { EDGE_KIND_NORMAL, EDGE_KIND_DEP };
        ir_node               **consumer;
-       int                   idx;
+       unsigned              idx;
 
        if (! consider_for_sched(env->arch_env->isa, irn))
                return;
@@ -663,6 +689,7 @@ static void refine_asap_alap_times(ir_node *irn, void *walk_env) {
 
 static INLINE void check_for_keeps(waitq *keeps, ir_node *block, ir_node *irn) {
        const ir_edge_t *edge;
+        (void) block;
 
        foreach_out_edge(irn, edge) {
                ir_node *user = get_edge_src_irn(edge);
@@ -1096,6 +1123,33 @@ static void create_variables(be_ilpsched_env_t *env, lpp_t *lpp, be_ilpsched_irn
  *
  *******************************************************/
 
+/**
+ * Collect all operands and nodes @p irn depends on.
+ * If there is a Proj within the dependencies, all other Projs of the parent node are added as well.
+ */
+static nodeset *sta_collect_in_deps(ir_node *irn, nodeset *deps) {
+       int i;
+
+       for (i = get_irn_ins_or_deps(irn) - 1; i >= 0; --i) {
+               ir_node *p = get_irn_in_or_dep(irn, i);
+
+               if (is_Proj(p)) {
+                       const ir_edge_t *edge;
+
+                       p = get_Proj_pred(p);
+                       foreach_out_edge(p, edge) {
+                               ir_node *src = get_edge_src_irn(edge);
+                               nodeset_insert(deps, src);
+                       }
+               }
+               else {
+                       nodeset_insert(deps, p);
+               }
+       }
+
+       return deps;
+}
+
 /**
  * Create following ILP constraints:
  * - the assignment constraints:
@@ -1116,10 +1170,12 @@ static void create_assignment_and_precedence_constraints(be_ilpsched_env_t *env,
 
        num_cst_assign = num_cst_prec = num_cst_dead = 0;
        foreach_linked_irns(ba->head_ilp_nodes, irn) {
-               int                  cst, tp_idx, i;
+               int                  cst, tp_idx;
                unsigned             cur_var;
                be_ilpsched_irn_t    *node;
                ilpsched_node_attr_t *na;
+               ir_node              *pred;
+               nodeset              *deps = new_nodeset(16);
 
                node    = get_ilpsched_irn(env, irn);
                na      = get_ilpsched_node_attr(node);
@@ -1143,13 +1199,15 @@ static void create_assignment_and_precedence_constraints(be_ilpsched_env_t *env,
                /* the precedence constraints */
                ilp_timer_push(t_cst_prec);
                bs_block_irns = bitset_clear_all(bs_block_irns);
-               for (i = get_irn_ins_or_deps(irn) - 1; i >= 0; --i) {
-                       ir_node              *pred = skip_normal_Proj(env->arch_env->isa, get_irn_in_or_dep(irn, i));
+
+               deps = sta_collect_in_deps(irn, deps);
+               foreach_nodeset(deps, pred) {
                        unsigned             t_low, t_high, t;
                        be_ilpsched_irn_t    *pred_node;
                        ilpsched_node_attr_t *pna;
                        unsigned             delay;
 
+                       pred = skip_normal_Proj(env->arch_env->isa, pred);
                        if (is_Phi(pred) || block_node->irn != get_nodes_block(pred) || is_NoMem(pred))
                                continue;
 
@@ -1216,6 +1274,7 @@ static void create_assignment_and_precedence_constraints(be_ilpsched_env_t *env,
                                DEL_ARR_F(tmp_var_idx);
                        }
                }
+               del_nodeset(deps);
                ilp_timer_pop();
        }
        DBG((env->dbg, LEVEL_1, "\t%u assignement constraints (%g sec)\n",
@@ -1813,6 +1872,7 @@ static void create_ilp(ir_node *block, void *walk_env) {
 
                DBG((env->dbg, LEVEL_1, "Creating LPP with estimated numbers: %d vars, %d cst\n",
                        estimated_n_var, estimated_n_cst));
+                (void) estimated_n_var;
 
                /* set up the LPP object */
                snprintf(name, sizeof(name), "ilp scheduling IRG %s", get_entity_ld_name(get_irg_entity(env->irg)));
@@ -1845,7 +1905,7 @@ static void create_ilp(ir_node *block, void *walk_env) {
                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(
+               DEBUG_ONLY({
                        if (firm_dbg_get_mask(env->dbg) > 1) {
                                char buf[1024];
                                FILE *f;
@@ -1857,7 +1917,7 @@ static void create_ilp(ir_node *block, void *walk_env) {
                                snprintf(buf, sizeof(buf), "lpp_block_%lu.mps", get_irn_node_nr(block));
                                lpp_dump(lpp, buf);
                        }
-               );
+               })
 
                /* set solve time limit */
                lpp_set_time_limit(lpp, env->opts->time_limit);
@@ -1885,20 +1945,20 @@ static void create_ilp(ir_node *block, void *walk_env) {
 
                /* check for valid solution */
                if (! lpp_is_sol_valid(lpp)) {
-                       char buf[1024];
-                       FILE *f;
-
-                       DEBUG_ONLY(
-                               if (firm_dbg_get_mask(env->dbg) >= 2) {
-                                       snprintf(buf, sizeof(buf), "lpp_block_%lu.infeasible.txt", get_irn_node_nr(block));
-                                       f = fopen(buf, "w");
-                                       lpp_dump_plain(lpp, f);
-                                       fclose(f);
-                                       snprintf(buf, sizeof(buf), "lpp_block_%lu.infeasible.mps", get_irn_node_nr(block));
-                                       lpp_dump(lpp, buf);
-                                       dump_ir_block_graph(env->irg, "-infeasible");
-                               }
-                       )
+                       DEBUG_ONLY({
+                            char buf[1024];
+                            FILE *f;
+
+                            if (firm_dbg_get_mask(env->dbg) >= 2) {
+                              snprintf(buf, sizeof(buf), "lpp_block_%lu.infeasible.txt", get_irn_node_nr(block));
+                              f = fopen(buf, "w");
+                              lpp_dump_plain(lpp, f);
+                              fclose(f);
+                              snprintf(buf, sizeof(buf), "lpp_block_%lu.infeasible.mps", get_irn_node_nr(block));
+                              lpp_dump(lpp, buf);
+                              dump_ir_block_graph(env->irg, "-infeasible");
+                           }
+                       })
 
                        ir_fprintf(stderr, "ILP found no solution within time (%+F, %+F), falling back to heuristics.\n", block, env->irg);
                        need_heur = 1;
@@ -1917,28 +1977,24 @@ static void create_ilp(ir_node *block, void *walk_env) {
        }
 
        /* apply solution */
-#ifdef FIRM_STATISTICS
-       if (be_stat_ev_is_active()) {
-               be_stat_ev("nodes", ba->block_last_idx);
-       }
-#endif /* FIRM_STATISTICS */
+       be_stat_ev("nodes", ba->block_last_idx);
+       be_stat_ev("vars", lpp ? lpp->var_next : 0);
+       be_stat_ev("csts", lpp ? lpp->cst_next : 0);
        if (need_heur) {
-#ifdef FIRM_STATISTICS
-               if (be_stat_ev_is_active()) {
                        be_stat_ev("time", -1);
-               }
-#endif /* FIRM_STATISTICS */
+                       be_stat_ev_dbl("opt", 0.0);
                list_sched_single_block(env->birg, block, env->be_opts);
        }
        else {
-#ifdef FIRM_STATISTICS
-               if (be_stat_ev_is_active()) {
-                       if (lpp)
-                               be_stat_ev_dbl("time", lpp->sol_time);
-                       else
-                               be_stat_ev("time", 0);
+               if (lpp) {
+                       double opt = lpp->sol_state == lpp_optimal ? 100.0 : 100.0 * lpp->best_bound / lpp->objval;
+                       be_stat_ev_dbl("time", lpp->sol_time);
+                       be_stat_ev_dbl("opt", opt);
+               }
+               else {
+                       be_stat_ev_dbl("time", 0.0);
+                       be_stat_ev_dbl("opt", 100.0);
                }
-#endif /* FIRM_STATISTICS */
                apply_solution(env, lpp, block);
        }
 
@@ -1954,32 +2010,29 @@ static void create_ilp(ir_node *block, void *walk_env) {
  */
 void be_ilp_sched(const be_irg_t *birg, be_options_t *be_opts) {
        be_ilpsched_env_t          env;
-       const char                 *name = "be ilp scheduling";
-       arch_isa_t                 *isa  = birg->main_env->arch_env->isa;
-       const ilp_sched_selector_t *sel  = isa->impl->get_ilp_sched_selector(isa);
+       const char                 *name     = "be ilp scheduling";
+       ir_graph                   *irg      = be_get_birg_irg(birg);
+       const arch_env_t           *arch_env = be_get_birg_arch_env(birg);
+       const arch_isa_t           *isa      = arch_env->isa;
+       const ilp_sched_selector_t *sel      = isa->impl->get_ilp_sched_selector(isa);
 
        FIRM_DBG_REGISTER(env.dbg, "firm.be.sched.ilp");
 
-#ifdef FIRM_STATISTICS
-       if (be_stat_ev_is_active()) {
-               be_stat_tags[STAT_TAG_CLS] = "ilpsched";
-               be_stat_ev_push(be_stat_tags, STAT_TAG_LAST, be_stat_file);
-       }
-#endif /* FIRM_STATISTICS */
+       stat_ev_ctx_push("ilpsched");
 
 //     firm_dbg_set_mask(env.dbg, 1);
 
-       env.irg_env    = be_ilp_sched_init_irg_ilp_schedule(sel, birg->irg);
+       env.irg_env    = be_ilp_sched_init_irg_ilp_schedule(sel, irg);
        env.sel        = sel;
-       env.irg        = birg->irg;
-       env.height     = heights_new(birg->irg);
+       env.irg        = irg;
+       env.height     = heights_new(irg);
        env.main_env   = birg->main_env;
-       env.arch_env   = birg->main_env->arch_env;
-       env.cpu        = arch_isa_get_machine(birg->main_env->arch_env->isa);
+       env.arch_env   = arch_env;
+       env.cpu        = arch_isa_get_machine(arch_env->isa);
        env.opts       = &ilp_opts;
        env.birg       = birg;
        env.be_opts    = be_opts;
-       phase_init(&env.ph, name, env.irg, PHASE_DEFAULT_GROWTH, init_ilpsched_irn);
+       phase_init(&env.ph, name, env.irg, PHASE_DEFAULT_GROWTH, init_ilpsched_irn, NULL);
 
        /* assign a unique per block number to all interesting nodes */
        irg_walk_in_or_dep_graph(env.irg, NULL, build_block_idx, &env);
@@ -2022,11 +2075,7 @@ void be_ilp_sched(const be_irg_t *birg, be_options_t *be_opts) {
        /* notify backend */
        be_ilp_sched_finish_irg_ilp_schedule(sel, birg->irg, env.irg_env);
 
-#ifdef FIRM_STATISTICS
-       if (be_stat_ev_is_active()) {
-               be_stat_ev_pop();
-       }
-#endif /* FIRM_STATISTICS */
+       stat_ev_ctx_pop("ilpsched");
 }
 
 /**