Commit 787aa344 authored by Matthias Braun's avatar Matthias Braun
Browse files

- Added a function that finds and removes dead nodes from schedule

- Use this function in bespill.c, simplifies it and fixes some bugs
- Renamed the misleading is_mem_phi to is_spilled_phi
- Fixed bug where the morgan spiller was invoking the belady spiller without resetting the is_spilled_phi function
parent 8eedd8f6
......@@ -14,6 +14,7 @@
#include "irnode_t.h"
#include "irgraph_t.h"
#include "iredges_t.h"
#include "ircons.h"
#include "debug.h"
#include "bearch.h"
......@@ -260,3 +261,51 @@ ir_node **sched_create_block_schedule(ir_graph *irg)
}
return blk_list;
}
typedef struct remove_dead_nodes_env_t_ {
ir_graph *irg;
bitset_t *reachable;
} remove_dead_nodes_env_t;
static void mark_dead_nodes_walker(ir_node *node, void *data)
{
remove_dead_nodes_env_t *env = (remove_dead_nodes_env_t*) data;
bitset_set(env->reachable, get_irn_idx(node));
}
static void remove_dead_nodes_walker(ir_node *block, void *data)
{
remove_dead_nodes_env_t *env = (remove_dead_nodes_env_t*) data;
ir_node *node;
for(node = sched_first(block); !sched_is_end(node); ) {
// get next node now, as after calling sched_remove it will be invalid
ir_node* next = sched_next(node);
int i, arity;
if(bitset_is_set(env->reachable, get_irn_idx(node))) {
node = next;
continue;
}
sched_remove(node);
arity = get_irn_arity(node);
for(i = 0; i < arity; ++i)
set_irn_n(node, i, new_r_Bad(env->irg));
node = next;
}
}
void be_remove_dead_nodes_from_schedule(ir_graph *irg)
{
remove_dead_nodes_env_t env;
env.irg = irg;
env.reachable = bitset_alloca(get_irg_last_idx(irg));
// mark all reachable nodes
irg_walk_graph(irg, mark_dead_nodes_walker, NULL, &env);
// walk schedule and remove non-marked nodes
irg_block_walk_graph(irg, remove_dead_nodes_walker, NULL, &env);
}
......@@ -66,4 +66,10 @@ ir_node *sched_irg_first(const ir_graph *irg);
*/
ir_node **sched_create_block_schedule(ir_graph *irg);
/**
* Removes dead nodes from schedule
* @param irg the graph
*/
void be_remove_dead_nodes_from_schedule(ir_graph *irg);
#endif /* _BESCHED_H */
......@@ -58,7 +58,7 @@ struct _spill_env_t {
set *spill_ctxs;
set *spills; /**< all spill_info_t's, which must be placed */
pset *mem_phis; /**< set of all special spilled phis. allocated and freed separately */
decide_irn_t is_mem_phi; /**< callback func to decide if a phi needs special spilling */
decide_irn_t is_spilled_phi;/**< callback func to decide if a phi needs special spilling */
void *data; /**< data passed to all callbacks */
DEBUG_ONLY(firm_dbg_module_t *dbg;)
};
......@@ -104,18 +104,23 @@ void be_set_spill_env_dbg_module(spill_env_t *env, firm_dbg_module_t *dbg) {
)
/* Creates a new spill environment. */
spill_env_t *be_new_spill_env(const be_chordal_env_t *chordal_env, decide_irn_t is_mem_phi, void *data) {
spill_env_t *env = xmalloc(sizeof(env[0]));
env->spill_ctxs = new_set(cmp_spillctx, 1024);
env->spills = new_set(cmp_spillinfo, 1024);
env->cls = chordal_env->cls;
env->is_mem_phi = is_mem_phi;
env->data = data;
env->chordal_env = chordal_env;
spill_env_t *be_new_spill_env(const be_chordal_env_t *chordal_env, decide_irn_t is_spilled_phi, void *data) {
spill_env_t *env = xmalloc(sizeof(env[0]));
env->spill_ctxs = new_set(cmp_spillctx, 1024);
env->spills = new_set(cmp_spillinfo, 1024);
env->cls = chordal_env->cls;
env->is_spilled_phi = is_spilled_phi;
env->data = data;
env->chordal_env = chordal_env;
obstack_init(&env->obst);
return env;
}
void be_set_is_spilled_phi(spill_env_t *env, decide_irn_t is_spilled_phi, void *data) {
env->is_spilled_phi = is_spilled_phi;
env->data = data;
}
/* Deletes a spill environment. */
void be_delete_spill_env(spill_env_t *senv) {
del_set(senv->spill_ctxs);
......@@ -399,7 +404,7 @@ static ir_node *do_remat(spill_env_t *senv, ir_node *spilled, ir_node *reloader)
/**
* Walker: fills the mem_phis set by evaluating Phi nodes
* using the is_mem_phi() callback.
* using the is_spilled_phi() callback.
*/
static void phi_walker(ir_node *irn, void *env) {
spill_env_t *senv = env;
......@@ -407,7 +412,7 @@ static void phi_walker(ir_node *irn, void *env) {
if (is_Phi(irn)) {
const arch_env_t *arch = senv->chordal_env->birg->main_env->arch_env;
if (arch_irn_has_reg_class(arch, irn, 0, senv->cls) &&
senv->is_mem_phi(irn, senv->data)) {
senv->is_spilled_phi(irn, senv->data)) {
DBG((senv->dbg, LEVEL_1, " %+F\n", irn));
pset_insert_ptr(senv->mem_phis, irn);
}
......@@ -420,7 +425,6 @@ void be_insert_spills_reloads(spill_env_t *senv, pset *reload_set) {
unsigned visited_nr;
ir_node *irn;
spill_info_t *si;
pdeq *possibly_dead;
/* get all special spilled phis */
DBG((senv->dbg, LEVEL_1, "Mem-phis:\n"));
......@@ -448,12 +452,10 @@ void be_insert_spills_reloads(spill_env_t *senv, pset *reload_set) {
/* process each spilled node */
DBG((senv->dbg, LEVEL_1, "Insert spills and reloads:\n"));
possibly_dead = new_pdeq();
for(si = set_first(senv->spills); si; si = set_next(senv->spills)) {
int i;
reloader_t *rld;
ir_mode *mode = get_irn_mode(si->spilled_node);
ir_node *value;
//ir_node *value;
pset *values = pset_new_ptr(16);
/* go through all reloads for this spill */
......@@ -466,7 +468,7 @@ void be_insert_spills_reloads(spill_env_t *senv, pset *reload_set) {
#ifdef REMAT
if (check_remat_conditions(senv, spill, si->spilled_node, rld->reloader)) {
new_val = do_remat(senv, si->spilled_node, rld->reloader);
pdeq_putl(possibly_dead, spill);
//pdeq_putl(possibly_dead, spill);
}
else
#endif
......@@ -484,71 +486,13 @@ void be_insert_spills_reloads(spill_env_t *senv, pset *reload_set) {
pset_insert_ptr(values, si->spilled_node);
be_ssa_constr_set_ignore(senv->chordal_env->dom_front, values, senv->mem_phis);
/* Remove reloads which are not used by anyone */
/* TODO: Better call a general garbage collection routine here... this here gets clunky
* and doesn't handle all cases (like memphis)
*/
foreach_pset(values, value) {
if(get_irn_n_edges(value) == 0) {
sched_remove(value);
// remove the node from preds
if(be_is_Reload(value)) {
ir_node* spill = get_irn_n(value, be_pos_Reload_mem);
if(be_is_Spill(spill)) {
assert(be_is_Spill(spill));
set_irn_n(value, be_pos_Reload_mem, new_r_Bad(irg));
set_irn_n(value, be_pos_Reload_frame, new_r_Bad(irg));
// maybe the spill is not used anymoe too now?
if(get_irn_n_edges(spill) == 0) {
sched_remove(spill);
set_irn_n(spill, be_pos_Spill_val, new_r_Bad(irg));
set_irn_n(spill, be_pos_Spill_frame, new_r_Bad(irg));
}
} else if(is_Phi(spill)) {
// TODO memphi
} else {
assert(0 && "Only spill or mem-phi expected here");
}
} else if(is_Phi(value)) {
for(i = 0; i < get_Phi_n_preds(value); ++i)
set_irn_n(value, i, new_r_Bad(irg));
} else {
assert(0);
}
}
}
del_pset(values);
}
foreach_pset(senv->mem_phis, irn) {
int i, n;
for (i = 0, n = get_irn_arity(irn); i < n; ++i) {
pdeq_putl(possibly_dead, get_irn_n(irn, i));
set_irn_n(irn, i, new_r_Bad(senv->chordal_env->irg));
}
sched_remove(irn);
}
/* check if possibly dead nodes are really dead yet */
while (! pdeq_empty(possibly_dead)) {
ir_node *irn = pdeq_getr(possibly_dead);
const ir_edge_t *edge = get_irn_out_edge_first(irn);
if (! edge) {
int i;
for (i = get_irn_arity(irn) - 1; i >= 0; --i) {
pdeq_putl(possibly_dead, get_irn_n(irn, i));
set_irn_n(irn, i, new_r_Bad(senv->chordal_env->irg));
}
sched_remove(irn);
}
}
del_pdeq(possibly_dead);
del_pset(senv->mem_phis);
be_remove_dead_nodes_from_schedule(senv->chordal_env->irg);
// reloads are placed now, but we might reuse the spill environment for further spilling decisions
del_set(senv->spills);
senv->spills = new_set(cmp_spillinfo, 1024);
......@@ -636,7 +580,7 @@ static void compute_spill_slots_walker(ir_node *spill, void *env) {
struct _arch_env_t *arch_env = ssenv->cenv->birg->main_env->arch_env;
const arch_register_class_t *cls = arch_get_irn_reg_class(arch_env, spill, be_pos_Spill_val);
int size = get_mode_size_bytes(arch_register_class_mode(cls));
assert(ss->size == size && "Different sizes for the same spill slot are not allowed.");
assert((int) ss->size == size && "Different sizes for the same spill slot are not allowed.");
for (irn = pset_first(ss->members); irn; irn = pset_next(ss->members)) {
/* use values_interfere here, because it uses the dominance check,
which does work for values in memory */
......
......@@ -25,10 +25,15 @@ typedef int(*decide_irn_t)(const ir_node*, void*);
* Creates a new spill environment.
*
* @param chordal
* @param is_mem_phi a function that evaluates a Phi node
* @param data context parameter for the is_mem_phi function
* @param is_spilled_phi a function that evaluates a phi node and returns true if it is a spilled phi node
* @param data context parameter for the is_spilled_phi function
*/
spill_env_t *be_new_spill_env(const be_chordal_env_t *chordal, decide_irn_t is_mem_phi, void *data);
spill_env_t *be_new_spill_env(const be_chordal_env_t *chordal, decide_irn_t is_spilled_phi, void *data);
/**
* (re-)sets the is_spilled_phi callback
*/
void be_set_is_spilled_phi(spill_env_t *env, decide_irn_t is_spilled_phi, void *data);
/**
* Deletes a spill environment.
......
......@@ -658,6 +658,7 @@ void be_spill_belady_spill_env(const be_chordal_env_t *chordal_env, spill_env_t
bel.senv = be_new_spill_env(chordal_env, is_mem_phi, NULL);
} else {
bel.senv = spill_env;
be_set_is_spilled_phi(bel.senv, is_mem_phi, NULL);
}
DEBUG_ONLY(be_set_spill_env_dbg_module(bel.senv, dbg);)
bel.reloads = pset_new_ptr_default();
......
......@@ -30,8 +30,8 @@
#include "irphase_t.h"
#include "irprintf.h"
// remove me later
#include "bespillbelady.h"
#include "beverify.h"
#define DBG_LIVE 1
#define DBG_PRESSURE 2
......@@ -448,6 +448,7 @@ typedef struct _liveness_dump_env_t {
FILE *f;
} liveness_dump_env_t;
#if 0
/**
* Pre-walker: dump liveness data to a file
*/
......@@ -519,7 +520,7 @@ static void dump_liveness_info(const be_chordal_env_t *chordal_env, const char*
irg_block_walk_graph(chordal_env->irg, dump_liveness_walker, NULL, &env);
fclose(env.f);
}
#endif
void be_spill_morgan(const be_chordal_env_t *chordal_env) {
morgan_env_t env;
......@@ -560,6 +561,7 @@ void be_spill_morgan(const be_chordal_env_t *chordal_env) {
reduce_register_pressure_in_loop(&env, get_irg_loop(env.irg), 0);
be_insert_spills_reloads(env.senv, NULL);
DEBUG_ONLY(be_verify_schedule(env.irg);)
// cleanup
be_end_uses(env.uses);
......@@ -567,14 +569,9 @@ void be_spill_morgan(const be_chordal_env_t *chordal_env) {
del_set(env.loop_attr_set);
del_set(env.block_attr_set);
be_liveness(env.irg);
dump_liveness_info(chordal_env, "spillmorgan");
// fix the remaining places with too high register pressure with beladies algorithm
be_spill_belady_spill_env(chordal_env, env.senv);
be_liveness(env.irg);
dump_liveness_info(chordal_env, "spillcomplete");
be_spill_belady_spill_env(chordal_env, env.senv);
be_delete_spill_env(env.senv);
phase_free(&env.phase);
......
......@@ -26,6 +26,17 @@ typedef struct be_verify_register_pressure_env_t_ {
int problem_found;
} be_verify_register_pressure_env_t;
static void print_living_values(pset *live_nodes)
{
ir_node *node;
ir_printf("\t");
foreach_pset(live_nodes, node) {
ir_printf("%+F ", node);
}
ir_printf("\n");
}
static void verify_liveness_walker(ir_node *bl, void *data)
{
be_verify_register_pressure_env_t *env = (be_verify_register_pressure_env_t*) data;
......@@ -37,8 +48,9 @@ static void verify_liveness_walker(ir_node *bl, void *data)
be_liveness_end_of_block(env->arch_env, env->cls, bl, live_nodes);
pressure = pset_count(live_nodes);
if(pressure > env->registers_available) {
ir_printf("Verify Warning: Register pressure too high at end of block %+F (%d/%d).\n",
ir_printf("Verify Warning: Register pressure too high at end of block %+F (%d/%d):\n",
bl, pressure, env->registers_available);
print_living_values(live_nodes);
env->problem_found = 1;
}
sched_foreach_reverse(bl, irn) {
......@@ -53,6 +65,7 @@ static void verify_liveness_walker(ir_node *bl, void *data)
if(pressure > env->registers_available) {
ir_printf("Verify Warning: Register pressure too high before %+F (in block %+F) (%d/%d).\n",
irn, bl, pressure, env->registers_available);
print_living_values(live_nodes);
env->problem_found = 1;
}
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment