From: Matthias Braun Date: Fri, 8 Sep 2006 09:12:09 +0000 (+0000) Subject: make belady look for uses beyond block borders X-Git-Url: http://nsz.repo.hu/git/?a=commitdiff_plain;h=e7de04b0c2ffcb0903e0aed1a7310d3b3b1dd0be;p=libfirm make belady look for uses beyond block borders --- diff --git a/ir/be/bespillbelady.c b/ir/be/bespillbelady.c index 169a897d9..e53032839 100644 --- a/ir/be/bespillbelady.c +++ b/ir/be/bespillbelady.c @@ -50,7 +50,18 @@ #define DEBUG_LVL 0 //(DBG_START | DBG_DECIDE | DBG_WSETS | DBG_FIX | DBG_SPILL) DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;) -typedef struct _workset_t workset_t; +/** + * An association between a node and a point in time. + */ +typedef struct _loc_t { + ir_node *irn; /**< A node. */ + unsigned time; /**< A use time (see beuses.h). */ +} loc_t; + +typedef struct _workset_t { + int len; /**< current length */ + loc_t vals[0]; /**< inlined array of the values/distances in this working set */ +} workset_t; typedef struct _belady_env_t { struct obstack ob; @@ -68,10 +79,12 @@ typedef struct _belady_env_t { spill_env_t *senv; /**< see bespill.h */ } belady_env_t; -struct _workset_t { - int len; /**< current length */ - loc_t vals[0]; /**< inlined array of the values/distances in this working set */ -}; +static int loc_compare(const void *a, const void *b) +{ + const loc_t *p = a; + const loc_t *q = b; + return p->time - q->time; +} void workset_print(const workset_t *w) { @@ -217,14 +230,19 @@ static INLINE void *new_block_info(struct obstack *ob) { static INLINE unsigned get_distance(belady_env_t *env, const ir_node *from, unsigned from_step, const ir_node *def, int skip_from_uses) { int flags = arch_irn_get_flags(env->arch, def); - unsigned dist = be_get_next_use(env->uses, from, from_step, def, skip_from_uses); + unsigned dist; assert(! (flags & arch_irn_flags_ignore)); - /* we have to keep nonspillable nodes in the workingset */ + /* We have to keep nonspillable nodes in the workingset */ if(flags & arch_irn_flags_dont_spill) return 0; + dist = be_get_next_use(env->uses, from, from_step, def, skip_from_uses); + + if(USES_IS_INFINITE(dist)) + dist = USES_INFINITY; + return dist; } @@ -317,8 +335,10 @@ static void displace(belady_env_t *env, workset_t *new_vals, int is_usage) { /* Only make more free room if we do not have enough */ if (len > max_allowed) { /* get current next-use distance */ - for (i = 0; i < ws->len; ++i) - workset_set_time(ws, i, get_distance(env, env->instr, env->instr_nr, workset_get_val(ws, i), !is_usage)); + for (i = 0; i < ws->len; ++i) { + unsigned dist = get_distance(env, env->instr, env->instr_nr, workset_get_val(ws, i), !is_usage); + workset_set_time(ws, i, dist); + } /* FIX for don't spill nodes: @@ -628,7 +648,7 @@ void be_spill_belady_spill_env(const be_chordal_env_t *chordal_env, spill_env_t env.cls = chordal_env->cls; env.n_regs = env.cls->n_regs - be_put_ignore_regs(chordal_env->birg, chordal_env->cls, NULL); env.ws = new_workset(&env, &env.ob); - env.uses = be_begin_uses(chordal_env->irg, chordal_env->lv, chordal_env->birg->main_env->arch_env, env.cls); + env.uses = be_begin_uses(chordal_env->irg, chordal_env->exec_freq, chordal_env->lv); if(spill_env == NULL) { env.senv = be_new_spill_env(chordal_env); } else { diff --git a/ir/be/beuses.c b/ir/be/beuses.c index d9cf998ab..559ebb8cc 100644 --- a/ir/be/beuses.c +++ b/ir/be/beuses.c @@ -1,13 +1,16 @@ /** * @file beuse.c * @date 27.06.2005 - * @author Sebastian Hack + * @author Sebastian Hack, Matthias Braun * * Methods to compute when a value will be used again. * * Copyright (C) 2005 Universitaet Karlsruhe * Released under the GPL */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif #include #include @@ -34,135 +37,145 @@ #include "beuses_t.h" #include "benodesets.h" -#define DBG_LEVEL SET_LEVEL_0 +#define SCAN_INTERBLOCK_USES typedef struct _be_use_t { - const ir_node *bl; - const ir_node *irn; + const ir_node *block; + const ir_node *node; unsigned next_use; } be_use_t; struct _be_uses_t { - set *uses; - ir_graph *irg; - const be_lv_t *lv; - const arch_env_t *arch_env; - DEBUG_ONLY(firm_dbg_module_t *dbg;) + set *uses; + ir_graph *irg; + const exec_freq_t *execfreqs; + const be_lv_t *lv; + DEBUG_ONLY(firm_dbg_module_t *dbg;) }; static int cmp_use(const void *a, const void *b, size_t n) { - const be_use_t *p = a; - const be_use_t *q = b; - return !(p->bl == q->bl && p->irn == q->irn); + const be_use_t *p = a; + const be_use_t *q = b; + return !(p->block == q->block && p->node == q->node); } -static INLINE be_use_t *get_or_set_use(be_uses_t *uses, - const ir_node *bl, const ir_node *def, unsigned next_use) +static const be_use_t *get_or_set_use_block(be_uses_t *uses, + const ir_node *block, + const ir_node *def) { - unsigned hash = HASH_COMBINE(nodeset_hash(bl), nodeset_hash(def)); - be_use_t templ; - be_use_t* result; - - templ.bl = bl; - templ.irn = def; - templ.next_use = be_get_next_use(uses, sched_first(bl), 0, def, 0); - result = set_insert(uses->uses, &templ, sizeof(templ), hash); + unsigned hash = HASH_COMBINE(nodeset_hash(block), nodeset_hash(def)); + be_use_t temp; + be_use_t* result; - return result; -} + temp.block = block; + temp.node = def; + result = set_find(uses->uses, &temp, sizeof(temp), hash); -unsigned be_get_next_use(be_uses_t *uses, const ir_node *from, - unsigned from_step, const ir_node *def, int skip_from_uses); + if(result == NULL) { + // insert templ first as we might end in a loop in the get_next_use + // call otherwise + temp.next_use = USES_INFINITY; + result = set_insert(uses->uses, &temp, sizeof(temp), hash); -static unsigned get_next_use_bl(be_uses_t *uses, const ir_node *bl, - const ir_node *def) -{ - be_use_t *u = get_or_set_use(uses, bl, def, 0); + result->next_use = be_get_next_use(uses, sched_first(block), 0, def, 0); + } - return u->next_use; + return result; } -static unsigned get_next_use(be_uses_t *uses, const ir_node *from, unsigned from_step, const ir_node *def, int skip_from_uses, unsigned long visited_nr) +unsigned be_get_next_use(be_uses_t *uses, const ir_node *from, + unsigned from_step, const ir_node *def, + int skip_from_uses) { - unsigned next_use = USES_INFINITY; - unsigned step = from_step; - unsigned n = 0; - ir_node *bl = get_nodes_block(from); - const ir_node *irn; - const ir_edge_t *succ_edge; + unsigned step = from_step; + ir_node *block = get_nodes_block(from); + const ir_node *node; + const ir_edge_t *edge; - set_irn_visited(bl, visited_nr); + if(skip_from_uses) { + step++; + node = sched_next(node); + } - sched_foreach_from(from, irn) { - int i, n; + sched_foreach_from(from, node) { + int i, arity; - if (! skip_from_uses) { - for (i = 0, n = get_irn_arity(irn); i < n; ++i) { - ir_node *operand = get_irn_n(irn, i); + arity = get_irn_arity(node); + for (i = 0; i < arity; ++i) { + const ir_node *operand = get_irn_n(node, i); - if (operand == def) { - DBG((uses->dbg, LEVEL_3, "found use of %+F at %+F\n", operand, irn)); - return step; - } + if (operand == def) { + DBG((uses->dbg, LEVEL_3, "found use of %+F at %+F\n", operand, node)); + return step; } } - skip_from_uses = 0; step++; } - /* FIXME: quick and dirty hack to prevent ignore nodes (like stack pointer) from being spilled */ - return be_is_live_end(uses->lv, bl, def) ? step : USES_INFINITY; + if(be_is_live_end(uses->lv, block, def)) + return step; + +#ifdef SCAN_INTERBLOCK_USES + { + double best_execfreq = -1; + unsigned next_use = USES_INFINITY; + + foreach_block_succ(block, edge) { + const be_use_t *use; + const ir_node *succ_block = get_edge_src_irn(edge); + double execfreq = get_block_execfreq(uses->execfreqs, succ_block); - next_use = USES_INFINITY; - foreach_block_succ(bl, succ_edge) { - const ir_node *succ_bl = succ_edge->src; - if(get_irn_visited(succ_bl) < visited_nr && (be_is_live_in(uses->lv, succ_bl, def) || (get_irn_arity(succ_bl) > 1 && be_is_live_end(uses->lv, bl, def)))) { - unsigned next = get_next_use_bl(uses, succ_bl, def); + //execfreq_sum += execfreq; - DBG((uses->dbg, LEVEL_2, "\t\tnext use in succ %+F: %d\n", succ_bl, next)); - next_use = MIN(next_use, next); - n++; + if(execfreq > best_execfreq) { + best_execfreq = execfreq; + + if(!be_is_live_in(uses->lv, succ_block, def)) { + next_use = USES_INFINITY; + continue; + } + + use = get_or_set_use_block(uses, succ_block, def); + //if(USES_IS_INFINITE(use->next_use)) + // continue; + + next_use = use->next_use; } + + //next_use += use->next_use / execfreq; } - return next_use + step; -} + /*if(next_use == 0) + return USES_INFINITY;*/ -unsigned be_get_next_use(be_uses_t *uses, const ir_node *from, unsigned from_step, const ir_node *def, int skip_from_uses) -{ - unsigned long visited_nr = get_irg_visited(uses->irg) + 1; + //next_use /= execfreq_sum; - set_irg_visited(uses->irg, visited_nr); - return get_next_use(uses, from, from_step, def, skip_from_uses, visited_nr); + return ((unsigned) next_use) + step; + } +#else + return USES_INFINITY; +#endif } - -be_uses_t *be_begin_uses(ir_graph *irg, const be_lv_t *lv, const arch_env_t *arch_env, const arch_register_class_t *cls) +be_uses_t *be_begin_uses(ir_graph *irg, const exec_freq_t *execfreqs, const be_lv_t *lv) { - be_uses_t *uses = xmalloc(sizeof(uses[0])); + be_uses_t *uses = xmalloc(sizeof(uses[0])); - edges_assure(irg); + edges_assure(irg); - uses->arch_env = arch_env; - uses->uses = new_set(cmp_use, 512); - uses->irg = irg; - uses->lv = lv; - FIRM_DBG_REGISTER(uses->dbg, "firm.be.uses"); + uses->uses = new_set(cmp_use, 512); + uses->irg = irg; + uses->execfreqs = execfreqs; + uses->lv = lv; + FIRM_DBG_REGISTER(uses->dbg, "firm.be.uses"); - return uses; + return uses; } void be_end_uses(be_uses_t *uses) { - del_set(uses->uses); - free(uses); -} - -int loc_compare(const void *a, const void *b) -{ - const loc_t *p = a; - const loc_t *q = b; - return p->time - q->time; + del_set(uses->uses); + free(uses); } diff --git a/ir/be/beuses.h b/ir/be/beuses.h index 2300bde6b..604ae0d99 100644 --- a/ir/be/beuses.h +++ b/ir/be/beuses.h @@ -1,14 +1,13 @@ /** * @file beuse.h * @date 27.06.2005 - * @author Sebastian Hack + * @author Sebastian Hack, Matthias Braun * * Determine future usages of values. * * Copyright (C) 2005 Universitaet Karlsruhe * Released under the GPL */ - #ifndef _BEUSES_H #define _BEUSES_H @@ -16,15 +15,20 @@ #include "belive.h" #define USES_INFINITY 1000000 -#define USES_IS_INIFINITE(x) ((x) >= USES_INFINITY) -typedef struct _loc_t loc_t; +static INLINE int USES_IS_INFINITE(unsigned time) +{ + return time >= USES_INFINITY; +} + typedef struct _be_uses_t be_uses_t; unsigned be_get_next_use(be_uses_t *uses, const ir_node *from, - unsigned from_step, const ir_node *def, int skip_from_uses); + unsigned from_step, const ir_node *def, + int skip_from_uses); -be_uses_t *be_begin_uses(ir_graph *irg, const be_lv_t *lv, const arch_env_t *arch_env, const arch_register_class_t *cls); +be_uses_t *be_begin_uses(ir_graph *irg, const exec_freq_t *execfreqs, + const be_lv_t *lv); void be_end_uses(be_uses_t *uses); diff --git a/ir/be/beuses_t.h b/ir/be/beuses_t.h index 369bf1d0b..42127918b 100644 --- a/ir/be/beuses_t.h +++ b/ir/be/beuses_t.h @@ -15,22 +15,4 @@ #include "beuses.h" -/** - * An association between a node and a point in time. - */ -struct _loc_t { - ir_node *irn; /**< A node. */ - unsigned time; /**< A time. */ -}; - -#define LOC_IS_INFINITE(loc) USES_IS_INIFINITE((loc)->time) - -/** - * Comparison function for locations. - * @param a The first location. - * @param b The second one. - * @return see qsort(3) for semantic of the compare functions. - */ -int loc_compare(const void *loc1, const void *loc2); - #endif /* _BEUSES_T_H */