Commit 8eee0e63 authored by Sebastian Hack's avatar Sebastian Hack
Browse files

* Added a new file: beintlive_t.h which subsumes all interferene/liveness checks

  - it uses the new liveness checking algos in ana/irlivechk.h
  - value_dominates, etc. was erased from bera.h because it does not belong there

* bechordal.c features an experimental coloring (by defualt disabled by macro)
  which can color the routine in a single pass without building the "borders".
  A long term goal is to disable borders completely but they are used in other
  places, too.

* The 1st parameter of values_interfere is now a birg and not a be_lv_t. There
  is now a special routine lv_values_interfere() for those who want to use the
  computed liveness explicitly. changing the parameter makes it more easy to
  switch to other liveness implementations.

All other files were modified to respect the changes

[r13762]
parent 73660ffa
......@@ -46,6 +46,7 @@
#include "irdump.h"
#include "irdom.h"
#include "irtools.h"
#include "irbitset.h"
#include "debug.h"
#include "xmalloc.h"
#include "iredges.h"
......@@ -61,6 +62,7 @@
#include "beinsn_t.h"
#include "bestatevent.h"
#include "beirg_t.h"
#include "beintlive_t.h"
#include "bera.h"
#include "bechordal_t.h"
#include "bechordal_draw.h"
......@@ -72,6 +74,9 @@ DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)
#define DUMP_INTERVALS
/* new style assign routine without borders. */
#undef NEW_STYLE_ASSIGN
typedef struct _be_chordal_alloc_env_t {
be_chordal_env_t *chordal_env;
......@@ -178,8 +183,7 @@ static INLINE border_t *border_add(be_chordal_env_t *env, struct list_head *head
*/
static INLINE int has_reg_class(const be_chordal_env_t *env, const ir_node *irn)
{
return arch_irn_has_reg_class(env->birg->main_env->arch_env, irn, -1, env->cls);
// return arch_irn_consider_in_reg_alloc(env->birg->main_env->arch_env, env->cls, irn);
return arch_irn_consider_in_reg_alloc(env->birg->main_env->arch_env, env->cls, irn);
}
#define has_limited_constr(req, irn) \
......@@ -232,7 +236,8 @@ static be_insn_t *chordal_scan_insn(be_chordal_env_t *env, ir_node *irn)
static ir_node *prepare_constr_insn(be_chordal_env_t *env, ir_node *irn)
{
const arch_env_t *aenv = env->birg->main_env->arch_env;
const be_irg_t *birg = env->birg;
const arch_env_t *aenv = birg->main_env->arch_env;
bitset_t *tmp = bitset_alloca(env->cls->n_regs);
bitset_t *def_constr = bitset_alloca(env->cls->n_regs);
ir_node *bl = get_nodes_block(irn);
......@@ -325,7 +330,7 @@ static ir_node *prepare_constr_insn(be_chordal_env_t *env, ir_node *irn)
3) is constrained to a register occuring in out constraints.
*/
if(!op->has_constraints ||
!values_interfere(lv, insn->irn, op->carrier) ||
!values_interfere(birg, insn->irn, op->carrier) ||
bitset_popcnt(tmp) == 0)
continue;
......@@ -372,7 +377,6 @@ static void pair_up_operands(const be_chordal_alloc_env_t *alloc_env, be_insn_t
int n_defs = be_insn_n_defs(insn);
bitset_t *bs = bitset_alloca(env->cls->n_regs);
int *pairing = alloca(MAX(n_defs, n_uses) * sizeof(pairing[0]));
be_lv_t *lv = env->birg->lv;
int i, j;
......@@ -392,7 +396,7 @@ static void pair_up_operands(const be_chordal_alloc_env_t *alloc_env, be_insn_t
if (op->partner != NULL)
continue;
if (values_interfere(lv, op->irn, op->carrier))
if (values_interfere(env->birg, op->irn, op->carrier))
continue;
bitset_clear_all(bs);
......@@ -503,7 +507,7 @@ static ir_node *handle_constraints(be_chordal_alloc_env_t *alloc_env, ir_node *i
be_insn_t *insn = chordal_scan_insn(env, irn);
ir_node *res = insn->next_insn;
int be_silent = *silent;
be_lv_t *lv = env->birg->lv;
be_irg_t *birg = env->birg;
if(insn->pre_colored) {
int i;
......@@ -594,7 +598,7 @@ static ir_node *handle_constraints(be_chordal_alloc_env_t *alloc_env, ir_node *i
assert(is_Proj(proj));
if(!values_interfere(lv, proj, irn) || pmap_contains(partners, proj))
if(!values_interfere(birg, proj, irn) || pmap_contains(partners, proj))
continue;
assert(n_alloc < n_regs);
......@@ -932,6 +936,129 @@ static void assign(ir_node *block, void *env_ptr)
del_pset(live_in);
}
/**
* A new assign...
*/
static void assign_new(ir_node *block, be_chordal_alloc_env_t *alloc_env, bitset_t *live_end_dom)
{
be_chordal_env_t *env = alloc_env->chordal_env;
bitset_t *colors = alloc_env->colors;
bitset_t *in_colors = alloc_env->in_colors;
bitset_t *live = bitset_irg_malloc(env->irg);
const arch_env_t *arch_env = env->birg->main_env->arch_env;
be_irg_t *birg = env->birg;
lv_chk_t *lv = be_get_birg_liveness_chk(birg);
bitset_pos_t elm;
ir_node *irn;
bitset_clear_all(colors);
bitset_clear_all(in_colors);
/*
* All variables which are live in to this block are live out
* of the immediate dominator thanks to SSA properties. As we
* have already visited the immediate dominator, we know these
* variables. The only tjing left is to check wheather they are live
* in here (they also could be phi arguments to some ohi not
* in this block, hence we have to check).
*/
bitset_foreach (live_end_dom, elm) {
ir_node *irn = get_idx_irn(env->irg, elm);
if (lv_chk_bl_in(lv, block, irn)) {
const arch_register_t *reg = arch_get_irn_register(arch_env, irn);
int col;
assert(be_is_live_in(env->birg->lv, block, irn));
assert(reg && "Node must have been assigned a register");
col = arch_register_get_index(reg);
DBG((dbg, LEVEL_4, "%+F has reg %s\n", irn, reg->name));
/* Mark the color of the live in value as used. */
bitset_set(colors, col);
bitset_set(in_colors, col);
/* Mark the value live in. */
bitset_set(live, elm);
}
else {
assert(!be_is_live_in(env->birg->lv, block, irn));
}
}
/*
* Mind that the sequence of defs from back to front defines a perfect
* elimination order. So, coloring the definitions from first to last
* will work.
*/
sched_foreach (block, irn) {
int nr = get_irn_idx(irn);
int ignore = arch_irn_is(arch_env, irn, ignore);
/* Clear the color upon a last use. */
if(!is_Phi(irn)) {
int i;
for (i = get_irn_arity(irn) - 1; i >= 0; --i) {
ir_node *op = get_irn_n(irn, i);
/*
* If the reg class matches and the operand is not live after
* the node, irn is a last use of op and the register can
* be freed.
*/
if (has_reg_class(env, op)) {
if (!be_lv_chk_after_irn(birg, op, irn)) {
const arch_register_t *reg = arch_get_irn_register(arch_env, op);
int col;
assert(reg && "Register must have been assigned");
col = arch_register_get_index(reg);
bitset_clear(colors, col);
bitset_clear(live, nr);
}
}
}
}
if (has_reg_class(env, irn)) {
const arch_register_t *reg;
int col = NO_COLOR;
/*
* Assign a color, if it is a local def. Global defs already have a
* color.
*/
if(ignore || pset_find_ptr(alloc_env->pre_colored, irn)) {
reg = arch_get_irn_register(arch_env, irn);
col = reg->index;
assert(!bitset_is_set(colors, col) && "pre-colored register must be free");
} else {
col = get_next_free_reg(alloc_env, colors);
reg = arch_register_for_index(env->cls, col);
assert(arch_get_irn_register(arch_env, irn) == NULL && "This node must not have been assigned a register yet");
assert(!arch_register_type_is(reg, ignore) && "Must not assign ignore register");
}
bitset_set(colors, col);
arch_set_irn_register(arch_env, irn, reg);
DBG((dbg, LEVEL_1, "\tassigning register %s(%d) to %+F\n", arch_register_get_name(reg), col, irn));
assert(!bitset_is_set(live, nr) && "Value's definition must not have been encountered");
bitset_set(live, nr);
}
}
dominates_for_each (block, irn) {
assign_new(irn, alloc_env, live);
}
bitset_free(live);
}
void be_ra_chordal_color(be_chordal_env_t *chordal_env)
{
be_chordal_alloc_env_t env;
......@@ -972,7 +1099,11 @@ void be_ra_chordal_color(be_chordal_env_t *chordal_env)
dom_tree_walk_irg(irg, pressure, NULL, &env);
/* Assign the colors */
#ifdef NEW_STYLE_ASSIGN
assign_new(get_irg_start_block(irg), &env, env.live);
#else
dom_tree_walk_irg(irg, assign, NULL, &env);
#endif
if(chordal_env->opts->dump_flags & BE_CH_DUMP_TREE_INTV) {
plotter_t *plotter;
......@@ -988,7 +1119,7 @@ void be_ra_chordal_color(be_chordal_env_t *chordal_env)
void be_init_chordal(void)
{
FIRM_DBG_REGISTER(dbg, "firm.be.chordal.constr");
FIRM_DBG_REGISTER(dbg, "firm.be.chordal");
}
BE_REGISTER_MODULE_CONSTRUCTOR(be_init_chordal);
......@@ -44,7 +44,7 @@
#include "becopyopt_t.h"
#include "becopystat.h"
#include "benodesets.h"
#include "bera.h"
#include "beintlive_t.h"
#include "beirg_t.h"
DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)
......@@ -96,7 +96,7 @@ static INLINE int nodes_interfere(const be_chordal_env_t *env, const ir_node *a,
if (env->ifg)
return be_ifg_connected(env->ifg, a, b);
else
return values_interfere(env->birg->lv, a, b);
return values_interfere(env->birg, a, b);
}
static int set_cmp_conflict_t(const void *x, const void *y, size_t size) {
......
......@@ -54,6 +54,7 @@
#include "benode_t.h"
#include "beutil.h"
#include "beifg_t.h"
#include "beintlive_t.h"
#include "becopyopt_t.h"
#include "becopystat.h"
#include "belive_t.h"
......@@ -64,7 +65,6 @@
#include "bestatevent.h"
#include "beirg_t.h"
#include "error.h"
#include "bera.h"
#include <libcore/lc_timing.h>
#include <libcore/lc_opts.h>
......@@ -176,7 +176,7 @@ static int nodes_interfere(const be_chordal_env_t *env, const ir_node *a, const
if (env->ifg)
return be_ifg_connected(env->ifg, a, b);
else
return values_interfere(env->birg->lv, a, b);
return values_interfere(env->birg, a, b);
}
......
......@@ -45,7 +45,7 @@
#include "becopystat.h"
#include "beirg_t.h"
#include "bemodule.h"
#include "bera.h"
#include "beintlive_t.h"
#define DEBUG_LVL SET_LEVEL_1
DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)
......@@ -239,10 +239,9 @@ static void stat_phi_node(be_chordal_env_t *chordal_env, ir_node *phi) {
* Collect register-constrained node data
*/
static void stat_copy_node(be_chordal_env_t *chordal_env, ir_node *root) {
be_lv_t *lv = be_get_birg_liveness(chordal_env->birg);
curr_vals[I_CPY_CNT]++;
curr_vals[I_COPIES_MAX]++;
if (values_interfere(lv, root, get_Perm_src(root))) {
if (values_interfere(chordal_env->birg, root, get_Perm_src(root))) {
curr_vals[I_COPIES_IF]++;
assert(0 && "A Perm pair (in/out) should never interfere!");
}
......@@ -253,7 +252,6 @@ static void stat_copy_node(be_chordal_env_t *chordal_env, ir_node *root) {
*/
static void stat_phi_class(be_chordal_env_t *chordal_env, ir_node **pc) {
int i, o, size, if_free, phis;
be_lv_t *lv = be_get_birg_liveness(chordal_env->birg);
/* phi class count */
curr_vals[I_CLS_CNT]++;
......@@ -279,7 +277,7 @@ static void stat_phi_class(be_chordal_env_t *chordal_env, ir_node **pc) {
curr_vals[I_CLS_IF_MAX] += size * (size - 1) / 2;
for (if_free = 1, i = 0; i < size - 1; ++i)
for (o = i + 1; o < size; ++o)
if (values_interfere(lv, pc[i], pc[o])) {
if (values_interfere(chordal_env->birg, pc[i], pc[o])) {
if_free = 0;
curr_vals[I_CLS_IF_CNT]++;
}
......
......@@ -40,7 +40,7 @@
#include "bearch_t.h"
#include "be_t.h"
#include "bera.h"
#include "beintlive_t.h"
#include "beifg_t.h"
#include "bechordal_t.h"
#include "benodesets.h"
......
......@@ -45,7 +45,7 @@
#include "beifg_t.h"
#include "bechordal_t.h"
#include "beirg_t.h"
#include "bera.h"
#include "beintlive_t.h"
typedef struct _ifg_std_t ifg_std_t;
......@@ -62,8 +62,7 @@ static void ifg_std_free(void *self)
static int ifg_std_connected(const void *self, const ir_node *a, const ir_node *b)
{
const ifg_std_t *ifg = self;
be_lv_t *lv = ifg->env->birg->lv;
return values_interfere(lv, a, b);
return values_interfere(ifg->env->birg, a, b);
}
typedef struct _nodes_iter_t {
......
/**
* @file beintlive_t.h
* @date 10.05.2007
* @author Sebastian Hack
*
* Principal routines for liveness and interference checks.
*
* Copyright (C) 2007 Universitaet Karlsruhe
* Released under the GPL
*/
#ifndef _BELIVECHK_T_H
#define _BELIVECHK_T_H
#include "irgraph_t.h"
#include "irphase_t.h"
#include "iredges_t.h"
#include "irlivechk.h"
#include "beirg_t.h"
#include "besched_t.h"
/**
* Check dominance of two nodes in the same block.
* @param a The first node.
* @param b The second node.
* @return 1 if a comes before b in the same block or if a == b, 0 else.
*/
static INLINE int _value_dominates_intrablock(const ir_node *a, const ir_node *b)
{
/* TODO: ? : can be removed?! */
sched_timestep_t as = is_Phi(a) ? 0 : sched_get_time_step(a);
sched_timestep_t bs = is_Phi(b) ? 0 : sched_get_time_step(b);
return as <= bs;
}
/**
* Check, if one value dominates the other.
* The dominance is not strict here.
* @param a The first node.
* @param b The second node.
* @return 1 if a dominates b or if a == b, 0 else.
*/
static INLINE int _value_dominates(const ir_node *a, const ir_node *b)
{
const ir_node *block_a = get_block(a);
const ir_node *block_b = get_block(b);
/*
* a and b are not in the same block,
* so dominance is determined by the dominance of the blocks.
*/
if(block_a != block_b) {
return block_dominates(block_a, block_b);
}
/*
* Dominance is determined by the time steps of the schedule.
*/
return _value_dominates_intrablock(a, b);
}
/**
* Check, if two values interfere.
* @param lv Liveness information (in the future we should use a be_irg_t here).
* @param a The first value.
* @param b The second value.
* @return 1, if a and b interfere, 0 if not.
*/
static INLINE int _lv_values_interfere(const be_lv_t *lv, const ir_node *a, const ir_node *b)
{
int a2b = _value_dominates(a, b);
int b2a = _value_dominates(b, a);
/* If there is no dominance relation, they do not interfere. */
if((a2b | b2a) > 0) {
const ir_edge_t *edge;
ir_node *bb;
/*
* Adjust a and b so, that a dominates b if
* a dominates b or vice versa.
*/
if(b2a) {
const ir_node *t = a;
a = b;
b = t;
}
bb = get_nodes_block(b);
/*
* If a is live end in b's block it is
* live at b's definition (a dominates b)
*/
if(be_is_live_end(lv, bb, a))
return 1;
/*
* Look at all usages of a.
* If there's one usage of a in the block of b, then
* we check, if this use is dominated by b, if that's true
* a and b interfere. Note that b must strictly dominate the user,
* since if b is the last user of in the block, b and a do not
* interfere.
* Uses of a not in b's block can be disobeyed, because the
* check for a being live at the end of b's block is already
* performed.
*/
foreach_out_edge(a, edge) {
const ir_node *user = get_edge_src_irn(edge);
if(get_nodes_block(user) == bb && !is_Phi(user) && b != user && _value_dominates(b, user))
return 1;
}
}
return 0;
}
/**
* Check if a node dominates a use.
* Note that the use of a phi is in its corresponding predecessor.
* @param irn The node.
* @param edge The use.
* @return 1, if @p irn dominates the use @p edge.
*/
static INLINE int _dominates_use(const ir_node *irn, const ir_edge_t *edge)
{
ir_node *use = get_edge_src_irn(edge);
if (is_Phi(use)) {
int pos = get_edge_src_pos(edge);
ir_node *phi_bl = get_nodes_block(use);
ir_node *use_bl = get_Block_cfgpred_block(phi_bl, pos);
ir_node *irn_bl = get_nodes_block(irn);
return block_dominates(irn_bl, use_bl);
}
return _value_dominates(irn, use);
}
/**
* Check if a node strictly dominates a use.
* Note that the use of a phi is in its corresponding predecessor.
* @param irn The node.
* @param edge The use.
* @return 1, if @p irn strictly dominates the use @p edge.
*/
static INLINE int _strictly_dominates_use(const ir_node *irn, const ir_edge_t *edge)
{
return get_edge_src_irn(edge) != irn && _dominates_use(irn, edge);
}
/**
* Check, if a node is live in front of another.
* @param birg The backend irg.
* @param irn The node.
* @param where The location to check for.
* @return 1, if @p irn is live in front of @p where.
*/
static INLINE int _be_lv_chk_before_irn(const be_irg_t *birg, const ir_node *irn, const ir_node *where)
{
const lv_chk_t *lv = be_get_birg_liveness_chk(birg);
const ir_edge_t *edge;
/* the node must strictly dominate the location, else it cannot be live there. */
if (!_value_dominates(irn, where) || irn == where)
return 0;
/*
* now that it is clear that it strictly dominates the location it is surely live
* if it is also live end at the block.
*/
if (lv_chk_bl_end(lv, get_nodes_block(where), irn))
return 1;
/*
* If the node is not live out, we have to check if there
* is a use which is dominated by the location.
*/
foreach_out_edge (irn, edge) {
if (_dominates_use(where, edge))
return 1;
}
return 0;
}
/**
* Check, if a node is live after another node.
* @param birg The backend irg.
* @param irn The node.
* @param where The location to check for.
* @return 1, if @p irn is live after @p where.
*/
static INLINE int _be_lv_chk_after_irn(const be_irg_t *birg, const ir_node *irn, const ir_node *where)
{
const lv_chk_t *lv = be_get_birg_liveness_chk(birg);
const ir_edge_t *edge;
if (!_value_dominates(irn, where))
return 0;
if (lv_chk_bl_end(lv, get_nodes_block(where), irn))
return 1;
foreach_out_edge (irn, edge) {
if (_strictly_dominates_use(where, edge))
return 1;
}
return 0;
}
/**
* Check, if two nodes interfere.
* This will become the favored rotine to call but it is not used yet.
* @param birg The backend irg.
* @param a The first node.
* @param b The second node.
* @return 1, if a and b interfere, 0 if not.
*/
static INLINE int _be_lv_chk_values_interfere(const be_irg_t *birg, const ir_node *a, const ir_node *b)
{
int adb = _value_dominates(a, b);
int bda = _value_dominates(b, a);
if (bda) {
const ir_node *t = a;
a = b;
b = t;
adb = 1;
}
return adb && _be_lv_chk_after_irn(birg, a, b);
}
#define value_dominates_intrablock(a, b) _value_dominates_intrablock(a, b)
#define value_dominates(a, b) _value_dominates(a, b)
#define lv_values_interfere(lv, a, b) _lv_values_interfere(lv, a, b)
#define values_interfere(birg, a, b) _lv_values_interfere(be_get_birg_liveness(birg), a, b)
#define dominates_use(a, e) _dominates_use(a, e)
#define strictly_dominates_use(a, e) _strictly_dominates_use(a, e)
#define be_lv_chk_before_irn(birg, a, b) _be_lv_chk_before_irn(birg, a, b)
#define be_lv_chk_after_irn(birg, a, b) _be_lv_chk_after_irn(birg, a, b)
#define be_lv_chk_values_interfere(birg, a, b) _be_lv_chk_values_interfere(birg, a, b)
#endif /* _BELIVECHK_T_H */
......@@ -31,6 +31,14 @@
#include "execfreq.h"
#include "beirg_t.h"
void be_assure_liveness_chk(be_irg_t *birg)
{
if (birg->lv_chk != NULL)
return;
birg->lv_chk = lv_chk_new(birg->irg);
}
void be_assure_liveness(be_irg_t *birg)
{
if (birg->lv != NULL)
......@@ -95,6 +103,11 @@ be_lv_t *(be_get_birg_liveness)(const be_irg_t *birg)
return _be_get_birg_liveness(birg);
}
lv_chk_t *(be_get_birg_liveness_chk)(const be_irg_t *birg)
{
return _be_get_birg_liveness_chk(birg);
}
be_dom_front_info_t *(be_get_birg_dom_front)(const be_irg_t *birg)
{
return _be_get_birg_dom_front(birg);
......
......@@ -35,6 +35,7 @@ typedef struct be_irg_t be_irg_t;
ir_graph *be_get_birg_irg(const be_irg_t *birg);
void be_assure_liveness(<