Commit da230f5e authored by Christoph Mallon's avatar Christoph Mallon
Browse files

Add magic for better code emission of 64bit minus.

[r15730]
parent cec4e902
...@@ -1920,6 +1920,121 @@ void emit_ia32_LdTls(ia32_emit_env_t *env, const ir_node *node) { ...@@ -1920,6 +1920,121 @@ void emit_ia32_LdTls(ia32_emit_env_t *env, const ir_node *node) {
be_emit_finish_line_gas(env, node); be_emit_finish_line_gas(env, node);
} }
/* helper function for emit_ia32_Minus64Bit */
static void emit_mov(ia32_emit_env_t *env, const ir_node* node, const arch_register_t *src, const arch_register_t *dst)
{
be_emit_cstring(env, "\tmovl ");
ia32_emit_register(env, src);
be_emit_cstring(env, ", ");
ia32_emit_register(env, dst);
be_emit_finish_line_gas(env, node);
}
/* helper function for emit_ia32_Minus64Bit */
static void emit_neg(ia32_emit_env_t *env, const ir_node* node, const arch_register_t *reg)
{
be_emit_cstring(env, "\tnegl ");
ia32_emit_register(env, reg);
be_emit_finish_line_gas(env, node);
}
/* helper function for emit_ia32_Minus64Bit */
static void emit_sbb0(ia32_emit_env_t *env, const ir_node* node, const arch_register_t *reg)
{
be_emit_cstring(env, "\tsbbl $0, ");
ia32_emit_register(env, reg);
be_emit_finish_line_gas(env, node);
}
/* helper function for emit_ia32_Minus64Bit */
static void emit_sbb(ia32_emit_env_t *env, const ir_node* node, const arch_register_t *src, const arch_register_t *dst)
{
be_emit_cstring(env, "\tsbbl ");
ia32_emit_register(env, src);
be_emit_cstring(env, ", ");
ia32_emit_register(env, dst);
be_emit_finish_line_gas(env, node);
}
/* helper function for emit_ia32_Minus64Bit */
static void emit_xchg(ia32_emit_env_t *env, const ir_node* node, const arch_register_t *src, const arch_register_t *dst)
{
be_emit_cstring(env, "\txchgl ");
ia32_emit_register(env, src);
be_emit_cstring(env, ", ");
ia32_emit_register(env, dst);
be_emit_finish_line_gas(env, node);
}
/* helper function for emit_ia32_Minus64Bit */
static void emit_zero(ia32_emit_env_t *env, const ir_node* node, const arch_register_t *reg)
{
if (env->isa->opt_arch == arch_pentium_4) {
/* P4 prefers sub r, r, others xor r, r */
be_emit_cstring(env, "\tsubl ");
} else {
be_emit_cstring(env, "\txorl ");
}
ia32_emit_register(env, reg);
be_emit_cstring(env, ", ");
ia32_emit_register(env, reg);
be_emit_finish_line_gas(env, node);
}
static void emit_ia32_Minus64Bit(ia32_emit_env_t *env, const ir_node *node)
{
const arch_register_t *in_lo = get_in_reg( env, node, 0);
const arch_register_t *in_hi = get_in_reg( env, node, 1);
const arch_register_t *out_lo = get_out_reg(env, node, 0);
const arch_register_t *out_hi = get_out_reg(env, node, 1);
if (out_lo == in_lo) {
if (out_hi != in_hi) {
/* a -> a, b -> d */
goto zero_neg;
} else {
/* a -> a, b -> b */
goto normal_neg;
}
} else if (out_lo == in_hi) {
if (out_hi == in_lo) {
/* a -> b, b -> a */
emit_xchg(env, node, in_lo, in_hi);
goto normal_neg;
} else {
/* a -> b, b -> d */
emit_mov(env, node, in_hi, out_hi);
emit_mov(env, node, in_lo, out_lo);
goto normal_neg;
}
} else {
if (out_hi == in_lo) {
/* a -> c, b -> a */
emit_mov(env, node, in_lo, out_lo);
goto zero_neg;
} else if (out_hi == in_hi) {
/* a -> c, b -> b */
emit_mov(env, node, in_lo, out_lo);
goto normal_neg;
} else {
/* a -> c, b -> d */
emit_mov(env, node, in_lo, out_lo);
goto zero_neg;
}
}
normal_neg:
emit_neg( env, node, out_hi);
emit_neg( env, node, out_lo);
emit_sbb0(env, node, out_hi);
return;
zero_neg:
emit_zero(env, node, out_hi);
emit_neg( env, node, out_lo);
emit_sbb( env, node, in_hi, out_hi);
}
static static
void emit_be_Return(ia32_emit_env_t *env, const ir_node *node) void emit_be_Return(ia32_emit_env_t *env, const ir_node *node)
{ {
...@@ -1989,6 +2104,7 @@ void ia32_register_emitters(void) { ...@@ -1989,6 +2104,7 @@ void ia32_register_emitters(void) {
IA32_EMIT(Conv_I2I8Bit); IA32_EMIT(Conv_I2I8Bit);
IA32_EMIT(Const); IA32_EMIT(Const);
IA32_EMIT(LdTls); IA32_EMIT(LdTls);
IA32_EMIT(Minus64Bit);
IA32_EMIT(xCmp); IA32_EMIT(xCmp);
IA32_EMIT(xCmpSet); IA32_EMIT(xCmpSet);
IA32_EMIT(xCmpCMov); IA32_EMIT(xCmpCMov);
......
...@@ -477,18 +477,12 @@ static int map_Minus(ir_node *call, void *ctx) { ...@@ -477,18 +477,12 @@ static int map_Minus(ir_node *call, void *ctx) {
ir_node *a_l = params[BINOP_Left_Low]; ir_node *a_l = params[BINOP_Left_Low];
ir_node *a_h = params[BINOP_Left_High]; ir_node *a_h = params[BINOP_Left_High];
ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0)); ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
ir_node *l_res, *h_res, *cnst, *res; ir_node *l_res, *h_res, *res;
(void) ctx; (void) ctx;
assert(l_mode == get_type_mode(get_method_res_type(method, 1)) && "64bit lowered into different modes"); assert(l_mode == get_type_mode(get_method_res_type(method, 1)) && "64bit lowered into different modes");
/* too bad: we need 0 in a register here */ res = new_rd_ia32_Minus64Bit(dbg, irg, block, a_l, a_h);
cnst = new_Const_long(l_mode, 0);
/* l_res = 0 - a_l */
/* h_res = 0 - a_h - carry */
res = new_rd_ia32_Minus64Bit(dbg, irg, block, cnst, a_l, a_h);
l_res = new_r_Proj(irg, block, res, l_mode, pn_ia32_Minus64Bit_low_res); l_res = new_r_Proj(irg, block, res, l_mode, pn_ia32_Minus64Bit_low_res);
h_res = new_r_Proj(irg, block, res, l_mode, pn_ia32_Minus64Bit_high_res); h_res = new_r_Proj(irg, block, res, l_mode, pn_ia32_Minus64Bit_high_res);
......
...@@ -873,13 +873,7 @@ NegMem => { ...@@ -873,13 +873,7 @@ NegMem => {
Minus64Bit => { Minus64Bit => {
irn_flags => "R", irn_flags => "R",
reg_req => { in => [ "gp", "gp", "gp" ], out => [ "!in", "!in" ] }, reg_req => { in => [ "gp", "gp" ], out => [ "in_r1", "gp" ] },
emit => '
. movl %S0, %D0
. movl %S0, %D1
. subl %S1, %D0
. sbbl %S2, %D1
',
outs => [ "low_res", "high_res" ], outs => [ "low_res", "high_res" ],
units => [ "GP" ], units => [ "GP" ],
modified_flags => $status_flags modified_flags => $status_flags
......
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