sparc: implement float->unsigned conversions
[libfirm] / ir / be / ia32 / ia32_optimize.c
index 29a5f5f..c46bdc8 100644 (file)
@@ -21,7 +21,6 @@
  * @file
  * @brief       Implements several optimizations for IA32.
  * @author      Matthias Braun, Christian Wuerdig
- * @version     $Id$
  */
 #include "config.h"
 
 #include "irgmod.h"
 #include "irgwalk.h"
 #include "heights.h"
-#include "irbitset.h"
 #include "irprintf.h"
 #include "irdump.h"
 #include "error.h"
 
-#include "../be_t.h"
-#include "../beabi.h"
-#include "../benode.h"
-#include "../besched.h"
-#include "../bepeephole.h"
+#include "be_t.h"
+#include "beabi.h"
+#include "benode.h"
+#include "besched.h"
+#include "bepeephole.h"
 
 #include "ia32_new_nodes.h"
 #include "ia32_optimize.h"
@@ -69,17 +67,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 +127,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 +222,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 +245,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 +271,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);
 
@@ -849,7 +850,7 @@ static const arch_register_t *get_free_gp_reg(ir_graph *irg)
                if (!rbitset_is_set(birg->allocatable_regs, reg->global_index))
                        continue;
 
-               if (be_peephole_get_value(CLASS_ia32_gp, i) == NULL)
+               if (be_peephole_get_value(reg->global_index) == NULL)
                        return reg;
        }
 
@@ -976,7 +977,7 @@ static void peephole_ia32_Const(ir_node *node)
        if (ia32_cg_config.use_mov_0)
                return;
        /* xor destroys the flags, so no-one must be using them */
-       if (be_peephole_get_value(CLASS_ia32_flags, REG_FLAGS_EFLAGS) != NULL)
+       if (be_peephole_get_value(REG_EFLAGS) != NULL)
                return;
 
        reg = arch_get_irn_register(node);
@@ -1066,7 +1067,7 @@ static void peephole_ia32_Lea(ir_node *node)
        assert(is_ia32_Lea(node));
 
        /* we can only do this if it is allowed to clobber the flags */
-       if (be_peephole_get_value(CLASS_ia32_flags, REG_FLAGS_EFLAGS) != NULL)
+       if (be_peephole_get_value(REG_EFLAGS) != NULL)
                return;
 
        base  = get_irn_n(node, n_ia32_Lea_base);
@@ -1272,23 +1273,30 @@ static void register_peephole_optimisation(ir_op *op, peephole_opt_func func)
 /* Perform peephole-optimizations. */
 void ia32_peephole_optimization(ir_graph *irg)
 {
-       /* register peephole optimisations */
-       clear_irp_opcodes_generic_func();
-       register_peephole_optimisation(op_ia32_Const,    peephole_ia32_Const);
-       register_peephole_optimisation(op_be_IncSP,      peephole_be_IncSP);
-       register_peephole_optimisation(op_ia32_Lea,      peephole_ia32_Lea);
+       /* we currently do it in 2 passes because:
+        *    Lea -> Add could be usefull as flag producer for Test later
+        */
+
+       /* pass 1 */
+       ir_clear_opcodes_generic_func();
        register_peephole_optimisation(op_ia32_Cmp,      peephole_ia32_Cmp);
        register_peephole_optimisation(op_ia32_Cmp8Bit,  peephole_ia32_Cmp);
-       register_peephole_optimisation(op_ia32_Test,     peephole_ia32_Test);
-       register_peephole_optimisation(op_ia32_Test8Bit, peephole_ia32_Test);
-       register_peephole_optimisation(op_be_Return,     peephole_ia32_Return);
-       if (! ia32_cg_config.use_imul_mem_imm32)
-               register_peephole_optimisation(op_ia32_IMul, peephole_ia32_Imul_split);
-       if (ia32_cg_config.use_pxor)
-               register_peephole_optimisation(op_ia32_xZero, peephole_ia32_xZero);
+       register_peephole_optimisation(op_ia32_Lea,      peephole_ia32_Lea);
        if (ia32_cg_config.use_short_sex_eax)
                register_peephole_optimisation(op_ia32_Conv_I2I, peephole_ia32_Conv_I2I);
+       if (ia32_cg_config.use_pxor)
+               register_peephole_optimisation(op_ia32_xZero, peephole_ia32_xZero);
+       if (! ia32_cg_config.use_imul_mem_imm32)
+               register_peephole_optimisation(op_ia32_IMul, peephole_ia32_Imul_split);
+       be_peephole_opt(irg);
 
+       /* pass 2 */
+       ir_clear_opcodes_generic_func();
+       register_peephole_optimisation(op_ia32_Const,    peephole_ia32_Const);
+       register_peephole_optimisation(op_be_IncSP,      peephole_be_IncSP);
+       register_peephole_optimisation(op_ia32_Test,     peephole_ia32_Test);
+       register_peephole_optimisation(op_ia32_Test8Bit, peephole_ia32_Test);
+       register_peephole_optimisation(op_be_Return,     peephole_ia32_Return);
        be_peephole_opt(irg);
 }