From ce02c80c053c2a8a63ce6e87f5779a8dc5f470ee Mon Sep 17 00:00:00 2001
From: marxin <mliska@suse.cz>
Date: Mon, 25 Apr 2016 14:29:01 +0200
Subject: [PATCH 3/3] Enhance dumps of IVOPTS

gcc/ChangeLog:

2016-05-12  Martin Liska  <mliska@suse.cz>

	* tree-ssa-loop-ivopts.c (avg_loop_niter): Fix coding style.
	(struct cost_pair): Replace inv_expr_id with direct pointer
	to a iv_inv_expr_ent.
	(struct iv_inv_expr_ent): Add comment for struct fields.
	(struct iv_ca): Remove used_inv_exprs and replace it with a
	hash_map called used_inv_exprs.
	(niter_for_exit): Fix coding style.
	(determine_base_object): Likewise.
	(alloc_iv): Likewise.
	(find_interesting_uses_outside): Likewise.
	(add_candidate_1): Likewise.
	(add_standard_iv_candidates): Likewise.
	(set_group_iv_cost): Use inv_expr instead of inv_expr_id.
	(prepare_decl_rtl): Fix coding style.
	(get_address_cost): Likewise.
	(get_shiftadd_cost): Likewise.
	(force_expr_to_var_cost): Likewise.
	(compare_aff_trees): Likewise.
	(get_expr_id): Return iv_inv_expr_ent * instead of inv_expr_id.
	(get_loop_invariant_expr_id): Likewise.
	(get_computation_cost_at):
	(get_computation_cost): Replace usage of inv_expr_id (int) with
	inv_expr (iv_inv_expr_ent *).
	(determine_group_iv_cost_generic): Likewise.
	(determine_group_iv_cost_address): Likewise.
	(iv_period): Fix coding style.
	(iv_elimination_compare_lt): Likewise.
	(may_eliminate_iv): Likewise.
	(determine_group_iv_cost_cond): Replace usage of inv_expr_id (int) with
	inv_expr (iv_inv_expr_ent *).
	(determine_group_iv_costs): Likewise.
	(iv_ca_recount_cost): Use used_inv_exprs to determine # of
	used invariant expressions.
	(iv_ca_set_remove_invariants): Fix coding style.
	(iv_ca_set_no_cp): Use newly added hash_map.
	(iv_ca_set_add_invariants): Likewise.
	(iv_ca_set_cp): Likewise.
	(iv_ca_new): Initialize the newly added hash_map.
	(iv_ca_free): Delete it.
	(iv_ca_dump): Fix coding style and dump used invariant
	expressions.
	(iv_ca_extend): Fix coding style.
	(try_add_cand_for): Likewise.
	(create_new_ivs): Display information about # of avg niters and
	# of used invariant expressions.
	(rewrite_use_compare): Fix coding style.

gcc/ChangeLog:

gcc/testsuite/ChangeLog:

2016-04-29  Martin Liska  <mliska@suse.cz>

	* g++.dg/tree-ssa/ivopts-3.C: Change test-case to follow
	the new format of dump output.
---
 gcc/testsuite/g++.dg/tree-ssa/ivopts-3.C |   2 +-
 gcc/tree-ssa-loop-ivopts.c               | 378 ++++++++++++++++---------------
 2 files changed, 201 insertions(+), 179 deletions(-)

diff --git a/gcc/testsuite/g++.dg/tree-ssa/ivopts-3.C b/gcc/testsuite/g++.dg/tree-ssa/ivopts-3.C
index 6194e9d..eb72581 100644
--- a/gcc/testsuite/g++.dg/tree-ssa/ivopts-3.C
+++ b/gcc/testsuite/g++.dg/tree-ssa/ivopts-3.C
@@ -72,4 +72,4 @@ int main ( int , char** ) {
 
 // Verify that on x86_64 and i?86 we use a single IV for the innermost loop
 
-// { dg-final { scan-tree-dump "Selected IV set for loop \[0-9\]* at \[^ \]*:64, 1 IVs" "ivopts" { target x86_64-*-* i?86-*-* } } }
+// { dg-final { scan-tree-dump "Selected IV set for loop \[0-9\]* at \[^ \]*:64, 3 avg niters, 1 expressions, 1 IVs" "ivopts" { target x86_64-*-* i?86-*-* } } }
diff --git a/gcc/tree-ssa-loop-ivopts.c b/gcc/tree-ssa-loop-ivopts.c
index 17af590..5a48db2 100644
--- a/gcc/tree-ssa-loop-ivopts.c
+++ b/gcc/tree-ssa-loop-ivopts.c
@@ -130,7 +130,7 @@ avg_loop_niter (struct loop *loop)
     {
       niter = max_stmt_executions_int (loop);
       if (niter == -1 || niter > AVG_LOOP_NITER (loop))
-        return AVG_LOOP_NITER (loop);
+	return AVG_LOOP_NITER (loop);
     }
 
   return niter;
@@ -485,6 +485,9 @@ comp_cost::get_no_cost ()
   return comp_cost ();
 }
 
+/* Forward declaration.  */
+struct iv_inv_expr_ent;
+
 /* The candidate - cost pair.  */
 struct cost_pair
 {
@@ -496,7 +499,7 @@ struct cost_pair
 			   the final value of the iv.  For iv elimination,
 			   the new bound to compare with.  */
   enum tree_code comp;	/* For iv elimination, the comparison.  */
-  int inv_expr_id;      /* Loop invariant expression id.  */
+  iv_inv_expr_ent *inv_expr; /* Loop invariant expression.  */
 };
 
 /* Use.  */
