From da230f5e2ba4806c03f611a3585154b316610bb4 Mon Sep 17 00:00:00 2001 From: Christoph Mallon Date: Mon, 10 Sep 2007 12:02:53 +0000 Subject: [PATCH] Add magic for better code emission of 64bit minus. [r15730] --- ir/be/ia32/ia32_emitter.c | 116 +++++++++++++++++++++++++++++++++++ ir/be/ia32/ia32_intrinsics.c | 10 +-- ir/be/ia32/ia32_spec.pl | 8 +-- 3 files changed, 119 insertions(+), 15 deletions(-) diff --git a/ir/be/ia32/ia32_emitter.c b/ir/be/ia32/ia32_emitter.c index 8b5c66b6a..d9675b0d7 100644 --- a/ir/be/ia32/ia32_emitter.c +++ b/ir/be/ia32/ia32_emitter.c @@ -1920,6 +1920,121 @@ void emit_ia32_LdTls(ia32_emit_env_t *env, const ir_node *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 void emit_be_Return(ia32_emit_env_t *env, const ir_node *node) { @@ -1989,6 +2104,7 @@ void ia32_register_emitters(void) { IA32_EMIT(Conv_I2I8Bit); IA32_EMIT(Const); IA32_EMIT(LdTls); + IA32_EMIT(Minus64Bit); IA32_EMIT(xCmp); IA32_EMIT(xCmpSet); IA32_EMIT(xCmpCMov); diff --git a/ir/be/ia32/ia32_intrinsics.c b/ir/be/ia32/ia32_intrinsics.c index 18a355236..7c0fc48eb 100644 --- a/ir/be/ia32/ia32_intrinsics.c +++ b/ir/be/ia32/ia32_intrinsics.c @@ -477,18 +477,12 @@ static int map_Minus(ir_node *call, void *ctx) { ir_node *a_l = params[BINOP_Left_Low]; ir_node *a_h = params[BINOP_Left_High]; 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; 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 */ - 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); + res = new_rd_ia32_Minus64Bit(dbg, irg, block, a_l, a_h); 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); diff --git a/ir/be/ia32/ia32_spec.pl b/ir/be/ia32/ia32_spec.pl index 86d69c241..e33debbfa 100644 --- a/ir/be/ia32/ia32_spec.pl +++ b/ir/be/ia32/ia32_spec.pl @@ -873,13 +873,7 @@ NegMem => { Minus64Bit => { irn_flags => "R", - reg_req => { in => [ "gp", "gp", "gp" ], out => [ "!in", "!in" ] }, - emit => ' -. movl %S0, %D0 -. movl %S0, %D1 -. subl %S1, %D0 -. sbbl %S2, %D1 -', + reg_req => { in => [ "gp", "gp" ], out => [ "in_r1", "gp" ] }, outs => [ "low_res", "high_res" ], units => [ "GP" ], modified_flags => $status_flags -- 2.20.1