ia32: improve Test peephole optimisation
authorMatthias Braun <matze@braunis.de>
Fri, 4 Nov 2011 17:26:02 +0000 (18:26 +0100)
committerMatthias Braun <matze@braunis.de>
Fri, 4 Nov 2011 17:28:13 +0000 (18:28 +0100)
A test can exactly be removed if we are only interested in the sign and
zero flag. Rewrote and refactored code.
Now we don't miss some cases anymore where only sign was requested.

ir/be/ia32/ia32_optimize.c

index 700479b..fd7afe2 100644 (file)
@@ -69,17 +69,19 @@ static void copy_mark(const ir_node *old, ir_node *newn)
 
 typedef enum produces_flag_t {
        produces_no_flag,
-       produces_flag_zero,
-       produces_flag_carry
+       produces_zero_sign,
+       produces_zero_in_carry
 } produces_flag_t;
 
 /**
- * Return which usable flag the given node produces
+ * Return which usable flag the given node produces about the result.
+ * That is zero (ZF) and sign(SF).
+ * We do not check for carry (CF) or overflow (OF).
  *
  * @param node  the node to check
  * @param pn    the projection number of the used result
  */
-static produces_flag_t produces_test_flag(ir_node *node, int pn)
+static produces_flag_t check_produces_zero_sign(ir_node *node, int pn)
 {
        ir_node                     *count;
        const ia32_immediate_attr_t *imm_attr;
@@ -127,14 +129,13 @@ check_shift_amount:
 
                case iro_ia32_Mul:
                        return pn == pn_ia32_Mul_res_high ?
-                               produces_flag_carry : produces_no_flag;
+                               produces_zero_in_carry : produces_no_flag;
 
                default:
                        return produces_no_flag;
        }
 
-       return pn == pn_ia32_res ?
-               produces_flag_zero : produces_no_flag;
+       return pn == pn_ia32_res ? produces_zero_sign : produces_no_flag;
 }
 
 /**
@@ -223,6 +224,7 @@ static void peephole_ia32_Test(ir_node *node)
                ir_mode         *op_mode;
                ir_node         *schedpoint;
                const ir_edge_t *edge;
+               produces_flag_t  produced;
 
                if (get_nodes_block(left) != block)
                        return;
@@ -245,36 +247,22 @@ static void peephole_ia32_Test(ir_node *node)
                                panic("couldn't find left");
                }
 
-               /* make sure only Lg/Eq tests are used */
+               produced = check_produces_zero_sign(op, pn);
+               if (produced == produces_no_flag)
+                       return;
+
+               /* make sure users only look at the sign/zero flag */
                foreach_out_edge(node, edge) {
                        ir_node              *user = get_edge_src_irn(edge);
                        ia32_condition_code_t cc  = get_ia32_condcode(user);
 
-                       if (cc != ia32_cc_equal && cc != ia32_cc_not_equal) {
-                               return;
+                       if (cc == ia32_cc_equal || cc == ia32_cc_not_equal)
+                               continue;
+                       if (produced == produces_zero_sign
+                               && (cc == ia32_cc_sign || cc == ia32_cc_not_sign)) {
+                               continue;
                        }
-               }
-
-               switch (produces_test_flag(op, pn)) {
-                       case produces_flag_zero:
-                               break;
-
-                       case produces_flag_carry:
-                               foreach_out_edge(node, edge) {
-                                       ir_node              *user = get_edge_src_irn(edge);
-                                       ia32_condition_code_t cc   = get_ia32_condcode(user);
-
-                                       switch (cc) {
-                                       case ia32_cc_equal:     cc = ia32_cc_above_equal; break; /* CF = 0 */
-                                       case ia32_cc_not_equal: cc = ia32_cc_below;       break; /* CF = 1 */
-                                       default: panic("unexpected pn");
-                                       }
-                                       set_ia32_condcode(user, cc);
-                               }
-                               break;
-
-                       default:
-                               return;
+                       return;
                }
 
                op_mode = get_ia32_ls_mode(op);
@@ -285,6 +273,21 @@ static void peephole_ia32_Test(ir_node *node)
                if (get_mode_size_bits(op_mode) != get_mode_size_bits(get_ia32_ls_mode(node)))
                        return;
 
+               if (produced == produces_zero_in_carry) {
+                       /* patch users to look at the carry instead of the zero flag */
+                       foreach_out_edge(node, edge) {
+                               ir_node              *user = get_edge_src_irn(edge);
+                               ia32_condition_code_t cc   = get_ia32_condcode(user);
+
+                               switch (cc) {
+                               case ia32_cc_equal:     cc = ia32_cc_above_equal; break;
+                               case ia32_cc_not_equal: cc = ia32_cc_below;       break;
+                               default: panic("unexpected pn");
+                               }
+                               set_ia32_condcode(user, cc);
+                       }
+               }
+
                if (get_irn_mode(op) != mode_T) {
                        set_irn_mode(op, mode_T);