]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/tree-predcom.c
Merge from trunk.
[thirdparty/gcc.git] / gcc / tree-predcom.c
index b1dce08e017e77fe442044be9d5556b6df832587..55dd7c324750c4742f14515841b369a185028e51 100644 (file)
@@ -1,6 +1,5 @@
 /* Predictive commoning.
-   Copyright (C) 2005, 2007, 2008, 2009, 2010, 2011, 2012
-   Free Software Foundation, Inc.
+   Copyright (C) 2005-2013 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -192,7 +191,23 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree.h"
 #include "tm_p.h"
 #include "cfgloop.h"
-#include "tree-flow.h"
+#include "gimple.h"
+#include "gimplify.h"
+#include "gimple-iterator.h"
+#include "gimplify-me.h"
+#include "gimple-ssa.h"
+#include "tree-phinodes.h"
+#include "ssa-iterators.h"
+#include "stringpool.h"
+#include "tree-ssanames.h"
+#include "tree-ssa-loop-ivopts.h"
+#include "tree-ssa-loop-manip.h"
+#include "tree-ssa-loop-niter.h"
+#include "tree-ssa-loop.h"
+#include "tree-into-ssa.h"
+#include "expr.h"
+#include "tree-dfa.h"
+#include "tree-ssa.h"
 #include "ggc.h"
 #include "tree-data-ref.h"
 #include "tree-scalar-evolution.h"
@@ -202,6 +217,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-pass.h"
 #include "tree-affine.h"
 #include "tree-inline.h"
+#include "wide-int-print.h"
 
 /* The maximum number of iterations between the considered memory
    references.  */
@@ -229,7 +245,7 @@ typedef struct dref_d
   unsigned distance;
 
   /* Number of iterations offset from the first reference in the component.  */
-  double_int offset;
+  widest_int offset;
 
   /* Number of the reference in a component, in dominance ordering.  */
   unsigned pos;
@@ -345,7 +361,7 @@ dump_dref (FILE *file, dref ref)
               DR_IS_READ (ref->ref) ? "" : ", write");
 
       fprintf (file, "      offset ");
-      dump_double_int (file, ref->offset, false);
+      print_decs (ref->offset, file);
       fprintf (file, "\n");
 
       fprintf (file, "      distance %u\n", ref->distance);
@@ -618,7 +634,7 @@ aff_combination_dr_offset (struct data_reference *dr, aff_tree *offset)
 
   tree_to_aff_combination_expand (DR_OFFSET (dr), type, offset,
                                  &name_expansions);
-  aff_combination_const (&delta, type, tree_to_double_int (DR_INIT (dr)));
+  aff_combination_const (&delta, type, wi::to_widest (DR_INIT (dr)));
   aff_combination_add (offset, &delta);
 }
 
