#include "lc_opts.h"
#include "lc_opts_enum.h"
+/* we have prolog, "normal" and epilog */
+#define N_PRIORITY_CLASSES 3
+
DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL);
/**
* Environment for a block scheduler.
*/
typedef struct block_sched_env_t {
- unsigned *scheduled; /**< scheduling info per node, copied from the
- global scheduler object */
- ir_nodeset_t cands; /**< the set of candidates */
- ir_node *block; /**< the current block */
- sched_env_t *sched_env; /**< the scheduler environment */
+ /** scheduling info per node, copied from the global scheduler object */
+ unsigned *scheduled;
+ /** the set of candidates */
+ ir_nodeset_t cands[N_PRIORITY_CLASSES];
+ ir_node *block; /**< the current block */
+ sched_env_t *sched_env; /**< the scheduler environment */
const list_sched_selector_t *selector;
- void *selector_block_env;
+ void *selector_block_env;
} block_sched_env_t;
+/**
+ * map prolog/normal/epilog into 3 priority levels
+ */
+static unsigned get_priority(const ir_node *node)
+{
+ arch_irn_flags_t flags = arch_irn_get_flags(node);
+ if (flags & arch_irn_flags_prolog) {
+ assert(! (flags & arch_irn_flags_epilog));
+ return 0;
+ } else if (flags & arch_irn_flags_epilog) {
+ return 2;
+ }
+ return 1;
+}
+
/**
* Returns non-zero if the node is already scheduled
*/
-static bool is_already_scheduled(block_sched_env_t *env, ir_node *n)
+static bool is_already_scheduled(const sched_env_t *env, ir_node *n)
{
unsigned idx = get_irn_idx(n);
return rbitset_is_set(env->scheduled, idx);
/**
* Mark a node as already scheduled
*/
-static void set_already_scheduled(block_sched_env_t *env, ir_node *n)
+static void set_already_scheduled(sched_env_t *env, ir_node *n)
{
unsigned idx = get_irn_idx(n);
rbitset_set(env->scheduled, idx);
/* Keeps must be scheduled immediately */
add_to_sched(env, irn);
} else {
- ir_nodeset_insert(&env->cands, irn);
+ unsigned priority = get_priority(irn);
+ ir_nodeset_insert(&env->cands[priority], irn);
/* Notify selector about the ready node. */
if (env->selector->node_ready)
/* If the operand is local to the scheduled block and not yet
* scheduled, this nodes cannot be made ready, so exit. */
- if (get_nodes_block(op) == env->block && !is_already_scheduled(env, op))
+ if (get_nodes_block(op) == env->block
+ && !is_already_scheduled(env->sched_env, op))
return;
}
env->selector->node_selected(env->selector_block_env, node);
/* Insert the node in the set of all available scheduled nodes. */
- set_already_scheduled(env, node);
+ set_already_scheduled(env->sched_env, node);
/* check users, they might be ready now */
foreach_out_edge(node, edge) {
*/
static void add_to_sched(block_sched_env_t *env, ir_node *irn)
{
+ unsigned priority = get_priority(irn);
+
assert(! (arch_irn_get_flags(irn) & arch_irn_flags_not_scheduled));
sched_add_before(env->block, irn);
DB((dbg, LEVEL_2, "\tschedule %+F\n", irn));
/* Remove the node from the ready set */
- ir_nodeset_remove(&env->cands, irn);
+ ir_nodeset_remove(&env->cands[priority], irn);
selected(env, irn);
}
block_sched_env_t be;
const ir_edge_t *edge;
+ unsigned p;
/* Initialize the block's list head that will hold the schedule. */
sched_init_block(block);
/* Initialize the block scheduling environment */
- be.scheduled = env->scheduled;
- be.block = block;
- ir_nodeset_init_size(&be.cands, get_irn_n_edges(block));
- be.selector = selector;
- be.sched_env = env;
+ be.block = block;
+ be.selector = selector;
+ be.sched_env = env;
+ for (p = 0; p < N_PRIORITY_CLASSES; ++p) {
+ ir_nodeset_init_size(&be.cands[p], get_irn_n_edges(block));
+ }
DB((dbg, LEVEL_1, "scheduling %+F\n", block));
}
/* Iterate over all remaining nodes */
- while (ir_nodeset_size(&be.cands) > 0) {
- ir_node *irn = be.selector->select(be.selector_block_env, &be.cands);
- DB((dbg, LEVEL_2, "\tpicked node %+F\n", irn));
-
- /* remove the scheduled node from the ready list. */
- ir_nodeset_remove(&be.cands, irn);
- /* Add the node to the schedule. */
- add_to_sched(&be, irn);
+ for (p = 0; p < N_PRIORITY_CLASSES; ++p) {
+ ir_nodeset_t *p_cands = &be.cands[p];
+ while (ir_nodeset_size(p_cands) > 0) {
+ ir_node *irn = be.selector->select(be.selector_block_env, p_cands);
+ DB((dbg, LEVEL_2, "\tpicked node %+F\n", irn));
+
+ /* remove the scheduled node from the ready list. */
+ ir_nodeset_remove(p_cands, irn);
+ /* Add the node to the schedule. */
+ add_to_sched(&be, irn);
+ }
}
if (selector->finish_block)
selector->finish_block(be.selector_block_env);
- ir_nodeset_destroy(&be.cands);
+ for (p = 0; p < N_PRIORITY_CLASSES; ++p) {
+ /** all cand lists should be empty. Otherwise there was some invalid
+ * dependencies between priority classes (ie. priority 0 value depending
+ * on a priority 1 value) */
+ assert(ir_nodeset_size(&be.cands[p]) == 0);
+ ir_nodeset_init_size(&be.cands[p], get_irn_n_edges(block));
+ }
}
/* List schedule a graph. */