fix Mulh, Div, IDiv handling
authorMatthias Braun <matze@braunis.de>
Tue, 27 Feb 2007 11:10:57 +0000 (11:10 +0000)
committerMatthias Braun <matze@braunis.de>
Tue, 27 Feb 2007 11:10:57 +0000 (11:10 +0000)
ir/be/ia32/ia32_emitter.c
ir/be/ia32/ia32_spec.pl
ir/be/ia32/ia32_transform.c

index 2e2f348..c5ec338 100644 (file)
@@ -343,7 +343,7 @@ void ia32_emit_x87_name(ia32_emit_env_t *env, const ir_node *node, int pos)
 {
        ia32_attr_t *attr = get_ia32_attr(node);
 
-       assert(pos < 7);
+       assert(pos < 3);
        ia32_emit_char(env, '%');
        ia32_emit_string(env, attr->x87[pos]->name);
 }
@@ -515,11 +515,10 @@ void ia32_emit_unop(ia32_emit_env_t *env, const ir_node *node) {
                                ia32_emit_char(env, '$');
                                ia32_emit_immediate(env, node);
                        } else {
-                               if (is_ia32_IMul(node) || is_ia32_Mulh(node)) {
-                                       /* MulS and Mulh implicitly multiply by EAX */
+                               if (is_ia32_Mul(node) || is_ia32_IMul1OP(node)) {
                                        ia32_emit_source_register(env, node, 3);
-                               } else if(is_ia32_IDiv(node)) {
-                                       ia32_emit_source_register(env, node, 1);
+                               } else if(is_ia32_IDiv(node) || is_ia32_Div(node)) {
+                                       ia32_emit_source_register(env, node, 4);
                                } else if(is_ia32_Push(node)) {
                                        ia32_emit_source_register(env, node, 2);
                                } else if(is_ia32_Pop(node)) {
index 409b1d4..116c9b3 100644 (file)
@@ -114,7 +114,7 @@ $arch = "ia32";
                { "name" => "ebp", "type" => 2 },
                { "name" => "esp", "type" => 4 },
                { "name" => "gp_NOREG", "type" => 4 | 8 | 16 }, # we need a dummy register for NoReg nodes
-               { "name" => "gp_UKNWN", "type" => 4 | 8 | 16},  # we need a dummy register for Unknown nodes
+               { "name" => "gp_UKNWN", "type" => 4 | 8 | 16 },  # we need a dummy register for Unknown nodes
                { "mode" => "mode_Iu" }
        ],
        "xmm" => [
@@ -127,7 +127,7 @@ $arch = "ia32";
                { "name" => "xmm6", "type" => 1 },
                { "name" => "xmm7", "type" => 1 },
                { "name" => "xmm_NOREG", "type" => 4 | 8 | 16 }, # we need a dummy register for NoReg nodes
-               { "name" => "xmm_UKNWN", "type" => 4 | 8 | 16},  # we need a dummy register for Unknown nodes
+               { "name" => "xmm_UKNWN", "type" => 4 | 8 | 16 },  # we need a dummy register for Unknown nodes
                { "mode" => "mode_E" }
        ],
        "vfp" => [
@@ -140,7 +140,7 @@ $arch = "ia32";
                { "name" => "vf6", "type" => 1 | 16 },
                { "name" => "vf7", "type" => 1 | 16 },
                { "name" => "vfp_NOREG", "type" => 4 | 8 | 16 }, # we need a dummy register for NoReg nodes
-               { "name" => "vfp_UKNWN", "type" => 4 | 8 | 16},  # we need a dummy register for Unknown nodes
+               { "name" => "vfp_UKNWN", "type" => 4 | 8 | 16 },  # we need a dummy register for Unknown nodes
                { "mode" => "mode_E" }
        ],
        "st" => [
@@ -323,6 +323,16 @@ $default_cmp_attr = "return ia32_compare_attr(attr_a, attr_b);";
   "mode"      => "mode_Iu",
 },
 
+"IMul1OP" => {
+  "irn_flags" => "R",
+  "comment"   => "construct Mul (1 operand format): Mul(a, b) = Mul(b, a) = a * b",
+  "reg_req"   => { "in" => [ "gp", "gp", "eax", "gp", "none" ], "out" => [ "eax", "edx", "none" ] },
+  "emit"      => '. imull %unop',
+  "outs"      => [ "EAX", "EDX", "M" ],
+  "latency"   => 5,
+  "units"     => [ "GP" ],
+},
+
 "l_IMul" => {
   "op_flags"  => "C",
   "cmp_attr"  => "return 1;",
@@ -330,20 +340,6 @@ $default_cmp_attr = "return ia32_compare_attr(attr_a, attr_b);";
   "arity"     => 2
 },
 
-# Mulh is an exception from the 4 INs with AM because the target is always EAX:EDX
-# Matze: It's not clear to me why we have a separate Mulh node and not just use
-# the IMul node...
-"Mulh" => {
-  # we should not rematrialize this node. It produces 2 results and has
-  # very strict constrains
-  "comment"   => "construct Mul: Mul(a, b) = Mul(b, a) = a * b",
-  "reg_req"   => { "in" => [ "gp", "gp", "eax", "gp", "none" ], "out" => [ "eax", "edx" ] },
-  "emit"      => '. imull %unop',
-  "outs"      => [ "EAX", "EDX", "M" ],
-  "latency"   => 5,
-  "units"     => [ "GP" ],
-},
-
 "And" => {
   "irn_flags" => "R",
   "comment"   => "construct And: And(a, b) = And(b, a) = a AND b",
@@ -428,7 +424,7 @@ $default_cmp_attr = "return ia32_compare_attr(attr_a, attr_b);";
 "IDiv" => {
   "op_flags"  => "F|L",
   "state"     => "exc_pinned",
-  "reg_req"   => { "in" => [ "eax", "gp", "edx", "none" ], "out" => [ "eax", "edx", "none" ] },
+  "reg_req"   => { "in" => [ "gp", "gp", "eax", "edx", "gp", "none" ], "out" => [ "eax", "edx", "none" ] },
   "attr"      => "ia32_op_flavour_t dm_flav",
   "init_attr" => "attr->data.op_flav = dm_flav;",
   "emit"      => ". idivl %unop",
@@ -440,7 +436,7 @@ $default_cmp_attr = "return ia32_compare_attr(attr_a, attr_b);";
 "Div" => {
   "op_flags"  => "F|L",
   "state"     => "exc_pinned",
-  "reg_req"   => { "in" => [ "eax", "gp", "edx", "none" ], "out" => [ "eax", "edx", "none" ] },
+  "reg_req"   => { "in" => [ "gp", "gp", "eax", "edx", "gp", "none" ], "out" => [ "eax", "edx", "none" ] },
   "attr"      => "ia32_op_flavour_t dm_flav",
   "init_attr" => "attr->data.op_flav = dm_flav;",
   "emit"      => ". divl %unop",
@@ -1125,7 +1121,7 @@ if (get_ia32_immop_type(node) == ia32_ImmNone) {
   "state"    => "exc_pinned",
   "comment"  => "store ST0 onto stack",
   "reg_req"  => { "in" => [ "gp", "gp", "none" ] },
-  "emit"     => '. fstp%M %AM',
+  "emit"     => '. fstp%XM %AM',
   "latency"  => 4,
   "units"    => [ "SSE" ],
   "mode"     => "mode_M",
@@ -1726,7 +1722,7 @@ if (get_ia32_immop_type(node) == ia32_ImmNone) {
   "state"     => "exc_pinned",
   "comment"   => "x87 fp Load: Load(ptr, mem) = LD ptr -> reg",
   "reg_req"   => { },
-  "emit"      => '. fld%M %AM',
+  "emit"      => '. fld%XM %AM',
 },
 
 "fst" => {
@@ -1735,7 +1731,7 @@ if (get_ia32_immop_type(node) == ia32_ImmNone) {
   "state"     => "exc_pinned",
   "comment"   => "x87 fp Store: Store(ptr, val, mem) = ST ptr,val",
   "reg_req"   => { },
-  "emit"      => '. fst%M %AM',
+  "emit"      => '. fst%XM %AM',
   "mode"      => "mode_M",
 },
 
@@ -1745,7 +1741,7 @@ if (get_ia32_immop_type(node) == ia32_ImmNone) {
   "state"     => "exc_pinned",
   "comment"   => "x87 fp Store: Store(ptr, val, mem) = ST ptr,val",
   "reg_req"   => { },
-  "emit"      => '. fstp%M %AM',
+  "emit"      => '. fstp%XM %AM',
   "mode"      => "mode_M",
 },
 
@@ -1756,7 +1752,7 @@ if (get_ia32_immop_type(node) == ia32_ImmNone) {
   "rd_constructor" => "NONE",
   "comment"   => "x87 fp integer Load: Load(ptr, mem) = iLD ptr -> reg",
   "reg_req"   => { },
-  "emit"      => '. fild%M %AM',
+  "emit"      => '. fild%XM %AM',
 },
 
 "fist" => {
index 008168e..434d6dd 100644 (file)
@@ -521,7 +521,7 @@ static ir_node *gen_binop(ia32_transform_env_t *env, ir_node *node,
        ir_node  *new_op2  = transform_node(env, op2);
 
        new_node = func(dbg, irg, block, noreg_gp, noreg_gp, new_op1, new_op2, nomem);
-       if(func == new_rd_ia32_Mul) {
+       if(func == new_rd_ia32_IMul) {
                set_ia32_am_support(new_node, ia32_am_Source);
        } else {
                set_ia32_am_support(new_node, ia32_am_Full);
@@ -884,18 +884,24 @@ static ir_node *gen_Mulh(ia32_transform_env_t *env, ir_node *node) {
        ir_node *new_op1 = transform_node(env, op1);
        ir_node *new_op2 = transform_node(env, op2);
        ir_node   *noreg = ia32_new_NoReg_gp(env->cg);
-       ir_node *proj_EAX, *proj_EDX, *mulh;
+       ir_node *proj_EAX, *proj_EDX, *res;
        ir_mode *mode = get_irn_mode(node);
        ir_node *in[1];
 
        assert(!mode_is_float(mode) && "Mulh with float not supported");
-       mulh = new_rd_ia32_Mulh(dbg, irg, block, noreg, noreg, new_op1, new_op2, new_NoMem());
-       set_ia32_commutative(mulh);
-       set_ia32_am_support(mulh, ia32_am_Source);
+       if(mode_is_signed(mode)) {
+               res = new_rd_ia32_IMul1OP(dbg, irg, block, noreg, noreg, new_op1, new_op2, new_NoMem());
+       } else {
+               res = new_rd_ia32_Mul(dbg, irg, block, noreg, noreg, new_op1, new_op2, new_NoMem());
+       }
 
-       /* imediates are not supported, so no fold_immediate */
-       proj_EAX = new_rd_Proj(dbg, irg, block, mulh, mode_Iu, pn_EAX);
-       proj_EDX = new_rd_Proj(dbg, irg, block, mulh, mode_Iu, pn_EDX);
+       set_ia32_commutative(res);
+       set_ia32_am_support(res, ia32_am_Source);
+
+       set_ia32_am_support(res, ia32_am_Source);
+
+       proj_EAX = new_rd_Proj(dbg, irg, block, res, mode_Iu, pn_EAX);
+       proj_EDX = new_rd_Proj(dbg, irg, block, res, mode_Iu, pn_EDX);
 
        /* keep EAX */
        in[0] = proj_EAX;
@@ -1196,6 +1202,7 @@ static ir_node *generate_DivMod(ia32_transform_env_t *env, ir_node *node,
        ir_node  *in_keep[1];
        ir_node  *mem, *new_mem;
        ir_node  *projs[pn_DivMod_max];
+       ir_node  *noreg = ia32_new_NoReg_gp(env->cg);
        ir_node *new_dividend = transform_node(env, dividend);
        ir_node *new_divisor = transform_node(env, divisor);
 
@@ -1233,10 +1240,17 @@ static ir_node *generate_DivMod(ia32_transform_env_t *env, ir_node *node,
        }
 
        if(mode_is_signed(mode)) {
-               res = new_rd_ia32_IDiv(dbg, irg, block, new_dividend, new_divisor, edx_node, new_mem, dm_flav);
+               res = new_rd_ia32_IDiv(dbg, irg, block, noreg, noreg, new_dividend, edx_node, new_divisor, new_mem, dm_flav);
        } else {
-               res = new_rd_ia32_Div(dbg, irg, block, new_dividend, new_divisor, edx_node, new_mem, dm_flav);
+               res = new_rd_ia32_Div(dbg, irg, block, noreg, noreg, new_dividend, edx_node, new_divisor, new_mem, dm_flav);
        }
+
+       /* Matze: code can't handle this at the moment... */
+#if 0
+       /* set AM support */
+       set_ia32_am_support(res, ia32_am_Source);
+#endif
+
        set_ia32_n_res(res, 2);
 
        /* Only one proj is used -> We must add a second proj and */
@@ -3387,7 +3401,7 @@ static ir_node *gen_Proj_be_AddSP(ia32_transform_env_t *env, ir_node *node) {
        dbg_info *dbg = get_irn_dbg_info(node);
        ir_node *pred = get_Proj_pred(node);
        ir_node *new_pred = transform_node(env, pred);
-       int proj      = get_Proj_proj(node);
+       long proj = get_Proj_proj(node);
 
        if(proj == pn_be_AddSP_res) {
                ir_node *res = new_rd_Proj(dbg, irg, block, new_pred, mode_Iu, pn_ia32_AddSP_stack);
@@ -3407,7 +3421,7 @@ static ir_node *gen_Proj_be_SubSP(ia32_transform_env_t *env, ir_node *node) {
        dbg_info *dbg = get_irn_dbg_info(node);
        ir_node *pred = get_Proj_pred(node);
        ir_node *new_pred = transform_node(env, pred);
-       int proj      = get_Proj_proj(node);
+       long proj = get_Proj_proj(node);
 
        if(proj == pn_be_SubSP_res) {
                ir_node *res = new_rd_Proj(dbg, irg, block, new_pred, mode_Iu, pn_ia32_AddSP_stack);
@@ -3427,7 +3441,7 @@ static ir_node *gen_Proj_Load(ia32_transform_env_t *env, ir_node *node) {
        dbg_info *dbg = get_irn_dbg_info(node);
        ir_node *pred = get_Proj_pred(node);
        ir_node *new_pred = transform_node(env, pred);
-       int proj      = get_Proj_proj(node);
+       long proj = get_Proj_proj(node);
 
        /* renumber the proj */
        if(is_ia32_Load(new_pred)) {
@@ -3462,7 +3476,7 @@ static ir_node *gen_Proj_DivMod(ia32_transform_env_t *env, ir_node *node) {
 
        ir_node *pred = get_Proj_pred(node);
        ir_node *new_pred = transform_node(env, pred);
-       int proj = get_Proj_proj(node);
+       long proj = get_Proj_proj(node);
 
        assert(is_ia32_Div(new_pred) || is_ia32_IDiv(new_pred));
 
@@ -3516,7 +3530,7 @@ static ir_node *gen_Proj_CopyB(ia32_transform_env_t *env, ir_node *node)
 
        ir_node *pred = get_Proj_pred(node);
        ir_node *new_pred = transform_node(env, pred);
-       int proj = get_Proj_proj(node);
+       long proj = get_Proj_proj(node);
 
        switch(proj) {
        case pn_CopyB_M_regular:
@@ -3545,7 +3559,7 @@ static ir_node *gen_Proj_l_vfdiv(ia32_transform_env_t *env, ir_node *node)
 
        ir_node *pred = get_Proj_pred(node);
        ir_node *new_pred = transform_node(env, pred);
-       int proj = get_Proj_proj(node);
+       long proj = get_Proj_proj(node);
 
        switch(proj) {
        case pn_ia32_l_vfdiv_M:
@@ -3568,7 +3582,7 @@ static ir_node *gen_Proj_Quot(ia32_transform_env_t *env, ir_node *node)
 
        ir_node *pred = get_Proj_pred(node);
        ir_node *new_pred = transform_node(env, pred);
-       int proj = get_Proj_proj(node);
+       long proj = get_Proj_proj(node);
 
        switch(proj) {
        case pn_Quot_M:
@@ -3607,11 +3621,30 @@ static ir_node *gen_Proj_tls(ia32_transform_env_t *env, ir_node *node) {
        return res;
 }
 
+static ir_node *gen_Proj_be_Call(ia32_transform_env_t *env, ir_node *node) {
+       ir_graph *irg = env->irg;
+       dbg_info *dbg = get_irn_dbg_info(node);
+       ir_node *pred = get_Proj_pred(node);
+       long proj = get_Proj_proj(node);
+       ir_mode *mode = get_irn_mode(node);
+       ir_node *block = transform_node(env, get_nodes_block(node));
+       ir_node *new_pred = transform_node(env, pred);
+
+       /* transform call modes to the mode_Iu or mode_E */
+       if(mode_is_float(mode)) {
+               mode = mode_E;
+       } else if(mode != mode_M) {
+               mode = mode_Iu;
+       }
+
+       return new_rd_Proj(dbg, irg, block, new_pred, mode, proj);
+}
+
 static ir_node *gen_Proj(ia32_transform_env_t *env, ir_node *node) {
        ir_graph *irg = env->irg;
        dbg_info *dbg = get_irn_dbg_info(node);
        ir_node *pred = get_Proj_pred(node);
-       int proj = get_Proj_proj(node);
+       long proj = get_Proj_proj(node);
 
        if(is_Store(pred) || be_is_FrameStore(pred)) {
                if(proj == pn_Store_M) {
@@ -3634,6 +3667,8 @@ static ir_node *gen_Proj(ia32_transform_env_t *env, ir_node *node) {
                return gen_Proj_be_SubSP(env, node);
        } else if(be_is_AddSP(pred)) {
                return gen_Proj_be_AddSP(env, node);
+       } else if(be_is_Call(pred)) {
+               return gen_Proj_be_Call(env, node);
        } else if(get_irn_op(pred) == op_Start) {
                if(proj == pn_Start_X_initial_exec) {
                        ir_node *block = get_nodes_block(pred);