Disallow pointer operands for |, ^ and partly & [PR106878]

Message ID YyGGD/5HXAXh13N0@tucnak
State New, archived
Headers
Series Disallow pointer operands for |, ^ and partly & [PR106878] |

Commit Message

Jakub Jelinek Sept. 14, 2022, 7:43 a.m. UTC
  Hi!

My change to match.pd (that added the two simplifications this patch
touches) results in more |/^/& assignments with pointer arguments,
but since r12-1608 we reject pointer operands for BIT_NOT_EXPR.

Disallowing them for BIT_NOT_EXPR and allowing for BIT_{IOR,XOR,AND}_EXPR
leads to a match.pd maintainance nightmare (see one of the patches in the
PR), so either we want to allow pointer operand on BIT_NOT_EXPR (but then
we run into issues e.g. with the ranger which expects it can emulate
BIT_NOT_EXPR ~X as - 1 - X which doesn't work for pointers which don't
support MINUS_EXPR), or the following patch disallows pointer arguments
for all of BIT_{IOR,XOR,AND}_EXPR with the exception of BIT_AND_EXPR
with INTEGER_CST last operand (for simpler pointer realignment).
I had to tweak one reassoc optimization and the two match.pd
simplifications.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

P.S.: I know it would be better for the verifiers to have positive
set of types it wants to allow for each operation, but I have no idea
what exactly we use there right now.

2022-09-14  Jakub Jelinek  <jakub@redhat.com>

	PR tree-optimization/106878
	* tree-cfg.cc (verify_gimple_assign_binary): Disallow pointer,
	reference or OFFSET_TYPE BIT_IOR_EXPR, BIT_XOR_EXPR or, unless
	the second argument is INTEGER_CST, BIT_AND_EXPR.
	* match.pd ((type) X op CST -> (type) (X op ((type-x) CST)),
	(type) (((type2) X) op Y) -> (X op (type) Y)): Punt for
	POINTER_TYPE_P or OFFSET_TYPE.
	* tree-ssa-reassoc.cc (optimize_range_tests_cmp_bitwise): For
	pointers cast them to pointer sized integers first.

	* gcc.c-torture/compile/pr106878.c: New test.


	Jakub
  

Comments

Richard Biener Sept. 14, 2022, 7:58 a.m. UTC | #1
On Wed, 14 Sep 2022, Jakub Jelinek wrote:

> Hi!
> 
> My change to match.pd (that added the two simplifications this patch
> touches) results in more |/^/& assignments with pointer arguments,
> but since r12-1608 we reject pointer operands for BIT_NOT_EXPR.
> 
> Disallowing them for BIT_NOT_EXPR and allowing for BIT_{IOR,XOR,AND}_EXPR
> leads to a match.pd maintainance nightmare (see one of the patches in the
> PR), so either we want to allow pointer operand on BIT_NOT_EXPR (but then
> we run into issues e.g. with the ranger which expects it can emulate
> BIT_NOT_EXPR ~X as - 1 - X which doesn't work for pointers which don't
> support MINUS_EXPR), or the following patch disallows pointer arguments
> for all of BIT_{IOR,XOR,AND}_EXPR with the exception of BIT_AND_EXPR
> with INTEGER_CST last operand (for simpler pointer realignment).
> I had to tweak one reassoc optimization and the two match.pd
> simplifications.
> 
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

OK.

