diff mbox series

Fix up store_merging_13.c FAIL

Message ID 20171109131502.GA14653@tucnak
State New
Headers show
Series Fix up store_merging_13.c FAIL | expand

Commit Message

Jakub Jelinek Nov. 9, 2017, 1:15 p.m. UTC
Hi!

The gcc.dg/store_merging_13.c testcase worked when I was bootstrapping the
patch that introduced it, but doesn't anymore, because match.pd had
a ~X ^ Y -> ~(X ^ Y) transformation, the code was handling only ~ on
the loads (== arguments of &/|/^) but not on the result of the bitwise
binary operation.  The following patch handles inversion of the result
too, after all even ~X & ~Y is ~(X | Y) and ~X | ~Y is ~(X & Y).
In addition to this, I've added just in case some earlier passes wouldn't
do good enough job a check that we don't recognize
_1 = load; _2 = ~1; _3 = ~1; store = _3; and similar (or arbitrarily more
chained BIT_NOT_EXPRs), while we'd emit a working code, the has_single_use
accounting wouldn't be prepared for more than one BIT_NOT_EXPR on one
operand.

Ok for trunk if it passes bootstrap/regtest?

Just managed to reproduce the profiledbootstrap issue, so working on that
next.

2017-11-09  Jakub Jelinek  <jakub@redhat.com>

	* gimple-ssa-store-merging.c (struct store_immediate_info): Add
	bit_not_p field.
	(store_immediate_info::store_immediate_info): Add bitnotp argument,
	set bit_not_p to it.
	(imm_store_chain_info::coalesce_immediate_stores): Break group
	if bit_not_p is different.
	(count_multiple_uses, split_group,
	imm_store_chain_info::output_merged_store): Handle info->bit_not_p.
	(handled_load): Avoid multiple chained BIT_NOT_EXPRs.
	(pass_store_merging::process_store): Handle BIT_{AND,IOR,XOR}_EXPR
	result inverted using BIT_NOT_EXPR, compute bit_not_p, pass it
	to store_immediate_info ctor.


	Jakub

Comments

Marc Glisse Nov. 9, 2017, 2:23 p.m. UTC | #1
On Thu, 9 Nov 2017, Jakub Jelinek wrote:

> The gcc.dg/store_merging_13.c testcase worked when I was bootstrapping the
> patch that introduced it, but doesn't anymore, because match.pd had
> a ~X ^ Y -> ~(X ^ Y) transformation, the code was handling only ~ on
> the loads (== arguments of &/|/^) but not on the result of the bitwise
> binary operation.

Sorry about that. If this canonicalization causes too much trouble, we 
could revert it (it isn't important to me). Although it looks like you 
managed to extend the store merging code nicely instead :-)
Richard Biener Nov. 9, 2017, 3:11 p.m. UTC | #2
On Thu, 9 Nov 2017, Jakub Jelinek wrote:

> Hi!
> 
> The gcc.dg/store_merging_13.c testcase worked when I was bootstrapping the
> patch that introduced it, but doesn't anymore, because match.pd had
> a ~X ^ Y -> ~(X ^ Y) transformation, the code was handling only ~ on
> the loads (== arguments of &/|/^) but not on the result of the bitwise
> binary operation.  The following patch handles inversion of the result
> too, after all even ~X & ~Y is ~(X | Y) and ~X | ~Y is ~(X & Y).
> In addition to this, I've added just in case some earlier passes wouldn't
> do good enough job a check that we don't recognize
> _1 = load; _2 = ~1; _3 = ~1; store = _3; and similar (or arbitrarily more
> chained BIT_NOT_EXPRs), while we'd emit a working code, the has_single_use
> accounting wouldn't be prepared for more than one BIT_NOT_EXPR on one
> operand.
> 
> Ok for trunk if it passes bootstrap/regtest?

Nice.

Ok.
Thanks,
Richard.

> Just managed to reproduce the profiledbootstrap issue, so working on that
> next.
> 
> 2017-11-09  Jakub Jelinek  <jakub@redhat.com>
> 
> 	* gimple-ssa-store-merging.c (struct store_immediate_info): Add
> 	bit_not_p field.
> 	(store_immediate_info::store_immediate_info): Add bitnotp argument,
> 	set bit_not_p to it.
> 	(imm_store_chain_info::coalesce_immediate_stores): Break group
> 	if bit_not_p is different.
> 	(count_multiple_uses, split_group,
> 	imm_store_chain_info::output_merged_store): Handle info->bit_not_p.
> 	(handled_load): Avoid multiple chained BIT_NOT_EXPRs.
> 	(pass_store_merging::process_store): Handle BIT_{AND,IOR,XOR}_EXPR
> 	result inverted using BIT_NOT_EXPR, compute bit_not_p, pass it
> 	to store_immediate_info ctor.
> 
> --- gcc/gimple-ssa-store-merging.c.jj	2017-11-09 12:40:27.000000000 +0100
> +++ gcc/gimple-ssa-store-merging.c	2017-11-09 14:00:46.269673305 +0100
> @@ -209,12 +209,13 @@ struct store_immediate_info
>    /* INTEGER_CST for constant stores, MEM_REF for memory copy or
>       BIT_*_EXPR for logical bitwise operation.  */
>    enum tree_code rhs_code;
> +  bool bit_not_p;
>    /* Operands.  For BIT_*_EXPR rhs_code both operands are used, otherwise
>       just the first one.  */
>    store_operand_info ops[2];
>    store_immediate_info (unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT,
>  			unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT,
> -			gimple *, unsigned int, enum tree_code,
> +			gimple *, unsigned int, enum tree_code, bool,
>  			const store_operand_info &,
>  			const store_operand_info &);
>  };
> @@ -226,10 +227,11 @@ store_immediate_info::store_immediate_in
>  					    gimple *st,
>  					    unsigned int ord,
>  					    enum tree_code rhscode,
> +					    bool bitnotp,
>  					    const store_operand_info &op0r,
>  					    const store_operand_info &op1r)
>    : bitsize (bs), bitpos (bp), bitregion_start (brs), bitregion_end (bre),
> -    stmt (st), order (ord), rhs_code (rhscode)
> +    stmt (st), order (ord), rhs_code (rhscode), bit_not_p (bitnotp)
>  #if __cplusplus >= 201103L
>      , ops { op0r, op1r }
>  {
> @@ -1169,7 +1171,8 @@ imm_store_chain_info::coalesce_immediate
>  	 Merge it into the current store group.  There can be gaps in between
>  	 the stores, but there can't be gaps in between bitregions.  */
>        else if (info->bitregion_start <= merged_store->bitregion_end
> -	       && info->rhs_code == merged_store->stores[0]->rhs_code)
> +	       && info->rhs_code == merged_store->stores[0]->rhs_code
> +	       && info->bit_not_p == merged_store->stores[0]->bit_not_p)
>  	{
>  	  store_immediate_info *infof = merged_store->stores[0];
>  
> @@ -1386,6 +1389,17 @@ count_multiple_uses (store_immediate_inf
>      case BIT_AND_EXPR:
>      case BIT_IOR_EXPR:
>      case BIT_XOR_EXPR:
> +      if (info->bit_not_p)
> +	{
> +	  if (!has_single_use (gimple_assign_rhs1 (stmt)))
> +	    ret = 1; /* Fall through below to return
> +			the BIT_NOT_EXPR stmt and then
> +			BIT_{AND,IOR,XOR}_EXPR and anything it
> +			uses.  */
> +	  else
> +	    /* stmt is after this the BIT_NOT_EXPR.  */
> +	    stmt = SSA_NAME_DEF_STMT (gimple_assign_rhs1 (stmt));
> +	}
>        if (!has_single_use (gimple_assign_rhs1 (stmt)))
>  	{
>  	  ret += 1 + info->ops[0].bit_not_p;
> @@ -1479,6 +1493,8 @@ split_group (merged_store_group *group,
>  	case BIT_AND_EXPR:
>  	case BIT_IOR_EXPR:
>  	case BIT_XOR_EXPR:
> +	  if (info->bit_not_p)
> +	    total_orig[0]++; /* The orig BIT_NOT_EXPR stmt.  */
>  	  total_orig[0]++; /* The orig BIT_*_EXPR stmt.  */
>  	  break;
>  	default:
> @@ -1649,6 +1665,8 @@ split_group (merged_store_group *group,
>  	case BIT_AND_EXPR:
>  	case BIT_IOR_EXPR:
>  	case BIT_XOR_EXPR:
> +	  if (info->bit_not_p)
> +	    total_new[0] += ret; /* The new BIT_NOT_EXPR stmt.  */
>  	  total_new[0] += ret; /* The new BIT_*_EXPR stmt.  */
>  	  break;
>  	default:
> @@ -1918,6 +1936,17 @@ imm_store_chain_info::output_merged_stor
>  	      else
>  		gimple_seq_add_stmt_without_update (&seq, stmt);
>  	      src = gimple_assign_lhs (stmt);
> +	      if (split_store->orig_stores[0]->bit_not_p)
> +		{
> +		  stmt = gimple_build_assign (make_ssa_name (int_type),
> +					      BIT_NOT_EXPR, src);
> +		  gimple_set_location (stmt, bit_loc);
> +		  if (load_addr[1] == NULL_TREE && gsi_bb (load_gsi[0]))
> +		    gimple_seq_add_stmt_without_update (&load_seq[0], stmt);
> +		  else
> +		    gimple_seq_add_stmt_without_update (&seq, stmt);
> +		  src = gimple_assign_lhs (stmt);
> +		}
>  	      break;
>  	    default:
>  	      src = ops[0];
> @@ -2232,6 +2261,11 @@ handled_load (gimple *stmt, store_operan
>  	  && handled_load (SSA_NAME_DEF_STMT (rhs1), op, bitsize, bitpos,
>  			   bitregion_start, bitregion_end))
>  	{
> +	  /* Don't allow _1 = load; _2 = ~1; _3 = ~_2; which should have
> +	     been optimized earlier, but if allowed here, would confuse the
> +	     multiple uses counting.  */
> +	  if (op->bit_not_p)
> +	    return false;
>  	  op->bit_not_p = !op->bit_not_p;
>  	  return true;
>  	}
> @@ -2283,6 +2317,7 @@ pass_store_merging::process_store (gimpl
>  		  || ((bitsize > MAX_BITSIZE_MODE_ANY_INT)
>  		       && (TREE_CODE (rhs) != INTEGER_CST)));
>    enum tree_code rhs_code = ERROR_MARK;
> +  bool bit_not_p = false;
>    store_operand_info ops[2];
>    if (invalid)
>      ;
> @@ -2301,7 +2336,17 @@ pass_store_merging::process_store (gimpl
>        else if (handled_load (def_stmt, &ops[0], bitsize, bitpos,
>  			     bitregion_start, bitregion_end))
>  	rhs_code = MEM_REF;
> -      else
> +      else if (gimple_assign_rhs_code (def_stmt) == BIT_NOT_EXPR) 
> +	{
> +	  tree rhs1 = gimple_assign_rhs1 (def_stmt);
> +	  if (TREE_CODE (rhs1) == SSA_NAME
> +	      && is_gimple_assign (SSA_NAME_DEF_STMT (rhs1)))
> +	    {
> +	      bit_not_p = true;
> +	      def_stmt = SSA_NAME_DEF_STMT (rhs1);
> +	    }
> +	}
> +      if (rhs_code == ERROR_MARK && !invalid)
>  	switch ((rhs_code = gimple_assign_rhs_code (def_stmt)))
>  	  {
>  	  case BIT_AND_EXPR:
> @@ -2355,7 +2400,7 @@ pass_store_merging::process_store (gimpl
>        unsigned int ord = (*chain_info)->m_store_info.length ();
>        info = new store_immediate_info (bitsize, bitpos, bitregion_start,
>  				       bitregion_end, stmt, ord, rhs_code,
> -				       ops[0], ops[1]);
> +				       bit_not_p, ops[0], ops[1]);
>        if (dump_file && (dump_flags & TDF_DETAILS))
>  	{
>  	  fprintf (dump_file, "Recording immediate store from stmt:\n");
> @@ -2383,7 +2428,7 @@ pass_store_merging::process_store (gimpl
>      = new imm_store_chain_info (m_stores_head, base_addr);
>    info = new store_immediate_info (bitsize, bitpos, bitregion_start,
>  				   bitregion_end, stmt, 0, rhs_code,
> -				   ops[0], ops[1]);
> +				   bit_not_p, ops[0], ops[1]);
>    new_chain->m_store_info.safe_push (info);
>    m_stores.put (base_addr, new_chain);
>    if (dump_file && (dump_flags & TDF_DETAILS))
> 
> 	Jakub
> 
>
diff mbox series

Patch

--- gcc/gimple-ssa-store-merging.c.jj	2017-11-09 12:40:27.000000000 +0100
+++ gcc/gimple-ssa-store-merging.c	2017-11-09 14:00:46.269673305 +0100
@@ -209,12 +209,13 @@  struct store_immediate_info
   /* INTEGER_CST for constant stores, MEM_REF for memory copy or
      BIT_*_EXPR for logical bitwise operation.  */
   enum tree_code rhs_code;
+  bool bit_not_p;
   /* Operands.  For BIT_*_EXPR rhs_code both operands are used, otherwise
      just the first one.  */
   store_operand_info ops[2];
   store_immediate_info (unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT,
 			unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT,
-			gimple *, unsigned int, enum tree_code,
+			gimple *, unsigned int, enum tree_code, bool,
 			const store_operand_info &,
 			const store_operand_info &);
 };
@@ -226,10 +227,11 @@  store_immediate_info::store_immediate_in
 					    gimple *st,
 					    unsigned int ord,
 					    enum tree_code rhscode,
+					    bool bitnotp,
 					    const store_operand_info &op0r,
 					    const store_operand_info &op1r)
   : bitsize (bs), bitpos (bp), bitregion_start (brs), bitregion_end (bre),
-    stmt (st), order (ord), rhs_code (rhscode)
+    stmt (st), order (ord), rhs_code (rhscode), bit_not_p (bitnotp)
 #if __cplusplus >= 201103L
     , ops { op0r, op1r }
 {
@@ -1169,7 +1171,8 @@  imm_store_chain_info::coalesce_immediate
 	 Merge it into the current store group.  There can be gaps in between
 	 the stores, but there can't be gaps in between bitregions.  */
       else if (info->bitregion_start <= merged_store->bitregion_end
-	       && info->rhs_code == merged_store->stores[0]->rhs_code)
+	       && info->rhs_code == merged_store->stores[0]->rhs_code
+	       && info->bit_not_p == merged_store->stores[0]->bit_not_p)
 	{
 	  store_immediate_info *infof = merged_store->stores[0];
 
@@ -1386,6 +1389,17 @@  count_multiple_uses (store_immediate_inf
     case BIT_AND_EXPR:
     case BIT_IOR_EXPR:
     case BIT_XOR_EXPR:
+      if (info->bit_not_p)
+	{
+	  if (!has_single_use (gimple_assign_rhs1 (stmt)))
+	    ret = 1; /* Fall through below to return
+			the BIT_NOT_EXPR stmt and then
+			BIT_{AND,IOR,XOR}_EXPR and anything it
+			uses.  */
+	  else
+	    /* stmt is after this the BIT_NOT_EXPR.  */
+	    stmt = SSA_NAME_DEF_STMT (gimple_assign_rhs1 (stmt));
+	}
       if (!has_single_use (gimple_assign_rhs1 (stmt)))
 	{
 	  ret += 1 + info->ops[0].bit_not_p;
@@ -1479,6 +1493,8 @@  split_group (merged_store_group *group,
 	case BIT_AND_EXPR:
 	case BIT_IOR_EXPR:
 	case BIT_XOR_EXPR:
+	  if (info->bit_not_p)
+	    total_orig[0]++; /* The orig BIT_NOT_EXPR stmt.  */
 	  total_orig[0]++; /* The orig BIT_*_EXPR stmt.  */
 	  break;
 	default:
@@ -1649,6 +1665,8 @@  split_group (merged_store_group *group,
 	case BIT_AND_EXPR:
 	case BIT_IOR_EXPR:
 	case BIT_XOR_EXPR:
+	  if (info->bit_not_p)
+	    total_new[0] += ret; /* The new BIT_NOT_EXPR stmt.  */
 	  total_new[0] += ret; /* The new BIT_*_EXPR stmt.  */
 	  break;
 	default:
@@ -1918,6 +1936,17 @@  imm_store_chain_info::output_merged_stor
 	      else
 		gimple_seq_add_stmt_without_update (&seq, stmt);
 	      src = gimple_assign_lhs (stmt);
+	      if (split_store->orig_stores[0]->bit_not_p)
+		{
+		  stmt = gimple_build_assign (make_ssa_name (int_type),
+					      BIT_NOT_EXPR, src);
+		  gimple_set_location (stmt, bit_loc);
+		  if (load_addr[1] == NULL_TREE && gsi_bb (load_gsi[0]))
+		    gimple_seq_add_stmt_without_update (&load_seq[0], stmt);
+		  else
+		    gimple_seq_add_stmt_without_update (&seq, stmt);
+		  src = gimple_assign_lhs (stmt);
+		}
 	      break;
 	    default:
 	      src = ops[0];
@@ -2232,6 +2261,11 @@  handled_load (gimple *stmt, store_operan
 	  && handled_load (SSA_NAME_DEF_STMT (rhs1), op, bitsize, bitpos,
 			   bitregion_start, bitregion_end))
 	{
+	  /* Don't allow _1 = load; _2 = ~1; _3 = ~_2; which should have
+	     been optimized earlier, but if allowed here, would confuse the
+	     multiple uses counting.  */
+	  if (op->bit_not_p)
+	    return false;
 	  op->bit_not_p = !op->bit_not_p;
 	  return true;
 	}
@@ -2283,6 +2317,7 @@  pass_store_merging::process_store (gimpl
 		  || ((bitsize > MAX_BITSIZE_MODE_ANY_INT)
 		       && (TREE_CODE (rhs) != INTEGER_CST)));
   enum tree_code rhs_code = ERROR_MARK;
+  bool bit_not_p = false;
   store_operand_info ops[2];
   if (invalid)
     ;
@@ -2301,7 +2336,17 @@  pass_store_merging::process_store (gimpl
       else if (handled_load (def_stmt, &ops[0], bitsize, bitpos,
 			     bitregion_start, bitregion_end))
 	rhs_code = MEM_REF;
-      else
+      else if (gimple_assign_rhs_code (def_stmt) == BIT_NOT_EXPR) 
+	{
+	  tree rhs1 = gimple_assign_rhs1 (def_stmt);
+	  if (TREE_CODE (rhs1) == SSA_NAME
+	      && is_gimple_assign (SSA_NAME_DEF_STMT (rhs1)))
+	    {
+	      bit_not_p = true;
+	      def_stmt = SSA_NAME_DEF_STMT (rhs1);
+	    }
+	}
+      if (rhs_code == ERROR_MARK && !invalid)
 	switch ((rhs_code = gimple_assign_rhs_code (def_stmt)))
 	  {
 	  case BIT_AND_EXPR:
@@ -2355,7 +2400,7 @@  pass_store_merging::process_store (gimpl
       unsigned int ord = (*chain_info)->m_store_info.length ();
       info = new store_immediate_info (bitsize, bitpos, bitregion_start,
 				       bitregion_end, stmt, ord, rhs_code,
-				       ops[0], ops[1]);
+				       bit_not_p, ops[0], ops[1]);
       if (dump_file && (dump_flags & TDF_DETAILS))
 	{
 	  fprintf (dump_file, "Recording immediate store from stmt:\n");
@@ -2383,7 +2428,7 @@  pass_store_merging::process_store (gimpl
     = new imm_store_chain_info (m_stores_head, base_addr);
   info = new store_immediate_info (bitsize, bitpos, bitregion_start,
 				   bitregion_end, stmt, 0, rhs_code,
-				   ops[0], ops[1]);
+				   bit_not_p, ops[0], ops[1]);
   new_chain->m_store_info.safe_push (info);
   m_stores.put (base_addr, new_chain);
   if (dump_file && (dump_flags & TDF_DETAILS))