- If-conversion can generate SSE min and max nodes again.
authorMichael Beck <beck@ipd.info.uni-karlsruhe.de>
Tue, 20 May 2008 14:22:57 +0000 (14:22 +0000)
committerMichael Beck <beck@ipd.info.uni-karlsruhe.de>
Tue, 20 May 2008 14:22:57 +0000 (14:22 +0000)
- preliminary support for If-conversion without Cmov

[r19689]

ir/be/ia32/bearch_ia32.c
ir/be/ia32/ia32_transform.c

index ab6b3eb..2f7a488 100644 (file)
@@ -2066,37 +2066,88 @@ static ir_graph **ia32_get_irg_list(const void *self, ir_graph ***irg_list)
  */
 static int ia32_is_psi_allowed(ir_node *sel, ir_node *phi_list, int i, int j)
 {
-       ir_node *phi;
+       ir_node *phi, *left;
+       ir_node *cmp = NULL;
+       ir_mode *cmp_mode;
+
+       if (ia32_cg_config.use_cmov) {
+               /* we can't handle psis with 64bit compares yet */
+               if (is_Proj(sel)) {
+                       cmp = get_Proj_pred(sel);
+                       if (is_Cmp(cmp)) {
+                               left     = get_Cmp_left(cmp);
+                               cmp_mode = get_irn_mode(left);
+                               if (!mode_is_float(cmp_mode) && get_mode_size_bits(cmp_mode) > 32)
+                                       return 0;
+                       } else {
+                               cmp = NULL;
+                       }
+               }
 
-       (void)sel;
-       (void)i;
-       (void)j;
+               if (ia32_cg_config.use_sse2 && cmp != NULL) {
+                       /* check the Phi nodes: no 64bit and no floating point cmov */
+                       for (phi = phi_list; phi; phi = get_irn_link(phi)) {
+                               ir_mode *mode = get_irn_mode(phi);
+
+                               if (mode_is_float(mode)) {
+                                       /* check for Min, Max */
+                                       ir_node *t  = get_Phi_pred(phi, i);
+                                       ir_node *f  = get_Phi_pred(phi, j);
+                                       pn_Cmp pn   = get_Proj_proj(sel);
+                                       ir_node *cl = get_Cmp_left(cmp);
+                                       ir_node *cr = get_Cmp_right(cmp);
+                                       int res     = 0;
+
+                                       /* SSE2 supports Min & Max */
+                                       if (pn == pn_Cmp_Lt || pn == pn_Cmp_Le || pn == pn_Cmp_Ge || pn == pn_Cmp_Gt) {
+                                               if (cl == t && cr == f) {
+                                                       /* Psi(a <=/>= b, a, b) => MIN, MAX */
+                                                       res = 1;
+                                               } else if (cl == f && cr == t) {
+                                                       /* Psi(a <=/>= b, b, a) => MAX, MIN */
+                                                       res = 1;
+                                               }
+                                       }
+                                       if (! res)
+                                               return 0;
+
+                               } else if (get_mode_size_bits(mode) > 32)
+                                       return 0;
+                       }
+               } else {
+                       /* check the Phi nodes: no 64bit and no floating point cmov */
+                       for (phi = phi_list; phi; phi = get_irn_link(phi)) {
+                               ir_mode *mode = get_irn_mode(phi);
 
-       if(!ia32_cg_config.use_cmov) {
-               /* TODO: we could still handle abs(x)... */
-               return 0;
-       }
+                               if (mode_is_float(mode) || get_mode_size_bits(mode) > 32)
+                                       return 0;
+                       }
+               }
 
-       /* we can't handle psis with 64bit compares yet */
-       if(is_Proj(sel)) {
-               ir_node *pred = get_Proj_pred(sel);
-               if(is_Cmp(pred)) {
-                       ir_node *left     = get_Cmp_left(pred);
-                       ir_mode *cmp_mode = get_irn_mode(left);
-                       if(!mode_is_float(cmp_mode) && get_mode_size_bits(cmp_mode) > 32)
+               return 1;
+       } else {
+               /* No cmov, only some special cases */
+               if (! is_Proj(sel))
+                       return 0;
+               cmp = get_Proj_pred(sel);
+               if (! is_Cmp(cmp))
+                       return 0;
+
+               left     = get_Cmp_left(cmp);
+               cmp_mode = get_irn_mode(left);
+
+               /* no floating point and no 64bit yet */
+               for (phi = phi_list; phi; phi = get_irn_link(phi)) {
+                       ir_mode *mode = get_irn_mode(phi);
+
+                       if (mode_is_float(mode) || get_mode_size_bits(mode) > 32)
                                return 0;
                }
-       }
-
-       /* check the Phi nodes */
-       for (phi = phi_list; phi; phi = get_irn_link(phi)) {
-               ir_mode *mode = get_irn_mode(phi);
+               /* Add checks for some supported cases here */
 
-               if (mode_is_float(mode) || get_mode_size_bits(mode) > 32)
-                       return 0;
+               return 0;
        }
-
-       return 1;
+       return 0;
 }
 
 /**
index e3b16f6..e9d62b5 100644 (file)
@@ -2993,22 +2993,57 @@ static ir_node *gen_Psi(ir_node *node)
        ir_node  *psi_true    = get_Psi_val(node, 0);
        ir_node  *psi_default = get_Psi_default(node);
        ir_node  *cond        = get_Psi_cond(node, 0);
+       ir_mode  *mode        = get_irn_mode(node);
        ir_node  *flags       = NULL;
        ir_node  *new_node;
        pn_Cmp    pnc;
 
        assert(get_Psi_n_conds(node) == 1);
        assert(get_irn_mode(cond) == mode_b);
-       assert(mode_needs_gp_reg(get_irn_mode(node)));
 
-       flags = get_flags_node(cond, &pnc);
+       if (mode_is_float(mode)) {
+               ir_node *cmp       = get_Proj_pred(cond);
+               ir_node *cmp_left  = get_Cmp_left(cmp);
+               ir_node *cmp_right = get_Cmp_right(cmp);
+               pn_Cmp  pnc        = get_Proj_proj(cond);
+
+               if (ia32_cg_config.use_sse2) {
+                       if (pnc == pn_Cmp_Lt || pnc == pn_Cmp_Le) {
+                               if (cmp_left == psi_true && cmp_right == psi_default) {
+                                       /* psi(a <= b, a, b) => MIN */
+                                       return gen_binop(node, cmp_left, cmp_right, new_rd_ia32_xMin,
+                                        match_commutative | match_am);
+                               } else if (cmp_left == psi_default && cmp_right == psi_true) {
+                                       /* psi(a <= b, b, a) => MAX */
+                                       return gen_binop(node, cmp_left, cmp_right, new_rd_ia32_xMax,
+                                        match_commutative | match_am);
+                               }
+                       } else if (pnc == pn_Cmp_Gt || pnc == pn_Cmp_Ge) {
+                               if (cmp_left == psi_true && cmp_right == psi_default) {
+                                       /* psi(a >= b, a, b) => MAX */
+                                       return gen_binop(node, cmp_left, cmp_right, new_rd_ia32_xMax,
+                                        match_commutative | match_am);
+                               } else if (cmp_left == psi_default && cmp_right == psi_true) {
+                                       /* psi(a >= b, b, a) => MIN */
+                                       return gen_binop(node, cmp_left, cmp_right, new_rd_ia32_xMin,
+                                        match_commutative | match_am);
+                               }
+                       }
+               }
+               panic("cannot transform floating point Psi");
 
-       if(is_Const_1(psi_true) && is_Const_0(psi_default)) {
-               new_node = create_set_32bit(dbgi, new_block, flags, pnc, node, 0);
-       } else if(is_Const_0(psi_true) && is_Const_1(psi_default)) {
-               new_node = create_set_32bit(dbgi, new_block, flags, pnc, node, 1);
        } else {
-               new_node = create_CMov(node, cond, flags, pnc);
+               assert(mode_needs_gp_reg(mode));
+
+               flags = get_flags_node(cond, &pnc);
+
+               if (is_Const_1(psi_true) && is_Const_0(psi_default)) {
+                       new_node = create_set_32bit(dbgi, new_block, flags, pnc, node, 0);
+               } else if(is_Const_0(psi_true) && is_Const_1(psi_default)) {
+                       new_node = create_set_32bit(dbgi, new_block, flags, pnc, node, 1);
+               } else {
+                       new_node = create_CMov(node, cond, flags, pnc);
+               }
        }
        return new_node;
 }