diff mbox

stabilize store merging

Message ID orefy4zrov.fsf@lxoliva.fsfla.org
State New
Headers show

Commit Message

Alexandre Oliva March 10, 2017, 10:34 p.m. UTC
On Mar 10, 2017, Alexandre Oliva <aoliva@redhat.com> wrote:

> Now, if there's something you dislike about maps, we could make it a
> doubly-linked list, or maybe even a singly-linked list.

Scratch that, there's a use that may remove after a lookup by base_addr,
so a singly-linked list would require a linear walk of the list in this
case.  So, doubly-linked it is, which means...

> it costs just a pointer vs an int in the chains and an additional
> pointer over your suggestion, but it saves the shuffling and sorting.

... make it two pointers instead.


How's this?  Regstrapping now...  Ok if it passes?


Don't let pointer randomization change the order in which we process
store chains.  This may cause SSA_NAMEs to be released in different
order, and if they're reused later, they may cause differences in SSA
partitioning, leading to differences in expand, and ultimately to
different code.

bootstrap-debug-lean (-fcompare-debug) on i686-linux-gnu has failed in
haifa-sched.c since r245196 exposed the latent ordering problem in
store merging.  In this case, the IR differences (different SSA names
selected for copies in out-of-SSA, resulting in some off-by-one
differences in pseudos) were not significant enough to be visible in
the compiler output.


for  gcc/ChangeLog

	* gimple-ssa-store-merging.c (struct imm_store_chain_info):
	Add linked-list forward and backlinks.  Insert on
	construction, remove on destruction.
	(class pass_store_merging): Add m_stores_head field.
	(pass_store_merging::terminate_and_process_all_chains):
	Iterate over m_stores_head list.
	(pass_store_merging::terminate_all_aliasing_chains):
	Likewise.
	(pass_store_merging::execute): Check for debug stmts first.
	Push new chains onto the m_stores_head stack.
---
 gcc/gimple-ssa-store-merging.c |   65 ++++++++++++++++++++++++++++++----------
 1 file changed, 49 insertions(+), 16 deletions(-)

Comments

Richard Biener March 13, 2017, 8:53 a.m. UTC | #1
On Fri, Mar 10, 2017 at 11:34 PM, Alexandre Oliva <aoliva@redhat.com> wrote:
> On Mar 10, 2017, Alexandre Oliva <aoliva@redhat.com> wrote:
>
>> Now, if there's something you dislike about maps, we could make it a
>> doubly-linked list, or maybe even a singly-linked list.

I indeed mis-matched std::map for hash_map but I also think we should
use GCCs own interfaces and STL uses are generally discouraged.

> Scratch that, there's a use that may remove after a lookup by base_addr,
> so a singly-linked list would require a linear walk of the list in this
> case.  So, doubly-linked it is, which means...
>
>> it costs just a pointer vs an int in the chains and an additional
>> pointer over your suggestion, but it saves the shuffling and sorting.
>
> ... make it two pointers instead.
>
>
> How's this?  Regstrapping now...  Ok if it passes?

Ok.

[now C++-ish the next/pnxp could be abstracted as a (templated) base class]

Thanks,
Richard.

