From: Christian Würdig Date: Wed, 22 Mar 2006 16:32:32 +0000 (+0000) Subject: fixed convs X-Git-Url: http://nsz.repo.hu/git/?a=commitdiff_plain;h=e5f6aa9b7683f5d844875968400e37a3e0eef3cf;p=libfirm fixed convs --- diff --git a/ir/be/ia32/ia32_emitter.c b/ir/be/ia32/ia32_emitter.c index d39137044..5b973f088 100644 --- a/ir/be/ia32/ia32_emitter.c +++ b/ir/be/ia32/ia32_emitter.c @@ -26,6 +26,7 @@ #include "ia32_emitter.h" #include "gen_ia32_emitter.h" +#include "gen_ia32_regalloc_if.h" #include "ia32_nodes_attr.h" #include "ia32_new_nodes.h" #include "ia32_map_regs.h" @@ -251,6 +252,20 @@ const lc_arg_env_t *ia32_get_arg_env(void) { return env; } +static char *ia32_get_reg_name_for_mode(ia32_emit_env_t *env, ir_mode *mode, const arch_register_t *reg) { + switch(get_mode_size_bits(mode)) { + case 8: + return ia32_get_mapped_reg_name(env->isa->regs_8bit, reg); + case 16: + return ia32_get_mapped_reg_name(env->isa->regs_16bit, reg); + case 32: + return (char *)arch_register_get_name(reg); + default: + assert(0 && "unsupported mode size"); + return NULL; + } +} + /** * Emits registers and/or address mode of a binary operation. */ @@ -304,27 +319,11 @@ char *ia32_emit_binop(const ir_node *n, ia32_emit_env_t *env) { } else { const arch_register_t *in1 = get_in_reg(n, 2); - const char *reg_name; - ir_mode *mode = get_ia32_res_mode(n); + ir_mode *mode = get_ia32_res_mode(n); mode = mode ? mode : get_ia32_ls_mode(n); - - switch(get_mode_size_bits(mode)) { - case 8: - reg_name = ia32_get_mapped_reg_name(env->isa->regs_8bit, in1); - break; - case 16: - reg_name = ia32_get_mapped_reg_name(env->isa->regs_16bit, in1); - break; - case 32: - reg_name = arch_register_get_name(in1); - break; - default: - assert(0 && "unsupported mode size"); - break; - } - - lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "%s, %%%s", ia32_emit_am(n, env), reg_name); + lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "%s, %%%s", + ia32_emit_am(n, env), ia32_get_reg_name_for_mode(env, mode, in1)); } break; default: @@ -1007,7 +1006,7 @@ void emit_ia32_CopyB_i(const ir_node *irn, ia32_emit_env_t *emit_env) { /** * Emit code for conversions (I, FP), (FP, I) and (FP, FP). */ -static void emit_ia32_Conv(const ir_node *irn, ia32_emit_env_t *emit_env) { +static void emit_ia32_Conv_with_FP(const ir_node *irn, ia32_emit_env_t *emit_env) { FILE *F = emit_env->out; const lc_arg_env_t *env = ia32_get_arg_env(); char *from, *to, buf[64]; @@ -1037,18 +1036,90 @@ static void emit_ia32_Conv(const ir_node *irn, ia32_emit_env_t *emit_env) { } void emit_ia32_Conv_I2FP(const ir_node *irn, ia32_emit_env_t *emit_env) { - emit_ia32_Conv(irn, emit_env); + emit_ia32_Conv_with_FP(irn, emit_env); } void emit_ia32_Conv_FP2I(const ir_node *irn, ia32_emit_env_t *emit_env) { - emit_ia32_Conv(irn, emit_env); + emit_ia32_Conv_with_FP(irn, emit_env); } void emit_ia32_Conv_FP2FP(const ir_node *irn, ia32_emit_env_t *emit_env) { - emit_ia32_Conv(irn, emit_env); + emit_ia32_Conv_with_FP(irn, emit_env); } +/** + * Emits code for an Int conversion. + */ +void emit_ia32_Conv_I2I(const ir_node *irn, ia32_emit_env_t *emit_env) { + FILE *F = emit_env->out; + const lc_arg_env_t *env = ia32_get_arg_env(); + char *move_cmd, *conv_cmd; + ir_mode *src_mode, *tgt_mode; + int n, m; + char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN]; + const arch_register_t *in_reg, *out_reg; + + src_mode = is_ia32_AddrModeS(irn) ? get_ia32_ls_mode(irn) : get_irn_mode(get_irn_n(irn, 2)); + tgt_mode = get_ia32_res_mode(irn); + + n = get_mode_size_bits(src_mode); + m = get_mode_size_bits(tgt_mode); + if (mode_is_signed(n < m ? src_mode : tgt_mode)) { + move_cmd = "movsx"; + if (n == 8 || m == 8) + conv_cmd = "cbw"; + else if (n == 16 || m == 16) + conv_cmd = "cwde"; + else + assert(0 && "unsupported Conv_I2I"); + } + else { + move_cmd = "movzx"; + conv_cmd = NULL; + } + + switch(get_ia32_op_type(irn)) { + case ia32_Normal: + in_reg = get_in_reg(irn, 2); + out_reg = get_out_reg(irn, 0); + + if (REGS_ARE_EQUAL(in_reg, &ia32_gp_regs[REG_EAX]) && + REGS_ARE_EQUAL(out_reg, in_reg) && + mode_is_signed(n < m ? src_mode : tgt_mode)) + { + /* argument and result are both in EAX and */ + /* signedness is ok: -> use converts */ + lc_esnprintf(env, cmd_buf, SNPRINTF_BUF_LEN, "%s", conv_cmd); + } + else if (REGS_ARE_EQUAL(out_reg, in_reg) && + ! mode_is_signed(n < m ? src_mode : tgt_mode)) + { + /* argument and result are in the same register */ + /* and signedness is ok: -> use and with mask */ + int mask = (1 << (n < m ? n : m)) - 1; + lc_esnprintf(env, cmd_buf, SNPRINTF_BUF_LEN, "and %1D, 0x%x", irn, mask); + } + else { + /* use move w/o sign extension */ + lc_esnprintf(env, cmd_buf, SNPRINTF_BUF_LEN, "%s %1D, %%%s", + move_cmd, irn, ia32_get_reg_name_for_mode(emit_env, n < m ? src_mode : tgt_mode, in_reg)); + } + + break; + case ia32_AddrModeS: + lc_esnprintf(env, cmd_buf, SNPRINTF_BUF_LEN, "%s %1D, %s", + move_cmd, irn, ia32_emit_am(irn, emit_env)); + break; + default: + assert(0 && "unsupported op type for Conv"); + } + + lc_esnprintf(env, cmnt_buf, SNPRINTF_BUF_LEN, "/* %+F(%d Bit mode_%F -> %d Bit mode_%F) */", + irn, n, src_mode, m, tgt_mode); + + IA32_DO_EMIT; +} /******************************************* * _ _ @@ -1173,6 +1244,7 @@ static void ia32_register_emitters(void) { IA32_EMIT(Conv_I2FP); IA32_EMIT(Conv_FP2I); IA32_EMIT(Conv_FP2FP); + IA32_EMIT(Conv_I2I); /* benode emitter */ BE_EMIT(Call); diff --git a/ir/be/ia32/ia32_spec.pl b/ir/be/ia32/ia32_spec.pl index afc7581b7..59ef61566 100644 --- a/ir/be/ia32/ia32_spec.pl +++ b/ir/be/ia32/ia32_spec.pl @@ -156,6 +156,8 @@ $comment_string = "/*"; "cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n", "reg_req" => { "in" => [ "gp", "gp", "gp", "gp", "none" ], "out" => [ "in_r3" ] }, "emit" => '. add %ia32_emit_binop /* Add(%A1, %A2) -> %D1 */' +# "params" => "int a_x, int a_y", +# "init" => " attr.x = x; attr.y = y;" }, "Mul" => { @@ -575,6 +577,12 @@ $comment_string = "/*"; # Conversions +"Conv_I2I" => { + "reg_req" => { "in" => [ "gp", "gp", "gp", "none" ], "out" => [ "gp", "none" ] }, + "cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n", + "comment" => "construct Conv Int -> Int" +}, + "Conv_I2FP" => { "reg_req" => { "in" => [ "gp", "gp", "gp", "none" ], "out" => [ "fp", "none" ] }, "cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n", diff --git a/ir/be/ia32/ia32_transform.c b/ir/be/ia32/ia32_transform.c index 1cec30fd6..f6256a201 100644 --- a/ir/be/ia32/ia32_transform.c +++ b/ir/be/ia32/ia32_transform.c @@ -1380,15 +1380,14 @@ static ir_node *gen_Mux(ia32_transform_env_t *env) { * * INT -> INT * ============ - * 1) n bit -> m bit n < m (upscale) - * always ignored + * 1) n bit -> m bit n > m (downscale) + * a) target is signed: movsx + * b) target is unsigned: and with lower bits sets * 2) n bit -> m bit n == m (sign change) * always ignored - * 3) n bit -> m bit n > m (downscale) - * a) Un -> Um = AND Un, (1 << m) - 1 - * b) Sn -> Um same as a) - * c) Un -> Sm same as a) - * d) Sn -> Sm = ASHL Sn, (n - m); ASHR Sn, (n - m) + * 3) n bit -> m bit n < m (upscale) + * a) source is signed: movsx + * b) source is unsigned: and with lower bits sets * * INT -> FLOAT * ============== @@ -1404,39 +1403,35 @@ static ir_node *gen_Mux(ia32_transform_env_t *env) { * SSE(1/2) convert from float or double to double or float (cvtss/sd2sd/ss) */ -static ir_node *gen_int_downscale_conv(ia32_transform_env_t *env, ir_node *op, - ir_mode *src_mode, ir_mode *tgt_mode) -{ - int n = get_mode_size_bits(src_mode); - int m = get_mode_size_bits(tgt_mode); - dbg_info *dbg = env->dbg; - ir_graph *irg = env->irg; - ir_node *block = env->block; - ir_node *noreg = ia32_new_NoReg_gp(env->cg); - ir_node *nomem = new_rd_NoMem(irg); - ir_node *new_op, *proj; - - assert(n > m && "downscale expected"); - - if (mode_is_signed(src_mode) && mode_is_signed(tgt_mode)) { - /* ASHL Sn, n - m */ - new_op = new_rd_ia32_Shl(dbg, irg, block, noreg, noreg, op, noreg, nomem, mode_T); - proj = new_rd_Proj(dbg, irg, block, new_op, src_mode, 0); - set_ia32_Immop_tarval(new_op, new_tarval_from_long(n - m, mode_Is)); - set_ia32_am_support(new_op, ia32_am_Source); - SET_IA32_ORIG_NODE(new_op, get_old_node_name(env)); - - /* ASHR Sn, n - m */ - new_op = new_rd_ia32_Shrs(dbg, irg, block, noreg, noreg, proj, noreg, nomem, mode_T); - set_ia32_Immop_tarval(new_op, new_tarval_from_long(n - m, mode_Is)); - } - else { - new_op = new_rd_ia32_And(dbg, irg, block, noreg, noreg, op, noreg, nomem, mode_T); - set_ia32_Immop_tarval(new_op, new_tarval_from_long((1 << m) - 1, mode_Is)); - } - - return new_op; -} +//static ir_node *gen_int_downscale_conv(ia32_transform_env_t *env, ir_node *op, +// ir_mode *src_mode, ir_mode *tgt_mode) +//{ +// int n = get_mode_size_bits(src_mode); +// int m = get_mode_size_bits(tgt_mode); +// dbg_info *dbg = env->dbg; +// ir_graph *irg = env->irg; +// ir_node *block = env->block; +// ir_node *noreg = ia32_new_NoReg_gp(env->cg); +// ir_node *nomem = new_rd_NoMem(irg); +// ir_node *new_op, *proj; +// assert(n > m && "downscale expected"); +// if (mode_is_signed(src_mode) && mode_is_signed(tgt_mode)) { +// /* ASHL Sn, n - m */ +// new_op = new_rd_ia32_Shl(dbg, irg, block, noreg, noreg, op, noreg, nomem, mode_T); +// proj = new_rd_Proj(dbg, irg, block, new_op, src_mode, 0); +// set_ia32_Immop_tarval(new_op, new_tarval_from_long(n - m, mode_Is)); +// set_ia32_am_support(new_op, ia32_am_Source); +// SET_IA32_ORIG_NODE(new_op, get_old_node_name(env)); +// /* ASHR Sn, n - m */ +// new_op = new_rd_ia32_Shrs(dbg, irg, block, noreg, noreg, proj, noreg, nomem, mode_T); +// set_ia32_Immop_tarval(new_op, new_tarval_from_long(n - m, mode_Is)); +// } +// else { +// new_op = new_rd_ia32_And(dbg, irg, block, noreg, noreg, op, noreg, nomem, mode_T); +// set_ia32_Immop_tarval(new_op, new_tarval_from_long((1 << m) - 1, mode_Is)); +// } +// return new_op; +//} /** * Transforms a Conv node. @@ -1480,7 +1475,7 @@ static ir_node *gen_Conv(ia32_transform_env_t *env, ir_node *op) { set_ia32_am_support(new_op, ia32_am_Source); proj = new_rd_Proj(dbg, irg, block, new_op, mode_Is, 0); - new_op = gen_int_downscale_conv(env, proj, src_mode, tgt_mode); + new_op = new_rd_ia32_Conv_I2I(dbg, irg, block, noreg, noreg, proj, nomem, mode_T); } } } @@ -1493,13 +1488,13 @@ static ir_node *gen_Conv(ia32_transform_env_t *env, ir_node *op) { } else { /* ... to int */ - if (get_mode_size_bits(src_mode) <= get_mode_size_bits(tgt_mode)) { - DB((mod, LEVEL_1, "omitting upscale Conv(%+F, %+F) ...", src_mode, tgt_mode)); + if (get_mode_size_bits(src_mode) == get_mode_size_bits(tgt_mode)) { + DB((mod, LEVEL_1, "omitting equal size Conv(%+F, %+F) ...", src_mode, tgt_mode)); edges_reroute(env->irn, op, irg); } else { - DB((mod, LEVEL_1, "create downscale Conv(%+F, %+F) ...", src_mode, tgt_mode)); - new_op = gen_int_downscale_conv(env, op, src_mode, tgt_mode); + DB((mod, LEVEL_1, "create Conv(int, int) ...", src_mode, tgt_mode)); + new_op = new_rd_ia32_Conv_I2I(dbg, irg, block, noreg, noreg, op, nomem, mode_T); } } }