From 2ba0d75357dc87479522d0db5b6e4ba6de5c9585 Mon Sep 17 00:00:00 2001 From: Matthias Braun Date: Wed, 13 Apr 2011 14:18:35 +0200 Subject: [PATCH] adapt sparc backend to new prolog/epilog handling --- ir/be/benode.c | 57 +++++++++++++++++ ir/be/benode.h | 13 +++- ir/be/ia32/bearch_ia32.c | 45 +------------- ir/be/ia32/bearch_ia32_t.h | 5 -- ir/be/ia32/ia32_fpu.c | 2 +- ir/be/ia32/ia32_transform.c | 3 +- ir/be/sparc/bearch_sparc.c | 2 + ir/be/sparc/bearch_sparc_t.h | 2 + ir/be/sparc/sparc_finish.c | 111 ++++++++++++++++++++++++++++++++++ ir/be/sparc/sparc_transform.c | 39 ------------ 10 files changed, 189 insertions(+), 90 deletions(-) diff --git a/ir/be/benode.c b/ir/be/benode.c index 4d6b9daa6..181310147 100644 --- a/ir/be/benode.c +++ b/ir/be/benode.c @@ -1050,6 +1050,63 @@ static const arch_irn_ops_t be_node_irn_ops = { NULL, /* perform_memory_operand */ }; +static int get_start_reg_index(ir_graph *irg, const arch_register_t *reg) +{ + ir_node *start = get_irg_start(irg); + unsigned n_outs = arch_irn_get_n_outs(start); + int i; + + /* do a naive linear search... */ + for (i = 0; i < (int)n_outs; ++i) { + const arch_register_req_t *out_req + = arch_get_out_register_req(start, i); + if (! (out_req->type & arch_register_req_type_limited)) + continue; + if (out_req->cls != arch_register_get_class(reg)) + 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) +{ + int i = get_start_reg_index(irg, reg); + ir_node *start = get_irg_start(irg); + ir_mode *mode = arch_register_class_mode(arch_register_get_class(reg)); + const ir_edge_t *edge; + + foreach_out_edge(start, edge) { + ir_node *proj = get_edge_src_irn(edge); + if (!is_Proj(proj)) // maybe End/Anchor + continue; + if (get_Proj_proj(proj) == i) { + return proj; + } + } + return new_r_Proj(start, mode, i); +} + +int be_find_return_reg_input(ir_node *ret, const arch_register_t *reg) +{ + int arity = get_irn_arity(ret); + int i; + /* do a naive linear search... */ + for (i = 0; i < arity; ++i) { + const arch_register_req_t *req = arch_get_in_register_req(ret, i); + if (! (req->type & arch_register_req_type_limited)) + continue; + if (req->cls != arch_register_get_class(reg)) + continue; + if (!rbitset_is_set(req->limited, reg->index)) + continue; + return i; + } + panic("Tried querying undefined register '%s' at Return", reg->name); +} + static arch_irn_class_t dummy_classify(const ir_node *node) { (void) node; diff --git a/ir/be/benode.h b/ir/be/benode.h index 38cecd056..b80907882 100644 --- a/ir/be/benode.h +++ b/ir/be/benode.h @@ -479,6 +479,17 @@ void be_dump_phi_reg_reqs(FILE *out, ir_node *node, dump_reason_t reason); ir_node *be_new_Phi(ir_node *block, int n_ins, ir_node **ins, ir_mode *mode, const arch_register_class_t *cls); +/** + * Search for output of start node with a specific register + */ +ir_node *be_get_initial_reg_value(ir_graph *irg, const arch_register_t *reg); + +/** + * Search for input of a return node with a specific register and return + * its number. + */ +int be_find_return_reg_input(ir_node *ret, const arch_register_t *reg); + static inline int be_is_Spill (const ir_node *irn) { return get_irn_opcode(irn) == beo_Spill ; } static inline int be_is_Reload (const ir_node *irn) { return get_irn_opcode(irn) == beo_Reload ; } static inline int be_is_Copy (const ir_node *irn) { return get_irn_opcode(irn) == beo_Copy ; } @@ -491,7 +502,7 @@ static inline int be_is_Return (const ir_node *irn) { return get_irn_opcode(ir static inline int be_is_IncSP (const ir_node *irn) { return get_irn_opcode(irn) == beo_IncSP ; } static inline int be_is_AddSP (const ir_node *irn) { return get_irn_opcode(irn) == beo_AddSP ; } static inline int be_is_SubSP (const ir_node *irn) { return get_irn_opcode(irn) == beo_SubSP ; } -static inline int be_is_Start (const ir_node *irn) { return get_irn_opcode(irn) == beo_Start; } +static inline int be_is_Start (const ir_node *irn) { return get_irn_opcode(irn) == beo_Start ; } static inline int be_is_FrameAddr(const ir_node *irn) { return get_irn_opcode(irn) == beo_FrameAddr; } #endif diff --git a/ir/be/ia32/bearch_ia32.c b/ir/be/ia32/bearch_ia32.c index b246f68f8..1fc791085 100644 --- a/ir/be/ia32/bearch_ia32.c +++ b/ir/be/ia32/bearch_ia32.c @@ -263,45 +263,6 @@ static int ia32_get_sp_bias(const ir_node *node) return 0; } -static int get_start_reg_index(ir_graph *irg, const arch_register_t *reg) -{ - ir_node *start = get_irg_start(irg); - unsigned n_outs = arch_irn_get_n_outs(start); - int i; - - /* do a naive linear search... */ - for (i = 0; i < (int)n_outs; ++i) { - const arch_register_req_t *out_req - = arch_get_out_register_req(start, i); - if (! (out_req->type & arch_register_req_type_limited)) - continue; - if (out_req->cls != arch_register_get_class(reg)) - 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 *ia32_get_initial_reg_value(ir_graph *irg, const arch_register_t *reg) -{ - int i = get_start_reg_index(irg, reg); - ir_node *start = get_irg_start(irg); - ir_mode *mode = arch_register_class_mode(arch_register_get_class(reg)); - const ir_edge_t *edge; - - foreach_out_edge(start, edge) { - ir_node *proj = get_edge_src_irn(edge); - if (!is_Proj(proj)) // maybe End/Anchor - continue; - if (get_Proj_proj(proj) == i) { - return proj; - } - } - return new_r_Proj(start, mode, i); -} - /** * Build the between type and entities if not already build. */ @@ -1028,7 +989,7 @@ static void transform_MemPerm(ir_node *node) { ir_node *block = get_nodes_block(node); ir_graph *irg = get_irn_irg(node); - ir_node *sp = ia32_get_initial_reg_value(irg, &ia32_registers[REG_ESP]); + ir_node *sp = be_get_initial_reg_value(irg, &ia32_registers[REG_ESP]); int arity = be_get_MemPerm_entity_arity(node); ir_node **pops = ALLOCAN(ir_node*, arity); ir_node *in[1]; @@ -1292,7 +1253,7 @@ static void introduce_prolog_epilog(ir_graph *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 = ia32_get_initial_reg_value(irg, sp); + ir_node *initial_sp = be_get_initial_reg_value(irg, sp); ir_node *curr_sp = initial_sp; ir_mode *mode_gp = mode_Iu; @@ -1300,7 +1261,7 @@ static void introduce_prolog_epilog(ir_graph *irg) /* push ebp */ ir_node *mem = get_irg_initial_mem(irg); ir_node *noreg = ia32_new_NoReg_gp(irg); - ir_node *initial_bp = ia32_get_initial_reg_value(irg, bp); + ir_node *initial_bp = be_get_initial_reg_value(irg, bp); ir_node *curr_bp = initial_bp; ir_node *push = new_bd_ia32_Push(NULL, block, noreg, noreg, mem, curr_bp, curr_sp); ir_node *incsp; diff --git a/ir/be/ia32/bearch_ia32_t.h b/ir/be/ia32/bearch_ia32_t.h index dae6feb49..91514bbfa 100644 --- a/ir/be/ia32/bearch_ia32_t.h +++ b/ir/be/ia32/bearch_ia32_t.h @@ -154,9 +154,4 @@ ir_entity *ia32_get_return_address_entity(ir_graph *irg); */ ir_entity *ia32_get_frame_address_entity(ir_graph *irg); -/** - * Get node representing the initial value of a register - */ -ir_node *ia32_get_initial_reg_value(ir_graph *irg, const arch_register_t *reg); - #endif diff --git a/ir/be/ia32/ia32_fpu.c b/ir/be/ia32/ia32_fpu.c index 35d2faf04..bb3ab792a 100644 --- a/ir/be/ia32/ia32_fpu.c +++ b/ir/be/ia32/ia32_fpu.c @@ -260,7 +260,7 @@ static void rewire_fpu_mode_nodes(ir_graph *irg) return; } - initial_value = ia32_get_initial_reg_value(irg, reg); + initial_value = be_get_initial_reg_value(irg, reg); be_ssa_construction_init(&senv, irg); be_ssa_construction_add_copies(&senv, env.state_nodes, ARR_LEN(env.state_nodes)); diff --git a/ir/be/ia32/ia32_transform.c b/ir/be/ia32/ia32_transform.c index 9fca9ebe3..a9acd89fd 100644 --- a/ir/be/ia32/ia32_transform.c +++ b/ir/be/ia32/ia32_transform.c @@ -5822,8 +5822,7 @@ void ia32_transform_graph(ir_graph *irg) initial_fpcw = NULL; ia32_no_pic_adjust = 0; - old_initial_fpcw - = ia32_get_initial_reg_value(irg, &ia32_registers[REG_FPCW]); + old_initial_fpcw = be_get_initial_reg_value(irg, &ia32_registers[REG_FPCW]); be_timer_push(T_HEIGHTS); ia32_heights = heights_new(irg); diff --git a/ir/be/sparc/bearch_sparc.c b/ir/be/sparc/bearch_sparc.c index 499c71f42..f53f9834b 100644 --- a/ir/be/sparc/bearch_sparc.c +++ b/ir/be/sparc/bearch_sparc.c @@ -292,6 +292,8 @@ static void sparc_after_ra(ir_graph *irg) be_free_frame_entity_coalescer(fec_env); irg_block_walk_graph(irg, NULL, sparc_after_ra_walker, NULL); + + sparc_introduce_prolog_epilog(irg); } static void sparc_init_graph(ir_graph *irg) diff --git a/ir/be/sparc/bearch_sparc_t.h b/ir/be/sparc/bearch_sparc_t.h index 5648fc76e..650ec68cf 100644 --- a/ir/be/sparc/bearch_sparc_t.h +++ b/ir/be/sparc/bearch_sparc_t.h @@ -74,4 +74,6 @@ static inline bool sparc_is_value_imm_encodeable(int32_t value) void sparc_finish(ir_graph *irg); +void sparc_introduce_prolog_epilog(ir_graph *irg); + #endif diff --git a/ir/be/sparc/sparc_finish.c b/ir/be/sparc/sparc_finish.c index 9f1806c52..9d060f4c9 100644 --- a/ir/be/sparc/sparc_finish.c +++ b/ir/be/sparc/sparc_finish.c @@ -44,11 +44,120 @@ #include "sparc_new_nodes.h" #include "irprog.h" #include "irgmod.h" +#include "ircons.h" #include "../bepeephole.h" #include "../benode.h" #include "../besched.h" +static void kill_unused_stacknodes(ir_node *node) +{ + if (get_irn_n_edges(node) > 0) + return; + + if (be_is_IncSP(node)) { + sched_remove(node); + kill_node(node); + } else if (is_Phi(node)) { + int arity = get_irn_arity(node); + ir_node **ins = ALLOCAN(ir_node*, arity); + int i; + sched_remove(node); + memcpy(ins, get_irn_in(node), arity*sizeof(ins[0])); + kill_node(node); + + for (i = 0; i < arity; ++i) + kill_unused_stacknodes(ins[i]); + } +} + +static void introduce_epilog(ir_node *ret) +{ + const arch_register_t *sp_reg = &sparc_registers[REG_SP]; + ir_graph *irg = get_irn_irg(ret); + be_stack_layout_t *layout = be_get_irg_stack_layout(irg); + ir_node *block = get_nodes_block(ret); + ir_type *frame_type = get_irg_frame_type(irg); + unsigned frame_size = get_type_size_bytes(frame_type); + int sp_idx = be_find_return_reg_input(ret, sp_reg); + ir_node *sp = get_irn_n(ret, sp_idx); + + if (!layout->sp_relative) { + const arch_register_t *fp_reg = &sparc_registers[REG_FRAME_POINTER]; + ir_node *fp = be_get_initial_reg_value(irg, fp_reg); + ir_node *restore = new_bd_sparc_RestoreZero(NULL, block, fp); + sched_add_before(ret, restore); + arch_set_irn_register(restore, sp_reg); + set_irn_n(ret, sp_idx, restore); + + kill_unused_stacknodes(sp); + } else { + ir_node *incsp = be_new_IncSP(sp_reg, block, sp, frame_size, 0); + set_irn_n(ret, sp_idx, incsp); + sched_add_before(ret, incsp); + } +} + +void sparc_introduce_prolog_epilog(ir_graph *irg) +{ + const arch_register_t *sp_reg = &sparc_registers[REG_SP]; + ir_node *start = get_irg_start(irg); + be_stack_layout_t *layout = be_get_irg_stack_layout(irg); + ir_node *block = get_nodes_block(start); + ir_node *initial_sp = be_get_initial_reg_value(irg, sp_reg); + ir_node *sp = initial_sp; + ir_node *schedpoint = start; + ir_type *frame_type = get_irg_frame_type(irg); + unsigned frame_size = get_type_size_bytes(frame_type); + + /* introduce epilog for every return node */ + { + ir_node *end_block = get_irg_end_block(irg); + int arity = get_irn_arity(end_block); + int i; + + for (i = 0; i < arity; ++i) { + ir_node *ret = get_irn_n(end_block, i); + assert(be_is_Return(ret)); + introduce_epilog(ret); + } + } + + while (be_is_Keep(sched_next(schedpoint))) + schedpoint = sched_next(schedpoint); + + if (!layout->sp_relative) { + ir_node *incsp; + ir_node *save = new_bd_sparc_Save_imm(NULL, block, sp, NULL, + -SPARC_MIN_STACKSIZE); + arch_set_irn_register(save, sp_reg); + sched_add_after(schedpoint, save); + schedpoint = save; + + incsp = be_new_IncSP(sp_reg, block, save, frame_size, 0); + edges_reroute(initial_sp, incsp); + set_irn_n(save, n_sparc_Save_stack, initial_sp); + sched_add_after(schedpoint, incsp); + schedpoint = incsp; + + /* we still need the IncSP even if noone is explicitely using the + * value. (TODO: this isn't 100% correct yet, something at the end of + * the function should hold the IncSP, even if we use a restore + * which just overrides it instead of using the value) + */ + if (get_irn_n_edges(incsp) == 0) { + ir_node *in[] = { incsp }; + ir_node *keep = be_new_Keep(block, 1, in); + sched_add_after(schedpoint, keep); + } + } else { + ir_node *incsp = be_new_IncSP(sp_reg, block, sp, frame_size, 0); + edges_reroute(initial_sp, incsp); + be_set_IncSP_pred(incsp, sp); + sched_add_after(schedpoint, incsp); + } +} + static void finish_sparc_Save(ir_node *node) { sparc_attr_t *attr = get_sparc_attr(node); @@ -265,11 +374,13 @@ static void register_peephole_optimisation(ir_op *op, peephole_opt_func func) void sparc_finish(ir_graph *irg) { + /* perform peephole optimizations */ clear_irp_opcodes_generic_func(); register_peephole_optimisation(op_be_IncSP, peephole_be_IncSP); register_peephole_optimisation(op_sparc_FrameAddr, peephole_sparc_FrameAddr); be_peephole_opt(irg); + /* perform legalizations (mostly fix nodes with too big immediates) */ clear_irp_opcodes_generic_func(); register_peephole_optimisation(op_be_IncSP, finish_be_IncSP); register_peephole_optimisation(op_be_Return, finish_be_Return); diff --git a/ir/be/sparc/sparc_transform.c b/ir/be/sparc/sparc_transform.c index 06c891395..e7b3dc58e 100644 --- a/ir/be/sparc/sparc_transform.c +++ b/ir/be/sparc/sparc_transform.c @@ -1301,9 +1301,7 @@ static ir_node *gen_Start(ir_node *node) ir_node *block = get_nodes_block(node); ir_node *new_block = be_transform_node(block); dbg_info *dbgi = get_irn_dbg_info(node); - ir_node *mem; ir_node *start; -ir_node *sp; size_t i; /* stackpointer is important at function prolog */ @@ -1337,25 +1335,6 @@ ir_node *sp; } start = be_prolog_create_start(abihelper, dbgi, new_block); -#if 0 - mem = be_prolog_get_memory(abihelper); - sp = be_prolog_get_reg_value(abihelper, sp_reg); - - if (!cconv->omit_fp) { - ir_node *save = new_bd_sparc_Save_imm(NULL, block, sp, NULL, - -SPARC_MIN_STACKSIZE); - arch_irn_add_flags(save, arch_irn_flags_prolog); - arch_set_irn_register(save, sp_reg); - sp = save; - keep_alive(save); - } - - sp = be_new_IncSP(sp_reg, new_block, sp, BE_STACK_FRAME_SIZE_EXPAND, 0); - arch_irn_add_flags(sp, arch_irn_flags_prolog); - be_prolog_set_reg_value(abihelper, sp_reg, sp); - be_prolog_set_memory(abihelper, mem); -#endif - return start; } @@ -1428,24 +1407,6 @@ static ir_node *gen_Return(ir_node *node) } } -#if 0 - /* we need a restore instruction */ - if (!cconv->omit_fp) { - ir_node *fp = be_prolog_get_reg_value(abihelper, fp_reg); - ir_node *restore = new_bd_sparc_RestoreZero(NULL, block, fp); - arch_irn_add_flags(restore, arch_irn_flags_epilog); - arch_set_irn_register(restore, sp_reg); - be_epilog_set_reg_value(abihelper, sp_reg, restore); - } else { - /* epilog code: an incsp */ - sp = be_epilog_get_reg_value(abihelper, sp_reg); - sp = be_new_IncSP(sp_reg, new_block, sp, - BE_STACK_FRAME_SIZE_SHRINK, 0); - arch_irn_add_flags(sp, arch_irn_flags_epilog); - be_epilog_set_reg_value(abihelper, sp_reg, sp); - } -#endif - bereturn = be_epilog_create_return(abihelper, dbgi, new_block); return bereturn; } -- 2.20.1