Commit a09efb2c authored by Matthias Braun's avatar Matthias Braun
Browse files

rework schedulers to register similar like regallocators/spillers

parent 546bbbe4
......@@ -62,51 +62,6 @@
DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL);
enum {
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 {
BE_SCHED_PREP_NONE = 0,
BE_SCHED_PREP_MRIS = 2,
BE_SCHED_PREP_RSS = 3
};
typedef struct list_sched_options_t {
int select; /**< the node selector */
} list_sched_options_t;
static list_sched_options_t list_sched_options = {
BE_SCHED_SELECT_NORMAL, /* mueller heuristic selector */
};
/* schedule selector options. */
static const lc_opt_enum_int_items_t sched_select_items[] = {
{ "trivial", BE_SCHED_SELECT_TRIVIAL },
{ "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 },
{ NULL, 0 }
};
static lc_opt_enum_int_var_t sched_select_var = {
&list_sched_options.select, sched_select_items
};
static const lc_opt_table_entry_t list_sched_option_table[] = {
LC_OPT_ENT_ENUM_PTR("select", "node selector", &sched_select_var),
LC_OPT_LAST
};
/**
* All scheduling info needed per node.
*/
......@@ -502,23 +457,10 @@ static void list_sched_block(ir_node *block, void *env_ptr)
}
/* List schedule a graph. */
void list_sched(ir_graph *irg)
void be_list_sched_graph(ir_graph *irg, const list_sched_selector_t *selector)
{
int num_nodes;
sched_env_t env;
const list_sched_selector_t *selector;
/* Select a scheduler based on backend options */
switch (list_sched_options.select) {
case BE_SCHED_SELECT_TRIVIAL: selector = &trivial_selector; break;
case BE_SCHED_SELECT_RANDOM: selector = &random_selector; break;
case BE_SCHED_SELECT_REGPRESS: selector = &reg_pressure_selector; break;
case BE_SCHED_SELECT_MUCHNIK: selector = &muchnik_selector; break;
case BE_SCHED_SELECT_HEUR: selector = &heuristic_selector; break;
case BE_SCHED_SELECT_NORMAL: selector = &normal_selector; break;
default:
case BE_SCHED_SELECT_HMUCHNIK: selector = &heuristic_selector; break;
}
#if 1
/* Matze: This is very slow, we should avoid it to improve backend speed,
......@@ -540,14 +482,14 @@ void list_sched(ir_graph *irg)
memset(env.sched_info, 0, num_nodes * sizeof(env.sched_info[0]));
if (env.selector->init_graph)
env.selector_env = env.selector->init_graph(env.selector, irg);
if (selector->init_graph != NULL)
env.selector_env = selector->init_graph(irg);
/* Schedule each single block. */
irg_block_walk_graph(irg, list_sched_block, NULL, &env);
if (env.selector->finish_graph)
env.selector->finish_graph(env.selector_env);
if (selector->finish_graph != NULL)
selector->finish_graph(env.selector_env);
DEL_ARR_F(env.sched_info);
}
......@@ -555,10 +497,5 @@ void list_sched(ir_graph *irg)
BE_REGISTER_MODULE_CONSTRUCTOR(be_init_listsched);
void be_init_listsched(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, "listsched");
lc_opt_add_table(sched_grp, list_sched_option_table);
FIRM_DBG_REGISTER(dbg, "firm.be.sched");
}
......@@ -19,7 +19,7 @@
/**
* @file
* @brief Primitive list scheduling with different node selectors.
* @brief Common functions for creating listscheduling algorithms
* @author Sebastian Hack
* @date 20.10.2004
* @version $Id$
......@@ -68,7 +68,7 @@ static inline bool to_appear_in_schedule(const ir_node *irn)
* You can implement your own list scheduler by implementing these
* functions.
*/
struct list_sched_selector_t {
typedef struct list_sched_selector_t {
/**
* Called before a graph is being scheduled.
......@@ -78,7 +78,7 @@ struct list_sched_selector_t {
* @param irg The backend graph.
* @return The environment pointer that is passed to all other functions in this struct.
*/
void *(*init_graph)(const list_sched_selector_t *vtab, ir_graph *irg);
void *(*init_graph)(ir_graph *irg);
/**
* Called before scheduling starts on a block.
......@@ -124,28 +124,6 @@ struct list_sched_selector_t {
*/
void (*node_selected)(void *block_env, ir_node *irn);
/**
* Returns the execution time of node irn.
* May be NULL.
*
* @param block_env The block environment.
* @param irn The selected node.
*/
unsigned (*exectime)(void *block_env, const ir_node *irn);
/**
* Calculates the latency of executing cycle curr_cycle of node curr in cycle pred_cycle
* of node pred.
* May be NULL.
*
* @param block_env The block environment.
* @param pred The previous node.
* @param pred_cycle The previous node execution cycle.
* @param curr The current node.
* @param curr_cycle The current node execution cycle.
*/
unsigned (*latency)(void *block_env, const ir_node *pred, int pred_cycle, const ir_node *curr, int curr_cycle);
/**
* Called after a block has been scheduled.
* May be NULL.
......@@ -162,41 +140,7 @@ struct list_sched_selector_t {
* @param env The environment.
*/
void (*finish_graph)(void *env);
};
/**
* A trivial selector, that just selects the first ready node.
*/
extern const list_sched_selector_t trivial_selector;
/**
* A trivial selector that selects a pseudo-random-node (deterministic).
*/
extern const list_sched_selector_t random_selector;
/**
* A selector that tries to minimize the register pressure.
* @note Not really operational yet.
*/
extern const list_sched_selector_t reg_pressure_selector;
/**
* A selector based on trace scheduling as introduced by Muchnik[TM]
*/
extern const list_sched_selector_t muchnik_selector;
/**
* A selector based on trace scheduling as introduced by Muchnik[TM]
* but using the Mueller heuristic selector.
*/
extern const list_sched_selector_t heuristic_selector;
/**
* A selector based on the strong normal form theorem (ie minimizing
* the register pressure).
*/
extern const list_sched_selector_t normal_selector;
} list_sched_selector_t;
/**
* List schedule a graph.
......@@ -206,6 +150,6 @@ extern const list_sched_selector_t normal_selector;
*
* @param irg The backend irg.
*/
void list_sched(ir_graph *irg);
void be_list_sched_graph(ir_graph *irg, const list_sched_selector_t *selector);
#endif
......@@ -659,7 +659,7 @@ static void be_main_loop(FILE *file_handle, const char *cup_name)
/* schedule the irg */
be_timer_push(T_SCHED);
list_sched(irg);
be_schedule_graph(irg);
be_timer_pop(T_SCHED);
dump(DUMP_SCHED, irg, "sched");
......
......@@ -38,6 +38,11 @@ void be_init_blocksched(void);
void be_init_spill(void);
void be_init_spilloptions(void);
void be_init_listsched(void);
void be_init_sched_rand(void);
void be_init_sched_normal(void);
void be_init_sched_regpress(void);
void be_init_sched_trace(void);
void be_init_sched_trivial(void);
void be_init_chordal(void);
void be_init_pbqp_coloring(void);
void be_init_chordal_main(void);
......@@ -97,7 +102,14 @@ void be_init_modules(void)
be_init_spill();
be_init_spilloptions();
be_init_dbgout();
be_init_listsched();
be_init_sched_normal();
be_init_sched_trace();
be_init_sched_regpress();
be_init_sched_rand();
be_init_sched_trivial();
be_init_chordal_main();
be_init_chordal_common();
be_init_chordal();
......
......@@ -44,6 +44,10 @@
#include "belistsched.h"
#include "belive.h"
#include "lc_opts.h"
#include "lc_opts_enum.h"
#include "irtools.h"
#define SCHED_INITIAL_GRANULARITY (1 << 14)
static void sched_renumber(const ir_node *block)
......@@ -145,7 +149,27 @@ void sched_remove(ir_node *irn)
info->prev = NULL;
}
static be_module_list_entry_t *schedulers;
static schedule_func scheduler;
void be_register_scheduler(const char *name, schedule_func func)
{
if (scheduler == NULL)
scheduler = func;
be_add_module_to_list(&schedulers, name, func);
}
void be_schedule_graph(ir_graph *irg)
{
scheduler(irg);
}
BE_REGISTER_MODULE_CONSTRUCTOR(be_init_sched);
void be_init_sched(void)
{
lc_opt_entry_t *be_grp = lc_opt_get_grp(firm_opt_get_root(), "be");
be_add_module_list_opt(be_grp, "scheduler", "scheduling algorithm",
&schedulers, (void**)&scheduler);
}
......@@ -228,4 +228,19 @@ static inline bool sched_comes_after(const ir_node *n1, const ir_node *n2)
#define sched_foreach_Phi(block,phi) \
for (phi = sched_first(block); is_Phi(phi); phi = sched_next(phi))
/**
* Type for a function scheduling a graph
*/
typedef void (*schedule_func) (ir_graph *irg);
/**
* Register new scheduling algorithm
*/
void be_register_scheduler(const char *name, schedule_func func);
/**
* schedule a graph with the currenty selected scheduler.
*/
void be_schedule_graph(ir_graph *irg);
#endif
......@@ -34,6 +34,7 @@
#include "irtools.h"
#include "irgwalk.h"
#include "benode.h"
#include "bemodule.h"
#include "array_t.h"
// XXX there is no one time init for schedulers
......@@ -376,14 +377,11 @@ static void normal_sched_block(ir_node* block, void* env)
}
static void *normal_init_graph(const list_sched_selector_t *vtab,
ir_graph *irg)
static void *normal_init_graph(ir_graph *irg)
{
instance_t *inst = XMALLOC(instance_t);
ir_heights_t *heights;
(void)vtab;
be_clear_links(irg);
obstack_init(&inst->obst);
......@@ -438,14 +436,22 @@ static void normal_finish_graph(void *env)
xfree(inst);
}
const list_sched_selector_t normal_selector = {
normal_init_graph,
normal_init_block,
normal_select,
NULL, /* node_ready */
NULL, /* node_selected */
NULL, /* exectime */
NULL, /* latency */
NULL, /* finish_block */
normal_finish_graph
};
static void sched_normal(ir_graph *irg)
{
static const list_sched_selector_t normal_selector = {
normal_init_graph,
normal_init_block,
normal_select,
NULL, /* node_ready */
NULL, /* node_selected */
NULL, /* finish_block */
normal_finish_graph
};
be_list_sched_graph(irg, &normal_selector);
}
BE_REGISTER_MODULE_CONSTRUCTOR(be_init_sched_normal);
void be_init_sched_normal(void)
{
be_register_scheduler("normal", sched_normal);
}
......@@ -30,6 +30,7 @@
#include "besched.h"
#include "belistsched.h"
#include "bemodule.h"
/**
* The random selector:
......@@ -75,13 +76,10 @@ static ir_node *random_select(void *block_env, ir_nodeset_t *ready_set,
return irn;
}
static void *random_init_graph(const list_sched_selector_t *vtab, ir_graph *irg)
static void *random_init_graph(ir_graph *irg)
{
(void)vtab;
(void)irg;
/* Using time(NULL) as a seed here gives really random results,
but is NOT deterministic which makes debugging impossible.
Moreover no-one want non-deterministic compilers ... */
/* TODO: add commandline option for the seed */
srand(0x4711);
return NULL;
}
......@@ -93,14 +91,22 @@ static void *random_init_block(void *graph_env, ir_node *block)
return NULL;
}
const list_sched_selector_t random_selector = {
random_init_graph,
random_init_block,
random_select,
NULL, /* node_ready */
NULL, /* node_selected */
NULL, /* exectime */
NULL, /* latency */
NULL, /* finish_block */
NULL /* finish_graph */
};
static void sched_random(ir_graph *irg)
{
static const list_sched_selector_t random_selector = {
random_init_graph,
random_init_block,
random_select,
NULL, /* node_ready */
NULL, /* node_selected */
NULL, /* finish_block */
NULL /* finish_graph */
};
be_list_sched_graph(irg, &random_selector);
}
BE_REGISTER_MODULE_CONSTRUCTOR(be_init_sched_rand);
void be_init_sched_rand(void)
{
be_register_scheduler("random", sched_random);
}
......@@ -35,6 +35,7 @@
#include "besched.h"
#include "belistsched.h"
#include "benode.h"
#include "bemodule.h"
typedef struct usage_stats_t {
......@@ -46,13 +47,8 @@ typedef struct usage_stats_t {
scheduled. */
} usage_stats_t;
typedef struct {
const list_sched_selector_t *vtab;
} reg_pressure_main_env_t;
typedef struct {
struct obstack obst;
const reg_pressure_main_env_t *main_env;
usage_stats_t *root;
ir_nodeset_t already_scheduled;
} reg_pressure_selector_env_t;
......@@ -171,25 +167,22 @@ static int compute_max_hops(reg_pressure_selector_env_t *env, ir_node *irn)
return res;
}
static void *reg_pressure_graph_init(const list_sched_selector_t *vtab, ir_graph *irg)
static void *reg_pressure_graph_init(ir_graph *irg)
{
reg_pressure_main_env_t *main_env = XMALLOC(reg_pressure_main_env_t);
main_env->vtab = vtab;
irg_walk_graph(irg, firm_clear_link, NULL, NULL);
return main_env;
return NULL;
}
static void *reg_pressure_block_init(void *graph_env, ir_node *bl)
{
ir_node *irn;
reg_pressure_selector_env_t *env = XMALLOC(reg_pressure_selector_env_t);
(void) graph_env;
obstack_init(&env->obst);
ir_nodeset_init(&env->already_scheduled);
env->root = NULL;
env->main_env = (reg_pressure_main_env_t*)graph_env;
/*
* Collect usage statistics.
......@@ -305,14 +298,22 @@ static ir_node *reg_pressure_select(void *block_env, ir_nodeset_t *ready_set,
return res;
}
const list_sched_selector_t reg_pressure_selector = {
reg_pressure_graph_init,
reg_pressure_block_init,
reg_pressure_select,
NULL, /* node_ready */
NULL, /* node_selected */
NULL, /* exectime */
NULL, /* latency */
reg_pressure_block_free,
free
};
static void sched_reg_pressure(ir_graph *irg)
{
static const list_sched_selector_t reg_pressure_selector = {
reg_pressure_graph_init,
reg_pressure_block_init,
reg_pressure_select,
NULL, /* node_ready */
NULL, /* node_selected */
reg_pressure_block_free,
free
};
be_list_sched_graph(irg, &reg_pressure_selector);
}
BE_REGISTER_MODULE_CONSTRUCTOR(be_init_sched_regpress);
void be_init_sched_regpress(void)
{
be_register_scheduler("regpress", sched_reg_pressure);
}
......@@ -34,6 +34,7 @@
#include "belistsched.h"
#include "benode.h"
#include "belive.h"
#include "bemodule.h"
/* we need a special mark */
static char _mark;
......@@ -52,8 +53,6 @@ typedef struct trace_irn {
typedef struct trace_env {
trace_irn_t *sched_info; /**< trace scheduling information about the nodes */
sched_timestep_t curr_time; /**< current time of the scheduler */
void *selector_env; /**< the backend selector environment */
const list_sched_selector_t *selector; /**< the actual backend selector */
be_lv_t *liveness; /**< The liveness for the irg */
DEBUG_ONLY(firm_dbg_module_t *dbg;)
} trace_env_t;
......@@ -228,10 +227,13 @@ static inline void set_irn_critical_path_len(trace_env_t *env, ir_node *n, unsig
*/
static sched_timestep_t exectime(trace_env_t *env, ir_node *n)
{
(void) env;
if (be_is_Keep(n) || is_Proj(n))
return 0;
#if 0
if (env->selector->exectime)
return env->selector->exectime(env->selector_env, n);
#endif
return 1;
}
......@@ -240,6 +242,8 @@ static sched_timestep_t exectime(trace_env_t *env, ir_node *n)
*/
static sched_timestep_t latency(trace_env_t *env, ir_node *pred, int pred_cycle, ir_node *curr, int curr_cycle)
{
(void) pred_cycle;
(void) curr_cycle;
/* a Keep hides a root */
if (be_is_Keep(curr))
return exectime(env, pred);
......@@ -252,8 +256,11 @@ static sched_timestep_t latency(trace_env_t *env, ir_node *pred, int pred_cycle,
if (is_Proj(pred))
pred = get_Proj_pred(pred);
#if 0
if (env->selector->latency)
return env->selector->latency(env->selector_env, pred, pred_cycle, curr, curr_cycle);
#endif
return 1;
}
......@@ -621,11 +628,9 @@ force_mcands:
return irn;
}
static void *muchnik_init_graph(const list_sched_selector_t *vtab, ir_graph *irg)
static void *muchnik_init_graph(ir_graph *irg)
{
trace_env_t *env = trace_init(irg);
env->selector = vtab;
env->selector_env = (void*) be_get_irg_arch_env(irg);
return (void *)env;
}
......@@ -636,17 +641,19 @@ static void *muchnik_init_block(void *graph_env, ir_node *bl)
return graph_env;
}
const list_sched_selector_t muchnik_selector = {
muchnik_init_graph,
muchnik_init_block,
muchnik_select,
trace_node_ready, /* node_ready */
trace_update_time, /* node_selected */
NULL, /* exectime */
NULL, /* latency */
NULL, /* finish_block */
trace_free /* finish_graph */
};
static void sched_muchnik(ir_graph *irg)
{
static const list_sched_selector_t muchnik_selector = {
muchnik_init_graph,
muchnik_init_block,
muchnik_select,
trace_node_ready, /* node_ready */
trace_update_time, /* node_selected */
NULL, /* finish_block */
trace_free /* finish_graph */
};
be_list_sched_graph(irg, &muchnik_selector);
}
/**
* Execute the heuristic function.
......@@ -723,14 +730,23 @@ static ir_node *heuristic_select(void *block_env, ir_nodeset_t *ns, ir_nodeset_t
return cand;
}
const list_sched_selector_t heuristic_selector = {
muchnik_init_graph,
muchnik_init_block,
heuristic_select,
trace_node_ready, /* node_ready */
trace_update_time, /* node_selected */
NULL, /* exectime */
NULL, /* latency */
NULL, /* finish_block */
trace_free /* finish_graph */
};
static void sched_heuristic(ir_graph *irg)
{
static const list_sched_selector_t heuristic_selector = {
muchnik_init_graph,
muchnik_init_block,
heuristic_select,
trace_node_ready, /* node_ready */
trace_update_time, /* node_selected */
NULL, /* finish_block */
trace_free /* finish_graph */
};
be_list_sched_graph(irg, &heuristic_selector);
}
BE_REGISTER_MODULE_CONSTRUCTOR(be_init_sched_trace);
void be_init_sched_trace(void)
{
be_register_scheduler("heur", sched_heuristic);
be_register_scheduler("muchnik", sched_muchnik);
}
......@@ -34,6 +34,8 @@
#include "bearch.h"