Did you check what breaks when we reverse the decision to allow
BIT_AND_EXPR to align pointers alltogether?  I think we don't
have any

 (T')(((T)ptr) & CST) -> ptr & CST

folding at least.  But I guess some passes that build pointer
re-alignments might need adjustment.

> P.S.: I know it would be better for the verifiers to have positive
> set of types it wants to allow for each operation, but I have no idea
> what exactly we use there right now.

I think for BIT_*_EXPR we want ANY_INTEGRAL_TYPE_P (well, likely
not complex int, but ...).  So if a patch to check that passes
bootstrap that would be nice to have.

Richard.

> 2022-09-14  Jakub Jelinek  <jakub@redhat.com>
> 
> 	PR tree-optimization/106878
> 	* tree-cfg.cc (verify_gimple_assign_binary): Disallow pointer,
> 	reference or OFFSET_TYPE BIT_IOR_EXPR, BIT_XOR_EXPR or, unless
> 	the second argument is INTEGER_CST, BIT_AND_EXPR.
> 	* match.pd ((type) X op CST -> (type) (X op ((type-x) CST)),
> 	(type) (((type2) X) op Y) -> (X op (type) Y)): Punt for
> 	POINTER_TYPE_P or OFFSET_TYPE.
> 	* tree-ssa-reassoc.cc (optimize_range_tests_cmp_bitwise): For
> 	pointers cast them to pointer sized integers first.
> 
> 	* gcc.c-torture/compile/pr106878.c: New test.
> 
> --- gcc/tree-cfg.cc.jj	2022-09-08 20:22:07.788184491 +0200
> +++ gcc/tree-cfg.cc	2022-09-13 09:28:53.563243962 +0200
> @@ -4167,6 +4167,8 @@ verify_gimple_assign_binary (gassign *st
>      case ROUND_MOD_EXPR:
>      case RDIV_EXPR:
>      case EXACT_DIV_EXPR:
> +    case BIT_IOR_EXPR:
> +    case BIT_XOR_EXPR:
>        /* Disallow pointer and offset types for many of the binary gimple. */
>        if (POINTER_TYPE_P (lhs_type)
>  	  || TREE_CODE (lhs_type) == OFFSET_TYPE)
> @@ -4182,9 +4184,23 @@ verify_gimple_assign_binary (gassign *st
>  
>      case MIN_EXPR:
>      case MAX_EXPR:
> -    case BIT_IOR_EXPR:
> -    case BIT_XOR_EXPR:
> +      /* Continue with generic binary expression handling.  */
> +      break;
> +
>      case BIT_AND_EXPR:
> +      if (POINTER_TYPE_P (lhs_type)
> +	  && TREE_CODE (rhs2) == INTEGER_CST)
> +	break;
> +      /* Disallow pointer and offset types for many of the binary gimple. */
> +      if (POINTER_TYPE_P (lhs_type)
> +	  || TREE_CODE (lhs_type) == OFFSET_TYPE)
> +	{
> +	  error ("invalid types for %qs", code_name);
> +	  debug_generic_expr (lhs_type);
> +	  debug_generic_expr (rhs1_type);
> +	  debug_generic_expr (rhs2_type);
> +	  return true;
> +	}
>        /* Continue with generic binary expression handling.  */
>        break;
>  
> --- gcc/match.pd.jj	2022-09-08 20:22:00.836276502 +0200
> +++ gcc/match.pd	2022-09-13 10:21:04.567853941 +0200
> @@ -1763,6 +1763,8 @@ (define_operator_list SYNC_FETCH_AND_AND
>  	 && (int_fits_type_p (@1, TREE_TYPE (@0))
>  	     || tree_nop_conversion_p (TREE_TYPE (@0), type)))
>  	|| types_match (@0, @1))
> +       && !POINTER_TYPE_P (TREE_TYPE (@0))
> +       && TREE_CODE (TREE_TYPE (@0)) != OFFSET_TYPE
>         /* ???  This transform conflicts with fold-const.cc doing
>  	  Convert (T)(x & c) into (T)x & (T)c, if c is an integer
>  	  constants (if x has signed type, the sign bit cannot be set
> @@ -1799,7 +1801,9 @@ (define_operator_list SYNC_FETCH_AND_AND
>    (if (GIMPLE
>         && TREE_CODE (@1) != INTEGER_CST
>         && tree_nop_conversion_p (type, TREE_TYPE (@2))
> -       && types_match (type, @0))
> +       && types_match (type, @0)
> +       && !POINTER_TYPE_P (TREE_TYPE (@0))
> +       && TREE_CODE (TREE_TYPE (@0)) != OFFSET_TYPE)
>     (bitop @0 (convert @1)))))
>  
>  (for bitop (bit_and bit_ior)
> --- gcc/tree-ssa-reassoc.cc.jj	2022-06-28 13:03:31.292684917 +0200
> +++ gcc/tree-ssa-reassoc.cc	2022-09-13 10:18:27.466085947 +0200
> @@ -3608,10 +3608,14 @@ optimize_range_tests_cmp_bitwise (enum t
>  	tree type2 = NULL_TREE;
>  	bool strict_overflow_p = false;
>  	candidates.truncate (0);
> +	if (POINTER_TYPE_P (type1))
> +	  type1 = pointer_sized_int_node;
>  	for (j = i; j; j = chains[j - 1])
>  	  {
>  	    tree type = TREE_TYPE (ranges[j - 1].exp);
>  	    strict_overflow_p |= ranges[j - 1].strict_overflow_p;
> +	    if (POINTER_TYPE_P (type))
> +	      type = pointer_sized_int_node;
>  	    if ((b % 4) == 3)
>  	      {
>  		/* For the signed < 0 cases, the types should be
> @@ -3642,6 +3646,8 @@ optimize_range_tests_cmp_bitwise (enum t
>  	    tree type = TREE_TYPE (ranges[j - 1].exp);
>  	    if (j == k)
>  	      continue;
> +	    if (POINTER_TYPE_P (type))
> +	      type = pointer_sized_int_node;
>  	    if ((b % 4) == 3)
>  	      {
>  		if (!useless_type_conversion_p (type1, type))
> @@ -3671,7 +3677,7 @@ optimize_range_tests_cmp_bitwise (enum t
>  		op = r->exp;
>  		continue;
>  	      }
> -	    if (id == l)
> +	    if (id == l || POINTER_TYPE_P (TREE_TYPE (op)))
>  	      {
>  		code = (b % 4) == 3 ? BIT_NOT_EXPR : NOP_EXPR;
>  		g = gimple_build_assign (make_ssa_name (type1), code, op);
> @@ -3695,6 +3701,14 @@ optimize_range_tests_cmp_bitwise (enum t
>  	    gimple_seq_add_stmt_without_update (&seq, g);
>  	    op = gimple_assign_lhs (g);
>  	  }
> +	type1 = TREE_TYPE (ranges[k - 1].exp);
> +	if (POINTER_TYPE_P (type1))
> +	  {
> +	    gimple *g
> +	      = gimple_build_assign (make_ssa_name (type1), NOP_EXPR, op);
> +	    gimple_seq_add_stmt_without_update (&seq, g);
> +	    op = gimple_assign_lhs (g);
> +	  }
>  	candidates.pop ();
>  	if (update_range_test (&ranges[k - 1], NULL, candidates.address (),
>  			       candidates.length (), opcode, ops, op,
> --- gcc/testsuite/gcc.c-torture/compile/pr106878.c.jj	2022-09-13 10:21:04.567853941 +0200
> +++ gcc/testsuite/gcc.c-torture/compile/pr106878.c	2022-09-13 10:21:04.567853941 +0200
> @@ -0,0 +1,15 @@
> +/* PR tree-optimization/106878 */
> +
> +typedef __INTPTR_TYPE__ intptr_t;
> +typedef __UINTPTR_TYPE__ uintptr_t;
> +int a;
> +
> +int
> +foo (const int *c)
> +{
> +  uintptr_t d = ((intptr_t) c | (intptr_t) &a) & 65535 << 16;
> +  intptr_t e = (intptr_t) c;
> +  if (d != (e & 65535 << 16))
> +    return 1;
> +  return 0;
> +}
> 
> 	Jakub
> 
>
  
Jakub Jelinek Sept. 14, 2022, 8:47 a.m. UTC | #2
On Wed, Sep 14, 2022 at 07:58:47AM +0000, Richard Biener wrote:
> > My change to match.pd (that added the two simplifications this patch
> > touches) results in more |/^/& assignments with pointer arguments,
> > but since r12-1608 we reject pointer operands for BIT_NOT_EXPR.
> > 
> > Disallowing them for BIT_NOT_EXPR and allowing for BIT_{IOR,XOR,AND}_EXPR
> > leads to a match.pd maintainance nightmare (see one of the patches in the
> > PR), so either we want to allow pointer operand on BIT_NOT_EXPR (but then
> > we run into issues e.g. with the ranger which expects it can emulate
> > BIT_NOT_EXPR ~X as - 1 - X which doesn't work for pointers which don't
> > support MINUS_EXPR), or the following patch disallows pointer arguments
> > for all of BIT_{IOR,XOR,AND}_EXPR with the exception of BIT_AND_EXPR
> > with INTEGER_CST last operand (for simpler pointer realignment).
> > I had to tweak one reassoc optimization and the two match.pd
> > simplifications.
> > 
> > Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
> 
> OK.

Thanks.

> Did you check what breaks when we reverse the decision to allow
> BIT_AND_EXPR to align pointers alltogether?  I think we don't
> have any
> 
>  (T')(((T)ptr) & CST) -> ptr & CST

I haven't tried that, but can try that next.
Would prefer a few days in between so if my current patch affects other
arches it is reported.

> I think for BIT_*_EXPR we want ANY_INTEGRAL_TYPE_P (well, likely
> not complex int, but ...).  So if a patch to check that passes
> bootstrap that would be nice to have.

And can try that as the third step then.

	Jakub
  

Patch

--- gcc/tree-cfg.cc.jj	2022-09-08 20:22:07.788184491 +0200
+++ gcc/tree-cfg.cc	2022-09-13 09:28:53.563243962 +0200
@@ -4167,6 +4167,8 @@  verify_gimple_assign_binary (gassign *st
     case ROUND_MOD_EXPR:
     case RDIV_EXPR:
     case EXACT_DIV_EXPR:
+    case BIT_IOR_EXPR:
+    case BIT_XOR_EXPR:
       /* Disallow pointer and offset types for many of the binary gimple. */
       if (POINTER_TYPE_P (lhs_type)
 	  || TREE_CODE (lhs_type) == OFFSET_TYPE)
@@ -4182,9 +4184,23 @@  verify_gimple_assign_binary (gassign *st
 
     case MIN_EXPR:
     case MAX_EXPR:
-    case BIT_IOR_EXPR:
-    case BIT_XOR_EXPR:
+      /* Continue with generic binary expression handling.  */
+      break;
+
     case BIT_AND_EXPR:
+      if (POINTER_TYPE_P (lhs_type)
+	  && TREE_CODE (rhs2) == INTEGER_CST)
+	break;
+      /* Disallow pointer and offset types for many of the binary gimple. */
+      if (POINTER_TYPE_P (lhs_type)
+	  || TREE_CODE (lhs_type) == OFFSET_TYPE)
+	{
+	  error ("invalid types for %qs", code_name);
+	  debug_generic_expr (lhs_type);
+	  debug_generic_expr (rhs1_type);
+	  debug_generic_expr (rhs2_type);
+	  return true;
+	}
       /* Continue with generic binary expression handling.  */
       break;
 
--- gcc/match.pd.jj	2022-09-08 20:22:00.836276502 +0200
+++ gcc/match.pd	2022-09-13 10:21:04.567853941 +0200
@@ -1763,6 +1763,8 @@  (define_operator_list SYNC_FETCH_AND_AND
 	 && (int_fits_type_p (@1, TREE_TYPE (@0))
 	     || tree_nop_conversion_p (TREE_TYPE (@0), type)))
 	|| types_match (@0, @1))
+       && !POINTER_TYPE_P (TREE_TYPE (@0))
+       && TREE_CODE (TREE_TYPE (@0)) != OFFSET_TYPE
        /* ???  This transform conflicts with fold-const.cc doing
 	  Convert (T)(x & c) into (T)x & (T)c, if c is an integer
 	  constants (if x has signed type, the sign bit cannot be set
@@ -1799,7 +1801,9 @@  (define_operator_list SYNC_FETCH_AND_AND
   (if (GIMPLE
        && TREE_CODE (@1) != INTEGER_CST
        && tree_nop_conversion_p (type, TREE_TYPE (@2))
-       && types_match (type, @0))
+       && types_match (type, @0)
+       && !POINTER_TYPE_P (TREE_TYPE (@0))
+       && TREE_CODE (TREE_TYPE (@0)) != OFFSET_TYPE)
    (bitop @0 (convert @1)))))
 
 (for bitop (bit_and bit_ior)
--- gcc/tree-ssa-reassoc.cc.jj	2022-06-28 13:03:31.292684917 +0200
+++ gcc/tree-ssa-reassoc.cc	2022-09-13 10:18:27.466085947 +0200
@@ -3608,10 +3608,14 @@  optimize_range_tests_cmp_bitwise (enum t
 	tree type2 = NULL_TREE;
 	bool strict_overflow_p = false;
 	candidates.truncate (0);
+	if (POINTER_TYPE_P (type1))
+	  type1 = pointer_sized_int_node;
 	for (j = i; j; j = chains[j - 1])
 	  {
 	    tree type = TREE_TYPE (ranges[j - 1].exp);
 	    strict_overflow_p |= ranges[j - 1].strict_overflow_p;
+	    if (POINTER_TYPE_P (type))
+	      type = pointer_sized_int_node;
 	    if ((b % 4) == 3)
 	      {
 		/* For the signed < 0 cases, the types should be
@@ -3642,6 +3646,8 @@  optimize_range_tests_cmp_bitwise (enum t
 	    tree type = TREE_TYPE (ranges[j - 1].exp);
 	    if (j == k)
 	      continue;
+	    if (POINTER_TYPE_P (type))
+	      type = pointer_sized_int_node;
 	    if ((b % 4) == 3)
 	      {
 		if (!useless_type_conversion_p (type1, type))
@@ -3671,7 +3677,7 @@  optimize_range_tests_cmp_bitwise (enum t
 		op = r->exp;
 		continue;
 	      }
-	    if (id == l)
+	    if (id == l || POINTER_TYPE_P (TREE_TYPE (op)))
 	      {
 		code = (b % 4) == 3 ? BIT_NOT_EXPR : NOP_EXPR;
 		g = gimple_build_assign (make_ssa_name (type1), code, op);
@@ -3695,6 +3701,14 @@  optimize_range_tests_cmp_bitwise (enum t
 	    gimple_seq_add_stmt_without_update (&seq, g);
 	    op = gimple_assign_lhs (g);
 	  }
+	type1 = TREE_TYPE (ranges[k - 1].exp);
+	if (POINTER_TYPE_P (type1))
+	  {
+	    gimple *g
+	      = gimple_build_assign (make_ssa_name (type1), NOP_EXPR, op);
+	    gimple_seq_add_stmt_without_update (&seq, g);
+	    op = gimple_assign_lhs (g);
+	  }
 	candidates.pop ();
 	if (update_range_test (&ranges[k - 1], NULL, candidates.address (),
 			       candidates.length (), opcode, ops, op,
--- gcc/testsuite/gcc.c-torture/compile/pr106878.c.jj	2022-09-13 10:21:04.567853941 +0200
+++ gcc/testsuite/gcc.c-torture/compile/pr106878.c	2022-09-13 10:21:04.567853941 +0200
@@ -0,0 +1,15 @@ 
+/* PR tree-optimization/106878 */
+
+typedef __INTPTR_TYPE__ intptr_t;
+typedef __UINTPTR_TYPE__ uintptr_t;
+int a;
+
+int
+foo (const int *c)
+{
+  uintptr_t d = ((intptr_t) c | (intptr_t) &a) & 65535 << 16;
+  intptr_t e = (intptr_t) c;
+  if (d != (e & 65535 << 16))
+    return 1;
+  return 0;
+}