fixed convs
authorChristian Würdig <chriswue@ipd.info.uni-karlsruhe.de>
Wed, 22 Mar 2006 16:32:32 +0000 (16:32 +0000)
committerChristian Würdig <chriswue@ipd.info.uni-karlsruhe.de>
Wed, 22 Mar 2006 16:32:32 +0000 (16:32 +0000)
ir/be/ia32/ia32_emitter.c
ir/be/ia32/ia32_spec.pl
ir/be/ia32/ia32_transform.c

index d391370..5b973f0 100644 (file)
@@ -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);
index afc7581..59ef615 100644 (file)
@@ -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",
index 1cec30f..f6256a2 100644 (file)
@@ -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);
                        }
                }
        }