simplify and speedup belady/loopana a bit
[libfirm] / ir / be / ia32 / ia32_transform.c
index fd042ea..2396a3b 100644 (file)
@@ -29,6 +29,7 @@
 #endif
 
 #include <limits.h>
+#include <stdbool.h>
 
 #include "irargs_t.h"
 #include "irnode_t.h"
@@ -47,6 +48,7 @@
 #include "irdom.h"
 #include "archop.h"
 #include "error.h"
+#include "array_t.h"
 #include "height.h"
 
 #include "../benode_t.h"
@@ -131,46 +133,46 @@ static ir_node *create_I2I_Conv(ir_mode *src_mode, ir_mode *tgt_mode,
                                 ir_node *op, ir_node *orig_node);
 
 /** Return non-zero is a node represents the 0 constant. */
-static int is_Const_0(ir_node *node) {
+static bool is_Const_0(ir_node *node) {
        return is_Const(node) && is_Const_null(node);
 }
 
 /** Return non-zero is a node represents the 1 constant. */
-static int is_Const_1(ir_node *node) {
+static bool is_Const_1(ir_node *node) {
        return is_Const(node) && is_Const_one(node);
 }
 
 /** Return non-zero is a node represents the -1 constant. */
-static int is_Const_Minus_1(ir_node *node) {
+static bool is_Const_Minus_1(ir_node *node) {
        return is_Const(node) && is_Const_all_one(node);
 }
 
 /**
  * returns true if constant can be created with a simple float command
  */
-static int is_simple_x87_Const(ir_node *node)
+static bool is_simple_x87_Const(ir_node *node)
 {
        tarval *tv = get_Const_tarval(node);
        if (tarval_is_null(tv) || tarval_is_one(tv))
-               return 1;
+               return true;
 
        /* TODO: match all the other float constants */
-       return 0;
+       return false;
 }
 
 /**
  * returns true if constant can be created with a simple float command
  */
-static int is_simple_sse_Const(ir_node *node)
+static bool is_simple_sse_Const(ir_node *node)
 {
        tarval  *tv   = get_Const_tarval(node);
        ir_mode *mode = get_tarval_mode(tv);
 
        if (mode == mode_F)
-               return 1;
+               return true;
 
        if (tarval_is_null(tv) || tarval_is_one(tv))
-               return 1;
+               return true;
 
        if (mode == mode_D) {
                unsigned val = get_tarval_sub_bits(tv, 0) |
@@ -179,11 +181,11 @@ static int is_simple_sse_Const(ir_node *node)
                        (get_tarval_sub_bits(tv, 3) << 24);
                if (val == 0)
                        /* lower 32bit are zero, really a 32bit constant */
-                       return 1;
+                       return true;
        }
 
        /* TODO: match all the other float constants */
-       return 0;
+       return false;
 }
 
 /**
@@ -800,6 +802,12 @@ static void match_arguments(ia32_address_mode_t *am, ir_node *block,
        am->commutative = commutative;
 }
 
+static void set_transformed_and_mark(ir_node *const old_node, ir_node *const new_node)
+{
+       mark_irn_visited(old_node);
+       be_set_transformed_node(old_node, new_node);
+}
+
 static ir_node *fix_mem_proj(ir_node *node, ia32_address_mode_t *am)
 {
        ir_mode  *mode;
@@ -812,8 +820,7 @@ static ir_node *fix_mem_proj(ir_node *node, ia32_address_mode_t *am)
        mode = get_irn_mode(node);
        load = get_Proj_pred(am->mem_proj);
 
-       mark_irn_visited(load);
-       be_set_transformed_node(load, node);
+       set_transformed_and_mark(load, node);
 
        if (mode != mode_T) {
                set_irn_mode(node, mode_T);
@@ -2023,12 +2030,6 @@ static int use_dest_am(ir_node *block, ir_node *node, ir_node *mem,
        return 1;
 }
 
-static void set_transformed_and_mark(ir_node *const old_node, ir_node *const new_node)
-{
-       mark_irn_visited(old_node);
-       be_set_transformed_node(old_node, new_node);
-}
-
 static ir_node *dest_am_binop(ir_node *node, ir_node *op1, ir_node *op2,
                               ir_node *mem, ir_node *ptr, ir_mode *mode,
                               construct_binop_dest_func *func,
@@ -2710,7 +2711,7 @@ static ir_node *create_Ucomi(ir_node *node)
  * helper function: checks whether all Cmp projs are Lg or Eq which is needed
  * to fold an and into a test node
  */
-static int can_fold_test_and(ir_node *node)
+static bool can_fold_test_and(ir_node *node)
 {
        const ir_edge_t *edge;
 
@@ -2719,10 +2720,77 @@ static int can_fold_test_and(ir_node *node)
                ir_node *proj = get_edge_src_irn(edge);
                pn_Cmp   pnc  = get_Proj_proj(proj);
                if(pnc != pn_Cmp_Eq && pnc != pn_Cmp_Lg)
-                       return 0;
+                       return false;
        }
 
-       return 1;
+       return true;
+}
+
+/**
+ * returns true if it is assured, that the upper bits of a node are "clean"
+ * which means for a 16 or 8 bit value, that the upper bits in the register
+ * are 0 for unsigned and a copy of the last significant bit for unsigned
+ * numbers.
+ */
+static bool upper_bits_clean(ir_node *transformed_node, ir_mode *mode)
+{
+       assert(ia32_mode_needs_gp_reg(mode));
+       if (get_mode_size_bits(mode) >= 32)
+               return true;
+
+       if (is_ia32_Conv_I2I(transformed_node)
+                       || is_ia32_Conv_I2I8Bit(transformed_node)) {
+               ir_mode *smaller_mode = get_ia32_ls_mode(transformed_node);
+               if (mode_is_signed(smaller_mode) != mode_is_signed(mode))
+                       return false;
+               if (get_mode_size_bits(smaller_mode) > get_mode_size_bits(mode))
+                       return false;
+
+               return true;
+       }
+
+       if (is_ia32_Shr(transformed_node) && !mode_is_signed(mode)) {
+               ir_node *right = get_irn_n(transformed_node, n_ia32_Shr_count);
+               if (is_ia32_Immediate(right) || is_ia32_Const(right)) {
+                       const ia32_immediate_attr_t *attr
+                               = get_ia32_immediate_attr_const(right);
+                       if (attr->symconst == 0
+                                       && (unsigned) attr->offset >= (32 - get_mode_size_bits(mode))) {
+                               return true;
+                       }
+               }
+       }
+
+       if (is_ia32_And(transformed_node) && !mode_is_signed(mode)) {
+               ir_node *right = get_irn_n(transformed_node, n_ia32_And_right);
+               if (is_ia32_Immediate(right) || is_ia32_Const(right)) {
+                       const ia32_immediate_attr_t *attr
+                               = get_ia32_immediate_attr_const(right);
+                       if (attr->symconst == 0
+                                       && (unsigned) attr->offset
+                                       <= (0xffffffff >> (32 - get_mode_size_bits(mode)))) {
+                               return true;
+                       }
+               }
+       }
+
+       if (is_ia32_Immediate(transformed_node)
+                       || is_ia32_Const(transformed_node)) {
+               const ia32_immediate_attr_t *attr
+                       = get_ia32_immediate_attr_const(transformed_node);
+               if (mode_is_signed(mode)) {
+                       long shifted = attr->offset >> (get_mode_size_bits(mode) - 1);
+                       if (shifted == 0 || shifted == -1)
+                               return true;
+               } else {
+                       unsigned long shifted = (unsigned long) attr->offset;
+                       shifted >>= get_mode_size_bits(mode);
+                       if (shifted == 0)
+                               return true;
+               }
+       }
+
+       return false;
 }
 
 /**
@@ -2761,22 +2829,35 @@ static ir_node *gen_Cmp(ir_node *node)
                /* Test(and_left, and_right) */
                ir_node *and_left  = get_And_left(left);
                ir_node *and_right = get_And_right(left);
-               ir_mode *mode      = get_irn_mode(and_left);
+
+               /* matze: code here used mode instead of cmd_mode, I think it is always
+                * the same as cmp_mode, but I leave this here to see if this is really
+                * true...
+                */
+               assert(get_irn_mode(and_left) == cmp_mode);
 
                match_arguments(&am, block, and_left, and_right, NULL,
                                                                                match_commutative |
                                                                                match_am | match_8bit_am | match_16bit_am |
                                                                                match_am_and_immediates | match_immediate |
                                                                                match_8bit | match_16bit);
-               if (get_mode_size_bits(mode) == 8) {
+
+               /* use 32bit compare mode if possible since the opcode is smaller */
+               if (upper_bits_clean(am.new_op1, cmp_mode)
+                               && upper_bits_clean(am.new_op2, cmp_mode)) {
+                       cmp_mode = mode_is_signed(cmp_mode) ? mode_Is : mode_Iu;
+               }
+
+               if (get_mode_size_bits(cmp_mode) == 8) {
                        new_node = new_rd_ia32_Test8Bit(dbgi, irg, new_block, addr->base,
-                                                                                                                                                       addr->index, addr->mem, am.new_op1,
-                                                                                                                                                       am.new_op2, am.ins_permuted,
-                                                                                                                                                       cmp_unsigned);
+                                                       addr->index, addr->mem, am.new_op1,
+                                                       am.new_op2, am.ins_permuted,
+                                                       cmp_unsigned);
                } else {
                        new_node = new_rd_ia32_Test(dbgi, irg, new_block, addr->base,
-                                                                                                                                       addr->index, addr->mem, am.new_op1,
-                                                                                                                                       am.new_op2, am.ins_permuted, cmp_unsigned);
+                                                   addr->index, addr->mem, am.new_op1,
+                                                   am.new_op2, am.ins_permuted,
+                                                                               cmp_unsigned);
                }
        } else {
                /* Cmp(left, right) */
@@ -2784,6 +2865,12 @@ static ir_node *gen_Cmp(ir_node *node)
                                match_commutative | match_am | match_8bit_am |
                                match_16bit_am | match_am_and_immediates |
                                match_immediate | match_8bit | match_16bit);
