Commit 939b0af7 authored by Matthias Braun's avatar Matthias Braun
Browse files

Another rewrite of prolog/epilog handling: Delay their creation until after register allocation

parent 7ddfd63e
......@@ -43,6 +43,7 @@
#include "TEMPLATE_emitter.h"
#include "gen_TEMPLATE_emitter.h"
#include "gen_TEMPLATE_regalloc_if.h"
#include "TEMPLATE_nodes_attr.h"
#include "TEMPLATE_new_nodes.h"
......@@ -110,16 +111,21 @@ void TEMPLATE_emit_immediate(const ir_node *node)
be_emit_tarval(attr->value);
}
static void emit_register(const arch_register_t *reg)
{
be_emit_string(arch_register_get_name(reg));
}
void TEMPLATE_emit_source_register(const ir_node *node, int pos)
{
const arch_register_t *reg = get_in_reg(node, pos);
be_emit_string(arch_register_get_name(reg));
emit_register(reg);
}
void TEMPLATE_emit_dest_register(const ir_node *node, int pos)
{
const arch_register_t *reg = get_out_reg(node, pos);
be_emit_string(arch_register_get_name(reg));
emit_register(reg);
}
/**
......@@ -164,8 +170,42 @@ static void emit_be_IncSP(const ir_node *node)
be_emit_finish_line_gas(node);
}
static void emit_be_Start(const ir_node *node)
{
ir_graph *irg = get_irn_irg(node);
ir_type *frame_type = get_irg_frame_type(irg);
unsigned size = get_type_size_bytes(frame_type);
/* emit function prolog */
/* allocate stackframe */
if (size > 0) {
be_emit_cstring("\tsub ");
emit_register(&TEMPLATE_registers[REG_SP]);
be_emit_irprintf(", %u, ", size);
emit_register(&TEMPLATE_registers[REG_SP]);
be_emit_finish_line_gas(node);
}
}
static void emit_be_Return(const ir_node *node)
{
ir_graph *irg = get_irn_irg(node);
ir_type *frame_type = get_irg_frame_type(irg);
unsigned size = get_type_size_bytes(frame_type);
/* emit function epilog here */
/* deallocate stackframe */
if (size > 0) {
be_emit_cstring("\tadd ");
emit_register(&TEMPLATE_registers[REG_SP]);
be_emit_irprintf(", %u, ", size);
emit_register(&TEMPLATE_registers[REG_SP]);
be_emit_finish_line_gas(node);
}
/* return */
be_emit_cstring("\tret");
be_emit_finish_line_gas(node);
}
......@@ -199,13 +239,13 @@ static void TEMPLATE_register_emitters(void)
/* custom emitters not provided by the spec */
set_emitter(op_TEMPLATE_Jmp, emit_TEMPLATE_Jmp);
set_emitter(op_be_Return, emit_be_Return);
set_emitter(op_be_IncSP, emit_be_IncSP);
set_emitter(op_be_Return, emit_be_Return);
set_emitter(op_be_Start, emit_be_Start);
/* no need to emit anything for the following nodes */
set_emitter(op_Phi, emit_nothing);
set_emitter(op_be_Keep, emit_nothing);
set_emitter(op_be_Start, emit_nothing);
}
typedef void (*emit_func_ptr) (const ir_node *);
......
......@@ -200,32 +200,16 @@ static const arch_register_class_t *TEMPLATE_get_reg_class_for_mode(const ir_mod
return &TEMPLATE_reg_classes[CLASS_TEMPLATE_gp];
}
typedef struct {
be_abi_call_flags_bits_t flags;
ir_graph *irg;
} TEMPLATE_abi_env_t;
static void *TEMPLATE_abi_init(const be_abi_call_t *call, ir_graph *irg)
{
TEMPLATE_abi_env_t *env = XMALLOC(TEMPLATE_abi_env_t);
be_abi_call_flags_t fl = be_abi_call_get_flags(call);
env->flags = fl.bits;
env->irg = irg;
return env;
}
/**
* Get the between type for that call.
* @param self The callback object.
* @return The between type of for that call.
*/
static ir_type *TEMPLATE_get_between_type(void *self)
static ir_type *TEMPLATE_get_between_type(ir_graph *irg)
{
static ir_type *between_type = NULL;
static ir_entity *old_bp_ent = NULL;
(void) self;
(void) irg;
if (!between_type) {
ir_entity *ret_addr_ent;
......@@ -244,39 +228,8 @@ static ir_type *TEMPLATE_get_between_type(void *self)
return between_type;
}
/**
* Build the prolog, return the BASE POINTER register
*/
static const arch_register_t *TEMPLATE_abi_prologue(void *self, ir_node **mem,
pmap *reg_map, int *stack_bias)
{
TEMPLATE_abi_env_t *env = (TEMPLATE_abi_env_t*)self;
const arch_env_t *arch_env = be_get_irg_arch_env(env->irg);
(void) reg_map;
(void) mem;
(void) stack_bias;
if (env->flags.try_omit_fp)
return arch_env->sp;
return arch_env->bp;
}
/* Build the epilog */
static void TEMPLATE_abi_epilogue(void *self, ir_node *bl, ir_node **mem,
pmap *reg_map)
{
(void) self;
(void) bl;
(void) mem;
(void) reg_map;
}
static const be_abi_callbacks_t TEMPLATE_abi_callbacks = {
TEMPLATE_abi_init,
free,
TEMPLATE_get_between_type,
TEMPLATE_abi_prologue,
TEMPLATE_abi_epilogue,
};
/**
......
......@@ -355,25 +355,16 @@ typedef struct {
ir_graph *irg;
} amd64_abi_env_t;
static void *amd64_abi_init(const be_abi_call_t *call, ir_graph *irg)
{
amd64_abi_env_t *env = XMALLOC(amd64_abi_env_t);
be_abi_call_flags_t fl = be_abi_call_get_flags(call);
env->flags = fl.bits;
env->irg = irg;
return env;
}
/**
* Get the between type for that call.
* @param self The callback object.
* @return The between type of for that call.
*/
static ir_type *amd64_get_between_type(void *self)
static ir_type *amd64_get_between_type(ir_graph *irg)
{
static ir_type *between_type = NULL;
static ir_entity *old_bp_ent = NULL;
(void) self;
(void) irg;
if(!between_type) {
ir_entity *ret_addr_ent;
......@@ -392,53 +383,8 @@ static ir_type *amd64_get_between_type(void *self)
return between_type;
}
/**
* Build the prolog, return the BASE POINTER register
*/
static const arch_register_t *amd64_abi_prologue(void *self, ir_node **mem,
pmap *reg_map, int *stack_bias)
{
amd64_abi_env_t *env = (amd64_abi_env_t*)self;
const arch_env_t *aenv = be_get_irg_arch_env(env->irg);
(void) mem;
(void) stack_bias;
(void) aenv;
(void) reg_map;
if (!env->flags.try_omit_fp) {
/* FIXME: maybe later here should be some code to generate
* the usual abi prologue */
return aenv->bp;
}
return aenv->sp;
}
/* Build the epilog */
static void amd64_abi_epilogue(void *self, ir_node *bl, ir_node **mem,
pmap *reg_map)
{
amd64_abi_env_t *env = (amd64_abi_env_t*)self;
const arch_env_t *aenv = be_get_irg_arch_env(env->irg);
ir_node *curr_sp = be_abi_reg_map_get(reg_map, aenv->sp);
ir_node *curr_bp = be_abi_reg_map_get(reg_map, aenv->bp);
(void) bl;
(void) mem;
if (env->flags.try_omit_fp) {
curr_sp = be_new_IncSP(aenv->sp, bl, curr_sp, BE_STACK_FRAME_SIZE_SHRINK, 0);
}
be_abi_reg_map_set(reg_map, aenv->sp, curr_sp);
be_abi_reg_map_set(reg_map, aenv->bp, curr_bp);
}
static const be_abi_callbacks_t amd64_abi_callbacks = {
amd64_abi_init,
free,
amd64_get_between_type,
amd64_abi_prologue,
amd64_abi_epilogue,
};
static const arch_register_t *gpreg_param_reg_std[] = {
......
......@@ -134,16 +134,21 @@ static const arch_register_t *get_out_reg(const ir_node *node, int pos)
return reg;
}
static void arm_emit_register(const arch_register_t *reg)
{
be_emit_string(arch_register_get_name(reg));
}
void arm_emit_source_register(const ir_node *node, int pos)
{
const arch_register_t *reg = get_in_reg(node, pos);
be_emit_string(arch_register_get_name(reg));
arm_emit_register(reg);
}
void arm_emit_dest_register(const ir_node *node, int pos)
{
const arch_register_t *reg = get_out_reg(node, pos);
be_emit_string(arch_register_get_name(reg));
arm_emit_register(reg);
}
void arm_emit_offset(const ir_node *node)
......@@ -739,11 +744,11 @@ static void emit_be_IncSP(const ir_node *irn)
be_emit_cstring(", ");
arm_emit_source_register(irn, 0);
be_emit_irprintf(", #0x%X", offs);
be_emit_finish_line_gas(irn);
} else {
/* omitted IncSP(0) */
return;
}
be_emit_finish_line_gas(irn);
}
static void emit_be_Copy(const ir_node *irn)
......@@ -847,8 +852,39 @@ static void emit_be_MemPerm(const ir_node *node)
assert(sp_change == 0);
}
static void emit_be_Start(const ir_node *node)
{
ir_graph *irg = get_irn_irg(node);
ir_type *frame_type = get_irg_frame_type(irg);
unsigned size = get_type_size_bytes(frame_type);
/* allocate stackframe */
if (size > 0) {
be_emit_cstring("\tsub ");
arm_emit_register(&arm_registers[REG_SP]);
be_emit_cstring(", ");
arm_emit_register(&arm_registers[REG_SP]);
be_emit_irprintf(", #0x%X", size);
be_emit_finish_line_gas(node);
}
}
static void emit_be_Return(const ir_node *node)
{
ir_graph *irg = get_irn_irg(node);
ir_type *frame_type = get_irg_frame_type(irg);
unsigned size = get_type_size_bytes(frame_type);
/* deallocate stackframe */
if (size > 0) {
be_emit_cstring("\tadd ");
arm_emit_register(&arm_registers[REG_SP]);
be_emit_cstring(", ");
arm_emit_register(&arm_registers[REG_SP]);
be_emit_irprintf(", #0x%X", size);
be_emit_finish_line_gas(node);
}
be_emit_cstring("\tmov pc, lr");
be_emit_finish_line_gas(node);
}
......@@ -918,11 +954,11 @@ static void arm_register_emitters(void)
set_emitter(op_be_MemPerm, emit_be_MemPerm);
set_emitter(op_be_Perm, emit_be_Perm);
set_emitter(op_be_Return, emit_be_Return);
set_emitter(op_be_Start, emit_be_Start);
/* no need to emit anything for the following nodes */
set_emitter(op_Phi, emit_nothing);
set_emitter(op_be_Keep, emit_nothing);
set_emitter(op_be_Start, emit_nothing);
}
/**
......
......@@ -1727,8 +1727,6 @@ static ir_node *gen_Start(ir_node *node)
ir_node *new_block = be_transform_node(block);
dbg_info *dbgi = get_irn_dbg_info(node);
ir_node *start;
ir_node *incsp;
ir_node *sp;
size_t i;
/* stackpointer is important at function prolog */
......@@ -1748,10 +1746,6 @@ static ir_node *gen_Start(ir_node *node)
}
start = be_prolog_create_start(abihelper, dbgi, new_block);
sp = be_prolog_get_reg_value(abihelper, sp_reg);
incsp = be_new_IncSP(sp_reg, new_block, sp, BE_STACK_FRAME_SIZE_EXPAND, 0);
be_prolog_set_reg_value(abihelper, sp_reg, incsp);
return start;
}
......@@ -1792,7 +1786,6 @@ static ir_node *gen_Return(ir_node *node)
ir_node *sp_proj = get_stack_pointer_for(node);
int n_res = get_Return_n_ress(node);
ir_node *bereturn;
ir_node *incsp;
int i;
be_epilog_begin(abihelper);
......@@ -1821,13 +1814,7 @@ static ir_node *gen_Return(ir_node *node)
}
/* epilog code: an incsp */
sp_proj = be_epilog_get_reg_value(abihelper, sp_reg);
incsp = be_new_IncSP(sp_reg, new_block, sp_proj,
BE_STACK_FRAME_SIZE_SHRINK, 0);
be_epilog_set_reg_value(abihelper, sp_reg, incsp);
bereturn = be_epilog_create_return(abihelper, dbgi, new_block);
return bereturn;
}
......
......@@ -50,13 +50,7 @@ typedef enum arch_irn_flags_t {
implementation in beflags */
arch_irn_flags_simple_jump = 1U << 3, /**< a simple jump instruction */
arch_irn_flags_not_scheduled = 1U << 4, /**< node must not be scheduled*/
/** mark node as belonging to the prolog. No spill instructions must appear
* in a schedule before a prolog node */
arch_irn_flags_prolog = 1U << 5,
/** mark node as belonging to the epilog. No spill instructions must appear
* after an epilog node */
arch_irn_flags_epilog = 1U << 6,
arch_irn_flags_backend = 1U << 7, /**< begin of custom backend
arch_irn_flags_backend = 1U << 5, /**< begin of custom backend
flags */
} arch_irn_flags_t;
ENUM_BITSET(arch_irn_flags_t)
......
......@@ -98,8 +98,6 @@ struct be_abi_irg_t {
int start_block_bias; /**< The stack bias at the end of the start block. */
void *cb; /**< ABI Callback self pointer. */
pmap *keep_map; /**< mapping blocks to keep nodes. */
ir_node **calls; /**< flexible array containing all be_Call nodes */
......@@ -1272,9 +1270,6 @@ static ir_node *create_be_return(be_abi_irg_t *env, ir_node *irn, ir_node *bl,
be_abi_reg_map_set(reg_map, arch_env->sp, stack);
/* Make the Epilogue node and call the arch's epilogue maker. */
call->cb->epilogue(env->cb, bl, &mem, reg_map);
/*
Maximum size of the in array for Return nodes is
return args + callee save/ignore registers + memory + stack pointer
......@@ -1319,7 +1314,6 @@ static ir_node *create_be_return(be_abi_irg_t *env, ir_node *irn, ir_node *bl,
/* we have to pop the shadow parameter in in case of struct returns */
pop = call->pop;
ret = be_new_Return(dbgi, irg, bl, n_res, pop, n, in);
arch_irn_add_flags(ret, arch_irn_flags_epilog);
/* Set the register classes of the return's parameter accordingly. */
for (i = 0; i < n; ++i) {
......@@ -1744,10 +1738,10 @@ static void modify_irg(ir_graph *irg)
}
}
bet_type = call->cb->get_between_type(env->cb);
stack_layout->sp_relative = call->flags.bits.try_omit_fp;
bet_type = call->cb->get_between_type(irg);
stack_frame_init(stack_layout, arg_type, bet_type,
get_irg_frame_type(irg), param_map);
stack_layout->sp_relative = call->flags.bits.try_omit_fp;
/* Count the register params and add them to the number of Projs for the RegParams node */
for (i = 0; i < n_params; ++i) {
......@@ -1773,6 +1767,9 @@ static void modify_irg(ir_graph *irg)
}
}
fp_reg = call->flags.bits.try_omit_fp ? arch_env->sp : arch_env->bp;
rbitset_clear(birg->allocatable_regs, fp_reg->global_index);
/* handle start block here (place a jump in the block) */
fix_start_block(irg);
......@@ -1780,17 +1777,15 @@ static void modify_irg(ir_graph *irg)
pmap_insert(env->regs, (void *) arch_env->bp, NULL);
start_bl = get_irg_start_block(irg);
env->start = be_new_Start(NULL, start_bl, pmap_count(env->regs) + 1);
arch_irn_add_flags(env->start, arch_irn_flags_prolog);
set_irg_start(irg, env->start);
/*
* make proj nodes for the callee save registers.
* memorize them, since Return nodes get those as inputs.
*
* Note, that if a register corresponds to an argument, the regs map contains
* the old Proj from start for that argument.
* Note, that if a register corresponds to an argument, the regs map
* contains the old Proj from start for that argument.
*/
rm = ALLOCAN(reg_node_map_t, pmap_count(env->regs));
reg_map_to_arr(rm, env->regs);
for (i = 0, n = pmap_count(env->regs); i < n; ++i) {
......@@ -1801,7 +1796,10 @@ static void modify_irg(ir_graph *irg)
ir_node *proj;
if (reg == sp)
add_type |= arch_register_req_type_produces_sp | arch_register_req_type_ignore;
add_type |= arch_register_req_type_produces_sp;
if (!rbitset_is_set(birg->allocatable_regs, reg->global_index)) {
add_type |= arch_register_req_type_ignore;
}
assert(nr >= 0);
proj = new_r_Proj(env->start, mode, nr + 1);
......@@ -1819,20 +1817,11 @@ static void modify_irg(ir_graph *irg)
mem = new_mem_proj;
set_irg_initial_mem(irg, mem);
/* Generate the Prologue */
fp_reg = call->cb->prologue(env->cb, &mem, env->regs, &stack_layout->initial_bias);
env->init_sp = be_abi_reg_map_get(env->regs, sp);
env->init_sp = be_new_IncSP(sp, start_bl, env->init_sp, BE_STACK_FRAME_SIZE_EXPAND, 0);
arch_irn_add_flags(env->init_sp, arch_irn_flags_prolog);
be_abi_reg_map_set(env->regs, sp, env->init_sp);
env->init_sp = be_abi_reg_map_get(env->regs, sp);
arch_set_irn_register(env->init_sp, sp);
/* set new frame_pointer */
frame_pointer = be_abi_reg_map_get(env->regs, fp_reg);
set_irg_frame(irg, frame_pointer);
rbitset_clear(birg->allocatable_regs, fp_reg->global_index);
/* rewire old mem users to new mem */
exchange(old_mem, mem);
......@@ -2118,10 +2107,10 @@ be_abi_irg_t *be_abi_introduce(ir_graph *irg)
ir_type *method_type = get_entity_type(entity);
be_irg_t *birg = be_birg_from_irg(irg);
struct obstack *obst = &birg->obst;
ir_node *dummy = new_r_Dummy(irg,
arch_env->sp->reg_class->mode);
unsigned r;
ir_node *dummy;
/* determine allocatable registers */
assert(birg->allocatable_regs == NULL);
birg->allocatable_regs = rbitset_obstack_alloc(obst, arch_env->n_registers);
......@@ -2144,7 +2133,7 @@ be_abi_irg_t *be_abi_introduce(ir_graph *irg)
env->call = be_abi_call_new(arch_env->sp->reg_class);
arch_env_get_call_abi(arch_env, method_type, env->call);
env->init_sp = dummy = new_r_Dummy(irg, arch_env->sp->reg_class->mode);
env->init_sp = dummy;
env->calls = NEW_ARR_F(ir_node*, 0);
if (options->pic) {
......@@ -2154,12 +2143,6 @@ be_abi_irg_t *be_abi_introduce(ir_graph *irg)
/* Lower all call nodes in the IRG. */
process_calls(irg);
/*
Beware: init backend abi call object after processing calls,
otherwise some information might be not yet available.
*/
env->cb = env->call->cb->init(env->call, irg);
/* Process the IRG */
modify_irg(irg);
......@@ -2178,8 +2161,6 @@ be_abi_irg_t *be_abi_introduce(ir_graph *irg)
exchange(dummy, env->init_sp);
exchange(old_frame, get_irg_frame(irg));
env->call->cb->done(env->cb);
env->cb = NULL;
return env;
}
......@@ -2269,7 +2250,6 @@ ir_node *be_abi_get_callee_save_irn(ir_graph *irg, const arch_register_t *reg)
ir_node *be_abi_get_ignore_irn(ir_graph *irg, const arch_register_t *reg)
{
const be_abi_irg_t *abi = be_get_irg_abi(irg);
assert(reg->type & arch_register_type_ignore);
assert(pmap_contains(abi->regs, (void *) reg));
return (ir_node*)pmap_get(abi->regs, (void *) reg);
}
......
......@@ -53,49 +53,12 @@ union be_abi_call_flags_t {
};
struct be_abi_callbacks_t {
/**
* Initialize the callback object.
* @param call The call object.
* @param irg The graph with the method.
* @return Some pointer. This pointer is passed to all other callback functions as self object.
*/
void *(*init)(const be_abi_call_t *call, ir_graph *irg);
/**
* Destroy the callback object.
* @param self The callback object.
*/
void (*done)(void *self);
/**
* Get the between type for that call.
* @param self The callback object.
* @return The between type of for that call.
*/
ir_type *(*get_between_type)(void *self);
/**
* Generate the prologue.
* @param self The callback object.
* @param mem A pointer to the mem node. Update this if you define new memory.
* @param reg_map A map mapping all callee_save/ignore/parameter registers to their defining nodes.
* @param stack_bias Points to the current stack bias, can be modified if needed.
* @return The register which shall be used as a stack frame base.
*
* All nodes which define registers in @p reg_map must keep @p reg_map current.
*/
const arch_register_t *(*prologue)(void *self, ir_node **mem, pmap *reg_map, int *stack_bias);
/**
* Generate the epilogue.
* @param self The callback object.
* @param mem Memory one can attach to.
* @param reg_map A mapping mapping all callee_save/ignore/return registers to their defining nodes.
*
* All nodes which define registers in @p reg_map must keep @p reg_map current.
* Also, the @p mem variable must be updated, if memory producing nodes are inserted.
*/
void (*epilogue)(void *self, ir_node *bl, ir_node **mem, pmap *reg_map);
ir_type *(*get_between_type)(ir_graph *irg);
};
/**
......
......@@ -267,8 +267,6 @@ ir_node *be_prolog_create_start(beabi_helper_env_t *env, dbg_info *dbgi,
ir_node *start = be_new_Start(dbgi, block, n_start_outs);
int o;
arch_irn_add_flags(start, arch_irn_flags_prolog);
assert(env->prolog.value_map == NULL);
env->prolog.value_map = NEW_ARR_F(ir_node*, n_start_outs);
......@@ -366,7 +364,6 @@ ir_node *be_epilog_create_return(beabi_helper_env_t *env, dbg_info *dbgi,
ret = be_new_Return(dbgi, get_irn_irg(block), block, n_res, pop,
n_return_in, in);
arch_irn_add_flags(ret, arch_irn_flags_epilog);
for (i = 0; i < n_return_in; ++i) {
const reg_flag_t *regflag = &env->epilog.regs[i];
const arch_register_t *reg = regflag->reg;
......@@ -414,10 +411,6 @@ static ir_node *add_to_keep(ir_node *last_keep,
}
}
op = skip_Proj_const(node);
if (arch_irn_get_flags(op) & arch_irn_flags_prolog)
arch_irn_add_flags(last_keep, arch_irn_flags_prolog);
if (arch_irn_get_flags(op) & arch_irn_flags_epilog)