From: Christoph Mallon Date: Sat, 18 Aug 2007 06:49:41 +0000 (+0000) Subject: Add a scheduler based on the strong normal form theorem. It seems to deliver good... X-Git-Url: http://nsz.repo.hu/git/?a=commitdiff_plain;h=2e2c4df2a1cc61e7ad16feb64f4ac84b785d4f23;p=libfirm Add a scheduler based on the strong normal form theorem. It seems to deliver good results for broad calculation trees/DAGs. Caution: The implemententation is a cruel hack so far. Contents may be hot. Slippery when wet. [r15564] --- diff --git a/ir/be/belistsched.c b/ir/be/belistsched.c index 6bdb442fe..c378e82c3 100644 --- a/ir/be/belistsched.c +++ b/ir/be/belistsched.c @@ -69,12 +69,13 @@ DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL); #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 { @@ -96,8 +97,9 @@ static list_sched_options_t list_sched_options = { /* 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 }, @@ -548,24 +550,14 @@ void list_sched(be_irg_t *birg, be_options_t *be_opts) /* 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 @@ -631,24 +623,14 @@ void list_sched_single_block(const be_irg_t *birg, ir_node *block, /* 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 */ diff --git a/ir/be/belistsched.h b/ir/be/belistsched.h index 16c4eeeae..454e22f2c 100644 --- a/ir/be/belistsched.h +++ b/ir/be/belistsched.h @@ -153,6 +153,11 @@ extern const list_sched_selector_t *muchnik_selector; */ extern const list_sched_selector_t *heuristic_selector; +/** + * A selector based on the strng normal form theorem + */ +extern const list_sched_selector_t *normal_selector; + /** * List schedule a graph. * Each block in the graph gets a list head to its link field being the diff --git a/ir/be/beschednormal.c b/ir/be/beschednormal.c new file mode 100644 index 000000000..74cffb9fc --- /dev/null +++ b/ir/be/beschednormal.c @@ -0,0 +1,372 @@ +/* + * 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 + +#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;