+               /* use 32bit compare mode if possible since the opcode is smaller */
+               if (upper_bits_clean(am.new_op1, cmp_mode)
+                               && upper_bits_clean(am.new_op2, cmp_mode)) {
+                       cmp_mode = mode_is_signed(cmp_mode) ? mode_Is : mode_Iu;
+               }
+
                if (get_mode_size_bits(cmp_mode) == 8) {
                        new_node = new_rd_ia32_Cmp8Bit(dbgi, irg, new_block, addr->base,
                                                       addr->index, addr->mem, am.new_op1,
@@ -3224,6 +3311,17 @@ static ir_node *create_I2I_Conv(ir_mode *src_mode, ir_mode *tgt_mode,
        match_arguments(&am, block, NULL, op, NULL,
                        match_8bit | match_16bit |
                        match_am | match_8bit_am | match_16bit_am);
+
+       if (upper_bits_clean(am.new_op2, smaller_mode)) {
+               /* unnecessary conv. in theory it shouldn't have been AM */
+               assert(is_ia32_NoReg_GP(addr->base));
+               assert(is_ia32_NoReg_GP(addr->index));
+               assert(is_NoMem(addr->mem));
+               assert(am.addr.offset == 0);
+               assert(am.addr.symconst_ent == NULL);
+               return am.new_op2;
+       }
+
        if (smaller_bits == 8) {
                new_node = new_rd_ia32_Conv_I2I8Bit(dbgi, irg, new_block, addr->base,
                                                    addr->index, addr->mem, am.new_op2,
@@ -3497,8 +3595,7 @@ static ir_node *gen_be_Return(ir_node *node) {
                                  arity, in);
        copy_node_attr(barrier, new_barrier);
        be_duplicate_deps(barrier, new_barrier);
-       be_set_transformed_node(barrier, new_barrier);
-       mark_irn_visited(barrier);
+       set_transformed_and_mark(barrier, new_barrier);
 
        /* transform normally */
        return be_duplicate_node(node);
@@ -3512,7 +3609,8 @@ static ir_node *gen_be_AddSP(ir_node *node)
        ir_node  *sz = get_irn_n(node, be_pos_AddSP_size);
        ir_node  *sp = get_irn_n(node, be_pos_AddSP_old_sp);
 
-       return gen_binop(node, sp, sz, new_rd_ia32_SubSP, match_am);
+       return gen_binop(node, sp, sz, new_rd_ia32_SubSP,
+                        match_am | match_immediate);
 }
 
 /**
@@ -3523,7 +3621,8 @@ static ir_node *gen_be_SubSP(ir_node *node)
        ir_node  *sz = get_irn_n(node, be_pos_SubSP_size);
        ir_node  *sp = get_irn_n(node, be_pos_SubSP_old_sp);
 
-       return gen_binop(node, sp, sz, new_rd_ia32_AddSP, match_am);
+       return gen_binop(node, sp, sz, new_rd_ia32_AddSP,
+                        match_am | match_immediate);
 }
 
 /**
@@ -3920,8 +4019,7 @@ static ir_node *gen_Proj_be_AddSP(ir_node *node) {
                return new_rd_Proj(dbgi, irg, block, new_pred, mode_M, pn_ia32_SubSP_M);
        }
 
-       assert(0);
-       return new_rd_Unknown(irg, get_irn_mode(node));
+       panic("No idea how to transform proj->AddSP");
 }
 
 /**
@@ -3944,8 +4042,7 @@ static ir_node *gen_Proj_be_SubSP(ir_node *node) {
                return new_rd_Proj(dbgi, irg, block, new_pred, mode_M, pn_ia32_AddSP_M);
        }
 
-       assert(0);
-       return new_rd_Unknown(irg, get_irn_mode(node));
+       panic("No idea how to transform proj->SubSP");
 }
 
 /**
@@ -4043,8 +4140,7 @@ static ir_node *gen_Proj_Load(ir_node *node) {
                return new_rd_Proj(dbgi, irg, block, new_pred, mode_M, 1);
        }
 
-       assert(0);
-       return new_rd_Unknown(irg, get_irn_mode(node));
+       panic("No idea how to transform proj");
 }
 
 /**
@@ -4056,7 +4152,6 @@ static ir_node *gen_Proj_DivMod(ir_node *node) {
        ir_node  *new_pred = be_transform_node(pred);
        ir_graph *irg      = current_ir_graph;
        dbg_info *dbgi     = get_irn_dbg_info(node);
-       ir_mode  *mode     = get_irn_mode(node);
        long     proj      = get_Proj_proj(node);
 
        assert(is_ia32_Div(new_pred) || is_ia32_IDiv(new_pred));
@@ -4111,8 +4206,7 @@ static ir_node *gen_Proj_DivMod(ir_node *node) {
                break;
        }
 
-       assert(0);
-       return new_rd_Unknown(irg, mode);
+       panic("No idea how to transform proj->DivMod");
 }
 
 /**
@@ -4124,7 +4218,6 @@ static ir_node *gen_Proj_CopyB(ir_node *node) {
        ir_node  *new_pred = be_transform_node(pred);
        ir_graph *irg      = current_ir_graph;
        dbg_info *dbgi     = get_irn_dbg_info(node);
-       ir_mode  *mode     = get_irn_mode(node);
        long     proj      = get_Proj_proj(node);
 
        switch(proj) {
@@ -4139,8 +4232,7 @@ static ir_node *gen_Proj_CopyB(ir_node *node) {
                break;
        }
 
-       assert(0);
-       return new_rd_Unknown(irg, mode);
+       panic("No idea how to transform proj->CopyB");
 }
 
 /**
@@ -4152,7 +4244,6 @@ static ir_node *gen_Proj_Quot(ir_node *node) {
        ir_node  *new_pred = be_transform_node(pred);
        ir_graph *irg      = current_ir_graph;
        dbg_info *dbgi     = get_irn_dbg_info(node);
-       ir_mode  *mode     = get_irn_mode(node);
        long     proj      = get_Proj_proj(node);
 
        switch(proj) {
@@ -4176,8 +4267,7 @@ static ir_node *gen_Proj_Quot(ir_node *node) {
                break;
        }
 
-       assert(0);
-       return new_rd_Unknown(irg, mode);
+       panic("No idea how to transform proj->Quot");
 }
 
 static ir_node *gen_be_Call(ir_node *node) {
@@ -4357,8 +4447,7 @@ static ir_node *gen_Proj(ir_node *node) {
                if (proj == pn_Store_M) {
                        return be_transform_node(pred);
                } else {
-                       assert(0);
-                       return new_r_Bad(current_ir_graph);
+                       panic("No idea how to transform proj->Store");
                }
        case iro_Load:
                return gen_Proj_Load(node);