> Don't let pointer randomization change the order in which we process
> store chains.  This may cause SSA_NAMEs to be released in different
> order, and if they're reused later, they may cause differences in SSA
> partitioning, leading to differences in expand, and ultimately to
> different code.
>
> bootstrap-debug-lean (-fcompare-debug) on i686-linux-gnu has failed in
> haifa-sched.c since r245196 exposed the latent ordering problem in
> store merging.  In this case, the IR differences (different SSA names
> selected for copies in out-of-SSA, resulting in some off-by-one
> differences in pseudos) were not significant enough to be visible in
> the compiler output.
>
>
> for  gcc/ChangeLog
>
>         * gimple-ssa-store-merging.c (struct imm_store_chain_info):
>         Add linked-list forward and backlinks.  Insert on
>         construction, remove on destruction.
>         (class pass_store_merging): Add m_stores_head field.
>         (pass_store_merging::terminate_and_process_all_chains):
>         Iterate over m_stores_head list.
>         (pass_store_merging::terminate_all_aliasing_chains):
>         Likewise.
>         (pass_store_merging::execute): Check for debug stmts first.
>         Push new chains onto the m_stores_head stack.
> ---
>  gcc/gimple-ssa-store-merging.c |   65 ++++++++++++++++++++++++++++++----------
>  1 file changed, 49 insertions(+), 16 deletions(-)
>
> diff --git a/gcc/gimple-ssa-store-merging.c b/gcc/gimple-ssa-store-merging.c
> index 17ac94a..5bdb459 100644
> --- a/gcc/gimple-ssa-store-merging.c
> +++ b/gcc/gimple-ssa-store-merging.c
> @@ -675,11 +675,34 @@ merged_store_group::apply_stores ()
>
>  struct imm_store_chain_info
>  {
> +  /* Doubly-linked list that imposes an order on chain processing.
> +     PNXP (prev's next pointer) points to the head of a list, or to
> +     the next field in the previous chain in the list.
> +     See pass_store_merging::m_stores_head for more rationale.  */
> +  imm_store_chain_info *next, **pnxp;
>    tree base_addr;
>    auto_vec<struct store_immediate_info *> m_store_info;
>    auto_vec<merged_store_group *> m_merged_store_groups;
>
> -  imm_store_chain_info (tree b_a) : base_addr (b_a) {}
> +  imm_store_chain_info (imm_store_chain_info *&inspt, tree b_a)
> +  : next (inspt), pnxp (&inspt), base_addr (b_a)
> +  {
> +    inspt = this;
> +    if (next)
> +      {
> +       gcc_checking_assert (pnxp == next->pnxp);
> +       next->pnxp = &next;
> +      }
> +  }
> +  ~imm_store_chain_info ()
> +  {
> +    *pnxp = next;
> +    if (next)
> +      {
> +       gcc_checking_assert (&next == next->pnxp);
> +       next->pnxp = pnxp;
> +      }
> +  }
>    bool terminate_and_process_chain ();
>    bool coalesce_immediate_stores ();
>    bool output_merged_store (merged_store_group *);
> @@ -718,6 +741,17 @@ public:
>  private:
>    hash_map<tree_operand_hash, struct imm_store_chain_info *> m_stores;
>
> +  /* Form a doubly-linked stack of the elements of m_stores, so that
> +     we can iterate over them in a predictable way.  Using this order
> +     avoids extraneous differences in the compiler output just because
> +     of tree pointer variations (e.g. different chains end up in
> +     different positions of m_stores, so they are handled in different
> +     orders, so they allocate or release SSA names in different
> +     orders, and when they get reused, subsequent passes end up
> +     getting different SSA names, which may ultimately change
> +     decisions when going out of SSA).  */
> +  imm_store_chain_info *m_stores_head;
> +
>    bool terminate_and_process_all_chains ();
>    bool terminate_all_aliasing_chains (imm_store_chain_info **,
>                                       bool, gimple *);
> @@ -730,11 +764,11 @@ private:
>  bool
>  pass_store_merging::terminate_and_process_all_chains ()
>  {
> -  hash_map<tree_operand_hash, struct imm_store_chain_info *>::iterator iter
> -    = m_stores.begin ();
>    bool ret = false;
> -  for (; iter != m_stores.end (); ++iter)
> -    ret |= terminate_and_release_chain ((*iter).second);
> +  while (m_stores_head)
> +    ret |= terminate_and_release_chain (m_stores_head);
> +  gcc_assert (m_stores.elements () == 0);
> +  gcc_assert (m_stores_head == NULL);
>
>    return ret;
>  }
> @@ -799,15 +833,14 @@ pass_store_merging::terminate_all_aliasing_chains (imm_store_chain_info
>         }
>      }
>
> -  hash_map<tree_operand_hash, struct imm_store_chain_info *>::iterator iter
> -    = m_stores.begin ();
> -
>    /* Check for aliasing with all other store chains.  */
> -  for (; iter != m_stores.end (); ++iter)
> +  for (imm_store_chain_info *next = m_stores_head, *cur = next; cur; cur = next)
>      {
> +      next = cur->next;
> +
>        /* We already checked all the stores in chain_info and terminated the
>          chain if necessary.  Skip it here.  */
> -      if (chain_info && (*chain_info) == (*iter).second)
> +      if (chain_info && (*chain_info) == cur)
>         continue;
>
>        /* We can't use the base object here as that does not reliably exist.
> @@ -815,11 +848,11 @@ pass_store_merging::terminate_all_aliasing_chains (imm_store_chain_info
>          minimum and maximum offset and the maximum size we could improve
>          things here).  */
>        ao_ref chain_ref;
> -      ao_ref_init_from_ptr_and_size (&chain_ref, (*iter).first, NULL_TREE);
> +      ao_ref_init_from_ptr_and_size (&chain_ref, cur->base_addr, NULL_TREE);
>        if (ref_maybe_used_by_stmt_p (stmt, &chain_ref)
>           || stmt_may_clobber_ref_p_1 (stmt, &chain_ref))
>         {
> -         terminate_and_release_chain ((*iter).second);
> +         terminate_and_release_chain (cur);
>           ret = true;
>         }
>      }
> @@ -1336,6 +1369,9 @@ pass_store_merging::execute (function *fun)
>         {
>           gimple *stmt = gsi_stmt (gsi);
>
> +         if (is_gimple_debug (stmt))
> +           continue;
> +
>           if (gimple_has_volatile_ops (stmt))
>             {
>               /* Terminate all chains.  */
> @@ -1346,9 +1382,6 @@ pass_store_merging::execute (function *fun)
>               continue;
>             }
>
> -         if (is_gimple_debug (stmt))
> -           continue;
> -
>           if (gimple_assign_single_p (stmt) && gimple_vdef (stmt)
>               && !stmt_can_throw_internal (stmt)
>               && lhs_valid_for_store_merging_p (gimple_assign_lhs (stmt)))
> @@ -1456,7 +1489,7 @@ pass_store_merging::execute (function *fun)
>                   terminate_all_aliasing_chains (chain_info, false, stmt);
>                   /* Start a new chain.  */
>                   struct imm_store_chain_info *new_chain
> -                   = new imm_store_chain_info (base_addr);
> +                   = new imm_store_chain_info (m_stores_head, base_addr);
>                   info = new store_immediate_info (bitsize, bitpos,
>                                                    stmt, 0);
>                   new_chain->m_store_info.safe_push (info);
>
>
> --
> Alexandre Oliva, freedom fighter    http://FSFLA.org/~lxoliva/
> You must be the change you wish to see in the world. -- Gandhi
> Be Free! -- http://FSFLA.org/   FSF Latin America board member
> Free Software Evangelist|Red Hat Brasil GNU Toolchain Engineer
diff mbox

Patch

diff --git a/gcc/gimple-ssa-store-merging.c b/gcc/gimple-ssa-store-merging.c
index 17ac94a..5bdb459 100644
--- a/gcc/gimple-ssa-store-merging.c
+++ b/gcc/gimple-ssa-store-merging.c
@@ -675,11 +675,34 @@  merged_store_group::apply_stores ()
 
 struct imm_store_chain_info
 {
+  /* Doubly-linked list that imposes an order on chain processing.
+     PNXP (prev's next pointer) points to the head of a list, or to
+     the next field in the previous chain in the list.
+     See pass_store_merging::m_stores_head for more rationale.  */
+  imm_store_chain_info *next, **pnxp;
   tree base_addr;
   auto_vec<struct store_immediate_info *> m_store_info;
   auto_vec<merged_store_group *> m_merged_store_groups;
 
-  imm_store_chain_info (tree b_a) : base_addr (b_a) {}
+  imm_store_chain_info (imm_store_chain_info *&inspt, tree b_a)
+  : next (inspt), pnxp (&inspt), base_addr (b_a)
+  {
+    inspt = this;
+    if (next)
+      {
+	gcc_checking_assert (pnxp == next->pnxp);
+	next->pnxp = &next;
+      }
+  }
+  ~imm_store_chain_info ()
+  {
+    *pnxp = next;
+    if (next)
+      {
+	gcc_checking_assert (&next == next->pnxp);
+	next->pnxp = pnxp;
+      }
+  }
   bool terminate_and_process_chain ();
   bool coalesce_immediate_stores ();
   bool output_merged_store (merged_store_group *);
@@ -718,6 +741,17 @@  public:
 private:
   hash_map<tree_operand_hash, struct imm_store_chain_info *> m_stores;
 
+  /* Form a doubly-linked stack of the elements of m_stores, so that
+     we can iterate over them in a predictable way.  Using this order
+     avoids extraneous differences in the compiler output just because
+     of tree pointer variations (e.g. different chains end up in
+     different positions of m_stores, so they are handled in different
+     orders, so they allocate or release SSA names in different
+     orders, and when they get reused, subsequent passes end up
+     getting different SSA names, which may ultimately change
+     decisions when going out of SSA).  */
+  imm_store_chain_info *m_stores_head;
+
   bool terminate_and_process_all_chains ();
   bool terminate_all_aliasing_chains (imm_store_chain_info **,
 				      bool, gimple *);
@@ -730,11 +764,11 @@  private:
 bool
 pass_store_merging::terminate_and_process_all_chains ()
 {
-  hash_map<tree_operand_hash, struct imm_store_chain_info *>::iterator iter
-    = m_stores.begin ();
   bool ret = false;
-  for (; iter != m_stores.end (); ++iter)
-    ret |= terminate_and_release_chain ((*iter).second);
+  while (m_stores_head)
+    ret |= terminate_and_release_chain (m_stores_head);
+  gcc_assert (m_stores.elements () == 0);
+  gcc_assert (m_stores_head == NULL);
 
   return ret;
 }
@@ -799,15 +833,14 @@  pass_store_merging::terminate_all_aliasing_chains (imm_store_chain_info
 	}
     }
 
-  hash_map<tree_operand_hash, struct imm_store_chain_info *>::iterator iter
-    = m_stores.begin ();
-
   /* Check for aliasing with all other store chains.  */
-  for (; iter != m_stores.end (); ++iter)
+  for (imm_store_chain_info *next = m_stores_head, *cur = next; cur; cur = next)
     {
+      next = cur->next;
+
       /* We already checked all the stores in chain_info and terminated the
 	 chain if necessary.  Skip it here.  */
-      if (chain_info && (*chain_info) == (*iter).second)
+      if (chain_info && (*chain_info) == cur)
 	continue;
 
       /* We can't use the base object here as that does not reliably exist.
@@ -815,11 +848,11 @@  pass_store_merging::terminate_all_aliasing_chains (imm_store_chain_info
 	 minimum and maximum offset and the maximum size we could improve
 	 things here).  */
       ao_ref chain_ref;
-      ao_ref_init_from_ptr_and_size (&chain_ref, (*iter).first, NULL_TREE);
+      ao_ref_init_from_ptr_and_size (&chain_ref, cur->base_addr, NULL_TREE);
       if (ref_maybe_used_by_stmt_p (stmt, &chain_ref)
 	  || stmt_may_clobber_ref_p_1 (stmt, &chain_ref))
 	{
-	  terminate_and_release_chain ((*iter).second);
+	  terminate_and_release_chain (cur);
 	  ret = true;
 	}
     }
@@ -1336,6 +1369,9 @@  pass_store_merging::execute (function *fun)
 	{
 	  gimple *stmt = gsi_stmt (gsi);
 
+	  if (is_gimple_debug (stmt))
+	    continue;
+
 	  if (gimple_has_volatile_ops (stmt))
 	    {
 	      /* Terminate all chains.  */
@@ -1346,9 +1382,6 @@  pass_store_merging::execute (function *fun)
 	      continue;
 	    }
 
-	  if (is_gimple_debug (stmt))
-	    continue;
-
 	  if (gimple_assign_single_p (stmt) && gimple_vdef (stmt)
 	      && !stmt_can_throw_internal (stmt)
 	      && lhs_valid_for_store_merging_p (gimple_assign_lhs (stmt)))
@@ -1456,7 +1489,7 @@  pass_store_merging::execute (function *fun)
 		  terminate_all_aliasing_chains (chain_info, false, stmt);
 		  /* Start a new chain.  */
 		  struct imm_store_chain_info *new_chain
-		    = new imm_store_chain_info (base_addr);
+		    = new imm_store_chain_info (m_stores_head, base_addr);
 		  info = new store_immediate_info (bitsize, bitpos,
 						   stmt, 0);
 		  new_chain->m_store_info.safe_push (info);