@@ -608,10 +611,14 @@ iv_common_cand_hasher::equal (const iv_common_cand *ccand1,
 }
 
 /* Loop invariant expression hashtable entry.  */
+
 struct iv_inv_expr_ent
 {
+  /* Tree expression of the entry.  */
   tree expr;
+  /* Unique indentifier.  */
   int id;
+  /* Hash value.  */
   hashval_t hash;
 };
 
@@ -744,12 +751,8 @@ struct iv_ca
   /* Number of times each invariant is used.  */
   unsigned *n_invariant_uses;
 
-  /* The array holding the number of uses of each loop
-     invariant expressions created by ivopt.  */
-  unsigned *used_inv_expr;
-
-  /* The number of created loop invariants.  */
-  unsigned num_used_inv_expr;
+  /* Hash set with used invariant expression.  */
+  hash_map <iv_inv_expr_ent *, unsigned> *used_inv_exprs;
 
   /* Total cost of the assignment.  */
   comp_cost cost;
@@ -1141,8 +1144,8 @@ niter_for_exit (struct ivopts_data *data, edge exit)
   if (!slot)
     {
       /* Try to determine number of iterations.  We cannot safely work with ssa
-         names that appear in phi nodes on abnormal edges, so that we do not
-         create overlapping life ranges for them (PR 27283).  */
+	 names that appear in phi nodes on abnormal edges, so that we do not
+	 create overlapping life ranges for them (PR 27283).  */
       desc = XNEW (struct tree_niter_desc);
       if (!number_of_iterations_exit (data->current_loop,
 				      exit, desc, true)
@@ -1231,7 +1234,7 @@ determine_base_object (tree expr)
 	return determine_base_object (TREE_OPERAND (base, 0));
 
       return fold_convert (ptr_type_node,
-		           build_fold_addr_expr (base));
+			   build_fold_addr_expr (base));
 
     case POINTER_PLUS_EXPR:
       return determine_base_object (TREE_OPERAND (expr, 0));
@@ -1290,7 +1293,7 @@ alloc_iv (struct ivopts_data *data, tree base, tree step,
      By doing this:
        1) More accurate cost can be computed for address expressions;
        2) Duplicate candidates won't be created for bases in different
-          forms, like &a[0] and &a.  */
+	  forms, like &a[0] and &a.  */
   STRIP_NOPS (expr);
   if ((TREE_CODE (expr) == ADDR_EXPR && !DECL_P (TREE_OPERAND (expr, 0)))
       || contain_complex_addr_expr (expr))
@@ -2566,7 +2569,7 @@ find_interesting_uses_outside (struct ivopts_data *data, edge exit)
       phi = psi.phi ();
       def = PHI_ARG_DEF_FROM_EDGE (phi, exit);
       if (!virtual_operand_p (def))
-        find_interesting_uses_op (data, def);
+	find_interesting_uses_op (data, def);
     }
 }
 
@@ -3086,8 +3089,8 @@ add_candidate_1 (struct ivopts_data *data,
 
       if (operand_equal_p (base, cand->iv->base, 0)
 	  && operand_equal_p (step, cand->iv->step, 0)
-          && (TYPE_PRECISION (TREE_TYPE (base))
-              == TYPE_PRECISION (TREE_TYPE (cand->iv->base))))
+	  && (TYPE_PRECISION (TREE_TYPE (base))
+	      == TYPE_PRECISION (TREE_TYPE (cand->iv->base))))
 	break;
     }
 
@@ -3237,14 +3240,14 @@ add_standard_iv_candidates (struct ivopts_data *data)
 
   /* The same for a double-integer type if it is still fast enough.  */
   if (TYPE_PRECISION
-        (long_integer_type_node) > TYPE_PRECISION (integer_type_node)
+	(long_integer_type_node) > TYPE_PRECISION (integer_type_node)
       && TYPE_PRECISION (long_integer_type_node) <= BITS_PER_WORD)
     add_candidate (data, build_int_cst (long_integer_type_node, 0),
 		   build_int_cst (long_integer_type_node, 1), true, NULL);
 
   /* The same for a double-integer type if it is still fast enough.  */
   if (TYPE_PRECISION
-        (long_long_integer_type_node) > TYPE_PRECISION (long_integer_type_node)
+	(long_long_integer_type_node) > TYPE_PRECISION (long_integer_type_node)
       && TYPE_PRECISION (long_long_integer_type_node) <= BITS_PER_WORD)
     add_candidate (data, build_int_cst (long_long_integer_type_node, 0),
 		   build_int_cst (long_long_integer_type_node, 1), true, NULL);
