Commit 84d9d910 authored by Matthias Braun's avatar Matthias Braun
Browse files

sparc: implement div instructions correctly

[r27952]
parent efa9475a
......@@ -412,7 +412,7 @@ static void emit_sparc_Div(const ir_node *node, bool is_signed)
be_emit_irprintf("\t%s ", is_signed ? "sdiv" : "udiv");
sparc_emit_source_register(node, 1);
be_emit_cstring(", ");
sparc_emit_source_register(node, 2);
sparc_emit_reg_or_imm(node, 2);
be_emit_cstring(", ");
sparc_emit_dest_register(node, 0);
be_emit_finish_line_gas(node);
......@@ -420,11 +420,7 @@ static void emit_sparc_Div(const ir_node *node, bool is_signed)
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");
emit_sparc_Div(node, true);
}
static void emit_sparc_UDiv(const ir_node *node)
......
......@@ -212,6 +212,17 @@ my %binop_operand_constructors = (
},
);
my %div_operand_constructors = (
imm => {
attr => "ir_entity *immediate_entity, int32_t immediate_value",
custominit => "sparc_set_attr_imm(res, immediate_entity, immediate_value);",
reg_req => { in => [ "gp", "gp" ], out => [ "gp" ] },
},
reg => {
reg_req => { in => [ "gp", "gp", "gp" ], out => [ "gp" ] },
},
);
my %float_binop_constructors = (
s => {
reg_req => { in => [ "fp", "fp" ], out => [ "fp" ] },
......@@ -501,24 +512,20 @@ Mulh => {
constructors => \%binop_operand_constructors,
},
# 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",
ins => [ "dividend_low", "divisor" ],
ins => [ "dividend_high", "dividend_low", "divisor" ],
outs => [ "res", "M" ],
constructors => \%binop_operand_constructors,
constructors => \%div_operand_constructors,
},
UDiv => {
irn_flags => [ "rematerializable" ],
state => "exc_pinned",
ins => [ "dividend_low", "divisor" ],
ins => [ "dividend_high", "dividend_low", "divisor" ],
outs => [ "res", "M" ],
constructors => \%binop_operand_constructors,
constructors => \%div_operand_constructors,
},
fcmp => {
......
......@@ -272,6 +272,11 @@ static ir_node *gen_helper_unfpop(ir_node *node, ir_mode *mode,
panic("unsupported mode %+F for float op", mode);
}
static ir_node *get_g0(void)
{
return be_prolog_get_reg_value(abihelper, &sparc_gp_regs[REG_G0]);
}
typedef struct address_t {
ir_node *base;
ir_entity *entity;
......@@ -531,6 +536,17 @@ static ir_node *gen_Mulh(ir_node *node)
return proj_res_hi;
}
static ir_node *gen_sign_extension_value(ir_node *node)
{
ir_node *block = get_nodes_block(node);
ir_node *new_block = be_transform_node(block);
ir_node *new_node = be_transform_node(node);
/* TODO: we could do some shortcuts for some value types probably.
* (For constants or other cases where we know the sign bit in
* advance) */
return new_bd_sparc_Sra_imm(NULL, new_block, new_node, NULL, 31);
}
/**
* Creates an sparc Div.
*
......@@ -538,17 +554,41 @@ 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;
dbg_info *dbgi = get_irn_dbg_info(node);
ir_node *block = get_nodes_block(node);
ir_node *new_block = be_transform_node(block);
ir_mode *mode = get_Div_resmode(node);
ir_node *left = get_Div_left(node);
ir_node *left_low = be_transform_node(left);
ir_node *right = get_Div_right(node);
ir_node *res;
assert(!mode_is_float(mode));
if (mode_is_signed(mode)) {
res = gen_helper_binop(node, 0, new_bd_sparc_SDiv_reg,
new_bd_sparc_SDiv_imm);
ir_node *left_high = gen_sign_extension_value(left);
if (is_imm_encodeable(right)) {
int32_t immediate = get_tarval_long(get_Const_tarval(right));
res = new_bd_sparc_SDiv_imm(dbgi, new_block, left_high, left_low,
NULL, immediate);
} else {
ir_node *new_right = be_transform_node(right);
res = new_bd_sparc_SDiv_reg(dbgi, new_block, left_high, left_low,
new_right);
}
} else {
res = gen_helper_binop(node, 0, new_bd_sparc_UDiv_reg,
new_bd_sparc_UDiv_imm);
ir_node *left_high = get_g0();
if (is_imm_encodeable(right)) {
int32_t immediate = get_tarval_long(get_Const_tarval(right));
res = new_bd_sparc_UDiv_imm(dbgi, new_block, left_high, left_low,
NULL, immediate);
} else {
ir_node *new_right = be_transform_node(right);
res = new_bd_sparc_UDiv_reg(dbgi, new_block, left_high, left_low,
new_right);
}
}
return res;
}
......@@ -579,11 +619,6 @@ static ir_node *gen_Abs(ir_node *node)
}
}
static ir_node *get_g0(void)
{
return be_prolog_get_reg_value(abihelper, &sparc_gp_regs[REG_G0]);
}
/**
* Transforms a Not node.
*
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment