]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/cse.c
Merge from trunk.
[thirdparty/gcc.git] / gcc / cse.c
index ff91b9d93f54d8f8de178240221645428931a37c..15e582cd223a581c70c9bb0e20e695ee44af95a2 100644 (file)
--- a/gcc/cse.c
+++ b/gcc/cse.c
@@ -1,7 +1,5 @@
 /* Common subexpression elimination for GNU compiler.
-   Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998
-   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
-   2011 Free Software Foundation, Inc.
+   Copyright (C) 1987-2013 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -470,7 +468,7 @@ struct table_elt
    a cost of 2.  Aside from these special cases, call `rtx_cost'.  */
 
 #define CHEAP_REGNO(N)                                                 \
-  (REGNO_PTR_FRAME_P(N)                                                        \
+  (REGNO_PTR_FRAME_P (N)                                               \
    || (HARD_REGISTER_NUM_P (N)                                         \
        && FIXED_REGNO_P (N) && REGNO_REG_CLASS (N) != NO_REGS))
 
@@ -1356,6 +1354,11 @@ try_const_anchors (rtx src_const, enum machine_mode mode)
   rtx lower_exp = NULL_RTX, upper_exp = NULL_RTX;
   unsigned lower_old, upper_old;
 
+  /* CONST_INT is used for CC modes, but we should leave those alone.  */
+  if (GET_MODE_CLASS (mode) == MODE_CC)
+    return NULL_RTX;
+
+  gcc_assert (SCALAR_INT_MODE_P (mode));
   if (!compute_const_anchors (src_const, &lower_base, &lower_offs,
                              &upper_base, &upper_offs))
     return NULL_RTX;
@@ -1826,7 +1829,7 @@ flush_hash_table (void)
       }
 }
 \f
-/* Function called for each rtx to check whether true dependence exist.  */
+/* Function called for each rtx to check whether an anti dependence exist.  */
 struct check_dependence_data
 {
   enum machine_mode mode;
@@ -1839,7 +1842,7 @@ check_dependence (rtx *x, void *data)
 {
   struct check_dependence_data *d = (struct check_dependence_data *) data;
   if (*x && MEM_P (*x))
-    return canon_true_dependence (d->exp, d->mode, d->addr, *x, NULL_RTX);
+    return canon_anti_dependence (*x, true, d->exp, d->mode, d->addr);
   else
     return 0;
 }
@@ -2333,15 +2336,23 @@ hash_rtx_cb (const_rtx x, enum machine_mode mode,
                + (unsigned int) INTVAL (x));
       return hash;
 
+    case CONST_WIDE_INT:
+      {
+       int i;
+       for (i = 0; i < CONST_WIDE_INT_NUNITS (x); i++)
+         hash += CONST_WIDE_INT_ELT (x, i);
+      }
+      return hash;
+
     case CONST_DOUBLE:
       /* This is like the general case, except that it only counts
         the integers representing the constant.  */
       hash += (unsigned int) code + (unsigned int) GET_MODE (x);
-      if (GET_MODE (x) != VOIDmode)
-       hash += real_hash (CONST_DOUBLE_REAL_VALUE (x));
-      else
+      if (TARGET_SUPPORTS_WIDE_INT == 0 && GET_MODE (x) == VOIDmode)
        hash += ((unsigned int) CONST_DOUBLE_LOW (x)
                 + (unsigned int) CONST_DOUBLE_HIGH (x));
+      else
+       hash += real_hash (CONST_DOUBLE_REAL_VALUE (x));
       return hash;
 
     case CONST_FIXED:
@@ -3285,8 +3296,8 @@ fold_rtx (rtx x, rtx insn)
          break;
 
        new_rtx = simplify_unary_operation (code, mode,
-                                       const_arg0 ? const_arg0 : folded_arg0,
-                                       mode_arg0);
+                                           const_arg0 ? const_arg0 : folded_arg0,
+                                           mode_arg0);
       }
       break;
 
@@ -3758,6 +3769,7 @@ equiv_constant (rtx x)
 
       /* See if we previously assigned a constant value to this SUBREG.  */
       if ((new_rtx = lookup_as_function (x, CONST_INT)) != 0
+         || (new_rtx = lookup_as_function (x, CONST_WIDE_INT)) != 0
           || (new_rtx = lookup_as_function (x, CONST_DOUBLE)) != 0
           || (new_rtx = lookup_as_function (x, CONST_FIXED)) != 0)
         return new_rtx;
