#define BE_SCHED_NODE(irn) (be_is_Keep(irn) || be_is_CopyKeep(irn) || be_is_RegParams(irn))
enum {
- BE_SCHED_SELECT_TRIVIAL = 0,
- BE_SCHED_SELECT_REGPRESS = 1,
- BE_SCHED_SELECT_MUCHNIK = 2,
- BE_SCHED_SELECT_HEUR = 3,
- BE_SCHED_SELECT_HMUCHNIK = 4,
- BE_SCHED_SELECT_RANDOM = 5
+ BE_SCHED_SELECT_TRIVIAL,
+ BE_SCHED_SELECT_REGPRESS,
+ BE_SCHED_SELECT_MUCHNIK,
+ BE_SCHED_SELECT_HEUR,
+ BE_SCHED_SELECT_HMUCHNIK,
+ BE_SCHED_SELECT_RANDOM,
+ BE_SCHED_SELECT_NORMAL,
};
enum {
/* schedule selector options. */
static const lc_opt_enum_int_items_t sched_select_items[] = {
{ "trivial", BE_SCHED_SELECT_TRIVIAL },
- { "random", BE_SCHED_SELECT_RANDOM },
+ { "random", BE_SCHED_SELECT_RANDOM },
{ "regpress", BE_SCHED_SELECT_REGPRESS },
+ { "normal", BE_SCHED_SELECT_NORMAL },
{ "muchnik", BE_SCHED_SELECT_MUCHNIK },
{ "heur", BE_SCHED_SELECT_HEUR },
{ "hmuchnik", BE_SCHED_SELECT_HMUCHNIK },
/* Select a scheduler based on backend options */
switch (list_sched_options.select) {
- case BE_SCHED_SELECT_TRIVIAL:
- memcpy(&sel, trivial_selector, sizeof(sel));
- break;
- case BE_SCHED_SELECT_RANDOM:
- memcpy(&sel, random_selector, sizeof(sel));
- break;
- case BE_SCHED_SELECT_REGPRESS:
- memcpy(&sel, reg_pressure_selector, sizeof(sel));
- break;
- case BE_SCHED_SELECT_MUCHNIK:
- memcpy(&sel, muchnik_selector, sizeof(sel));
- break;
- case BE_SCHED_SELECT_HEUR:
- memcpy(&sel, heuristic_selector, sizeof(sel));
- break;
- case BE_SCHED_SELECT_HMUCHNIK:
+ case BE_SCHED_SELECT_TRIVIAL: sel = *trivial_selector; break;
+ case BE_SCHED_SELECT_RANDOM: sel = *random_selector; break;
+ case BE_SCHED_SELECT_REGPRESS: sel = *reg_pressure_selector; break;
+ case BE_SCHED_SELECT_MUCHNIK: sel = *muchnik_selector; break;
+ case BE_SCHED_SELECT_HEUR: sel = *heuristic_selector; break;
+ case BE_SCHED_SELECT_NORMAL: sel = *normal_selector; break;
default:
- memcpy(&sel, trivial_selector, sizeof(sel));
+ case BE_SCHED_SELECT_HMUCHNIK: sel = *trivial_selector; break;
}
#if 1
/* Select a scheduler based on backend options */
switch (list_sched_options.select) {
- case BE_SCHED_SELECT_TRIVIAL:
- memcpy(&sel, trivial_selector, sizeof(sel));
- break;
- case BE_SCHED_SELECT_RANDOM:
- memcpy(&sel, random_selector, sizeof(sel));
- break;
- case BE_SCHED_SELECT_REGPRESS:
- memcpy(&sel, reg_pressure_selector, sizeof(sel));
- break;
- case BE_SCHED_SELECT_MUCHNIK:
- memcpy(&sel, muchnik_selector, sizeof(sel));
- break;
- case BE_SCHED_SELECT_HEUR:
- memcpy(&sel, heuristic_selector, sizeof(sel));
- break;
- case BE_SCHED_SELECT_HMUCHNIK:
+ case BE_SCHED_SELECT_TRIVIAL: sel = *trivial_selector; break;
+ case BE_SCHED_SELECT_RANDOM: sel = *random_selector; break;
+ case BE_SCHED_SELECT_REGPRESS: sel = *reg_pressure_selector; break;
+ case BE_SCHED_SELECT_MUCHNIK: sel = *muchnik_selector; break;
+ case BE_SCHED_SELECT_HEUR: sel = *heuristic_selector; break;
+ case BE_SCHED_SELECT_NORMAL: sel = *normal_selector; break;
default:
- memcpy(&sel, trivial_selector, sizeof(sel));
+ case BE_SCHED_SELECT_HMUCHNIK: sel = *trivial_selector; break;
}
/* Assure, that the out edges are computed */
--- /dev/null
+/*
+ * 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.
+ */
+
+/**
+ * @brief Use the strong normal form theorem (though it does not hold)
+ * @author Christoph Mallon
+ * @version $Id: beschedrand.c 14604 2007-06-18 14:07:07Z matze $
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+
+#include "besched_t.h"
+#include "belistsched.h"
+#include "belive_t.h"
+#include "beutil.h"
+#include "irtools.h"
+#include "irgwalk.h"
+
+
+// XXX there is no one time init for schedulers
+//#define NORMAL_DBG
+
+
+static const arch_env_t *cur_arch_env;
+
+
+static ir_node *normal_select(void *block_env, ir_nodeset_t *ready_set,
+ ir_nodeset_t *live_set)
+{
+ ir_nodeset_iterator_t iter;
+ ir_node* block;
+ ir_node* irn;
+ ir_node** sched;
+ int sched_count;
+
+ (void)block_env;
+ (void)live_set;
+
+ ir_nodeset_iterator_init(&iter, ready_set);
+ irn = ir_nodeset_iterator_next(&iter);
+ block = get_nodes_block(irn);
+ sched = get_irn_link(block);
+ sched_count = ARR_LEN(sched);
+ for (; sched_count-- != 0; ++sched) {
+ ir_node* irn = *sched;
+ if (ir_nodeset_contains(ready_set, irn) &&
+ !arch_irn_class_is(cur_arch_env, irn, branch)) {
+#if defined NORMAL_DBG
+ ir_fprintf(stderr, "scheduling %+F\n", irn);
+#endif
+ return irn;
+ }
+ }
+
+ return irn;
+}
+
+
+typedef struct irn_cost_pair {
+ ir_node* irn;
+ int cost;
+} irn_cost_pair;
+
+
+static int cost_cmp(const void* a, const void* b)
+{
+ const irn_cost_pair* a1 = a;
+ const irn_cost_pair* b1 = b;
+ return b1->cost - a1->cost;
+}
+
+
+typedef struct flag_and_cost {
+ int no_root;
+ irn_cost_pair costs[];
+} flag_and_cost;
+
+
+static int count_result(const ir_node* irn)
+{
+ const ir_mode* mode = get_irn_mode(irn);
+ return
+ mode != mode_M &&
+ mode != mode_X &&
+ !arch_irn_is(cur_arch_env, irn, ignore);
+}
+
+
+static int normal_tree_cost(ir_node* irn)
+{
+ flag_and_cost* fc = get_irn_link(irn);
+ ir_node* block = get_nodes_block(irn);
+ int arity = get_irn_arity(irn);
+ int cost_max = 0;
+ int count_max = 0;
+ int n_res;
+ int cost;
+
+ if (fc == NULL) {
+ irn_cost_pair* costs;
+ int i;
+
+ fc = malloc(sizeof(*fc) + sizeof(*fc->costs) * arity);
+ fc->no_root = 0;
+ costs = fc->costs;
+
+ for (i = 0; i < arity; ++i) {
+ ir_node* pred = get_irn_n(irn, i);
+ int cost;
+
+ if (is_Phi(irn) || get_irn_mode(pred) == mode_M) {
+ cost = 0;
+ } else if (get_nodes_block(pred) != block) {
+ cost = 1;
+ } else {
+ cost = normal_tree_cost(pred);
+ flag_and_cost* pred_fc = get_irn_link(pred);
+ pred_fc->no_root = 1;
+#if defined NORMAL_DBG
+ ir_fprintf(stderr, "%+F says that %+F is no root\n", irn, pred);
+#endif
+ }
+
+ costs[i].irn = pred;
+ costs[i].cost = cost;
+
+ if (cost > cost_max) {
+ cost_max = cost;
+ count_max = 1;
+ } else if (cost == cost_max) {
+ ++count_max;
+ }
+ }
+
+ qsort(costs, arity, sizeof(*costs), cost_cmp);
+ set_irn_link(irn, fc);
+ } else {
+ irn_cost_pair* costs = fc->costs;
+ int i;
+
+ if (arity > 0) {
+ cost_max = costs[0].cost;
+
+ for (i = 0; i < arity; ++i) {
+ if (costs[i].cost < cost_max) break;
+ ++count_max;
+ }
+ }
+ }
+
+ n_res = count_result(irn);
+ if (cost_max == 0) {
+ cost = n_res;
+ } else {
+ cost = MAX(n_res, cost_max + count_max - 1);
+ }
+
+#if defined NORMAL_DBG
+ ir_fprintf(stderr, "reguse of %+F is %d\n", irn, cost);
+#endif
+
+ return cost;
+}
+
+
+static void normal_tree_sched(ir_node* irn)
+{
+ irn_cost_pair* irns = get_irn_link(irn);
+ int arity = get_irn_arity(irn);
+ int i;
+
+ if (irns == NULL) return;
+
+ for (i = 0; i < arity; ++i) {
+ normal_tree_sched(irns[i].irn);
+ }
+
+ if (1) { // TODO check if node needs to be scheduled
+ ir_node* block = get_nodes_block(irn);
+ ir_node** sched = get_irn_link(block);
+
+#if defined NORMAL_DBG
+ ir_fprintf(stderr, "scheduling %+F in array %p\n", irn, sched);
+#endif
+
+ if (sched == NULL) {
+ sched = NEW_ARR_F(ir_node*, 0);
+ }
+ ARR_APP1(ir_node*, sched, irn);
+ set_irn_link(block, sched);
+ }
+
+ free(irns);
+ set_irn_link(irn, NULL);
+}
+
+
+static void normal_cost_walker(ir_node* irn, void* env)
+{
+ (void)env;
+
+#if defined NORMAL_DBG
+ ir_fprintf(stderr, "cost walking node %+F\n", irn);
+#endif
+ if (is_Block(irn)) return;
+ normal_tree_cost(irn);
+}
+
+
+static void collect_roots(ir_node* irn, void* env)
+{
+ flag_and_cost* fc;
+
+ (void)env;
+
+ if (is_Block(irn)) return;
+
+ fc = get_irn_link(irn);
+
+#if defined NORMAL_DBG
+ ir_fprintf(stderr, "%+F is %sroot\n", irn, fc->no_root ? "no " : "");
+#endif
+
+ if (!fc->no_root) {
+ ir_node* block = get_nodes_block(irn);
+ ir_node** roots = get_irn_link(block);
+ if (roots == NULL) {
+ roots = NEW_ARR_F(ir_node*, 0);
+ }
+ ARR_APP1(ir_node*, roots, irn);
+ set_irn_link(block, roots);
+ }
+}
+
+
+static ir_node** sched_node(ir_node** sched, ir_node* irn)
+{
+ ir_node* block = get_nodes_block(irn);
+ int arity = get_irn_arity(irn);
+ int i;
+
+ if (!is_Phi(irn)) {
+ for (i = 0; i < arity; ++i) {
+ ir_node* pred = get_irn_n(irn, i);
+ if (get_nodes_block(pred) != block) continue;
+ sched = sched_node(sched, pred);
+ }
+ }
+
+ ARR_APP1(ir_node*, sched, irn);
+ return sched;
+}
+
+
+static void normal_sched_block(ir_node* block, void* env)
+{
+ ir_node** roots = get_irn_link(block);
+ int root_count;
+ irn_cost_pair* root_costs;
+ int i;
+ ir_node** sched;
+
+ (void)env;
+
+#if defined NORMAL_DBG
+ ir_fprintf(stderr, "sched walking block %+F\n", block);
+#endif
+
+ if (roots == NULL) {
+#if defined NORMAL_DBG
+ fprintf(stderr, "has no roots\n");
+#endif
+ return;
+ }
+
+ root_count = ARR_LEN(roots);
+ NEW_ARR_A(irn_cost_pair, root_costs, root_count);
+ for (i = 0; i < root_count; ++i) {
+ root_costs[i].irn = roots[i];
+ root_costs[i].cost = normal_tree_cost(roots[i]);
+ }
+ qsort(root_costs, root_count, sizeof(*root_costs), cost_cmp);
+
+ sched = NEW_ARR_F(ir_node*, 0);
+ for (i = 0; i < root_count; ++i) {
+ ir_node* irn = root_costs[i].irn;
+ sched = sched_node(sched, irn);
+ }
+ set_irn_link(block, sched);
+ DEL_ARR_F(roots);
+
+#if defined NORMAL_DBG
+ {
+ int n = ARR_LEN(sched);
+ int i;
+
+ ir_fprintf(stderr, "Scheduling of %+F:\n", block);
+ for (i = 0; i < n; ++i) {
+ int j;
+ for (j = 0; j < i; ++j) {
+ if (sched[i] == sched[j]) goto skip;
+ }
+ ir_fprintf(stderr, " %+F\n", sched[i]);
+skip:;
+ }
+ fprintf(stderr, "\n");
+ }
+#endif
+}
+
+
+static void *normal_init_graph(const list_sched_selector_t *vtab,
+ const be_irg_t *birg)
+{
+ ir_graph* irg = be_get_birg_irg(birg);
+
+ (void)vtab;
+
+ cur_arch_env = be_get_birg_arch_env(birg);
+
+ be_clear_links(irg);
+
+ irg_walk_graph(irg, normal_cost_walker, NULL, NULL);
+ irg_walk_graph(irg, collect_roots, NULL, NULL);
+ irg_block_walk_graph(irg, normal_sched_block, NULL, NULL);
+
+ return NULL;
+}
+
+
+static void *normal_init_block(void *graph_env, ir_node *block)
+{
+ (void)graph_env;
+ (void)block;
+
+ return NULL;
+}
+
+
+static const list_sched_selector_t normal_selector_struct = {
+ normal_init_graph,
+ normal_init_block,
+ normal_select,
+ NULL, /* to_appear_in_schedule */
+ NULL, /* node_ready */
+ NULL, /* node_selected */
+ NULL, /* exectime */
+ NULL, /* latency */
+ NULL, /* finish_block */
+ NULL /* finish_graph */
+};
+
+const list_sched_selector_t *normal_selector = &normal_selector_struct;