@@ -3572,7 +3575,7 @@ static void
 set_group_iv_cost (struct ivopts_data *data,
 		   struct iv_group *group, struct iv_cand *cand,
 		   comp_cost cost, bitmap depends_on, tree value,
-		   enum tree_code comp, int inv_expr_id)
+		   enum tree_code comp, iv_inv_expr_ent *inv_expr)
 {
   unsigned i, s;
 
@@ -3589,7 +3592,7 @@ set_group_iv_cost (struct ivopts_data *data,
       group->cost_map[cand->id].depends_on = depends_on;
       group->cost_map[cand->id].value = value;
       group->cost_map[cand->id].comp = comp;
-      group->cost_map[cand->id].inv_expr_id = inv_expr_id;
+      group->cost_map[cand->id].inv_expr = inv_expr;
       return;
     }
 
@@ -3610,7 +3613,7 @@ found:
   group->cost_map[i].depends_on = depends_on;
   group->cost_map[i].value = value;
   group->cost_map[i].comp = comp;
-  group->cost_map[i].inv_expr_id = inv_expr_id;
+  group->cost_map[i].inv_expr = inv_expr;
 }
 
 /* Gets cost of (GROUP, CAND) pair.  */
@@ -3697,7 +3700,7 @@ prepare_decl_rtl (tree *expr_p, int *ws, void *data)
 	continue;
       obj = *expr_p;
       if (DECL_P (obj) && HAS_RTL_P (obj) && !DECL_RTL_SET_P (obj))
-        x = produce_memory_decl_rtl (obj, regno);
+	x = produce_memory_decl_rtl (obj, regno);
       break;
 
     case SSA_NAME:
@@ -4151,7 +4154,7 @@ get_address_cost (bool symbol_present, bool var_present,
 	    }
 	}
       if (i == -1)
-        off = 0;
+	off = 0;
       data->max_offset = off;
 
       if (dump_file && (dump_flags & TDF_DETAILS))
