X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;ds=sidebyside;f=ir%2Fbe%2Fia32%2Fbearch_ia32.c;h=a3af2ef496b30268a4a50da020a32deab5e7fa62;hb=0d22619b6ca7337e2b0fdda4a3b06e410759cc32;hp=3e74be700b86c90d9ffffecf9e3d1f07382e38d8;hpb=04500cf2b3528e7d91685a4d41af7eb175950622;p=libfirm diff --git a/ir/be/ia32/bearch_ia32.c b/ir/be/ia32/bearch_ia32.c index 3e74be700..a3af2ef49 100644 --- a/ir/be/ia32/bearch_ia32.c +++ b/ir/be/ia32/bearch_ia32.c @@ -6,21 +6,13 @@ #include "irgwalk.h" #include "irprog.h" #include "irprintf.h" +#include "iredges_t.h" #include "bitset.h" #include "debug.h" -#include - -#ifdef obstack_chunk_alloc -# undef obstack_chunk_alloc -# define obstack_chunk_alloc malloc -#else -# define obstack_chunk_alloc malloc -# define obstack_chunk_free free -#endif - #include "../bearch.h" /* the general register allocator interface */ +#include "../benode_t.h" #include "bearch_ia32_t.h" #include "ia32_new_nodes.h" /* ia32 nodes interface */ @@ -66,6 +58,21 @@ static int is_Call_Proj(const ir_node *n) { return 0; } +static int is_P_frame_base_Proj(const ir_node *n) { + if (is_Proj(n) && + get_irn_opcode(get_Proj_pred(n)) == iro_Start && + get_Proj_proj(n) == pn_Start_P_frame_base) + { + return 1; + } + + return 0; +} + +static int is_used_by_Keep(const ir_node *n) { + return be_is_Keep(get_edge_src_irn(get_irn_out_edge_first(n))); +} + /** * Return register requirements for an ia32 node. * If the node returns a tuple (mode_T) then the proj's @@ -85,7 +92,7 @@ static const arch_register_req_t *ia32_get_irn_reg_req(const arch_irn_ops_t *sel DBG((mod, LEVEL_1, "get requirements at pos %d for %+F ... ", pos, irn)); - if (is_Call_Proj(irn)) { + if (is_Call_Proj(irn) && is_used_by_Keep(irn)) { irn_req = ia32_projnum_reg_req_map[get_Proj_proj(irn)]; memcpy(req, &(irn_req->req), sizeof(*req)); return req; @@ -142,8 +149,6 @@ static const arch_register_req_t *ia32_get_irn_reg_req(const arch_irn_ops_t *sel case pn_Start_X_initial_exec: case pn_Start_P_value_arg_base: case pn_Start_P_globals: - memcpy(req, &(ia32_default_req_none.req), sizeof(*req)); - break; case pn_Start_P_frame_base: memcpy(req, &(ia32_default_req_none.req), sizeof(*req)); break; @@ -167,10 +172,10 @@ static const arch_register_req_t *ia32_get_irn_reg_req(const arch_irn_ops_t *sel static void ia32_set_irn_reg(const arch_irn_ops_t *self, ir_node *irn, const arch_register_t *reg) { int pos = 0; - if (is_Call_Proj(irn)) { + if ((is_Call_Proj(irn) && is_used_by_Keep(irn)) || is_P_frame_base_Proj(irn)) { /* don't skip the proj, we want to take the else below */ } - if (is_Proj(irn)) { + else if (is_Proj(irn)) { pos = ia32_translate_proj_pos(irn); irn = my_skip_proj(irn); } @@ -190,7 +195,7 @@ static const arch_register_t *ia32_get_irn_reg(const arch_irn_ops_t *self, const int pos = 0; const arch_register_t *reg = NULL; - if (is_Call_Proj(irn)) { + if ((is_Call_Proj(irn) && is_used_by_Keep(irn)) || is_P_frame_base_Proj(irn)) { /* don't skip the proj, we want to take the else below */ } else if (is_Proj(irn)) { @@ -255,25 +260,72 @@ static const arch_irn_ops_t ia32_irn_ops = { * |___/ **************************************************/ +static void check_for_alloca(ir_node *irn, void *env) { + int *has_alloca = env; + + if (get_irn_opcode(irn) == iro_Alloc) { + if (get_Alloc_where(irn) == stack_alloc) { + *has_alloca = 1; + } + } +} + /** * Transforms the standard firm graph into * an ia32 firm graph */ static void ia32_prepare_graph(void *self) { - ia32_code_gen_t *cg = self; + ia32_code_gen_t *cg = self; + int has_alloca = 0; + + if (! is_pseudo_ir_graph(cg->irg)) { + /* If there is a alloca in the irg, we use %ebp for stack addressing */ + /* instead of %esp, as alloca destroys %esp. */ + + /* check for alloca node */ + irg_walk_blkwise_graph(cg->irg, check_for_alloca, NULL, &has_alloca); + + if (has_alloca) { + ia32_general_purpose_regs[REG_EBP].type = arch_register_type_ignore; + } - if (! is_pseudo_ir_graph(cg->irg)) irg_walk_blkwise_graph(cg->irg, NULL, ia32_transform_node, cg); + } } /** - * Dummy functions for hooks we don't need but which must be filled. + * Set the register for P_frame_base Proj to %esp. + */ +static void ia32_set_P_frame_base_Proj_reg(ir_node *irn, void *env) { + ia32_code_gen_t *cg = env; + + if (is_P_frame_base_Proj(irn)) { + arch_set_irn_register(cg->arch_env, irn, &ia32_general_purpose_regs[REG_ESP]); + } +} + +/** + * This function is the hook before_sched but more important: it is + * called after the dead node elimination. The dead node elimination changes + * the memory location of the nodes, which will change the hash key of + * the Proj_P_frame_base(Start) and this will fuck up the firm_node -> register + * hash map. So we need to insert the register for this node after the dead node + * elimination. */ -static void ia32_before_sched(void *self) { +static void ia32_some_stuff_need_to_be_done_after_deadnode_elimination(void *self) { + ia32_code_gen_t *cg = self; + + if (! is_pseudo_ir_graph(cg->irg)) + irg_walk_blkwise_graph(cg->irg, NULL, ia32_set_P_frame_base_Proj_reg, cg); } + + +/** + * Dummy functions for hooks we don't need but which must be filled. + */ static void ia32_before_ra(void *self) { } @@ -308,7 +360,7 @@ static void *ia32_cg_init(FILE *F, ir_graph *irg, const arch_env_t *arch_env); static const arch_code_generator_if_t ia32_code_gen_if = { ia32_cg_init, ia32_prepare_graph, - ia32_before_sched, /* before scheduling hook */ + ia32_some_stuff_need_to_be_done_after_deadnode_elimination, /* before scheduling hook */ ia32_before_ra, /* before register allocation hook */ ia32_codegen /* emit && done */ }; @@ -411,6 +463,10 @@ long ia32_get_call_projnum_for_reg(const void *self, const arch_register_t *reg) return ia32_get_reg_projnum(reg, isa->reg_projnum_map); } +int ia32_to_appear_in_schedule(void *block_env, const ir_node *irn) { + return is_ia32_irn(irn); +} + /** * Initializes the code generator interface. */ @@ -418,11 +474,15 @@ static const arch_code_generator_if_t *ia32_get_code_generator_if(void *self) { return &ia32_code_gen_if; } +list_sched_selector_t ia32_sched_selector; + /** - * Returns the default scheduler + * Returns the reg_pressure scheduler with to_appear_in_schedule() overloaded */ static const list_sched_selector_t *ia32_get_list_sched_selector(const void *self) { - return reg_pressure_selector; + memcpy(&ia32_sched_selector, reg_pressure_selector, sizeof(list_sched_selector_t)); + ia32_sched_selector.to_appear_in_schedule = ia32_to_appear_in_schedule; + return &ia32_sched_selector; } #ifdef WITH_LIBCORE