From f7e854b67832df74cfd24c42c81b7f45f2d29df3 Mon Sep 17 00:00:00 2001 From: Matthias Braun Date: Fri, 8 Oct 2010 14:02:15 +0000 Subject: [PATCH] sparc: model restore as explicit node, refactor Save node [r28068] --- ir/be/sparc/bearch_sparc.c | 11 ++++-- ir/be/sparc/sparc_emitter.c | 65 +++++++++++++++++-------------- ir/be/sparc/sparc_new_nodes.c | 38 ------------------ ir/be/sparc/sparc_new_nodes.h | 3 -- ir/be/sparc/sparc_nodes_attr.h | 9 ----- ir/be/sparc/sparc_spec.pl | 70 +++++++++++++++++++++++++++------- ir/be/sparc/sparc_transform.c | 14 +++---- 7 files changed, 106 insertions(+), 104 deletions(-) diff --git a/ir/be/sparc/bearch_sparc.c b/ir/be/sparc/bearch_sparc.c index 737d88fb5..821f5a2c0 100644 --- a/ir/be/sparc/bearch_sparc.c +++ b/ir/be/sparc/bearch_sparc.c @@ -107,12 +107,15 @@ static void sparc_set_frame_offset(ir_node *node, int offset) static int sparc_get_sp_bias(const ir_node *node) { if (is_sparc_Save(node)) { - const sparc_save_attr_t *attr = get_sparc_save_attr_const(node); - /* Note we do not retport the change of the SPARC_MIN_STACKSIZE + const sparc_attr_t *attr = get_sparc_attr_const(node); + if (get_irn_arity(node) == 3) + panic("no support for _reg variant yet"); + + /* Note we do not report the change of the SPARC_MIN_STACKSIZE * size, since we have additional magic in the emitter which * calculates that! */ - assert(attr->initial_stacksize >= SPARC_MIN_STACKSIZE); - return attr->initial_stacksize - SPARC_MIN_STACKSIZE; + assert(attr->immediate_value <= -SPARC_MIN_STACKSIZE); + return attr->immediate_value + SPARC_MIN_STACKSIZE; } return 0; } diff --git a/ir/be/sparc/sparc_emitter.c b/ir/be/sparc/sparc_emitter.c index f796857d8..cd28c76e7 100644 --- a/ir/be/sparc/sparc_emitter.c +++ b/ir/be/sparc/sparc_emitter.c @@ -366,6 +366,8 @@ static bool is_no_instruction(const ir_node *node) if (src_reg == dest_reg) return true; } + if (be_is_IncSP(node) && be_get_IncSP_offset(node) == 0) + return true; /* Ba is not emitted if it is a simple fallthrough */ if (is_sparc_Ba(node) && ba_is_fallthrough(node)) return true; @@ -381,7 +383,8 @@ static bool has_delay_slot(const ir_node *node) return is_sparc_Bicc(node) || is_sparc_fbfcc(node) || is_sparc_Ba(node) || is_sparc_SwitchJmp(node) || is_sparc_Call(node) - || is_sparc_SDiv(node) || is_sparc_UDiv(node); + || is_sparc_SDiv(node) || is_sparc_UDiv(node) + || be_is_Return(node); } /** returns true if the emitter for this sparc node can produce more than one @@ -396,7 +399,7 @@ static bool emits_multiple_instructions(const ir_node *node) return true; return is_sparc_Mulh(node) || is_sparc_SDiv(node) || is_sparc_UDiv(node) - || be_is_MemPerm(node) || be_is_Perm(node) || be_is_Return(node); + || be_is_MemPerm(node) || be_is_Perm(node); } /** @@ -427,6 +430,20 @@ static const ir_node *pick_delay_slot_for(const ir_node *node) /* the Call also destroys the value of %o7, but since this is currently * marked as ignore register in the backend, it should never be used by * the instruction in the delay slot. */ + } else if (be_is_Return(node)) { + /* we only have to check the jump destination value */ + int arity = get_irn_arity(node); + int i; + + check = NULL; + for (i = 0; i < arity; ++i) { + ir_node *in = get_irn_n(node, i); + const arch_register_t *reg = arch_get_irn_register(in); + if (reg == &sparc_gp_regs[REG_O7]) { + check = skip_Proj(in); + break; + } + } } else { check = node; } @@ -485,19 +502,6 @@ static void emit_be_IncSP(const ir_node *irn) be_emit_finish_line_gas(irn); } -/** - * emits code for save instruction with min. required stack space - */ -static void emit_sparc_Save(const ir_node *irn) -{ - const sparc_save_attr_t *save_attr = get_sparc_save_attr_const(irn); - be_emit_cstring("\tsave "); - sparc_emit_source_register(irn, 0); - be_emit_irprintf(", %d, ", -save_attr->initial_stacksize); - sparc_emit_dest_register(irn, 0); - be_emit_finish_line_gas(irn); -} - /** * emits code for mulh */ @@ -566,18 +570,6 @@ static void emit_sparc_UDiv(const ir_node *node) emit_sparc_Div(node, false); } -/** - * Emits code for return node - */ -static void emit_be_Return(const ir_node *irn) -{ - be_emit_cstring("\tret"); - //be_emit_cstring("\tjmp %i7+8"); - be_emit_finish_line_gas(irn); - be_emit_cstring("\trestore"); - be_emit_finish_line_gas(irn); -} - /** * Emits code for Call node */ @@ -688,6 +680,24 @@ static void emit_be_MemPerm(const ir_node *node) assert(sp_change == 0); } +static void emit_be_Return(const ir_node *node) +{ + const char *destreg = "%o7"; + + /* hack: we don't explicitely model register changes because of the + * restore node. So we have to do it manually here */ + if (delay_slot_filler != NULL && + (is_sparc_Restore(delay_slot_filler) + || is_sparc_RestoreZero(delay_slot_filler))) { + destreg = "%i7"; + } + be_emit_cstring("\tjmp "); + be_emit_string(destreg); + be_emit_cstring("+8"); + be_emit_finish_line_gas(node); + fill_delay_slot(); +} + static void emit_sparc_FrameAddr(const ir_node *node) { const sparc_attr_t *attr = get_sparc_attr_const(node); @@ -1014,7 +1024,6 @@ static void sparc_register_emitters(void) set_emitter(op_sparc_fbfcc, emit_sparc_fbfcc); set_emitter(op_sparc_FrameAddr, emit_sparc_FrameAddr); set_emitter(op_sparc_Mulh, emit_sparc_Mulh); - set_emitter(op_sparc_Save, emit_sparc_Save); set_emitter(op_sparc_SDiv, emit_sparc_SDiv); set_emitter(op_sparc_SwitchJmp, emit_sparc_SwitchJmp); set_emitter(op_sparc_UDiv, emit_sparc_UDiv); diff --git a/ir/be/sparc/sparc_new_nodes.c b/ir/be/sparc/sparc_new_nodes.c index ae53eca47..bee435f26 100644 --- a/ir/be/sparc/sparc_new_nodes.c +++ b/ir/be/sparc/sparc_new_nodes.c @@ -60,11 +60,6 @@ static bool has_switch_jmp_attr(const ir_node *node) return is_sparc_SwitchJmp(node); } -static bool has_save_attr(const ir_node *node) -{ - return is_sparc_Save(node); -} - static bool has_fp_attr(const ir_node *node) { return is_sparc_fadd(node) || is_sparc_fsub(node) @@ -105,10 +100,6 @@ static void sparc_dump_node(FILE *F, ir_node *n, dump_reason_t reason) } else { ir_fprintf(F, "immediate value: %d\n", attr->immediate_value); } - if (has_save_attr(n)) { - const sparc_save_attr_t *attr = get_sparc_save_attr_const(n); - fprintf(F, "initial stacksize: %d\n", attr->initial_stacksize); - } if (sparc_has_load_store_attr(n)) { const sparc_load_store_attr_t *attr = get_sparc_load_store_attr_const(n); ir_fprintf(F, "load store mode: %+F\n", attr->load_store_mode); @@ -205,18 +196,6 @@ const sparc_switch_jmp_attr_t *get_sparc_switch_jmp_attr_const(const ir_node *no return (const sparc_switch_jmp_attr_t*) get_irn_generic_attr_const(node); } -sparc_save_attr_t *get_sparc_save_attr(ir_node *node) -{ - assert(has_save_attr(node)); - return (sparc_save_attr_t*) get_irn_generic_attr_const(node); -} - -const sparc_save_attr_t *get_sparc_save_attr_const(const ir_node *node) -{ - assert(has_save_attr(node)); - return (const sparc_save_attr_t*) get_irn_generic_attr_const(node); -} - sparc_fp_attr_t *get_sparc_fp_attr(ir_node *node) { assert(has_fp_attr(node)); @@ -275,12 +254,6 @@ static void init_sparc_load_store_attributes(ir_node *res, ir_mode *ls_mode, attr->is_reg_reg = is_reg_reg; } -static void init_sparc_save_attributes(ir_node *res, int initial_stacksize) -{ - sparc_save_attr_t *attr = get_sparc_save_attr(res); - attr->initial_stacksize = initial_stacksize; -} - static void init_sparc_fp_attributes(ir_node *res, ir_mode *fp_mode) { sparc_fp_attr_t *attr = get_sparc_fp_attr(res); @@ -370,17 +343,6 @@ static int cmp_attr_sparc_switch_jmp(ir_node *a, ir_node *b) return attr_a->default_proj_num != attr_b->default_proj_num; } -static int cmp_attr_sparc_save(ir_node *a, ir_node *b) -{ - const sparc_save_attr_t *attr_a = get_sparc_save_attr_const(a); - const sparc_save_attr_t *attr_b = get_sparc_save_attr_const(b); - - if (cmp_attr_sparc(a, b)) - return 1; - - return attr_a->initial_stacksize != attr_b->initial_stacksize; -} - static int cmp_attr_sparc_fp(ir_node *a, ir_node *b) { const sparc_fp_attr_t *attr_a = get_sparc_fp_attr_const(a); diff --git a/ir/be/sparc/sparc_new_nodes.h b/ir/be/sparc/sparc_new_nodes.h index 8fac05c8b..a130baa64 100644 --- a/ir/be/sparc/sparc_new_nodes.h +++ b/ir/be/sparc/sparc_new_nodes.h @@ -44,9 +44,6 @@ const sparc_jmp_cond_attr_t *get_sparc_jmp_cond_attr_const(const ir_node *node); sparc_switch_jmp_attr_t *get_sparc_switch_jmp_attr(ir_node *node); const sparc_switch_jmp_attr_t *get_sparc_switch_jmp_attr_const(const ir_node *node); -sparc_save_attr_t *get_sparc_save_attr(ir_node *node); -const sparc_save_attr_t *get_sparc_save_attr_const(const ir_node *node); - sparc_fp_attr_t *get_sparc_fp_attr(ir_node *node); const sparc_fp_attr_t *get_sparc_fp_attr_const(const ir_node *node); diff --git a/ir/be/sparc/sparc_nodes_attr.h b/ir/be/sparc/sparc_nodes_attr.h index 58665ac77..715a6268d 100644 --- a/ir/be/sparc/sparc_nodes_attr.h +++ b/ir/be/sparc/sparc_nodes_attr.h @@ -62,15 +62,6 @@ struct sparc_fp_conv_attr_t { ir_mode *dest_mode; }; -/** - * attribute for save instruction - */ -typedef struct sparc_save_attr_t sparc_save_attr_t; -struct sparc_save_attr_t { - sparc_attr_t base; /**< generic attribute */ - int initial_stacksize; /* the min. stack size required by the sparc ABI */ -}; - /** * attributes for load/store adressing modes */ diff --git a/ir/be/sparc/sparc_spec.pl b/ir/be/sparc/sparc_spec.pl index 484cf0290..d7d78e7f3 100644 --- a/ir/be/sparc/sparc_spec.pl +++ b/ir/be/sparc/sparc_spec.pl @@ -139,7 +139,6 @@ $default_copy_attr = "sparc_copy_attr"; sparc_jmp_cond_attr_t => "\tinit_sparc_attributes(res, flags, in_reqs, exec_units, n_res);", sparc_switch_jmp_attr_t => "\tinit_sparc_attributes(res, flags, in_reqs, exec_units, n_res);\n". "\tinit_sparc_switch_jmp_attributes(res, default_pn, jump_table);\n", - sparc_save_attr_t => "\tinit_sparc_attributes(res, flags, in_reqs, exec_units, n_res);", sparc_fp_attr_t => "\tinit_sparc_attributes(res, flags, in_reqs, exec_units, n_res);\n". "\tinit_sparc_fp_attributes(res, fp_mode);\n", sparc_fp_conv_attr_t => "\tinit_sparc_attributes(res, flags, in_reqs, exec_units, n_res);". @@ -151,7 +150,6 @@ $default_copy_attr = "sparc_copy_attr"; sparc_load_store_attr_t => "cmp_attr_sparc_load_store", sparc_jmp_cond_attr_t => "cmp_attr_sparc_jmp_cond", sparc_switch_jmp_attr_t => "cmp_attr_sparc_switch_jmp", - sparc_save_attr_t => "cmp_attr_sparc_save", sparc_fp_attr_t => "cmp_attr_sparc_fp", sparc_fp_conv_attr_t => "cmp_attr_sparc_fp_conv", ); @@ -161,9 +159,6 @@ $default_copy_attr = "sparc_copy_attr"; modifies_fp_flags => "sparc_arch_irn_flag_modifies_fp_flags", ); -# addressing modes: imm, reg, reg +/- imm, reg + reg -# max. imm = 13 bits signed (-4096 ... 4096) - my %cmp_operand_constructors = ( imm => { attr => "ir_entity *immediate_entity, int32_t immediate_value", @@ -260,7 +255,6 @@ Sub => { constructors => \%binop_operand_constructors, }, - # Load / Store Ld => { op_flags => [ "labeled", "fragile" ], @@ -320,15 +314,44 @@ St => { }, Save => { - reg_req => { - in => [ "sp", "none"], - out => [ "sp:I|S", "frame_pointer:I", "none" ] + emit => '. save %S0, %R1I, %D0', + outs => [ "stack" ], + constructors => { + imm => { + attr => "ir_entity *immediate_entity, int32_t immediate_value", + custominit => "sparc_set_attr_imm(res, immediate_entity, immediate_value);", + reg_req => { in => [ "sp" ], out => [ "sp:I|S" ] }, + ins => [ "stack" ], + }, + reg => { + reg_req => { in => [ "sp", "gp" ], out => [ "sp:I|S" ] }, + ins => [ "stack", "increment" ], + } }, - ins => [ "stack", "mem" ], - outs => [ "stack", "frame", "mem" ], - attr => "int initial_stacksize", - attr_type => "sparc_save_attr_t", - init_attr => "\tinit_sparc_save_attributes(res, initial_stacksize);", +}, + +Restore => { + emit => '. restore %S0, %R1I, %D0', + outs => [ "stack" ], + constructors => { + imm => { + attr => "ir_entity *immediate_entity, int32_t immediate_value", + custominit => "sparc_set_attr_imm(res, immediate_entity, immediate_value);", + reg_req => { in => [ "sp" ], out => [ "sp:I|S" ] }, + ins => [ "stack" ], + }, + reg => { + reg_req => { in => [ "sp", "gp" ], out => [ "sp:I|S" ] }, + ins => [ "stack", "increment" ], + } + }, +}, + +RestoreZero => { + emit => '. restore', + outs => [ ], + ins => [ ], + mode => "mode_T", }, SubSP => { @@ -384,6 +407,25 @@ Ba => { mode => "mode_X", }, +# This is a JumpLink instruction, but with the addition that you can add custom +# register constraints to model your calling conventions +Return => { + arity => "variable", + out_arity => "variable", + constructors => { + imm => { + attr => "ir_entity *entity, int32_t offset", + custominit => "\tsparc_set_attr_imm(res, entity, offset);", + arity => "variable", + out_arity => "variable", + }, + reg => { + arity => "variable", + out_arity => "variable", + } + }, +}, + Call => { irn_flags => [ "modifies_flags", "modifies_fp_flags" ], state => "exc_pinned", diff --git a/ir/be/sparc/sparc_transform.c b/ir/be/sparc/sparc_transform.c index 6858204d2..dbadaf7eb 100644 --- a/ir/be/sparc/sparc_transform.c +++ b/ir/be/sparc/sparc_transform.c @@ -1282,7 +1282,6 @@ static ir_node *gen_Start(ir_node *node) ir_node *mem; ir_node *start; ir_node *sp; - ir_node *fp; ir_node *barrier; ir_node *save; int i; @@ -1305,16 +1304,10 @@ static ir_node *gen_Start(ir_node *node) mem = be_prolog_get_memory(abihelper); sp = be_prolog_get_reg_value(abihelper, sp_reg); - save = new_bd_sparc_Save(NULL, block, sp, mem, SPARC_MIN_STACKSIZE); - fp = new_r_Proj(save, mode_gp, pn_sparc_Save_frame); + save = new_bd_sparc_Save_imm(NULL, block, sp, NULL, -SPARC_MIN_STACKSIZE); sp = new_r_Proj(save, mode_gp, pn_sparc_Save_stack); - mem = new_r_Proj(save, mode_M, pn_sparc_Save_mem); - arch_set_irn_register(fp, fp_reg); arch_set_irn_register(sp, sp_reg); - be_prolog_add_reg(abihelper, fp_reg, arch_register_req_type_ignore); - be_prolog_set_reg_value(abihelper, fp_reg, fp); - sp = be_new_IncSP(sp_reg, new_block, sp, BE_STACK_FRAME_SIZE_EXPAND, 0); be_prolog_set_reg_value(abihelper, sp_reg, sp); be_prolog_set_memory(abihelper, mem); @@ -1360,6 +1353,7 @@ 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 *restore; ir_node *incsp; int i; @@ -1390,6 +1384,10 @@ static ir_node *gen_Return(ir_node *node) BE_STACK_FRAME_SIZE_SHRINK, 0); be_epilog_set_reg_value(abihelper, sp_reg, incsp); + /* we need a restore instruction */ + restore = new_bd_sparc_RestoreZero(NULL, block); + keep_alive(restore); + bereturn = be_epilog_create_return(abihelper, dbgi, new_block); return bereturn; -- 2.20.1