From 035c482fe704a0f976727e4f7f0e3d2763bdc3f3 Mon Sep 17 00:00:00 2001 From: Matthias Braun Date: Tue, 27 Jul 2010 17:57:57 +0000 Subject: [PATCH] sparc: cleanup register classes, remove some unused code, try to cleanup Div [r27826] --- ir/be/sparc/bearch_sparc.c | 4 +- ir/be/sparc/sparc_emitter.c | 48 ++++++++++++++++-- ir/be/sparc/sparc_spec.pl | 96 ++++++++++++++++++++++------------- ir/be/sparc/sparc_transform.c | 35 +++++++------ 4 files changed, 124 insertions(+), 59 deletions(-) diff --git a/ir/be/sparc/bearch_sparc.c b/ir/be/sparc/bearch_sparc.c index e1cd752a1..e7c954e88 100644 --- a/ir/be/sparc/bearch_sparc.c +++ b/ir/be/sparc/bearch_sparc.c @@ -155,8 +155,8 @@ static void sparc_before_ra(void *self) { sparc_code_gen_t *cg = self; /* fixup flags register */ - be_sched_fix_flags(cg->irg, &sparc_reg_classes[CLASS_sparc_flags], NULL, - NULL); + be_sched_fix_flags(cg->irg, &sparc_reg_classes[CLASS_sparc_flags_class], + NULL, NULL); } /** diff --git a/ir/be/sparc/sparc_emitter.c b/ir/be/sparc/sparc_emitter.c index 898605dd0..2863ba04a 100644 --- a/ir/be/sparc/sparc_emitter.c +++ b/ir/be/sparc/sparc_emitter.c @@ -357,14 +357,50 @@ static void emit_sparc_Mulh(const ir_node *irn) // our result is in the y register now // we just copy it to the assigned target reg - be_emit_cstring("\tmov "); - be_emit_char('%'); - be_emit_string(arch_register_get_name(&sparc_flags_regs[REG_Y])); - be_emit_cstring(", "); + be_emit_cstring("\tmov %y, "); sparc_emit_dest_register(irn, 0); be_emit_finish_line_gas(irn); } +static void emit_sparc_Div(const ir_node *node, bool is_signed) +{ + /* can we get the delay count of the wr instruction somewhere? */ + unsigned wry_delay_count = 3; + unsigned i; + + be_emit_cstring("\twr "); + sparc_emit_source_register(node, 0); + be_emit_cstring(", 0, %y"); + be_emit_finish_line_gas(node); + + for (i = 0; i < wry_delay_count; ++i) { + be_emit_cstring("\tnop"); + be_emit_finish_line_gas(node); + } + + be_emit_irprintf("\t%s ", is_signed ? "sdiv" : "udiv"); + sparc_emit_source_register(node, 1); + be_emit_cstring(", "); + sparc_emit_source_register(node, 2); + be_emit_cstring(", "); + sparc_emit_dest_register(node, 0); + be_emit_finish_line_gas(node); +} + +static void emit_sparc_SDiv(const ir_node *node) +{ + (void) node; + /* aehm we would need an aditional register for an sra instruction to + * compute the upper bits... Just panic for now */ + //emit_sparc_Div(node, true); + panic("signed div is wrong"); +} + +static void emit_sparc_UDiv(const ir_node *node) +{ + emit_sparc_Div(node, false); +} + /** * Emits code for return node */ @@ -723,15 +759,17 @@ static void sparc_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_sparc_Ba, emit_sparc_Ba); set_emitter(op_sparc_BXX, emit_sparc_BXX); set_emitter(op_sparc_Call, emit_sparc_Call); set_emitter(op_sparc_FrameAddr, emit_sparc_FrameAddr); set_emitter(op_sparc_HiImm, emit_sparc_HiImm); - set_emitter(op_sparc_Ba, emit_sparc_Ba); set_emitter(op_sparc_LoImm, emit_sparc_LoImm); 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_SymConst, emit_sparc_SymConst); + set_emitter(op_sparc_UDiv, emit_sparc_UDiv); /* no need to emit anything for the following nodes */ set_emitter(op_be_Barrier, emit_nothing); diff --git a/ir/be/sparc/sparc_spec.pl b/ir/be/sparc/sparc_spec.pl index 4e2da4d9b..6733e6dba 100644 --- a/ir/be/sparc/sparc_spec.pl +++ b/ir/be/sparc/sparc_spec.pl @@ -5,6 +5,7 @@ $arch = "sparc"; $mode_gp = "mode_Iu"; $mode_flags = "mode_Bu"; +$mode_fpflags = "mode_Bu"; $mode_fp = "mode_D"; $normal = 0; # no special type @@ -18,50 +19,58 @@ $state = 32; # register represents a state # available SPARC registers: 8 globals, 24 window regs (8 ins, 8 outs, 8 locals) %reg_classes = ( gp => [ - { name => "g0", realname => "g0", type => $ignore }, # hardwired 0, behaves like /dev/null - { name => "g1", realname => "g1", type => $caller_save }, # temp. value - { name => "g2", realname => "g2", type => $caller_save }, - { name => "g3", realname => "g3", type => $caller_save }, - { name => "g4", realname => "g4", type => $caller_save }, - { name => "g5", realname => "g5", type => $ignore }, # reserved by SPARC ABI - { name => "g6", realname => "g6", type => $ignore }, # reserved by SPARC ABI - { name => "g7", realname => "g7", type => $ignore }, # reserved by SPARC ABI + { name => "g0", type => $ignore }, # hardwired 0, behaves like /dev/null + { name => "g1", type => $caller_save }, # temp. value + { name => "g2", type => $caller_save }, + { name => "g3", type => $caller_save }, + { name => "g4", type => $caller_save }, + { name => "g5", type => $ignore }, # reserved by SPARC ABI + { name => "g6", type => $ignore }, # reserved by SPARC ABI + { name => "g7", type => $ignore }, # reserved by SPARC ABI # window's out registers - { name => "o0", realname => "o0", type => $caller_save }, # param 1 / return value from callee - { name => "o1", realname => "o1", type => $caller_save }, # param 2 - { name => "o2", realname => "o2", type => $caller_save }, # param 3 - { name => "o3", realname => "o3", type => $caller_save }, # param 4 - { name => "o4", realname => "o4", type => $caller_save }, # param 5 - { name => "o5", realname => "o5", type => $caller_save }, # param 6 - { name => "sp", realname => "sp", type => $ignore }, # our stackpointer - { name => "o7", realname => "o6", type => $ignore }, # temp. value / address of CALL instr. + { name => "o0", type => $caller_save }, # param 1 / return value from callee + { name => "o1", type => $caller_save }, # param 2 + { name => "o2", type => $caller_save }, # param 3 + { name => "o3", type => $caller_save }, # param 4 + { name => "o4", type => $caller_save }, # param 5 + { name => "o5", type => $caller_save }, # param 6 + { name => "sp", type => $ignore }, # our stackpointer + { name => "o7", type => $ignore }, # temp. value / address of CALL instr. # window's local registers - { name => "l0", realname => "l0", type => 0 }, - { name => "l1", realname => "l1", type => 0 }, - { name => "l2", realname => "l2", type => 0 }, - { name => "l3", realname => "l3", type => 0 }, - { name => "l4", realname => "l4", type => 0 }, - { name => "l5", realname => "l5", type => 0 }, - { name => "l6", realname => "l6", type => 0 }, - { name => "l7", realname => "l7", type => 0 }, + { name => "l0", type => 0 }, + { name => "l1", type => 0 }, + { name => "l2", type => 0 }, + { name => "l3", type => 0 }, + { name => "l4", type => 0 }, + { name => "l5", type => 0 }, + { name => "l6", type => 0 }, + { name => "l7", type => 0 }, # window's in registers - { name => "i0", realname => "i0", type => 0 }, # incoming param1 / return value to caller - { name => "i1", realname => "i1", type => 0 }, # param 2 - { name => "i2", realname => "i2", type => 0 }, # param 3 - { name => "i3", realname => "i3", type => 0 }, # param 4 - { name => "i4", realname => "i4", type => 0 }, # param 5 - { name => "i5", realname => "i5", type => 0 }, # param 6 + { name => "i0", type => 0 }, # incoming param1 / return value to caller + { name => "i1", type => 0 }, # param 2 + { name => "i2", type => 0 }, # param 3 + { name => "i3", type => 0 }, # param 4 + { name => "i4", type => 0 }, # param 5 + { name => "i5", type => 0 }, # param 6 { name => "frame_pointer", realname => "fp", type => $ignore }, # our framepointer - { name => "i7", realname => "i7", type => $ignore }, # return address - 8 + { name => "i7", type => $ignore }, # return address - 8 { mode => $mode_gp } ], - flags => [ - { name => "y", realname => "y", type => $ignore }, # the multiply/divide state register + fp_flags => [ + { name => "fpflags", type => $ignore }, + { mode => $mode_fpflags, flags => "manual_ra" } + ], + flags_class => [ + { name => "flags", type => $ignore }, { mode => $mode_flags, flags => "manual_ra" } ], + mul_div_high_res => [ + { name => "y", type => $ignore }, + { mode => $mode_gp, flags => "manual_ra" } + ], # fp registers can be accessed any time fp => [ { name => "f0", type => $caller_save }, @@ -353,6 +362,8 @@ Call => { Cmp => { irn_flags => [ "rematerializable", "modify_flags" ], emit => '. cmp %S1, %R2I', + reg_req => { in => [ "gp", "gp" ], out => [ "flags" ] }, + ins => [ "left", "right" ], mode => $mode_flags, constructors => \%cmp_operand_constructors, }, @@ -425,7 +436,7 @@ Xor => { }, Mul => { - reg_req => { in => [ "gp", "gp" ], out => [ "gp" ] }, + reg_req => { in => [ "gp", "gp" ], out => [ "gp", "y" ] }, constructors => \%binop_operand_constructors, emit => '. mul %S1, %R2I, %D1', mode => $mode_gp, @@ -437,13 +448,26 @@ Mulh => { constructors => \%binop_operand_constructors, }, -Div => { +# The div instructions are kinda hacky. Things to improve: +# * Make high-value input explicitely. Either as a gp at first or ideally +# as an explicit y-register + +SDiv => { + irn_flags => [ "rematerializable" ], + state => "exc_pinned", + reg_req => { in => [ "gp", "gp" ], out => [ "gp", "none" ] }, + ins => [ "dividend_low", "divisor" ], + outs => [ "res", "M" ], + constructors => \%binop_operand_constructors, +}, + +UDiv => { irn_flags => [ "rematerializable" ], state => "exc_pinned", reg_req => { in => [ "gp", "gp" ], out => [ "gp", "none" ] }, + ins => [ "dividend_low", "divisor" ], outs => [ "res", "M" ], constructors => \%binop_operand_constructors, - emit => '. div %S1, %R2I, %D1', }, Minus => { diff --git a/ir/be/sparc/sparc_transform.c b/ir/be/sparc/sparc_transform.c index 2cbf4845d..c289ac771 100644 --- a/ir/be/sparc/sparc_transform.c +++ b/ir/be/sparc/sparc_transform.c @@ -407,8 +407,17 @@ static ir_node *gen_Mulh(ir_node *node) static ir_node *gen_Div(ir_node *node) { ir_mode *mode = get_Div_resmode(node); + ir_node *res; + assert(!mode_is_float(mode)); - return gen_helper_binop(node, MATCH_SIZE_NEUTRAL, new_bd_sparc_Div_reg, new_bd_sparc_Div_imm); + if (mode_is_signed(mode)) { + res = gen_helper_binop(node, 0, new_bd_sparc_SDiv_reg, + new_bd_sparc_SDiv_imm); + } else { + res = gen_helper_binop(node, 0, new_bd_sparc_UDiv_reg, + new_bd_sparc_UDiv_imm); + } + return res; } static ir_node *gen_Quot(ir_node *node) @@ -758,23 +767,17 @@ static ir_node *gen_Cmp(ir_node *node) ir_node *op2 = get_Cmp_right(node); ir_mode *cmp_mode = get_irn_mode(op1); dbg_info *dbgi = get_irn_dbg_info(node); - ir_node *new_op1; - ir_node *new_op2; + ir_node *new_op1 = be_transform_node(op1); + ir_node *new_op2 = be_transform_node(op2); if (mode_is_float(cmp_mode)) { panic("FloatCmp not implemented"); } - /* - if (get_mode_size_bits(cmp_mode) != 32) { - panic("CmpMode != 32bit not supported yet"); - } - */ - assert(get_irn_mode(op2) == cmp_mode); +#if 0 /* compare with 0 can be done with Tst */ - /* if (is_Const(op2) && tarval_is_null(get_Const_tarval(op2))) { new_op1 = be_transform_node(op1); return new_bd_sparc_Tst(dbgi, block, new_op1, false, @@ -786,12 +789,10 @@ static ir_node *gen_Cmp(ir_node *node) return new_bd_sparc_Tst(dbgi, block, new_op2, true, is_unsigned); } - */ +#endif /* integer compare */ - new_op1 = be_transform_node(op1); new_op1 = gen_extension(dbgi, block, new_op1, cmp_mode); - new_op2 = be_transform_node(op2); new_op2 = gen_extension(dbgi, block, new_op2, cmp_mode); return new_bd_sparc_Cmp_reg(dbgi, block, new_op1, new_op2); } @@ -1401,12 +1402,14 @@ static ir_node *gen_Proj_Div(ir_node *node) ir_node *new_pred = be_transform_node(pred); long pn = get_Proj_proj(node); - assert(is_sparc_Div(new_pred)); + assert(is_sparc_SDiv(new_pred) || is_sparc_UDiv(new_pred)); + assert(pn_sparc_SDiv_res == pn_sparc_UDiv_res); + assert(pn_sparc_SDiv_M == pn_sparc_UDiv_M); switch (pn) { case pn_Div_res: - return new_r_Proj(new_pred, mode_gp, pn_sparc_Div_res); + return new_r_Proj(new_pred, mode_gp, pn_sparc_SDiv_res); case pn_Div_M: - return new_r_Proj(new_pred, mode_gp, pn_sparc_Div_M); + return new_r_Proj(new_pred, mode_gp, pn_sparc_SDiv_M); default: break; } -- 2.20.1