@@ -4836,7 +4848,7 @@ cse_insn (rtx insn)
 
          /* Set what we are trying to extend and the operation it might
             have been extended with.  */
-         memset (memory_extend_rtx, 0, sizeof(*memory_extend_rtx));
+         memset (memory_extend_rtx, 0, sizeof (*memory_extend_rtx));
          PUT_CODE (memory_extend_rtx, LOAD_EXTEND_OP (mode));
          XEXP (memory_extend_rtx, 0) = src;
 
@@ -5313,33 +5325,33 @@ cse_insn (rtx insn)
        }
 
       /* If this is a single SET, we are setting a register, and we have an
-        equivalent constant, we want to add a REG_NOTE.   We don't want
-        to write a REG_EQUAL note for a constant pseudo since verifying that
-        that pseudo hasn't been eliminated is a pain.  Such a note also
-        won't help anything.
+        equivalent constant, we want to add a REG_EQUAL note if the constant
+        is different from the source.  We don't want to do it for a constant
+        pseudo since verifying that this pseudo hasn't been eliminated is a
+        pain; moreover such a note won't help anything.
 
         Avoid a REG_EQUAL note for (CONST (MINUS (LABEL_REF) (LABEL_REF)))
         which can be created for a reference to a compile time computable
         entry in a jump table.  */
-
-      if (n_sets == 1 && src_const && REG_P (dest)
+      if (n_sets == 1
+         && REG_P (dest)
+         && src_const
          && !REG_P (src_const)
-         && ! (GET_CODE (src_const) == CONST
-               && GET_CODE (XEXP (src_const, 0)) == MINUS
-               && GET_CODE (XEXP (XEXP (src_const, 0), 0)) == LABEL_REF
-               && GET_CODE (XEXP (XEXP (src_const, 0), 1)) == LABEL_REF))
+         && !(GET_CODE (src_const) == SUBREG
+              && REG_P (SUBREG_REG (src_const)))
+         && !(GET_CODE (src_const) == CONST
+              && GET_CODE (XEXP (src_const, 0)) == MINUS
+              && GET_CODE (XEXP (XEXP (src_const, 0), 0)) == LABEL_REF
+              && GET_CODE (XEXP (XEXP (src_const, 0), 1)) == LABEL_REF)
+         && !rtx_equal_p (src, src_const))
        {
-         /* We only want a REG_EQUAL note if src_const != src.  */
-         if (! rtx_equal_p (src, src_const))
-           {
-             /* Make sure that the rtx is not shared.  */
-             src_const = copy_rtx (src_const);
+         /* Make sure that the rtx is not shared.  */
+         src_const = copy_rtx (src_const);
 
-             /* Record the actual constant value in a REG_EQUAL note,
-                making a new one if one does not already exist.  */
-             set_unique_reg_note (insn, REG_EQUAL, src_const);
-             df_notes_rescan (insn);
-           }
+         /* Record the actual constant value in a REG_EQUAL note,
+            making a new one if one does not already exist.  */
+         set_unique_reg_note (insn, REG_EQUAL, src_const);
+         df_notes_rescan (insn);
        }
 
       /* Now deal with the destination.  */
@@ -5383,7 +5395,7 @@ cse_insn (rtx insn)
              && CONST_INT_P (width)
              && INTVAL (width) < HOST_BITS_PER_WIDE_INT
              && ! (INTVAL (src_const)
-                   & ((HOST_WIDE_INT) (-1) << INTVAL (width))))
+                   & (HOST_WIDE_INT_M1U << INTVAL (width))))
            /* Exception: if the value is constant,
               and it won't be truncated, record it.  */
            ;
@@ -6065,9 +6077,12 @@ cse_process_notes_1 (rtx x, rtx object, bool *changed)
       return x;
 
     case EXPR_LIST:
-    case INSN_LIST:
       if (REG_NOTE_KIND (x) == REG_EQUAL)
        XEXP (x, 0) = cse_process_notes (XEXP (x, 0), NULL_RTX, changed);