@@ -4283,9 +4286,9 @@ get_address_cost (bool symbol_present, bool var_present,
 	 However, the symbol will have to be loaded in any case before the
 	 loop (and quite likely we have it in register already), so it does not
 	 make much sense to penalize them too heavily.  So make some final
-         tweaks for the SYMBOL_PRESENT modes:
+	 tweaks for the SYMBOL_PRESENT modes:
 
-         If VAR_PRESENT is false, and the mode obtained by changing symbol to
+	 If VAR_PRESENT is false, and the mode obtained by changing symbol to
 	 var is cheaper, use this mode with small penalty.
 	 If VAR_PRESENT is true, try whether the mode with
 	 SYMBOL_PRESENT = false is cheaper even with cost of addition, and
@@ -4402,7 +4405,7 @@ get_address_cost (bool symbol_present, bool var_present,
 
 static bool
 get_shiftadd_cost (tree expr, machine_mode mode, comp_cost cost0,
-                   comp_cost cost1, tree mult, bool speed, comp_cost *cost)
+		   comp_cost cost1, tree mult, bool speed, comp_cost *cost)
 {
   comp_cost res;
   tree op1 = TREE_OPERAND (expr, 1);
@@ -4424,10 +4427,10 @@ get_shiftadd_cost (tree expr, machine_mode mode, comp_cost cost0,
   /* If the target has a cheap shift-and-add or shift-and-sub instruction,
      use that in preference to a shift insn followed by an add insn.  */
   sa_cost = (TREE_CODE (expr) != MINUS_EXPR
-             ? shiftadd_cost (speed, mode, m)
-             : (mult_in_op1
-                ? shiftsub1_cost (speed, mode, m)
-                : shiftsub0_cost (speed, mode, m)));
+	     ? shiftadd_cost (speed, mode, m)
+	     : (mult_in_op1
+		? shiftsub1_cost (speed, mode, m)
+		: shiftsub0_cost (speed, mode, m)));
 
   res = comp_cost (MIN (as_cost, sa_cost), 0);
   res += (mult_in_op1 ? cost0 : cost1);
@@ -4559,20 +4562,20 @@ force_expr_to_var_cost (tree expr, bool speed)
     case NEGATE_EXPR:
       cost = comp_cost (add_cost (speed, mode), 0);
       if (TREE_CODE (expr) != NEGATE_EXPR)
-        {
-          tree mult = NULL_TREE;
-          comp_cost sa_cost;
-          if (TREE_CODE (op1) == MULT_EXPR)
-            mult = op1;
-          else if (TREE_CODE (op0) == MULT_EXPR)
-            mult = op0;
-
-          if (mult != NULL_TREE
-              && cst_and_fits_in_hwi (TREE_OPERAND (mult, 1))
-              && get_shiftadd_cost (expr, mode, cost0, cost1, mult,
-                                    speed, &sa_cost))
-            return sa_cost;
-        }
+	{
+	  tree mult = NULL_TREE;
+	  comp_cost sa_cost;
+	  if (TREE_CODE (op1) == MULT_EXPR)
+	    mult = op1;
+	  else if (TREE_CODE (op0) == MULT_EXPR)
+	    mult = op0;
+
+	  if (mult != NULL_TREE
+	      && cst_and_fits_in_hwi (TREE_OPERAND (mult, 1))
+	      && get_shiftadd_cost (expr, mode, cost0, cost1, mult,
+				    speed, &sa_cost))
+	    return sa_cost;
+	}
       break;
 
     CASE_CONVERT:
@@ -4786,17 +4789,17 @@ compare_aff_trees (aff_tree *aff1, aff_tree *aff2)
   for (i = 0; i < aff1->n; i++)
     {
       if (aff1->elts[i].coef != aff2->elts[i].coef)
-        return false;
+	return false;
 
       if (!operand_equal_p (aff1->elts[i].val, aff2->elts[i].val, 0))
-        return false;
+	return false;
     }
   return true;
 }
 
 /* Stores EXPR in DATA->inv_expr_tab, and assigns it an inv_expr_id.  */
 
-static int
+static iv_inv_expr_ent *
 get_expr_id (struct ivopts_data *data, tree expr)
 {
   struct iv_inv_expr_ent ent;
@@ -4806,13 +4809,13 @@ get_expr_id (struct ivopts_data *data, tree expr)
   ent.hash = iterative_hash_expr (expr, 0);
   slot = data->inv_expr_tab->find_slot (&ent, INSERT);
   if (*slot)
-    return (*slot)->id;
+    return *slot;
 
   *slot = XNEW (struct iv_inv_expr_ent);
   (*slot)->expr = expr;
   (*slot)->hash = ent.hash;
   (*slot)->id = data->max_inv_expr_id++;
-  return (*slot)->id;
+  return *slot;
 }
 
 /* Returns the pseudo expr id if expression UBASE - RATIO * CBASE
@@ -4820,10 +4823,10 @@ get_expr_id (struct ivopts_data *data, tree expr)
    ADDRESS_P is a flag indicating if the expression is for address
    computation.  */
 
-static int
+static iv_inv_expr_ent *
 get_loop_invariant_expr_id (struct ivopts_data *data, tree ubase,
-                            tree cbase, HOST_WIDE_INT ratio,
-                            bool address_p)
+			    tree cbase, HOST_WIDE_INT ratio,
+			    bool address_p)
 {
   aff_tree ubase_aff, cbase_aff;
   tree expr, ub, cb;
@@ -4835,7 +4838,7 @@ get_loop_invariant_expr_id (struct ivopts_data *data, tree ubase,
 
   if ((TREE_CODE (ubase) == INTEGER_CST)
       && (TREE_CODE (cbase) == INTEGER_CST))
-    return -1;
+    return NULL;
 
   /* Strips the constant part. */
   if (TREE_CODE (ubase) == PLUS_EXPR
@@ -4843,7 +4846,7 @@ get_loop_invariant_expr_id (struct ivopts_data *data, tree ubase,
       || TREE_CODE (ubase) == POINTER_PLUS_EXPR)
     {
       if (TREE_CODE (TREE_OPERAND (ubase, 1)) == INTEGER_CST)
-        ubase = TREE_OPERAND (ubase, 0);
+	ubase = TREE_OPERAND (ubase, 0);
     }
 
   /* Strips the constant part. */
@@ -4852,60 +4855,60 @@ get_loop_invariant_expr_id (struct ivopts_data *data, tree ubase,
       || TREE_CODE (cbase) == POINTER_PLUS_EXPR)
     {
       if (TREE_CODE (TREE_OPERAND (cbase, 1)) == INTEGER_CST)
-        cbase = TREE_OPERAND (cbase, 0);
+	cbase = TREE_OPERAND (cbase, 0);
     }
 
   if (address_p)
     {
       if (((TREE_CODE (ubase) == SSA_NAME)
-           || (TREE_CODE (ubase) == ADDR_EXPR
-               && is_gimple_min_invariant (ubase)))
-          && (TREE_CODE (cbase) == INTEGER_CST))
-        return -1;
+	   || (TREE_CODE (ubase) == ADDR_EXPR
+	       && is_gimple_min_invariant (ubase)))
+	  && (TREE_CODE (cbase) == INTEGER_CST))
+	return NULL;
 
       if (((TREE_CODE (cbase) == SSA_NAME)
-           || (TREE_CODE (cbase) == ADDR_EXPR
-               && is_gimple_min_invariant (cbase)))
-          && (TREE_CODE (ubase) == INTEGER_CST))
-        return -1;
+	   || (TREE_CODE (cbase) == ADDR_EXPR
+	       && is_gimple_min_invariant (cbase)))
+	  && (TREE_CODE (ubase) == INTEGER_CST))
+	return NULL;
     }
 
   if (ratio == 1)
     {
       if (operand_equal_p (ubase, cbase, 0))
-        return -1;
+	return NULL;
 
       if (TREE_CODE (ubase) == ADDR_EXPR
-          && TREE_CODE (cbase) == ADDR_EXPR)
-        {
-          tree usym, csym;
-
-          usym = TREE_OPERAND (ubase, 0);
-          csym = TREE_OPERAND (cbase, 0);
-          if (TREE_CODE (usym) == ARRAY_REF)
-            {
-              tree ind = TREE_OPERAND (usym, 1);
-              if (TREE_CODE (ind) == INTEGER_CST
-                  && tree_fits_shwi_p (ind)
-                  && tree_to_shwi (ind) == 0)
-                usym = TREE_OPERAND (usym, 0);
-            }
-          if (TREE_CODE (csym) == ARRAY_REF)
-            {
-              tree ind = TREE_OPERAND (csym, 1);
-              if (TREE_CODE (ind) == INTEGER_CST
-                  && tree_fits_shwi_p (ind)
-                  && tree_to_shwi (ind) == 0)
-                csym = TREE_OPERAND (csym, 0);
-            }
-          if (operand_equal_p (usym, csym, 0))
-            return -1;
-        }
+	  && TREE_CODE (cbase) == ADDR_EXPR)
+	{
+	  tree usym, csym;
+
+	  usym = TREE_OPERAND (ubase, 0);
+	  csym = TREE_OPERAND (cbase, 0);
+	  if (TREE_CODE (usym) == ARRAY_REF)
+	    {
+	      tree ind = TREE_OPERAND (usym, 1);
+	      if (TREE_CODE (ind) == INTEGER_CST
+		  && tree_fits_shwi_p (ind)
+		  && tree_to_shwi (ind) == 0)
+		usym = TREE_OPERAND (usym, 0);
+	    }
+	  if (TREE_CODE (csym) == ARRAY_REF)
+	    {
+	      tree ind = TREE_OPERAND (csym, 1);
+	      if (TREE_CODE (ind) == INTEGER_CST
+		  && tree_fits_shwi_p (ind)
+		  && tree_to_shwi (ind) == 0)
+		csym = TREE_OPERAND (csym, 0);
+	    }
+	  if (operand_equal_p (usym, csym, 0))
+	    return NULL;
+	}
       /* Now do more complex comparison  */
       tree_to_aff_combination (ubase, TREE_TYPE (ubase), &ubase_aff);
       tree_to_aff_combination (cbase, TREE_TYPE (cbase), &cbase_aff);
       if (compare_aff_trees (&ubase_aff, &cbase_aff))
