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

Proper ordering of stack insns inside the basic block

parent 6cafacc9
/**
* ABI lowering.
*
*
*
* @author Sebastian Hack
* @date 7.3.2005
*/
#ifdef HAVE_CONFIG_H
......@@ -340,19 +340,31 @@ static INLINE int is_on_stack(be_abi_call_t *call, int pos)
return arg && !arg->in_reg;
}
/*
____ _ _
/ ___|__ _| | |___
| | / _` | | / __|
| |__| (_| | | \__ \
\____\__,_|_|_|___/
Adjustment of the calls inside a graph.
*/
/**
* Transform a call node.
* @param env The ABI environment for the current irg.
* @param irn THe call node.
* @param irn The call node.
* @param curr_sp The stack pointer node to use.
* @return The stack pointer after the call.
*/
static void adjust_call(be_abi_irg_t *env, ir_node *irn)
static ir_node *adjust_call(be_abi_irg_t *env, ir_node *irn, ir_node *curr_sp)
{
ir_graph *irg = env->birg->irg;
const arch_isa_t *isa = env->birg->main_env->arch_env->isa;
be_abi_call_t *call = be_abi_call_new();
ir_type *mt = get_Call_type(irn);
int n_params = get_method_n_params(mt);
ir_node *curr_sp = env->init_sp;
ir_node *curr_mem = get_Call_mem(irn);
ir_node *bl = get_nodes_block(irn);
pset *results = pset_new_ptr(8);
......@@ -365,13 +377,13 @@ static void adjust_call(be_abi_irg_t *env, ir_node *irn)
ir_node *no_mem = get_irg_no_mem(irg);
ir_node *res_proj = NULL;
int curr_res_proj = -1;
int curr_res_proj = pn_Call_max;
int n_low_args = 0;
int n_pos = 0;
ir_node *low_call;
ir_node **in;
ir_node *sp_proj;
ir_node **res_projs;
const ir_edge_t *edge;
int *low_args;
int *pos;
......@@ -503,8 +515,19 @@ static void adjust_call(be_abi_irg_t *env, ir_node *irn)
ir_node *res = get_edge_src_irn(res_edge);
assert(is_Proj(res));
proj = get_Proj_proj(res);
arg = get_call_arg(call, 1, proj);
/*
shift the proj number to the right, since we will drop the
unspeakable Proj_T from the Call. Therefore, all real argument
Proj numbers must be increased by pn_Call_max
*/
proj += pn_Call_max;
set_Proj_proj(res, proj);
obstack_ptr_grow(obst, res);
if(proj > curr_res_proj)
curr_res_proj = proj;
if(arg->in_reg)
......@@ -513,16 +536,23 @@ static void adjust_call(be_abi_irg_t *env, ir_node *irn)
}
}
curr_res_proj++;
obstack_ptr_grow(obst, NULL);
res_projs = obstack_finish(obst);
/* make the back end call node and set its register requirements. */
for(i = 0; i < n_low_args; ++i)
obstack_ptr_grow(obst, get_Call_param(irn, low_args[i]));
in = obstack_finish(obst);
// if(env->call->flags.bits.call_has_imm && get_irn_opcode());
low_call = be_new_Call(irg, bl, curr_mem, curr_sp, get_Call_ptr(irn), curr_res_proj, n_low_args, in);
obstack_free(obst, in);
exchange(irn, low_call);
/* redirect the result projs to the lowered call instead of the Proj_T */
for(i = 0; res_projs[i]; ++i)
set_Proj_pred(res_projs[i], low_call);
/* Make additional projs for the caller save registers
and the Keep node which keeps them alive. */
if(pset_count(caller_save) > 0) {
......@@ -530,11 +560,8 @@ static void adjust_call(be_abi_irg_t *env, ir_node *irn)
ir_node **in, *keep;
int i, n;
if(!res_proj)
res_proj = new_r_Proj(irg, bl, low_call, mode_T, pn_Call_T_result);
for(reg = pset_first(caller_save), n = 0; reg; reg = pset_next(caller_save), ++n) {
ir_node *proj = new_r_Proj(irg, bl, res_proj, reg->reg_class->mode, curr_res_proj++);
ir_node *proj = new_r_Proj(irg, bl, low_call, reg->reg_class->mode, curr_res_proj++);
/* memorize the register in the link field. we need afterwards to set the register class of the keep correctly. */
set_irn_link(proj, (void *) reg);
......@@ -552,29 +579,185 @@ static void adjust_call(be_abi_irg_t *env, ir_node *irn)
/* Clean up the stack. */
if(stack_size > 0) {
ir_node *last_inc_sp;
ir_node *mem_proj = NULL;
foreach_out_edge(low_call, edge) {
ir_node *irn = get_edge_src_irn(edge);
if(is_Proj(irn) && get_Proj_proj(irn) == pn_Call_M) {
mem_proj = irn;
break;
}
}
/* Get the result ProjT */
if(!res_proj)
res_proj = new_r_Proj(irg, bl, low_call, mode_T, pn_Call_T_result);
if(!mem_proj)
mem_proj = new_r_Proj(irg, bl, low_call, mode_M, pn_Call_M);
/* Make a Proj for the stack pointer. */
sp_proj = new_r_Proj(irg, bl, res_proj, sp->reg_class->mode, curr_res_proj++);
last_inc_sp = be_new_IncSP(sp, irg, bl, sp_proj, no_mem, stack_size, be_stack_dir_against);
curr_sp = be_new_IncSP(sp, irg, bl, curr_sp, mem_proj, stack_size, be_stack_dir_against);
}
be_abi_call_free(call);
obstack_free(obst, pos);
del_pset(results);
del_pset(caller_save);
return curr_sp;
}
/**
* Adjust an alloca.
* The alloca is transformed into a back end alloca node and connected to the stack nodes.
*/
static ir_node *adjust_alloc(be_abi_irg_t *env, ir_node *alloc, ir_node *curr_sp)
{
if(get_Alloc_where(alloc) == stack_alloc) {
ir_node *new_alloc;
ir_node *bl = get_nodes_block(alloc);
ir_graph *irg = get_irn_irg(bl);
new_alloc = be_new_Alloca(env->isa->sp, irg, bl, get_Alloc_mem(alloc), curr_sp, get_Alloc_size(alloc));
exchange(alloc, new_alloc);
curr_sp = new_r_Proj(irg, bl, new_alloc, mode_P, pn_Alloc_res);
}
return curr_sp;
}
/**
* Walker for dependent_on().
* This function searches a node tgt recursively from a given node
* but is restricted to the given block.
* @return 1 if tgt was reachable from curr, 0 if not.
*/
static int check_dependence(ir_node *curr, ir_node *tgt, ir_node *bl, unsigned long visited_nr)
{
int n, i;
if(get_irn_visited(curr) >= visited_nr)
return 0;
set_irn_visited(curr, visited_nr);
if(get_nodes_block(curr) != bl)
return 0;
if(curr == tgt)
return 1;
for(i = 0, n = get_irn_arity(curr); i < n; ++i) {
if(check_dependence(get_irn_n(curr, i), tgt, bl, visited_nr))
return 1;
}
return 0;
}
/**
* Check if a node is somehow data dependent on another one.
* both nodes must be in the same basic block.
* @param n1 The first node.
* @param n2 The second node.
* @return 1, if n1 is data dependent (transitively) on n2, 0 if not.
*/
static int dependent_on(ir_node *n1, ir_node *n2)
{
ir_node *bl = get_nodes_block(n1);
ir_graph *irg = get_irn_irg(bl);
long vis_nr = get_irg_visited(irg) + 1;
assert(bl == get_nodes_block(n2));
set_irg_visited(irg, vis_nr);
return check_dependence(n1, n2, bl, vis_nr);
}
static int cmp_call_dependecy(const void *c1, const void *c2)
{
ir_node *n1 = *(ir_node **) c1;
ir_node *n2 = *(ir_node **) c2;
/*
Classical qsort() comparison function behavior:
0 if both elements are equal
1 if second is "smaller" that first
-1 if first is "smaller" that second
*/
return n1 == n2 ? 0 : (dependent_on(n1, n2) ? -1 : 1);
}
static void link_calls_in_block_walker(ir_node *irn, void *data)
{
if(is_Call(irn)) {
ir_node *bl = get_nodes_block(irn);
void *save = get_irn_link(bl);
set_irn_link(irn, save);
set_irn_link(bl, irn);
}
}
/**
* Process all call nodes inside a basic block.
* Note that the link field of the block must contain a linked list of all
* Call nodes inside the block. We first order this list according to data dependency
* and that connect the calls together.
*/
static void process_calls_in_block(ir_node *bl, void *data)
{
be_abi_irg_t *env = data;
ir_node *curr_sp = env->init_sp;
ir_node *irn;
int n;
for(irn = get_irn_link(bl), n = 0; irn; irn = get_irn_link(irn), ++n)
obstack_ptr_grow(&env->obst, irn);
/* If there were call nodes in the block. */
if(n > 0) {
ir_node **nodes;
int i;
nodes = obstack_finish(&env->obst);
/* order the call nodes according to data dependency */
qsort(nodes, n, sizeof(nodes[0]), cmp_call_dependecy);
for(i = n - 1; i >= 0; --i) {
ir_node *irn = nodes[i];
switch(get_irn_opcode(irn)) {
case iro_Call:
curr_sp = adjust_call(env, irn, curr_sp);
break;
case iro_Alloc:
curr_sp = adjust_alloc(env, irn, curr_sp);
break;
default:
break;
}
}
obstack_free(&env->obst, nodes);
/* Keep the last stack state in the block by tying it to Keep node */
nodes[0] = curr_sp;
be_new_Keep(env->isa->sp->reg_class, get_irn_irg(bl), bl, 1, nodes);
}
set_irn_link(bl, curr_sp);
}
static void adjust_call_walker(ir_node *irn, void *data)
/**
* Adjust all call nodes in the graph to the ABI conventions.
*/
static void process_calls(be_abi_irg_t *env)
{
if(get_irn_opcode(irn) == iro_Call)
adjust_call(data, irn);
ir_graph *irg = env->birg->irg;
irg_walk_graph(irg, firm_clear_link, link_calls_in_block_walker, NULL);
irg_block_walk_graph(irg, NULL, process_calls_in_block, env);
}
#if 0
/**
* Walker to implement alloca-style allocations.
* They are implemented using an add to the stack pointer
......@@ -599,6 +782,7 @@ static void implement_stack_alloc(be_abi_irg_t *env, ir_node *irn)
res = be_new_Copy(isa->sp->reg_class, env->birg->irg, bl, res);
}
#endif
static void collect_return_walker(ir_node *irn, void *data)
{
......@@ -655,19 +839,19 @@ static void clearup_frame(be_abi_irg_t *env, ir_node *ret, struct obstack *obst)
const arch_register_t *sp = isa->sp;
const arch_register_t *bp = isa->bp;
ir_graph *irg = env->birg->irg;
ir_node *no_mem = get_irg_no_mem(irg);
ir_node *ret_mem = get_Return_mem(ret);
ir_node *frame = get_irg_frame(irg);
ir_node *stack = env->init_sp;
ir_node *bl = get_nodes_block(ret);
ir_node *stack = get_irn_link(bl);
pmap_entry *ent;
if(env->call->flags.bits.try_omit_fp) {
stack = be_new_IncSP(sp, irg, bl, stack, no_mem, BE_STACK_FRAME_SIZE, be_stack_dir_against);
stack = be_new_IncSP(sp, irg, bl, stack, ret_mem, BE_STACK_FRAME_SIZE, be_stack_dir_against);
}
else {
stack = be_new_SetSP(sp, irg, bl, stack, frame, get_Return_mem(ret));
stack = be_new_SetSP(sp, irg, bl, stack, frame, ret_mem);
be_set_constr_single_reg(stack, -1, sp);
be_node_set_flags(stack, -1, arch_irn_flags_ignore);
}
......@@ -716,16 +900,6 @@ static ir_type *compute_arg_type(be_abi_irg_t *env, be_abi_call_t *call, ir_type
return res;
}
static type *get_bp_type(const arch_register_t *bp)
{
static type *bp_type = NULL;
if(!bp_type) {
bp_type = new_type_primitive(new_id_from_str("bp_type"), bp->reg_class->mode);
set_type_size_bytes(bp_type, get_mode_size_bytes(bp->reg_class->mode));
}
return bp_type;
}
/**
* Modify the irg itself and the frame type.
*/
......@@ -951,7 +1125,7 @@ be_abi_irg_t *be_abi_introduce(be_irg_t *birg)
be_abi_irg_t *env = malloc(sizeof(env[0]));
int i;
ir_node **stack_allocs;
ir_node **nodes;
pmap_entry *ent;
env->isa = birg->main_env->arch_env->isa;
......@@ -959,23 +1133,30 @@ be_abi_irg_t *be_abi_introduce(be_irg_t *birg)
env->call = be_abi_call_new();
arch_isa_get_call_abi(env->isa, env->method_type, env->call);
env->dce_survivor = new_survive_dce();
env->birg = birg;
env->dbg = firm_dbg_register("firm.be.abi");
env->stack_phis = pset_new_ptr_default();
env->dce_survivor = new_survive_dce();
env->birg = birg;
env->dbg = firm_dbg_register("firm.be.abi");
env->stack_phis = pset_new_ptr(16);
env->init_sp = new_r_Unknown(birg->irg, env->isa->sp->reg_class->mode);
obstack_init(&env->obst);
memcpy(&env->irn_handler, &abi_irn_handler, sizeof(abi_irn_handler));
env->irn_ops.impl = &abi_irn_ops;
/* Lower all call nodes in the IRG. */
process_calls(env);
#if 0
/* search for stack allocation nodes and record them */
irg_walk_graph(env->birg->irg, collect_alloca_walker, NULL, env);
obstack_ptr_grow(&env->obst, NULL);
stack_allocs = obstack_finish(&env->obst);
nodes = obstack_finish(&env->obst);
/* If there are stack allocations in the irg, we need a frame pointer */
if(stack_allocs[0] != NULL)
if(nodes[0] != NULL)
env->call->flags.bits.try_omit_fp = 0;
#endif
modify_irg(env);
......@@ -985,11 +1166,10 @@ be_abi_irg_t *be_abi_introduce(be_irg_t *birg)
survive_dce_register_irn(env->dce_survivor, (ir_node **) &ent->value);
/* Fix the alloca-style allocations */
for(i = 0; stack_allocs[i] != NULL; ++i)
implement_stack_alloc(env, stack_allocs[i]);
/* Lower all call nodes in the IRG. */
irg_walk_graph(env->birg->irg, NULL, adjust_call_walker, env);
#if 0
for(i = 0; nodes[i] != NULL; ++i)
implement_stack_alloc(env, nodes[i]);
#endif
arch_env_push_irn_handler(env->birg->main_env->arch_env, &env->irn_handler);
......@@ -1002,7 +1182,7 @@ static void collect_stack_nodes(ir_node *irn, void *data)
switch(be_get_irn_opcode(irn)) {
case beo_IncSP:
case beo_AddSP:
// case beo_AddSP:
case beo_SetSP:
pset_insert_ptr(s, irn);
default:
......
Supports Markdown
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