Commit b267d8d2 authored by Sebastian Hack's avatar Sebastian Hack
Browse files

Misc changes

Added ILP spilling
parent 42f34c55
......@@ -26,7 +26,7 @@ SOURCES += Makefile.in besched.h belistsched.h belistsched.c \
becopyoptmain.c becopyopt.c becopyheur.c \
becopyilp.c becopystat.c bearch_firm.c bearch.c bechordal_draw.c \
bechordal_draw.h beirgmod.c beirgmod.h benode.c benode_t.h \
bessadestr.c beifg.c
bessadestr.c beifg.c bespillilp.c
include $(topdir)/MakeRules
......
......@@ -105,6 +105,12 @@ int arch_get_allocatable_regs(const arch_env_t *env, const ir_node *irn,
return 0;
}
int arch_get_n_operands(const arch_env_t *env, const ir_node *irn, int in_out)
{
const arch_irn_ops_t *ops = get_irn_ops(env, irn);
return ops->get_n_operands(ops, irn, in_out);
}
int arch_is_register_operand(const arch_env_t *env,
const ir_node *irn, int pos)
{
......@@ -168,3 +174,9 @@ extern arch_irn_class_t arch_irn_classify(const arch_env_t *env, const ir_node *
const arch_irn_ops_t *ops = get_irn_ops(env, irn);
return ops->classify(ops, irn);
}
extern arch_irn_flags_t arch_irn_get_flags(const arch_env_t *env, const ir_node *irn)
{
const arch_irn_ops_t *ops = get_irn_ops(env, irn);
return ops->get_flags(ops, irn);
}
......@@ -196,6 +196,13 @@ typedef enum _arch_irn_class_t {
arch_irn_class_branch
} arch_irn_class_t;
/**
* Some flags describing a node in more detail.
*/
typedef enum _arch_irn_flags_t {
arch_irn_flags_spillable = 1,
arch_irn_flags_rematerializable = 2
} arch_irn_flags_t;
/*
* Some words about positions and indices:
......@@ -305,9 +312,19 @@ struct _arch_irn_ops_t {
*/
arch_irn_class_t (*classify)(const arch_irn_ops_t *self, const ir_node *irn);
/**
* Get the flags of a node.
* @param self The irn ops themselves.
* @param irn The node.
* @return A set of flags.
*/
arch_irn_flags_t (*get_flags)(const arch_irn_ops_t *self, const ir_node *irn);
};
extern int
arch_get_n_operands(const arch_env_t *env, const ir_node *irm, int in_out);
/**
* Get the register requirements for a node.
* @param env The architecture environment.
......@@ -400,6 +417,14 @@ extern void arch_set_irn_register(const arch_env_t *env,
*/
extern arch_irn_class_t arch_irn_classify(const arch_env_t *env, const ir_node *irn);
/**
* Get the flags of a node.
* @param env The architecture environment.
* @param irn The node.
* @return The flags.
*/
extern arch_irn_flags_t arch_irn_get_flags(const arch_env_t *env, const ir_node *irn);
#define arch_irn_has_reg_class(env, irn, pos, cls) \
((cls) == arch_get_irn_reg_class(env, irn, pos))
......
......@@ -21,7 +21,7 @@
#include "irreflect.h"
#define N_REGS 512
#define N_REGS 6
static arch_register_t datab_regs[N_REGS];
......@@ -29,10 +29,8 @@ static arch_register_class_t reg_classes[] = {
{ "datab", N_REGS, datab_regs },
};
static ir_op *op_push_end;
static ir_op *op_push;
static ir_op *op_imm;
static type *push_type;
typedef struct {
enum { imm_Const, imm_SymConst } tp;
......@@ -83,14 +81,21 @@ static void firm_init(void)
* Create some opcodes and types to let firm look a little
* bit more like real machines.
*/
if(!op_push_end) {
op_push_end = new_ir_op(get_next_ir_opcode(), "PushEnd",
op_pin_state_pinned, 0, oparity_unary, 0, 0);
}
if(!op_push) {
op_push = new_ir_op(get_next_ir_opcode(), "Push",
rflct_sig_t *sig;
int push_opc = get_next_ir_opcode();
op_push = new_ir_op(push_opc, "Push",
op_pin_state_pinned, 0, oparity_binary, 0, 0);
sig = rflct_signature_allocate(1, 3);
rflct_signature_set_arg(sig, 0, 0, "Store", RFLCT_MC(Mem), 0, 0);
rflct_signature_set_arg(sig, 1, 0, "Block", RFLCT_MC(BB), 0, 0);
rflct_signature_set_arg(sig, 1, 1, "Store", RFLCT_MC(Mem), 0, 0);
rflct_signature_set_arg(sig, 1, 2, "Arg", RFLCT_MC(Datab), 0, 0);
rflct_new_opcode(push_opc, "Push", false);
rflct_opcode_add_signature(push_opc, sig);
}
if(!op_imm) {
......@@ -98,9 +103,6 @@ static void firm_init(void)
op_pin_state_pinned, 0, oparity_zero, 0, sizeof(imm_attr_t));
}
if(!push_type)
push_type = new_type_pointer(new_id_from_str("push_ptr"), get_glob_type());
}
static int firm_get_n_reg_class(void)
......@@ -142,7 +144,12 @@ firm_get_irn_reg_req(const arch_irn_ops_t *self,
static int firm_get_n_operands(const arch_irn_ops_t *self, const ir_node *irn, int in_out)
{
int sig = rflct_get_signature(irn);
int sig;
while(is_Proj(irn))
irn = get_Proj_pred(irn);
sig = rflct_get_signature(irn);
return rflct_get_args_count(get_irn_opcode(irn), sig, in_out >= 0);
}
......@@ -207,12 +214,38 @@ static arch_irn_class_t firm_classify(const arch_irn_ops_t *self, const ir_node
return res;
}
static arch_irn_flags_t firm_get_flags(const arch_irn_ops_t *self, const ir_node *irn)
{
arch_irn_flags_t res = arch_irn_flags_spillable;
if(get_irn_op(irn) == op_imm)
res |= arch_irn_flags_rematerializable;
switch(get_irn_opcode(irn)) {
case iro_Add:
case iro_Sub:
case iro_Shl:
case iro_Shr:
case iro_Shrs:
case iro_And:
case iro_Or:
case iro_Eor:
case iro_Not:
res |= arch_irn_flags_rematerializable;
default:
res = res;
}
return res;
}
static const arch_irn_ops_t irn_ops = {
firm_get_irn_reg_req,
firm_get_n_operands,
firm_set_irn_reg,
firm_get_irn_reg,
firm_classify
firm_classify,
firm_get_flags
};
static const arch_irn_ops_t *firm_get_irn_ops(const arch_irn_handler_t *self,
......@@ -225,19 +258,12 @@ const arch_irn_handler_t firm_irn_handler = {
firm_get_irn_ops,
};
static ir_node *new_PushEnd(ir_graph *irg, ir_node *bl, ir_node *arg)
{
ir_node *ins[1];
ins[0] = arg;
return new_ir_node(NULL, irg, bl, op_push_end, mode_P, 1, ins);
}
static ir_node *new_Push(ir_graph *irg, ir_node *bl, ir_node *push, ir_node *arg)
{
ir_node *ins[2];
ins[0] = push;
ins[1] = arg;
return new_ir_node(NULL, irg, bl, op_push, mode_P, 2, ins);
return new_ir_node(NULL, irg, bl, op_push, mode_M, 2, ins);
}
static ir_node *new_Imm(ir_graph *irg, ir_node *bl, ir_node *cnst)
......@@ -274,42 +300,38 @@ static void prepare_walker(ir_node *irn, void *data)
ir_node *bl = get_nodes_block(irn);
ir_graph *irg = get_irn_irg(bl);
ir_node *ins[1];
ir_node *store = get_Call_mem(irn);
ir_node *ptr = get_Call_ptr(irn);
type *ct = get_Call_type(irn);
int np = get_Call_n_params(irn) > 0 ? 1 : 0;
if(np > 0) {
ir_node *ins[1];
char buf[128];
ir_node *nc;
ir_node *push;
int i, n;
type *nt;
push = new_PushEnd(irg, bl, get_Call_param(irn, 0));
store = new_Push(irg, bl, store, get_Call_param(irn, 0));
for(i = 1, n = get_Call_n_params(irn); i < n; ++i) {
push = new_Push(irg, bl, push, get_Call_param(irn, i));
store = new_Push(irg, bl, store, get_Call_param(irn, i));
}
snprintf(buf, sizeof(buf), "push_%s", get_type_name(ct));
n = get_method_n_ress(ct);
nt = new_type_method(new_id_from_str(buf), 1, n);
nt = new_type_method(new_id_from_str(buf), 0, n);
for(i = 0; i < n; ++i)
set_method_res_type(nt, i, get_method_res_type(ct, i));
set_method_param_type(nt, 0, push_type);
ins[0] = push;
nc = new_r_Call(irg, bl, store, ptr, 1, ins, nt);
nc = new_r_Call(irg, bl, store, ptr, 0, ins, nt);
exchange(irn, nc);
set_irn_link(nc, nc);
}
}
#if 0
else if(opc == iro_Const || opc == iro_SymConst) {
ir_node *bl = get_nodes_block(irn);
ir_graph *irg = get_irn_irg(bl);
......@@ -318,7 +340,6 @@ static void prepare_walker(ir_node *irn, void *data)
exchange(irn, imm);
set_irn_link(imm, imm);
}
#endif
}
......
......@@ -259,7 +259,8 @@ 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->session_env->main_env->arch_env, irn, arch_pos_make_out(0), env->cls);
return arch_irn_has_reg_class(env->session_env->main_env->arch_env,
irn, arch_pos_make_out(0), env->cls);
}
/**
......@@ -303,10 +304,11 @@ static void pressure(ir_node *block, void *env_ptr)
* They are necessary to build up real intervals.
*/
for(irn = pset_first(live_end); irn; irn = pset_next(live_end)) {
DBG((dbg, LEVEL_3, "\tMaking live: %+F/%d\n", irn, get_irn_graph_nr(irn)));
bitset_set(live, get_irn_graph_nr(irn));
if(has_reg_class(env, irn))
if(has_reg_class(env, irn)) {
DBG((dbg, LEVEL_3, "\tMaking live: %+F/%d\n", irn, get_irn_graph_nr(irn)));
bitset_set(live, get_irn_graph_nr(irn));
border_use(irn, step, 0);
}
}
++step;
......@@ -618,3 +620,63 @@ set *be_ra_get_ifg_nodes(const be_chordal_env_t *env) {
}
#endif
typedef struct {
const be_main_session_env_t *env;
const arch_register_class_t *cls;
} check_pressure_info_t;
static int check_pressure_has_class(const check_pressure_info_t *i, const ir_node *irn)
{
return arch_irn_has_reg_class(i->env->main_env->arch_env,
irn, arch_pos_make_out(0), i->cls);
}
static void check_pressure_walker(ir_node *bl, void *data)
{
check_pressure_info_t *info = data;
int n_regs = arch_register_class_n_regs(info->cls);
pset *live = pset_new_ptr_default();
int step = 0;
ir_node *irn;
irn_live_t *li;
live_foreach(bl, li) {
if(live_is_end(li) && check_pressure_has_class(info, li->irn)) {
ir_node *irn = (ir_node *) li->irn;
pset_insert_ptr(live, irn);
}
}
sched_foreach_reverse(bl, irn) {
int i, n;
int pressure = pset_count(live);
if(pressure > n_regs) {
ir_node *x;
ir_printf("%+10F@%+10F: pressure to high: %d\n", bl, irn, pressure);
for(x = pset_first(live); x; x = pset_next(live))
ir_printf("\t%+10F\n", x);
}
if(check_pressure_has_class(info, irn))
pset_remove_ptr(live, irn);
for(i = 0, n = get_irn_arity(irn); i < n; i++) {
ir_node *op = get_irn_n(irn, i);
if(check_pressure_has_class(info, op) && !is_Phi(irn))
pset_insert_ptr(live, op);
}
step++;
}
}
void be_check_pressure(const be_main_session_env_t *env, const arch_register_class_t *cls)
{
check_pressure_info_t i;
i.env = env;
i.cls = cls;
irg_block_walk_graph(env->irg, check_pressure_walker, NULL, &i);
}
......@@ -131,4 +131,12 @@ void be_ra_chordal_done(be_chordal_env_t *info);
*/
void be_ra_chordal_init(void);
/**
* Check the register pressure in a graph.
* @param env The sesion env.
* @param cls The register class to consider.
*/
void be_check_pressure(const be_main_session_env_t *env, const arch_register_class_t *cls);
#endif /* _BECHORDAL_T_H */
......@@ -25,11 +25,12 @@
#include "besched_t.h"
#include "belive_t.h"
#include "benode_t.h"
#include "beutil.h"
#include "beirgmod.h"
#define DBG_MODULE firm_dbg_register("firm.be.irgmod")
#define DBG_LEVEL 0 //SET_LEVEL_4
#define DBG_LEVEL 0 // SET_LEVEL_4
struct _dom_front_info_t {
pmap *df_map;
......@@ -49,66 +50,9 @@ static INLINE ir_node *get_idom(ir_node *bl)
return idom == NULL ? bl : idom;
}
static void compute_df_local(ir_node *bl, void *data)
{
pmap *df_map = ((dom_front_info_t *) data)->df_map;
ir_node *idom = get_Block_idom(bl);
pset *df = pmap_get(df_map, bl);
int i, n;
/*
* In the case that the immediate dominator is NULL, the
* block is the start block and its immediate dominator
* must be itself, else it is inserted into its own
* dominance frontier.
*/
if(idom == NULL)
idom = bl;
/*
* Create a new dom frot set for this node,
* if none exists.
*/
if(!df)
pmap_insert(df_map, bl, pset_new_ptr(16));
for(i = 0, n = get_irn_arity(bl); i < n; ++i) {
/* The predecessor block */
ir_node *pred = get_nodes_block(get_irn_n(bl, i));
/* The dominance frontier set of the predecessor. */
pset *df = pmap_get(df_map, pred);
if(!df) {
df = pset_new_ptr(16);
pmap_insert(df_map, pred, df);
}
assert(df && "dom front set must have been created for this node");
if(pred != idom && bl)
pset_insert_ptr(df, bl);
}
}
static void compute_df_up(ir_node *bl, void *data)
{
pmap *df_map = ((dom_front_info_t *) data)->df_map;
ir_node *y;
for(y = get_Block_dominated_first(bl); y; y = get_Block_dominated_next(y)) {
ir_node *w;
pset *df = pmap_get(df_map, y);
for(w = pset_first(df); w; w = pset_next(df))
if(!block_dominates(bl, w) || bl == w)
pset_insert_ptr(df, w);
}
}
static void compute_df(ir_node *n, pmap *df_map)
{
ir_node *y, *c;
ir_node *c;
const ir_edge_t *edge;
pset *df = pset_new_ptr_default();
......@@ -133,7 +77,7 @@ static void compute_df(ir_node *n, pmap *df_map)
df_c = pmap_get(df_map, c);
for(w = pset_first(df_c); w; w = pset_next(df_c)) {
if(!block_dominates(n, w))
if(get_idom(w) != n)
pset_insert_ptr(df, w);
}
}
......@@ -150,14 +94,6 @@ dom_front_info_t *be_compute_dominance_frontiers(ir_graph *irg)
info->df_map = pmap_create();
compute_df(get_irg_start_block(irg), info->df_map);
#if 0
/*
* This must be called as a post walker, since the dom front sets
* of all predecessors must be created when a block is reached.
*/
dom_tree_walk_irg(irg, NULL, compute_df_local, info);
dom_tree_walk_irg(irg, NULL, compute_df_up, info);
#endif
return info;
}
......@@ -177,57 +113,22 @@ pset *be_get_dominance_frontier(dom_front_info_t *info, ir_node *block)
return pmap_get(info->df_map, block);
}
/**
* Algorithm to place the Phi-Functions.
* @see Appel, Modern Compiler Implementation in Java, 2nd ed., p. 399ff
*
* This function takes an original node and a set of already placed
* copies of that node called @p copies. It places phi nodes at the
* iterated dominance frontiers of these copies and puts these phi nodes
* in the @p copies set, since they are another form of copies of the
* original value.
*
* The rename phase (see below) is responsible for fixing up the usages
* of the original node.
*
* @param orig The original node.
* @param copies A set contianing nodes representing a copy of the
* original node. Each node must be inserted into the block's schedule.
* @param copy_blocks A set in which the blocks are recorded which
* contain a copy. This is just for efficiency in later phases (see
* rename).
*/
static void place_phi_functions(ir_node *orig, pset *copies,
pset *copy_blocks, dom_front_info_t *df_info)
static void determine_phi_blocks(ir_node *orig, pset *copies,
pset *copy_blocks, pset *phi_blocks, dom_front_info_t *df_info)
{
int i;
ir_node *orig_block = get_nodes_block(orig);
ir_graph *irg = get_irn_irg(orig);
ir_mode *mode = get_irn_mode(orig);
ir_node *bl;
ir_node *orig_block = get_nodes_block(orig);
pdeq *worklist = new_pdeq();
pset *phi_blocks = pset_new_ptr(8);
ir_node **ins = NULL;
void *it;
firm_dbg_module_t *dbg = DBG_MODULE;
/*
* Allocate an array for all blocks where the copies and the original
* value were defined.
*/
int n_orig_blocks = pset_count(copy_blocks);
ir_node **orig_blocks = malloc(n_orig_blocks * sizeof(orig_blocks[0]));
/*
* Fill the worklist queue and the rest of the orig blocks array.
*/
for(it = pset_first(copy_blocks), i = 0; it; it = pset_next(copy_blocks)) {
ir_node *copy_block = it;
assert(block_dominates(orig_block, copy_block)
for(bl = pset_first(copy_blocks); bl; bl = pset_next(copy_blocks)) {
assert(block_dominates(orig_block, bl)
&& "The block of the copy must be dominated by the block of the value");
pdeq_putr(worklist, copy_block);
orig_blocks[i++] = copy_block;
pdeq_putr(worklist, bl);
}
while(!pdeq_empty(worklist)) {
......@@ -240,67 +141,24 @@ static void place_phi_functions(ir_node *orig, pset *copies,
DBG((dbg, LEVEL_3, "\t%+F\n", y));
for(y = pset_first(df); y; y = pset_next(df)) {
int n_preds = get_irn_arity(y);
if(!pset_find_ptr(phi_blocks, y)) {
ir_node *phi;
int insert = 1;
/*
* Set the orig node as the only operand of the
* phi node.
*/
ins = realloc(ins, n_preds * sizeof(ins[0]));
for(i = 0; i < n_preds; ++i)
ins[i] = orig;
/* Insert phi node */
phi = new_r_Phi(irg, y, n_preds, ins, mode);
DBG((dbg, LEVEL_2, " inserting phi %+F with %d args in block %+F\n",
phi, n_preds, y));
/*
* The phi node itself is also a copy of the original
* value. So put it in the copies set also, so that
* the rename phase can treat them right.
*/
pset_insert_ptr(copies, phi);
pset_insert_ptr(copy_blocks, y);
/*
* Insert the phi node into the schedule if it
* can occur there (PhiM's are not to put into a schedule.
*/
if(to_appear_in_schedule(phi))
sched_add_before(sched_first(y), phi);
/* Insert the phi node in the phi blocks set. */
pset_insert_ptr(phi_blocks, y);
/*
* If orig or a copy of it were not defined in y,
* add y to the worklist.
*/
for(i = 0; i < n_orig_blocks; ++i)
if(orig_blocks[i] == y) {
insert = 0;
break;
}
/*
* Clear the link field of a possible phi block, since
* the possibly created phi will be stored there. See,
* search_def()
*/
set_irn_link(y, NULL);
if(insert)
pdeq_putr(worklist, y);
if(!pset_find_ptr(copy_blocks, y))
pdeq_putr(worklist, y);
}
}
}
del_pset(phi_blocks);
del_pdeq(worklist);
free(orig_blocks);
if(ins)
free(ins);
}
/**
......@@ -323,12 +181,12 @@ static void place_phi_functions(ir_node *orig, pset *copies,
* original node.
* @return The valid copy for usage.
*/
static ir_node *search_def(ir_node *usage, int pos, pset *copies, pset *copy_blocks)
static ir_node *search_def(ir_node *usage, int pos, pset *copies,
pset *copy_blocks, pset *phi_blocks, ir_mode *mode)
{
ir_node *curr_bl;
ir_node *start_irn;
firm_dbg_module_t *dbg = DBG_MODULE;