+      /* Fall through.  */
+
+    case INSN_LIST:
+    case INT_LIST:
       if (XEXP (x, 1))
        XEXP (x, 1) = cse_process_notes (XEXP (x, 1), NULL_RTX, changed);
       return x;
@@ -6194,7 +6209,7 @@ cse_find_path (basic_block first_bb, struct cse_basic_block_data *data,
              && e == BRANCH_EDGE (previous_bb_in_path))
            {
              bb = FALLTHRU_EDGE (previous_bb_in_path)->dest;
-             if (bb != EXIT_BLOCK_PTR
+             if (bb != EXIT_BLOCK_PTR_FOR_FN (cfun)
                  && single_pred_p (bb)
                  /* We used to assert here that we would only see blocks
                     that we have not visited yet.  But we may end up
@@ -6248,7 +6263,7 @@ cse_find_path (basic_block first_bb, struct cse_basic_block_data *data,
 
          if (e
              && !((e->flags & EDGE_ABNORMAL_CALL) && cfun->has_nonlocal_label)
-             && e->dest != EXIT_BLOCK_PTR
+             && e->dest != EXIT_BLOCK_PTR_FOR_FN (cfun)
              && single_pred_p (e->dest)
              /* Avoid visiting basic blocks twice.  The large comment
                 above explains why this can happen.  */
@@ -6520,6 +6535,7 @@ cse_main (rtx f ATTRIBUTE_UNUSED, int nregs)
   int i, n_blocks;
 
   df_set_flags (DF_LR_RUN_DCE);
+  df_note_add_problem ();
   df_analyze ();
   df_set_flags (DF_DEFER_INSN_RESCAN);
 
@@ -6732,6 +6748,7 @@ count_reg_usage (rtx x, int *counts, rtx dest, int incr)
       return;
 
     case INSN_LIST:
+    case INT_LIST:
       gcc_unreachable ();
 
     default:
@@ -7158,7 +7175,7 @@ cse_cc_succs (basic_block bb, basic_block orig_bb, rtx cc_reg, rtx cc_src,
        continue;
 
       if (EDGE_COUNT (e->dest->preds) != 1
-         || e->dest == EXIT_BLOCK_PTR
+         || e->dest == EXIT_BLOCK_PTR_FOR_FN (cfun)
          /* Avoid endless recursion on unreachable blocks.  */
          || e->dest == orig_bb)
        continue;
@@ -7450,28 +7467,45 @@ rest_of_handle_cse (void)
   return 0;
 }
 
-struct rtl_opt_pass pass_cse =
+namespace {
+
+const pass_data pass_data_cse =
 {
- {
-  RTL_PASS,
-  "cse1",                               /* name */
-  OPTGROUP_NONE,                        /* optinfo_flags */
-  gate_handle_cse,                      /* gate */
-  rest_of_handle_cse,                  /* execute */
-  NULL,                                 /* sub */
-  NULL,                                 /* next */
-  0,                                    /* static_pass_number */
-  TV_CSE,                               /* tv_id */
-  0,                                    /* properties_required */
-  0,                                    /* properties_provided */
-  0,                                    /* properties_destroyed */
-  0,                                    /* todo_flags_start */
-  TODO_df_finish | TODO_verify_rtl_sharing |
-  TODO_ggc_collect |
-  TODO_verify_flow,                     /* todo_flags_finish */
- }
+  RTL_PASS, /* type */
+  "cse1", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  true, /* has_gate */
+  true, /* has_execute */
+  TV_CSE, /* tv_id */
+  0, /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  ( TODO_df_finish | TODO_verify_rtl_sharing
+    | TODO_verify_flow ), /* todo_flags_finish */
 };
 
+class pass_cse : public rtl_opt_pass
+{
+public:
+  pass_cse (gcc::context *ctxt)
+    : rtl_opt_pass (pass_data_cse, ctxt)
+  {}
+
+  /* opt_pass methods: */
+  bool gate () { return gate_handle_cse (); }
+  unsigned int execute () { return rest_of_handle_cse (); }
+
+}; // class pass_cse
+
+} // anon namespace
+
+rtl_opt_pass *
+make_pass_cse (gcc::context *ctxt)
+{
+  return new pass_cse (ctxt);
+}
+
 
 static bool
 gate_handle_cse2 (void)
@@ -7513,28 +7547,45 @@ rest_of_handle_cse2 (void)
 }
 
 
-struct rtl_opt_pass pass_cse2 =
+namespace {
+
+const pass_data pass_data_cse2 =
 {
- {
-  RTL_PASS,
-  "cse2",                               /* name */
-  OPTGROUP_NONE,                        /* optinfo_flags */
-  gate_handle_cse2,                     /* gate */
-  rest_of_handle_cse2,                 /* execute */
-  NULL,                                 /* sub */
-  NULL,                                 /* next */
-  0,                                    /* static_pass_number */
-  TV_CSE2,                              /* tv_id */
-  0,                                    /* properties_required */
-  0,                                    /* properties_provided */
-  0,                                    /* properties_destroyed */
-  0,                                    /* todo_flags_start */
-  TODO_df_finish | TODO_verify_rtl_sharing |
-  TODO_ggc_collect |
-  TODO_verify_flow                      /* todo_flags_finish */
- }
+  RTL_PASS, /* type */
+  "cse2", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  true, /* has_gate */
+  true, /* has_execute */
+  TV_CSE2, /* tv_id */
+  0, /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  ( TODO_df_finish | TODO_verify_rtl_sharing
+    | TODO_verify_flow ), /* todo_flags_finish */
 };
 
+class pass_cse2 : public rtl_opt_pass
+{
+public:
+  pass_cse2 (gcc::context *ctxt)
+    : rtl_opt_pass (pass_data_cse2, ctxt)
+  {}
+
+  /* opt_pass methods: */
+  bool gate () { return gate_handle_cse2 (); }
+  unsigned int execute () { return rest_of_handle_cse2 (); }
+
+}; // class pass_cse2
+
+} // anon namespace
+
+rtl_opt_pass *
+make_pass_cse2 (gcc::context *ctxt)
+{
+  return new pass_cse2 (ctxt);
+}
+
 static bool
 gate_handle_cse_after_global_opts (void)
 {
@@ -7574,24 +7625,43 @@ rest_of_handle_cse_after_global_opts (void)
   return 0;
 }
 
-struct rtl_opt_pass pass_cse_after_global_opts =
+namespace {
+
+const pass_data pass_data_cse_after_global_opts =
 {
- {
-  RTL_PASS,
-  "cse_local",                          /* name */
-  OPTGROUP_NONE,                        /* optinfo_flags */
-  gate_handle_cse_after_global_opts,    /* gate */
-  rest_of_handle_cse_after_global_opts, /* execute */
-  NULL,                                 /* sub */
-  NULL,                                 /* next */
-  0,                                    /* static_pass_number */
-  TV_CSE,                               /* tv_id */
-  0,                                    /* properties_required */
-  0,                                    /* properties_provided */
-  0,                                    /* properties_destroyed */
-  0,                                    /* todo_flags_start */
-  TODO_df_finish | TODO_verify_rtl_sharing |
-  TODO_ggc_collect |
-  TODO_verify_flow                      /* todo_flags_finish */
- }
+  RTL_PASS, /* type */
+  "cse_local", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  true, /* has_gate */
+  true, /* has_execute */
+  TV_CSE, /* tv_id */
+  0, /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  ( TODO_df_finish | TODO_verify_rtl_sharing
+    | TODO_verify_flow ), /* todo_flags_finish */
 };
+
+class pass_cse_after_global_opts : public rtl_opt_pass
+{
+public:
+  pass_cse_after_global_opts (gcc::context *ctxt)
+    : rtl_opt_pass (pass_data_cse_after_global_opts, ctxt)
+  {}
+
+  /* opt_pass methods: */
+  bool gate () { return gate_handle_cse_after_global_opts (); }
+  unsigned int execute () {
+    return rest_of_handle_cse_after_global_opts ();
+  }
+
+}; // class pass_cse_after_global_opts
+
+} // anon namespace
+
+rtl_opt_pass *
+make_pass_cse_after_global_opts (gcc::context *ctxt)
+{
+  return new pass_cse_after_global_opts (ctxt);
+}