-        return -1;
+	return NULL;
     }
 
   tree_to_aff_combination (ub, TREE_TYPE (ub), &ubase_aff);
@@ -4932,7 +4935,7 @@ get_computation_cost_at (struct ivopts_data *data,
 			 struct iv_use *use, struct iv_cand *cand,
 			 bool address_p, bitmap *depends_on, gimple *at,
 			 bool *can_autoinc,
-                         int *inv_expr_id)
+			 iv_inv_expr_ent **inv_expr)
 {
   tree ubase = use->iv->base, ustep = use->iv->step;
   tree cbase, cstep;
@@ -5033,17 +5036,17 @@ get_computation_cost_at (struct ivopts_data *data,
 
       /* Check to see if any adjustment is needed.  */
       if (cstepi == 0 && stmt_is_after_inc)
-        {
-          aff_tree real_cbase_aff;
-          aff_tree cstep_aff;
+	{
+	  aff_tree real_cbase_aff;
+	  aff_tree cstep_aff;
 
-          tree_to_aff_combination (cbase, TREE_TYPE (real_cbase),
-                                   &real_cbase_aff);
-          tree_to_aff_combination (cstep, TREE_TYPE (cstep), &cstep_aff);
+	  tree_to_aff_combination (cbase, TREE_TYPE (real_cbase),
+				   &real_cbase_aff);
+	  tree_to_aff_combination (cstep, TREE_TYPE (cstep), &cstep_aff);
 
-          aff_combination_add (&real_cbase_aff, &cstep_aff);
-          real_cbase = aff_combination_to_tree (&real_cbase_aff);
-        }
+	  aff_combination_add (&real_cbase_aff, &cstep_aff);
+	  real_cbase = aff_combination_to_tree (&real_cbase_aff);
+	}
 
       cost = difference_cost (data,
 			      ubase, real_cbase,
@@ -5087,13 +5090,13 @@ get_computation_cost_at (struct ivopts_data *data,
   /* Record setup cost in scrach field.  */
   cost.set_scratch (cost.get_cost ());
 
-  if (inv_expr_id && depends_on && *depends_on)
+  if (inv_expr && depends_on && *depends_on)
     {
-      *inv_expr_id =
-          get_loop_invariant_expr_id (data, ubase, cbase, ratio, address_p);
+      *inv_expr
+	= get_loop_invariant_expr_id (data, ubase, cbase, ratio, address_p);
       /* Clear depends on.  */
-      if (*inv_expr_id != -1)
-        bitmap_clear (*depends_on);
+      if (inv_expr != NULL)
+	bitmap_clear (*depends_on);
     }
 
   /* If we are after the increment, the value of the candidate is higher by
@@ -5175,11 +5178,11 @@ static comp_cost
 get_computation_cost (struct ivopts_data *data,
 		      struct iv_use *use, struct iv_cand *cand,
 		      bool address_p, bitmap *depends_on,
-                      bool *can_autoinc, int *inv_expr_id)
+		      bool *can_autoinc, iv_inv_expr_ent **inv_expr)
 {
   return get_computation_cost_at (data,
 				  use, cand, address_p, depends_on, use->stmt,
-				  can_autoinc, inv_expr_id);
+				  can_autoinc, inv_expr);
 }
 
 /* Determines cost of computing the use in GROUP with CAND in a generic
@@ -5190,7 +5193,7 @@ determine_group_iv_cost_generic (struct ivopts_data *data,
 				 struct iv_group *group, struct iv_cand *cand)
 {
   comp_cost cost;
-  int inv_expr_id = -1;
+  iv_inv_expr_ent *inv_expr = NULL;
   bitmap depends_on = NULL;
   struct iv_use *use = group->vuses[0];
 
@@ -5202,10 +5205,10 @@ determine_group_iv_cost_generic (struct ivopts_data *data,
     cost = comp_cost::get_no_cost ();
   else
     cost = get_computation_cost (data, use, cand, false,
-				 &depends_on, NULL, &inv_expr_id);
+				 &depends_on, NULL, &inv_expr);
 
   set_group_iv_cost (data, group, cand, cost, depends_on,
-		     NULL_TREE, ERROR_MARK, inv_expr_id);
+		     NULL_TREE, ERROR_MARK, inv_expr);
   return !cost.infinite_cost_p ();
 }
 
@@ -5218,12 +5221,12 @@ determine_group_iv_cost_address (struct ivopts_data *data,
   unsigned i;
   bitmap depends_on;
   bool can_autoinc, first = true;
-  int inv_expr_id = -1;
+  iv_inv_expr_ent *inv_expr = NULL;
   struct iv_use *use = group->vuses[0];
   comp_cost sum_cost = comp_cost::get_no_cost (), cost;
 
   cost = get_computation_cost (data, use, cand, true,
-			       &depends_on, &can_autoinc, &inv_expr_id);
+			       &depends_on, &can_autoinc, &inv_expr);
 
   sum_cost = cost;
   if (!sum_cost.infinite_cost_p () && cand->ainc_use == use)
@@ -5271,7 +5274,7 @@ determine_group_iv_cost_address (struct ivopts_data *data,
       sum_cost += cost;
     }
   set_group_iv_cost (data, group, cand, sum_cost, depends_on,
-		     NULL_TREE, ERROR_MARK, inv_expr_id);
+		     NULL_TREE, ERROR_MARK, inv_expr);
 
   return !sum_cost.infinite_cost_p ();
 }
@@ -5327,8 +5330,8 @@ iv_period (struct iv *iv)
   pow2div = num_ending_zeros (step);
 
   period = build_low_bits_mask (type,
-                                (TYPE_PRECISION (type)
-                                 - tree_to_uhwi (pow2div)));
+				(TYPE_PRECISION (type)
+				 - tree_to_uhwi (pow2div)));
 
   return period;
 }
@@ -5461,7 +5464,7 @@ difference_cannot_overflow_p (struct ivopts_data *data, tree base, tree offset)
 
 static bool
 iv_elimination_compare_lt (struct ivopts_data *data,
-                           struct iv_cand *cand, enum tree_code *comp_p,
+			   struct iv_cand *cand, enum tree_code *comp_p,
 			   struct tree_niter_desc *niter)
 {
   tree cand_type, a, b, mbz, nit_type = TREE_TYPE (niter->niter), offset;
@@ -5510,10 +5513,10 @@ iv_elimination_compare_lt (struct ivopts_data *data,
 
       /* Handle b < a + 1.  */
       if (TREE_CODE (op1) == PLUS_EXPR && integer_onep (TREE_OPERAND (op1, 1)))
-        {
-          a = TREE_OPERAND (op1, 0);
-          b = TREE_OPERAND (mbz, 0);
-        }
+	{
+	  a = TREE_OPERAND (op1, 0);
+	  b = TREE_OPERAND (mbz, 0);
+	}
       else
 	return false;
     }
@@ -5599,15 +5602,15 @@ may_eliminate_iv (struct ivopts_data *data,
     {
       /* See cand_value_at.  */
       if (stmt_after_increment (loop, cand, use->stmt))
-        {
-          if (!tree_int_cst_lt (desc->niter, period))
-            return false;
-        }
+	{
+	  if (!tree_int_cst_lt (desc->niter, period))
+	    return false;
+	}
       else
-        {
-          if (tree_int_cst_lt (period, desc->niter))
-            return false;
-        }
+	{
+	  if (tree_int_cst_lt (period, desc->niter))
+	    return false;
+	}
     }
 
   /* If not, and if this is the only possible exit of the loop, see whether
@@ -5619,22 +5622,23 @@ may_eliminate_iv (struct ivopts_data *data,
 
       max_niter = desc->max;
       if (stmt_after_increment (loop, cand, use->stmt))
-        max_niter += 1;
+	max_niter += 1;
       period_value = wi::to_widest (period);
       if (wi::gtu_p (max_niter, period_value))
-        {
-          /* See if we can take advantage of inferred loop bound information.  */
-          if (data->loop_single_exit_p)
-            {
-              if (!max_loop_iterations (loop, &max_niter))
-                return false;
-              /* The loop bound is already adjusted by adding 1.  */
-              if (wi::gtu_p (max_niter, period_value))
-                return false;
-            }
-          else
-            return false;
-        }
+	{
+	  /* See if we can take advantage of inferred loop bound
+	     information.  */
+	  if (data->loop_single_exit_p)
+	    {
+	      if (!max_loop_iterations (loop, &max_niter))
+		return false;
+	      /* The loop bound is already adjusted by adding 1.  */
+	      if (wi::gtu_p (max_niter, period_value))
+		return false;
+	    }
+	  else
+	    return false;
+	}
     }
 
   cand_value_at (loop, cand, use->stmt, desc->niter, &bnd);
@@ -5690,7 +5694,7 @@ determine_group_iv_cost_cond (struct ivopts_data *data,
   bitmap depends_on_elim = NULL, depends_on_express = NULL, depends_on;
   comp_cost elim_cost, express_cost, cost, bound_cost;
   bool ok;
-  int elim_inv_expr_id = -1, express_inv_expr_id = -1, inv_expr_id;
+  iv_inv_expr_ent *elim_inv_expr = NULL, *express_inv_expr = NULL, *inv_expr;
   tree *control_var, *bound_cst;
   enum tree_code comp = ERROR_MARK;
   struct iv_use *use = group->vuses[0];
@@ -5710,10 +5714,10 @@ determine_group_iv_cost_cond (struct ivopts_data *data,
 	 that both 'base' and 'n' will be live during the loop.	 More likely,
 	 'base + n' will be loop invariant, resulting in only one live value
 	 during the loop.  So in that case we clear depends_on_elim and set
-        elim_inv_expr_id instead.  */
+	elim_inv_expr_id instead.  */
       if (depends_on_elim && bitmap_count_bits (depends_on_elim) > 1)
 	{
-	  elim_inv_expr_id = get_expr_id (data, bound);
+	  elim_inv_expr = get_expr_id (data, bound);
 	  bitmap_clear (depends_on_elim);
 	}
       /* The bound is a loop invariant, so it will be only computed
@@ -5743,7 +5747,7 @@ determine_group_iv_cost_cond (struct ivopts_data *data,
 
   express_cost = get_computation_cost (data, use, cand, false,
 				       &depends_on_express, NULL,
-                                       &express_inv_expr_id);
+				       &express_inv_expr);
   fd_ivopts_data = data;
   walk_tree (&cmp_iv->base, find_depends, &depends_on_express, NULL);
 
@@ -5761,7 +5765,7 @@ determine_group_iv_cost_cond (struct ivopts_data *data,
       cost = elim_cost;
       depends_on = depends_on_elim;
       depends_on_elim = NULL;
-      inv_expr_id = elim_inv_expr_id;
+      inv_expr = elim_inv_expr;
     }
   else
     {
@@ -5770,11 +5774,11 @@ determine_group_iv_cost_cond (struct ivopts_data *data,
       depends_on_express = NULL;
       bound = NULL_TREE;
       comp = ERROR_MARK;
-      inv_expr_id = express_inv_expr_id;
+      inv_expr = express_inv_expr;
     }
 
   set_group_iv_cost (data, group, cand, cost,
-		     depends_on, bound, comp, inv_expr_id);
+		     depends_on, bound, comp, inv_expr);
 
   if (depends_on_elim)
     BITMAP_FREE (depends_on_elim);
@@ -5988,9 +5992,9 @@ determine_group_iv_costs (struct ivopts_data *data)
 	      if (group->cost_map[j].depends_on)
 		bitmap_print (dump_file,
 			      group->cost_map[j].depends_on, "","");
-	      if (group->cost_map[j].inv_expr_id != -1)
+		if (group->cost_map[j].inv_expr != NULL)
 		fprintf (dump_file, " inv_expr:%d",
-			 group->cost_map[j].inv_expr_id);
+			 group->cost_map[j].inv_expr->id);
 	      fprintf (dump_file, "\n");
 	    }
 
@@ -6201,7 +6205,8 @@ iv_ca_recount_cost (struct ivopts_data *data, struct iv_ca *ivs)
   cost += ivs->cand_cost;
 
   cost += ivopts_global_cost_for_size (data,
-				       ivs->n_regs + ivs->num_used_inv_expr);
+				       ivs->n_regs
+				       + ivs->used_inv_exprs->elements ());
 
   ivs->cost = cost;
 }
@@ -6221,7 +6226,7 @@ iv_ca_set_remove_invariants (struct iv_ca *ivs, bitmap invs)
     {
       ivs->n_invariant_uses[iid]--;
       if (ivs->n_invariant_uses[iid] == 0)
-        ivs->n_regs--;
+	ivs->n_regs--;
     }
 }
 
@@ -6259,11 +6264,12 @@ iv_ca_set_no_cp (struct ivopts_data *data, struct iv_ca *ivs,
 
   iv_ca_set_remove_invariants (ivs, cp->depends_on);
 
-  if (cp->inv_expr_id != -1)
+  if (cp->inv_expr != NULL)
     {
-      ivs->used_inv_expr[cp->inv_expr_id]--;
-      if (ivs->used_inv_expr[cp->inv_expr_id] == 0)
-        ivs->num_used_inv_expr--;
+      unsigned *slot = ivs->used_inv_exprs->get (cp->inv_expr);
+      --(*slot);
+      if (*slot == 0)
+	ivs->used_inv_exprs->remove (cp->inv_expr);
     }
   iv_ca_recount_cost (data, ivs);
 }
@@ -6283,7 +6289,7 @@ iv_ca_set_add_invariants (struct iv_ca *ivs, bitmap invs)
     {
       ivs->n_invariant_uses[iid]++;
       if (ivs->n_invariant_uses[iid] == 1)
-        ivs->n_regs++;
+	ivs->n_regs++;
     }
 }
 
@@ -6323,12 +6329,11 @@ iv_ca_set_cp (struct ivopts_data *data, struct iv_ca *ivs,
       ivs->cand_use_cost += cp->cost;
       iv_ca_set_add_invariants (ivs, cp->depends_on);
 
-      if (cp->inv_expr_id != -1)
-        {
-          ivs->used_inv_expr[cp->inv_expr_id]++;
-          if (ivs->used_inv_expr[cp->inv_expr_id] == 1)
-            ivs->num_used_inv_expr++;
-        }
+      if (cp->inv_expr != NULL)
+	{
+	  unsigned *slot = &ivs->used_inv_exprs->get_or_insert (cp->inv_expr);
+	  ++(*slot);
+	}
       iv_ca_recount_cost (data, ivs);
     }
 }
@@ -6537,9 +6542,8 @@ iv_ca_new (struct ivopts_data *data)
   nw->cand_use_cost = comp_cost::get_no_cost ();
   nw->cand_cost = 0;
   nw->n_invariant_uses = XCNEWVEC (unsigned, data->max_inv_id + 1);
+  nw->used_inv_exprs = new hash_map <iv_inv_expr_ent *, unsigned> (13);
   nw->cost = comp_cost::get_no_cost ();
-  nw->used_inv_expr = XCNEWVEC (unsigned, data->max_inv_expr_id + 1);
-  nw->num_used_inv_expr = 0;
 
   return nw;
 }
@@ -6553,7 +6557,7 @@ iv_ca_free (struct iv_ca **ivs)
   free ((*ivs)->n_cand_uses);
   BITMAP_FREE ((*ivs)->cands);
   free ((*ivs)->n_invariant_uses);
-  free ((*ivs)->used_inv_expr);
+  delete ((*ivs)->used_inv_exprs);
   free (*ivs);
   *ivs = NULL;
 }
@@ -6579,7 +6583,7 @@ iv_ca_dump (struct ivopts_data *data, FILE *file, struct iv_ca *ivs)
       struct iv_group *group = data->vgroups[i];
       struct cost_pair *cp = iv_ca_cand_for_group (ivs, group);
       if (cp)
-        fprintf (file, "   group:%d --> iv_cand:%d, cost=(%d,%d)\n",
+	fprintf (file, "   group:%d --> iv_cand:%d, cost=(%d,%d)\n",
 		 group->id, cp->cand->id, cp->cost.get_cost (),
 		 cp->cost.get_complexity ());
       else
@@ -6592,6 +6596,20 @@ iv_ca_dump (struct ivopts_data *data, FILE *file, struct iv_ca *ivs)
 	fprintf (file, "%s%d", pref, i);
 	pref = ", ";
       }
+
+  if (ivs->used_inv_exprs->elements () > 0)
+    {
+      fprintf (dump_file, "\n  used invariant expressions:\n");
+      for (hash_map<iv_inv_expr_ent *, unsigned>::iterator it
+	   = ivs->used_inv_exprs->begin (); it != ivs->used_inv_exprs->end ();
+	   ++it)
+	{
+	  fprintf (dump_file, "   inv_expr:%d: \t", (*it).first->id);
+	  print_generic_expr (dump_file, (*it).first->expr, TDF_SLIM);
+	  fprintf (dump_file, "\n");
+	}
+    }
+
   fprintf (file, "\n\n");
 }
 
@@ -6628,7 +6646,7 @@ iv_ca_extend (struct ivopts_data *data, struct iv_ca *ivs,
 	continue;
 
       if (!min_ncand && !cheaper_cost_pair (new_cp, old_cp))
-        continue;
+	continue;
 
       *delta = iv_ca_delta_add (group, old_cp, new_cp, *delta);
     }
@@ -6932,7 +6950,7 @@ try_add_cand_for (struct ivopts_data *data, struct iv_ca *ivs,
 	continue;
 
       if (iv_ca_cand_used_p (ivs, cand))
-        continue;
+	continue;
 
       cp = get_group_iv_cost (data, group, cand);
       if (!cp)
@@ -6940,7 +6958,7 @@ try_add_cand_for (struct ivopts_data *data, struct iv_ca *ivs,
 
       iv_ca_set_cp (data, ivs, group, cp);
       act_cost = iv_ca_extend (data, ivs, cand, &act_delta, NULL,
-                               true);
+			       true);
       iv_ca_set_no_cp (data, ivs, group);
       act_delta = iv_ca_delta_add (group, NULL, cp, act_delta);
 
@@ -7253,12 +7271,16 @@ create_new_ivs (struct ivopts_data *data, struct iv_ca *set)
       if (data->loop_loc != UNKNOWN_LOCATION)
 	fprintf (dump_file, " at %s:%d", LOCATION_FILE (data->loop_loc),
 		 LOCATION_LINE (data->loop_loc));
+      fprintf (dump_file, ", %lu avg niters",
+	       avg_loop_niter (data->current_loop));
+      fprintf (dump_file, ", %lu expressions",
+	       set->used_inv_exprs->elements ());
       fprintf (dump_file, ", %lu IVs:\n", bitmap_count_bits (set->cands));
       EXECUTE_IF_SET_IN_BITMAP (set->cands, 0, i, bi)
-        {
-          cand = data->vcands[i];
-          dump_cand (dump_file, cand);
-        }
+	{
+	  cand = data->vcands[i];
+	  dump_cand (dump_file, cand);
+	}
       fprintf (dump_file, "\n");
     }
 }
@@ -7513,10 +7535,10 @@ rewrite_use_compare (struct ivopts_data *data,
       gimple_seq stmts;
 
       if (dump_file && (dump_flags & TDF_DETAILS))
-        {
-          fprintf (dump_file, "Replacing exit test: ");
-          print_gimple_stmt (dump_file, use->stmt, 0, TDF_SLIM);
-        }
+	{
+	  fprintf (dump_file, "Replacing exit test: ");
+	  print_gimple_stmt (dump_file, use->stmt, 0, TDF_SLIM);
+	}
       compare = cp->comp;
       bound = unshare_expr (fold_convert (var_type, bound));
       op = force_gimple_operand (bound, &stmts, true, NULL_TREE);
-- 
2.8.2