@@ -630,7 +646,7 @@ aff_combination_dr_offset (struct data_reference *dr, aff_tree *offset)
 
 static bool
 determine_offset (struct data_reference *a, struct data_reference *b,
-                 double_int *off)
+                 widest_int *off)
 {
   aff_tree diff, baseb, step;
   tree typea, typeb;
@@ -651,7 +667,7 @@ determine_offset (struct data_reference *a, struct data_reference *b,
     {
       /* If the references have loop invariant address, check that they access
         exactly the same location.  */
-      *off = double_int_zero;
+      *off = 0;
       return (operand_equal_p (DR_OFFSET (a), DR_OFFSET (b), 0)
              && operand_equal_p (DR_INIT (a), DR_INIT (b), 0));
     }
@@ -660,7 +676,7 @@ determine_offset (struct data_reference *a, struct data_reference *b,
      is a multiple of step.  */
   aff_combination_dr_offset (a, &diff);
   aff_combination_dr_offset (b, &baseb);
-  aff_combination_scale (&baseb, double_int_minus_one);
+  aff_combination_scale (&baseb, -1);
   aff_combination_add (&diff, &baseb);
 
   tree_to_aff_combination_expand (DR_STEP (a), TREE_TYPE (DR_STEP (a)),
@@ -734,7 +750,7 @@ split_data_refs_to_components (struct loop *loop,
 
   FOR_EACH_VEC_ELT (depends, i, ddr)
     {
-      double_int dummy_off;
+      widest_int dummy_off;
 
       if (DDR_ARE_DEPENDENT (ddr) == chrec_known)
        continue;
@@ -777,7 +793,7 @@ split_data_refs_to_components (struct loop *loop,
       dataref = XCNEW (struct dref_d);
       dataref->ref = dr;
       dataref->stmt = DR_STMT (dr);
-      dataref->offset = double_int_zero;
+      dataref->offset = 0;
       dataref->distance = 0;
 
       dataref->always_accessed
@@ -833,7 +849,7 @@ suitable_component_p (struct loop *loop, struct component *comp)
   first = comp->refs[0];
   ok = suitable_reference_p (first->ref, &comp->comp_step);
   gcc_assert (ok);
-  first->offset = double_int_zero;
+  first->offset = 0;
 
   for (i = 1; comp->refs.iterate (i, &a); i++)
     {
@@ -897,7 +913,7 @@ order_drefs (const void *a, const void *b)
 {
   const dref *const da = (const dref *) a;
   const dref *const db = (const dref *) b;
-  int offcmp = (*da)->offset.scmp ((*db)->offset);
+  int offcmp = wi::cmps ((*da)->offset, (*db)->offset);
 
   if (offcmp != 0)
     return offcmp;
@@ -919,16 +935,15 @@ static void
 add_ref_to_chain (chain_p chain, dref ref)
 {
   dref root = get_chain_root (chain);
-  double_int dist;
 
-  gcc_assert (root->offset.sle (ref->offset));
-  dist = ref->offset - root->offset;
-  if (double_int::from_uhwi (MAX_DISTANCE).ule (dist))
+  gcc_assert (wi::les_p (root->offset, ref->offset));
+  widest_int dist = ref->offset - root->offset;
+  if (wi::leu_p (MAX_DISTANCE, dist))
     {
       free (ref);
       return;
     }
-  gcc_assert (dist.fits_uhwi ());
+  gcc_assert (wi::fits_uhwi_p (dist));
 
   chain->refs.safe_push (ref);
 
@@ -1023,7 +1038,7 @@ valid_initializer_p (struct data_reference *ref,
                     unsigned distance, struct data_reference *root)
 {
   aff_tree diff, base, step;
-  double_int off;
+  widest_int off;
 
   /* Both REF and ROOT must be accessing the same object.  */
   if (!operand_equal_p (DR_BASE_ADDRESS (ref), DR_BASE_ADDRESS (root), 0))
@@ -1043,7 +1058,7 @@ valid_initializer_p (struct data_reference *ref,
      -DISTANCE-th iteration.  */
   aff_combination_dr_offset (root, &diff);
   aff_combination_dr_offset (ref, &base);
-  aff_combination_scale (&base, double_int_minus_one);
+  aff_combination_scale (&base, -1);
   aff_combination_add (&diff, &base);
 
   tree_to_aff_combination_expand (DR_STEP (root), TREE_TYPE (DR_STEP (root)),
@@ -1051,7 +1066,7 @@ valid_initializer_p (struct data_reference *ref,
   if (!aff_combination_constant_multiple_p (&diff, &step, &off))
     return false;
 
-  if (off != double_int::from_uhwi (distance))
+  if (off != distance)
     return false;
 
   return true;
@@ -1179,7 +1194,7 @@ determine_roots_comp (struct loop *loop,
   unsigned i;
   dref a;
   chain_p chain = NULL;
-  double_int last_ofs = double_int_zero;
+  widest_int last_ofs = 0;
 
   /* Invariants are handled specially.  */
   if (comp->comp_step == RS_INVARIANT)
@@ -1194,7 +1209,7 @@ determine_roots_comp (struct loop *loop,
   FOR_EACH_VEC_ELT (comp->refs, i, a)
     {
       if (!chain || DR_IS_WRITE (a->ref)
-         || double_int::from_uhwi (MAX_DISTANCE).ule (a->offset - last_ofs))
+         || wi::leu_p (MAX_DISTANCE, a->offset - last_ofs))
        {
          if (nontrivial_chain_p (chain))
            {
@@ -1324,90 +1339,43 @@ replace_ref_with (gimple stmt, tree new_tree, bool set, bool in_lhs)
   gsi_insert_after (&bsi, new_stmt, GSI_NEW_STMT);
 }
 
-/* Returns the reference to the address of REF in the ITER-th iteration of
-   LOOP, or NULL if we fail to determine it (ITER may be negative).  We
-   try to preserve the original shape of the reference (not rewrite it
-   as an indirect ref to the address), to make tree_could_trap_p in
-   prepare_initializers_chain return false more often.  */
+/* Returns a memory reference to DR in the ITER-th iteration of
+   the loop it was analyzed in.  Append init stmts to STMTS.  */
 
-static tree
-ref_at_iteration (struct loop *loop, tree ref, int iter)
+static tree 
+ref_at_iteration (data_reference_p dr, int iter, gimple_seq *stmts)
 {
-  tree idx, *idx_p, type, val, op0 = NULL_TREE, ret;
-  affine_iv iv;
-  bool ok;
-
-  if (handled_component_p (ref))
-    {
-      op0 = ref_at_iteration (loop, TREE_OPERAND (ref, 0), iter);
-      if (!op0)
-       return NULL_TREE;
-    }
-  else if (!INDIRECT_REF_P (ref)
-          && TREE_CODE (ref) != MEM_REF)
-    return unshare_expr (ref);
-
-  if (TREE_CODE (ref) == MEM_REF)
-    {
-      ret = unshare_expr (ref);
-      idx = TREE_OPERAND (ref, 0);
-      idx_p = &TREE_OPERAND (ret, 0);
-    }
-  else if (TREE_CODE (ref) == COMPONENT_REF)
-    {
-      /* Check that the offset is loop invariant.  */
-      if (TREE_OPERAND (ref, 2)
-         && !expr_invariant_in_loop_p (loop, TREE_OPERAND (ref, 2)))
-       return NULL_TREE;
-
-      return build3 (COMPONENT_REF, TREE_TYPE (ref), op0,
-                    unshare_expr (TREE_OPERAND (ref, 1)),
-                    unshare_expr (TREE_OPERAND (ref, 2)));
-    }
-  else if (TREE_CODE (ref) == ARRAY_REF)
-    {
-      /* Check that the lower bound and the step are loop invariant.  */
-      if (TREE_OPERAND (ref, 2)
-         && !expr_invariant_in_loop_p (loop, TREE_OPERAND (ref, 2)))
-       return NULL_TREE;
-      if (TREE_OPERAND (ref, 3)
-         && !expr_invariant_in_loop_p (loop, TREE_OPERAND (ref, 3)))
-       return NULL_TREE;
-
-      ret = build4 (ARRAY_REF, TREE_TYPE (ref), op0, NULL_TREE,
-                   unshare_expr (TREE_OPERAND (ref, 2)),
-                   unshare_expr (TREE_OPERAND (ref, 3)));
-      idx = TREE_OPERAND (ref, 1);
-      idx_p = &TREE_OPERAND (ret, 1);
-    }
+  tree off = DR_OFFSET (dr);
+  tree coff = DR_INIT (dr);
+  if (iter == 0)
+    ;
+  else if (TREE_CODE (DR_STEP (dr)) == INTEGER_CST)
+    coff = size_binop (PLUS_EXPR, coff,
+                      size_binop (MULT_EXPR, DR_STEP (dr), ssize_int (iter)));
   else
-    return NULL_TREE;
-
-  ok = simple_iv (loop, loop, idx, &iv, true);
-  if (!ok)
-    return NULL_TREE;
-  iv.base = expand_simple_operations (iv.base);
-  if (integer_zerop (iv.step))
-    *idx_p = unshare_expr (iv.base);
-  else
-    {
-      type = TREE_TYPE (iv.base);
-      if (POINTER_TYPE_P (type))
-       {
-         val = fold_build2 (MULT_EXPR, sizetype, iv.step,
-                            size_int (iter));
-         val = fold_build_pointer_plus (iv.base, val);
-       }
-      else
-       {
-         val = fold_build2 (MULT_EXPR, type, iv.step,
-                            build_int_cst_type (type, iter));
-         val = fold_build2 (PLUS_EXPR, type, iv.base, val);
-       }
-      *idx_p = unshare_expr (val);
+    off = size_binop (PLUS_EXPR, off,
+                     size_binop (MULT_EXPR, DR_STEP (dr), ssize_int (iter)));
+  tree addr = fold_build_pointer_plus (DR_BASE_ADDRESS (dr), off);
+  addr = force_gimple_operand_1 (addr, stmts, is_gimple_mem_ref_addr,
+                                NULL_TREE);
+  tree alias_ptr = fold_convert (reference_alias_ptr_type (DR_REF (dr)), coff);
+  /* While data-ref analysis punts on bit offsets it still handles
+     bitfield accesses at byte boundaries.  Cope with that.  Note that
+     we cannot simply re-apply the outer COMPONENT_REF because the
+     byte-granular portion of it is already applied via DR_INIT and
+     DR_OFFSET, so simply build a BIT_FIELD_REF knowing that the bits
+     start at offset zero.  */
+  if (TREE_CODE (DR_REF (dr)) == COMPONENT_REF
+      && DECL_BIT_FIELD (TREE_OPERAND (DR_REF (dr), 1)))
+    {
+      tree field = TREE_OPERAND (DR_REF (dr), 1);
+      return build3 (BIT_FIELD_REF, TREE_TYPE (DR_REF (dr)),
+                    build2 (MEM_REF, DECL_BIT_FIELD_TYPE (field),
+                            addr, alias_ptr),
+                    DECL_SIZE (field), bitsize_zero_node);
     }
-
-  return ret;
+  else
+    return fold_build2 (MEM_REF, TREE_TYPE (DR_REF (dr)), addr, alias_ptr);
 }
 
 /* Get the initialization expression for the INDEX-th temporary variable
@@ -2069,7 +2037,11 @@ combinable_refs_p (dref r1, dref r2,
 
   stmt = find_common_use_stmt (&name1, &name2);
 
-  if (!stmt)
+  if (!stmt
+      /* A simple post-dominance check - make sure the combination
+         is executed under the same condition as the references.  */
+      || (gimple_bb (stmt) != gimple_bb (r1->stmt)
+         && gimple_bb (stmt) != gimple_bb (r2->stmt)))
     return false;
 
   acode = gimple_assign_rhs_code (stmt);
@@ -2300,7 +2272,7 @@ try_combine_chains (vec<chain_p> *chains)
 {
   unsigned i, j;
   chain_p ch1, ch2, cch;
-  vec<chain_p> worklist = vec<chain_p>();
+  vec<chain_p> worklist = vNULL;
 
   FOR_EACH_VEC_ELT (*chains, i, ch1)
     if (chain_can_be_combined_p (ch1))
@@ -2366,14 +2338,10 @@ prepare_initializers_chain (struct loop *loop, chain_p chain)
       if (chain->inits[i] != NULL_TREE)
        continue;
 
-      init = ref_at_iteration (loop, DR_REF (dr), (int) i - n);
-      if (!init)
-       return false;
-
+      init = ref_at_iteration (dr, (int) i - n, &stmts);
       if (!chain->all_always_accessed && tree_could_trap_p (init))
        return false;
 
-      init = force_gimple_operand (init, &stmts, false, NULL_TREE);
       if (stmts)
        gsi_insert_seq_on_edge_immediate (entry, stmts);
 
@@ -2411,11 +2379,10 @@ prepare_initializers (struct loop *loop, vec<chain_p> chains)
 static bool
 tree_predictive_commoning_loop (struct loop *loop)
 {
-  vec<loop_p> loop_nest;
   vec<data_reference_p> datarefs;
   vec<ddr_p> dependences;
   struct component *components;
-  vec<chain_p> chains = vec<chain_p>();
+  vec<chain_p> chains = vNULL;
   unsigned unroll_factor;
   struct tree_niter_desc desc;
   bool unroll = false;
@@ -2427,15 +2394,14 @@ tree_predictive_commoning_loop (struct loop *loop)
 
   /* Find the data references and split them into components according to their
      dependence relations.  */
-  datarefs.create (10);
+  stack_vec<loop_p, 3> loop_nest;
   dependences.create (10);
-  loop_nest.create (3);
+  datarefs.create (10);
   if (! compute_data_dependences_for_loop (loop, true, &loop_nest, &datarefs,
                                           &dependences))
     {
       if (dump_file && (dump_flags & TDF_DETAILS))
        fprintf (dump_file, "Cannot analyze data dependencies\n");
-      loop_nest.release ();
       free_data_refs (datarefs);
       free_dependence_relations (dependences);
       return false;
@@ -2545,11 +2511,10 @@ tree_predictive_commoning (void)
 {
   bool unrolled = false;
   struct loop *loop;
-  loop_iterator li;
   unsigned ret = 0;
 
   initialize_original_copy_tables ();
-  FOR_EACH_LOOP (li, loop, LI_ONLY_INNERMOST)
+  FOR_EACH_LOOP (loop, LI_ONLY_INNERMOST)
     if (optimize_loop_for_speed_p (loop))
       {
        unrolled |= tree_predictive_commoning_loop (loop);
@@ -2564,3 +2529,60 @@ tree_predictive_commoning (void)
 
   return ret;
 }
+
+/* Predictive commoning Pass.  */
+
+static unsigned
+run_tree_predictive_commoning (void)
+{
+  if (!current_loops)
+    return 0;
+
+  return tree_predictive_commoning ();
+}
+
+static bool
+gate_tree_predictive_commoning (void)
+{
+  return flag_predictive_commoning != 0;
+}
+
+namespace {
+
+const pass_data pass_data_predcom =
+{
+  GIMPLE_PASS, /* type */
+  "pcom", /* name */
+  OPTGROUP_LOOP, /* optinfo_flags */
+  true, /* has_gate */
+  true, /* has_execute */
+  TV_PREDCOM, /* tv_id */
+  PROP_cfg, /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  TODO_update_ssa_only_virtuals, /* todo_flags_finish */
+};
+
+class pass_predcom : public gimple_opt_pass
+{
+public:
+  pass_predcom (gcc::context *ctxt)
+    : gimple_opt_pass (pass_data_predcom, ctxt)
+  {}
+
+  /* opt_pass methods: */
+  bool gate () { return gate_tree_predictive_commoning (); }
+  unsigned int execute () { return run_tree_predictive_commoning (); }
+
+}; // class pass_predcom
+
+} // anon namespace
+
+gimple_opt_pass *
+make_pass_predcom (gcc::context *ctxt)
+{
+  return new pass_predcom (ctxt);
+}
+
+