Commit 36de1849 authored by Christoph Mallon's avatar Christoph Mallon
Browse files

be: Reintroduce be_Start.

All backends have similar empty Start nodes, which just provide registers.
So having one generic backend Start node to share some infrastructure is sensible.
parent 4f7811db
......@@ -166,15 +166,6 @@ Jmp => {
out_reqs => [ "exec" ],
},
Start => {
irn_flags => [ "schedule_first" ],
state => "pinned",
out_reqs => [ "sp:I", "r0", "r1", "r2", "r3", "mem" ],
outs => [ "stack", "arg0", "arg1", "arg2", "arg3", "M" ],
ins => [],
emit => "",
},
Return => {
state => "pinned",
op_flags => [ "cfopcode" ],
......
......@@ -220,15 +220,24 @@ static ir_node *gen_Jmp(ir_node *node)
return new_bd_TEMPLATE_Jmp(dbgi, new_block);
}
static unsigned const reg_params[] = {
REG_R0,
REG_R1,
REG_R2,
REG_R3,
};
static ir_node *gen_Start(ir_node *node)
{
dbg_info *dbgi = get_irn_dbg_info(node);
ir_node *new_block = be_transform_nodes_block(node);
ir_node *result = new_bd_TEMPLATE_Start(dbgi, new_block);
/* we have to set ignore registers manually */
arch_set_irn_register_out(result, pn_TEMPLATE_Start_stack,
&TEMPLATE_registers[REG_SP]);
return result;
be_start_out outs[N_TEMPLATE_REGISTERS] = { [REG_SP] = BE_START_IGNORE };
/* function parameters in registers */
for (size_t i = 0; i != ARRAY_SIZE(reg_params); ++i) {
outs[reg_params[i]] = BE_START_REG;
}
ir_graph *const irg = get_irn_irg(node);
return be_new_Start(irg, outs);
}
static ir_node *gen_Return(ir_node *node)
......@@ -279,17 +288,12 @@ static ir_node *gen_Proj_Proj(ir_node *node)
ir_node *pred_pred = get_Proj_pred(pred);
if (is_Start(pred_pred)) {
if (get_Proj_num(pred) == pn_Start_T_args) {
ir_node *new_start = be_transform_node(pred_pred);
// assume everything is passed in gp registers
unsigned arg_num = get_Proj_num(node);
if (arg_num >= 4)
if (arg_num >= ARRAY_SIZE(reg_params))
panic("more than 4 arguments not supported");
static const unsigned pns[] = {
pn_TEMPLATE_Start_arg0, pn_TEMPLATE_Start_arg1,
pn_TEMPLATE_Start_arg2, pn_TEMPLATE_Start_arg3
};
assert(arg_num < ARRAY_SIZE(pns));
return be_new_Proj(new_start, pns[arg_num]);
ir_graph *const irg = get_irn_irg(node);
return be_get_Start_proj(irg, &TEMPLATE_registers[reg_params[arg_num]]);
}
}
panic("No transformer for %+F -> %+F -> %+F", node, pred, pred_pred);
......@@ -327,17 +331,15 @@ static ir_node *gen_Proj_Store(ir_node *node)
static ir_node *gen_Proj_Start(ir_node *node)
{
ir_node *start = get_Proj_pred(node);
ir_node *new_start = be_transform_node(start);
unsigned pn = get_Proj_num(node);
ir_graph *const irg = get_irn_irg(node);
unsigned const pn = get_Proj_num(node);
switch ((pn_Start)pn) {
case pn_Start_M:
return be_new_Proj(new_start, pn_TEMPLATE_Start_M);
return be_get_Start_mem(irg);
case pn_Start_T_args:
return new_r_Bad(get_irn_irg(node), mode_T);
return new_r_Bad(irg, mode_T);
case pn_Start_P_frame_base:
return be_new_Proj(new_start, pn_TEMPLATE_Start_stack);
return be_get_Start_proj(irg, &TEMPLATE_registers[REG_SP]);
}
panic("unexpected Start proj %u", pn);
}
......
......@@ -64,7 +64,7 @@ static void introduce_prologue(ir_graph *const irg)
arch_register_t const *const sp = &TEMPLATE_registers[REG_SP];
ir_node *const start = get_irg_start(irg);
ir_node *const block = get_nodes_block(start);
ir_node *const initial_sp = be_get_initial_reg_value(irg, sp);
ir_node *const initial_sp = be_get_Start_proj(irg, sp);
ir_type *const frame_type = get_irg_frame_type(irg);
unsigned const frame_size = get_type_size_bytes(frame_type);
ir_node *const incsp = be_new_IncSP(sp, block, initial_sp, frame_size, 0);
......
......@@ -452,15 +452,6 @@ call => {
emit => "call %*AM",
},
start => {
irn_flags => [ "schedule_first" ],
state => "pinned",
out_reqs => "...",
ins => [],
fixed => "amd64_op_mode_t op_mode = AMD64_OP_NONE;\n",
emit => "",
},
ret => {
state => "pinned",
op_flags => [ "cfopcode" ],
......
......@@ -37,8 +37,6 @@ DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)
static ir_mode *mode_gp;
static x86_cconv_t *current_cconv = NULL;
static be_start_info_t start_mem;
static be_start_info_t start_val[N_AMD64_REGISTERS];
static pmap *node_to_stack;
static be_stackorder_t *stackorder;
......@@ -248,17 +246,12 @@ static inline bool mode_needs_gp_reg(ir_mode *mode)
static ir_node *get_initial_sp(ir_graph *irg)
{
return be_get_start_proj(irg, &start_val[REG_RSP]);
return be_get_Start_proj(irg, &amd64_registers[REG_RSP]);
}
static ir_node *get_initial_fp(ir_graph *irg)
{
return be_get_start_proj(irg, &start_val[REG_RBP]);
}
static ir_node *get_initial_mem(ir_graph *irg)
{
return be_get_start_proj(irg, &start_mem);
return be_get_Start_proj(irg, &amd64_registers[REG_RBP]);
}
static ir_node *get_frame_base(ir_graph *irg)
......@@ -1394,46 +1387,26 @@ static ir_node *gen_Start(ir_node *node)
{
x86_cconv_t const *const cconv = current_cconv;
/* start building list of start constraints */
/* calculate number of outputs */
size_t n_outs = 2; /* memory, rsp */
/* function parameters */
n_outs += cconv->n_param_regs;
size_t n_callee_saves
= rbitset_popcount(cconv->callee_saves, N_AMD64_REGISTERS);
n_outs += n_callee_saves;
dbg_info *const dbgi = get_irn_dbg_info(node);
ir_node *const new_block = be_transform_nodes_block(node);
ir_node *const start = new_bd_amd64_start(dbgi, new_block, n_outs);
size_t o = 0;
/* first output is memory */
be_make_start_mem(&start_mem, start, o++);
/* the stack pointer */
be_make_start_out(&start_val[REG_RSP], start, o++, &amd64_registers[REG_RSP], true);
be_start_out outs[N_AMD64_REGISTERS] = { [REG_RSP] = BE_START_IGNORE };
/* function parameters in registers */
for (size_t i = 0, n = cconv->n_parameters; i != n; ++i) {
const reg_or_stackslot_t *param = &current_cconv->parameters[i];
const arch_register_t *reg = param->reg;
reg_or_stackslot_t const *const param = &cconv->parameters[i];
arch_register_t const *const reg = param->reg;
if (reg)
be_make_start_out(&start_val[reg->global_index], start, o++, reg, false);
outs[reg->global_index] = BE_START_REG;
}
/* callee saves */
for (size_t i = 0; i < N_AMD64_REGISTERS; ++i) {
if (!rbitset_is_set(cconv->callee_saves, i))
continue;
bool ignore = i == REG_RBP && !cconv->omit_fp;
be_make_start_out(&start_val[i], start, o++, &amd64_registers[i], ignore);
if (rbitset_is_set(cconv->callee_saves, i))
outs[i] = BE_START_REG;
}
assert(n_outs == o);
if (!cconv->omit_fp)
outs[REG_RBP] = BE_START_IGNORE;
return start;
ir_graph *const irg = get_irn_irg(node);
return be_new_Start(irg, outs);
}
static ir_node *gen_Proj_Start(ir_node *node)
......@@ -1444,7 +1417,7 @@ static ir_node *gen_Proj_Start(ir_node *node)
switch ((pn_Start)pn) {
case pn_Start_M:
return get_initial_mem(irg);
return be_get_Start_mem(irg);
case pn_Start_T_args:
return new_r_Bad(irg, mode_T);
case pn_Start_P_frame_base:
......@@ -1511,8 +1484,9 @@ static ir_node *gen_Return(ir_node *node)
for (size_t i = 0; i < N_AMD64_REGISTERS; ++i) {
if (!rbitset_is_set(cconv->callee_saves, i))
continue;
in[p] = be_get_start_proj(irg, &start_val[i]);
reqs[p] = amd64_registers[i].single_req;
arch_register_t const *const reg = &amd64_registers[i];
in[p] = be_get_Start_proj(irg, reg);
reqs[p] = reg->single_req;
++p;
}
assert(p == n_ins);
......@@ -1793,7 +1767,7 @@ static ir_node *gen_Proj_Proj_Start(ir_node *node)
arch_register_t const *const reg = param->reg;
if (reg) {
/* argument transmitted in register */
return be_get_start_proj(irg, &start_val[reg->global_index]);
return be_get_Start_proj(irg, reg);
} else {
/* argument transmitted on stack */
ir_mode *mode = get_type_mode(param->type);
......@@ -2695,9 +2669,6 @@ void amd64_transform_graph(ir_graph *irg)
| IR_GRAPH_PROPERTY_NO_BADS
| IR_GRAPH_PROPERTY_CONSISTENT_OUT_EDGES);
start_mem.irn = NULL;
memset(&start_val, 0, sizeof(start_val));
amd64_register_transformers();
mode_gp = mode_Lu;
node_to_stack = pmap_create();
......
......@@ -180,7 +180,7 @@ static ir_node* create_spproj(ir_node *pred, int pos)
static void transform_MemPerm(ir_node *node)
{
ir_graph *irg = get_irn_irg(node);
ir_node *sp = be_get_initial_reg_value(irg, &amd64_registers[REG_RSP]);
ir_node *sp = be_get_Start_proj(irg, &amd64_registers[REG_RSP]);
int arity = be_get_MemPerm_entity_arity(node);
ir_node **pops = ALLOCAN(ir_node*, arity);
int i;
......@@ -563,12 +563,12 @@ static void introduce_prologue(ir_graph *const irg)
ir_type *frame_type = get_irg_frame_type(irg);
unsigned frame_size = get_type_size_bytes(frame_type);
be_stack_layout_t *layout = be_get_irg_stack_layout(irg);
ir_node *initial_sp = be_get_initial_reg_value(irg, sp);
ir_node *initial_sp = be_get_Start_proj(irg, sp);
if (!layout->sp_relative) {
/* push rbp */
ir_node *const mem = get_irg_initial_mem(irg);
ir_node *const initial_bp = be_get_initial_reg_value(irg, bp);
ir_node *const initial_bp = be_get_Start_proj(irg, bp);
ir_node *const push = new_bd_amd64_push_reg(NULL, block, initial_sp, mem, initial_bp);
sched_add_after(start, push);
ir_node *const curr_mem = be_new_Proj(push, pn_amd64_push_reg_M);
......
......@@ -80,7 +80,7 @@ static void introduce_prolog_epilog(ir_graph *irg)
const arch_register_t *sp_reg = &arm_registers[REG_SP];
ir_node *start = get_irg_start(irg);
ir_node *block = get_nodes_block(start);
ir_node *initial_sp = be_get_initial_reg_value(irg, sp_reg);
ir_node *initial_sp = be_get_Start_proj(irg, sp_reg);
ir_type *frame_type = get_irg_frame_type(irg);
unsigned frame_size = get_type_size_bytes(frame_type);
......
......@@ -611,14 +611,6 @@ fConst => {
attr_type => "arm_fConst_attr_t",
},
Start => {
irn_flags => [ "schedule_first" ],
state => "pinned",
out_reqs => "...",
ins => [],
emit => "",
},
Return => {
state => "pinned",
op_flags => [ "cfopcode" ],
......
......@@ -42,8 +42,6 @@ DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)
static const arch_register_t *sp_reg = &arm_registers[REG_SP];
static be_stackorder_t *stackorder;
static calling_convention_t *cconv = NULL;
static be_start_info_t start_mem;
static be_start_info_t start_val[N_ARM_REGISTERS];
static pmap *node_to_stack;
static const arch_register_t *const callee_saves[] = {
......@@ -1469,16 +1467,17 @@ static ir_node *gen_Proj_Div(ir_node *node)
static ir_node *gen_Proj_Start(ir_node *node)
{
ir_graph *const irg = get_irn_irg(node);
unsigned pn = get_Proj_num(node);
switch ((pn_Start)pn) {
case pn_Start_M:
return be_get_start_proj(get_irn_irg(node), &start_mem);
return be_get_Start_mem(irg);
case pn_Start_T_args:
return new_r_Bad(get_irn_irg(node), mode_T);
return new_r_Bad(irg, mode_T);
case pn_Start_P_frame_base:
return be_get_start_proj(get_irn_irg(node), &start_val[REG_SP]);
return be_get_Start_proj(irg, &arm_registers[REG_SP]);
}
panic("unexpected start proj: %u", pn);
}
......@@ -1495,17 +1494,17 @@ static ir_node *gen_Proj_Proj_Start(ir_node *node)
arch_register_t const *const reg0 = param->reg0;
if (reg0 != NULL) {
/* argument transmitted in register */
ir_node *value = be_get_start_proj(irg, &start_val[reg0->global_index]);
ir_node *value = be_get_Start_proj(irg, reg0);
if (mode_is_float(reg0->cls->mode)) {
ir_node *value1 = NULL;
const arch_register_t *reg1 = param->reg1;
if (reg1 != NULL) {
value1 = be_get_start_proj(irg, &start_val[reg1->global_index]);
value1 = be_get_Start_proj(irg, reg1);
} else if (param->entity != NULL) {
ir_node *const fp = get_irg_frame(irg);
ir_node *const mem = be_get_start_proj(irg, &start_mem);
ir_node *const mem = be_get_Start_mem(irg);
ir_node *const ldr = new_bd_arm_Ldr(NULL, new_block, fp, mem,
arm_mode_gp, param->entity,
0, 0, true);
......@@ -1523,7 +1522,7 @@ static ir_node *gen_Proj_Proj_Start(ir_node *node)
} else {
/* argument transmitted on stack */
ir_node *const fp = get_irg_frame(irg);
ir_node *const mem = be_get_start_proj(irg, &start_mem);
ir_node *const mem = be_get_Start_mem(irg);
ir_mode *const mode = get_type_mode(param->type);
ir_node *load;
......@@ -1696,37 +1695,26 @@ static void create_stacklayout(ir_graph *irg)
*/
static ir_node *gen_Start(ir_node *node)
{
unsigned n_outs = 2; /* memory, sp */
n_outs += cconv->n_param_regs;
n_outs += ARRAY_SIZE(callee_saves);
dbg_info *const dbgi = get_irn_dbg_info(node);
ir_node *const new_block = be_transform_nodes_block(node);
ir_node *const start = new_bd_arm_Start(dbgi, new_block, n_outs);
unsigned o = 0;
be_make_start_mem(&start_mem, start, o++);
be_make_start_out(&start_val[REG_SP], start, o++, &arm_registers[REG_SP], true);
be_start_out outs[N_ARM_REGISTERS] = { [REG_SP] = BE_START_IGNORE };
/* function parameters in registers */
for (size_t i = 0, n = cconv->n_parameters; i != n; ++i) {
const reg_or_stackslot_t *param = &cconv->parameters[i];
const arch_register_t *reg0 = param->reg0;
if (reg0)
be_make_start_out(&start_val[reg0->global_index], start, o++, reg0, false);
outs[reg0->global_index] = BE_START_REG;
const arch_register_t *reg1 = param->reg1;
if (reg1)
be_make_start_out(&start_val[reg1->global_index], start, o++, reg1, false);
outs[reg1->global_index] = BE_START_REG;
}
/* callee save regs */
for (size_t i = 0; i < ARRAY_SIZE(callee_saves); ++i) {
arch_register_t const *const reg = callee_saves[i];
be_make_start_out(&start_val[reg->global_index], start, o++, reg, false);
outs[callee_saves[i]->global_index] = BE_START_REG;
}
assert(n_outs == o);
return start;
ir_graph *const irg = get_irn_irg(node);
return be_new_Start(irg, outs);
}
static ir_node *get_stack_pointer_for(ir_node *node)
......@@ -1737,7 +1725,7 @@ static ir_node *get_stack_pointer_for(ir_node *node)
/* first stack user in the current block. We can simply use the
* initial sp_proj for it */
ir_graph *irg = get_irn_irg(node);
return be_get_start_proj(irg, &start_val[REG_SP]);
return be_get_Start_proj(irg, &arm_registers[REG_SP]);
}
be_transform_node(stack_pred);
......@@ -1789,7 +1777,7 @@ static ir_node *gen_Return(ir_node *node)
/* connect callee saves with their values at the function begin */
for (unsigned i = 0; i < n_callee_saves; ++i) {
arch_register_t const *const reg = callee_saves[i];
in[p] = be_get_start_proj(irg, &start_val[reg->global_index]);
in[p] = be_get_Start_proj(irg, reg);
reqs[p] = reg->single_req;
++p;
}
......
......@@ -147,36 +147,6 @@ uint8_t arch_get_additional_pressure(ir_node const *const node,
return 0;
}
void be_make_start_mem(be_start_info_t *const info, ir_node *const start, unsigned const pos)
{
info->pos = pos;
info->irn = NULL;
arch_set_irn_register_req_out(start, pos, arch_memory_req);
}
void be_make_start_out(be_start_info_t *const info, ir_node *const start,
unsigned const pos, arch_register_t const *const reg,
bool const ignore)
{
info->pos = pos;
info->irn = NULL;
arch_register_req_t const *const req = ignore
? be_create_reg_req(be_get_be_obst(get_irn_irg(start)), reg, true)
: reg->single_req;
arch_set_irn_register_req_out(start, pos, req);
arch_set_irn_register_out(start, pos, reg);
}
ir_node *be_get_start_proj(ir_graph *const irg, be_start_info_t *const info)
{
if (!info->irn) {
/* This is already the transformed start node. */
ir_node *const start = get_irg_start(irg);
info->irn = be_new_Proj(start, info->pos);
}
return info->irn;
}
void arch_copy_irn_out_info(ir_node *const dst, unsigned const dst_pos, ir_node const *const src)
{
reg_out_info_t *const src_info = get_out_info(src);
......
......@@ -374,18 +374,6 @@ arch_register_t const *arch_find_register(char const *name);
bool arch_reg_is_allocatable(const arch_register_req_t *req,
const arch_register_t *reg);
typedef struct be_start_info_t {
unsigned pos;
ir_node *irn;
} be_start_info_t;
void be_make_start_mem(be_start_info_t *info, ir_node *start, unsigned pos);
void be_make_start_out(be_start_info_t *info, ir_node *start, unsigned pos,
arch_register_t const *reg, bool ignore);
ir_node *be_get_start_proj(ir_graph *irg, be_start_info_t *info);
void arch_copy_irn_out_info(ir_node *dst, unsigned dst_pos, ir_node const *src);
#endif
......@@ -85,8 +85,9 @@ void be_emit_finish_line_gas(const ir_node *node)
void be_init_emitters(void)
{
ir_clear_opcodes_generic_func();
be_set_emitter(op_Phi, be_emit_nothing);
be_set_emitter(op_be_Keep, be_emit_nothing);
be_set_emitter(op_Phi, be_emit_nothing);
be_set_emitter(op_be_Keep, be_emit_nothing);
be_set_emitter(op_be_Start, be_emit_nothing);
}
void be_emit_nothing(ir_node const *const node)
......
......@@ -66,6 +66,7 @@ ir_op *op_be_Keep;
ir_op *op_be_MemPerm;
ir_op *op_be_Perm;
ir_op *op_be_Relocation;
ir_op *op_be_Start;
#define be_op_tag FOURCC('B', 'E', '\0', '\0')
......@@ -394,31 +395,6 @@ unsigned be_get_IncSP_align(const ir_node *irn)
return a->align;
}
static unsigned get_start_reg_index(ir_graph *irg, const arch_register_t *reg)
{
/* do a naive linear search... */
ir_node *start = get_irg_start(irg);
be_foreach_out(start, i) {
arch_register_req_t const *const out_req
= arch_get_irn_register_req_out(start, i);
if (out_req->limited == NULL)
continue;
if (out_req->cls != reg->cls)
continue;
if (!rbitset_is_set(out_req->limited, reg->index))
continue;
return i;
}
panic("tried querying undefined register '%s' at Start", reg->name);
}
ir_node *be_get_initial_reg_value(ir_graph *irg, const arch_register_t *reg)
{
unsigned const i = get_start_reg_index(irg, reg);
ir_node *const start = get_irg_start(irg);
return be_get_or_make_Proj_for_pn(start, i);
}
ir_node *be_new_Phi(ir_node *block, int n_ins, ir_node **ins, ir_mode *mode,
const arch_register_req_t *req)
{
......@@ -522,6 +498,59 @@ ir_entity *be_get_Relocation_entity(ir_node const* const node)
return attr->entity;
}
ir_node *be_new_Start(ir_graph *const irg, be_start_out const *const outs)
{
ir_node *const block = get_irg_start_block(irg);
ir_node *const start = new_ir_node(NULL, irg, block, op_be_Start, mode_T, 0, NULL);
unsigned const n_regs = isa_if->n_registers;
/* Count the number of outsputs. */
unsigned k = 1; /* +1 for memory */
for (unsigned i = 0; i != n_regs; ++i) {
if (outs[i] != BE_START_NO)
++k;
}
be_info_init_irn(start, arch_irn_flag_schedule_first, NULL, k);
/* Set out requirements and registers. */
unsigned l = 0;
arch_set_irn_register_req_out(start, l++, arch_memory_req);
arch_register_t const *const regs = isa_if->registers;
for (unsigned i = 0; i != n_regs; ++i) {
if (outs[i] != BE_START_NO) {
arch_register_t const *const reg = &regs[i];
arch_register_req_t const *const req = outs[i] == BE_START_IGNORE
? be_create_reg_req(be_get_be_obst(irg), reg, true)
: reg->single_req;
arch_set_irn_register_req_out(start, l, req);
arch_set_irn_register_out( start, l, reg);
++l;
}
}
assert(l == k);
return start;
}
ir_node *be_get_Start_mem(ir_graph *const irg)
{
ir_node *const start = get_irg_start(irg);
return be_get_or_make_Proj_for_pn(start, 0);
}
ir_node *be_get_Start_proj(ir_graph *const irg, arch_register_t const *const reg)
{
ir_node *const start = get_irg_start(irg);
/* do a naive linear search... */
be_foreach_out(start, i) {
arch_register_t const *const out_reg = arch_get_irn_register_out(start, i);
if (out_reg == reg)
return be_get_or_make_Proj_for_pn(start, i);
}
panic("tried querying undefined register '%s' at Start", reg->name);
}
ir_node *be_new_Proj(ir_node *const pred, unsigned const pos)
{
arch_register_req_t const *const req = arch_get_irn_register_req_out(pred, pos);
......@@ -642,6 +671,7 @@ void be_init_op(void)
op_be_MemPerm = new_be_op(o+beo_MemPerm, "be_MemPerm", op_pin_state_exc_pinned, irop_flag_none, oparity_variable, sizeof(be_memperm_attr_t));
op_be_Perm = new_be_op(o+beo_Perm, "be_Perm", op_pin_state_exc_pinned, irop_flag_none, oparity_variable, sizeof(be_node_attr_t));
op_be_Relocation = new_be_op(o+beo_Relocation, "be_Relocation", op_pin_state_floats, irop_flag_constlike|irop_flag_start_block, oparity_any, sizeof(be_relocation_attr_t));
op_be_Start = new_be_op(o+beo_Start, "be_Start", op_pin_state_pinned, irop_flag_start_block, oparity_variable, sizeof(be_node_attr_t));
set_op_attrs_equal(op_be_Asm, be_asm_attr_equal);
set_op_attrs_equal(op_be_Copy, attrs_equal_be_node);
......
......@@ -29,7 +29,8 @@ typedef enum be_opcode {
beo_MemPerm,
beo_Perm,
beo_Relocation,
beo_last = beo_Relocation
beo_Start,