This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [RFC PATCH] Fix pointer diff (was: -fsanitize=pointer-overflow support (PR sanitizer/80998))


On Mon, 3 Jul 2017, Richard Biener wrote:

On Sat, 1 Jul 2017, Marc Glisse wrote:

I wrote a quick prototype to see what the fallout would look like.
Surprisingly, it actually passes bootstrap+testsuite on ppc64el with all
languages with no regression. Sure, it is probably not a complete
migration, there are likely a few places still converting to ptrdiff_t
to perform a regular subtraction, but this seems to indicate that the
work isn't as bad as using a signed type in pointer_plus_expr for
instance.

The fold_binary_loc hunk looks dangerous (it'll generate MINUS_EXPR
from POINTER_MINUS_EXPR in some cases I guess).

The tree code needs documenting in tree.def and generic.texi.

Otherwise ok(*).

Thanks,
Richard.

(*) ok, just kidding -- or maybe not

I updated the prototype a bit. Some things I noticed:

- the C front-end has support for address spaces that seems to imply that pointer subtraction (and division by the size) may be done in a type larger than ptrdiff_t. Currently, it generates (ptrdiff_t)(((inttype)q-(inttype)p)/size) for q-p where inttype is some type potentially larger than ptrdiff_t. I am thus generating a POINTER_DIFF_EXPR with that type, while I was originally hoping its type would always be ptrdiff_t. It complicates code and I am not sure I didn't break address spaces anyway... (expansion likely needs to do the inttype dance)

Are ptrdiff_t (what POINTER_DIFF_EXPR should return) and size_t (what POINTER_PLUS_EXPR takes as second argument) always the same type signed/unsigned? Counter-examples: m32c (when !TARGET_A16), visium, darwin, powerpcspe, s390, vms... and it isn't even always the same that is bigger than the other. That's quite messy.

- I had to use @@ in match.pd, not for constants, but because in GENERIC we sometimes ended up with pointers where operand_equal_p said yes but types_match disagreed.

- It currently regresses 2 go tests: net/http runtime/debug

--
Marc Glisse
Index: gcc/c/c-fold.c
===================================================================
--- gcc/c/c-fold.c	(revision 253536)
+++ gcc/c/c-fold.c	(working copy)
@@ -238,20 +238,21 @@ c_fully_fold_internal (tree expr, bool i
     case COMPOUND_EXPR:
     case MODIFY_EXPR:
     case PREDECREMENT_EXPR:
     case PREINCREMENT_EXPR:
     case POSTDECREMENT_EXPR:
     case POSTINCREMENT_EXPR:
     case PLUS_EXPR:
     case MINUS_EXPR:
     case MULT_EXPR:
     case POINTER_PLUS_EXPR:
+    case POINTER_DIFF_EXPR:
     case TRUNC_DIV_EXPR:
     case CEIL_DIV_EXPR:
     case FLOOR_DIV_EXPR:
     case TRUNC_MOD_EXPR:
     case RDIV_EXPR:
     case EXACT_DIV_EXPR:
     case LSHIFT_EXPR:
     case RSHIFT_EXPR:
     case BIT_IOR_EXPR:
     case BIT_XOR_EXPR:
Index: gcc/c/c-typeck.c
===================================================================
--- gcc/c/c-typeck.c	(revision 253536)
+++ gcc/c/c-typeck.c	(working copy)
@@ -3772,21 +3772,21 @@ parser_build_binary_op (location_t locat
       && TREE_CODE (type2) == ENUMERAL_TYPE
       && TYPE_MAIN_VARIANT (type1) != TYPE_MAIN_VARIANT (type2))
     warning_at (location, OPT_Wenum_compare,
 		"comparison between %qT and %qT",
 		type1, type2);
 
   return result;
 }
 
 /* Return a tree for the difference of pointers OP0 and OP1.
-   The resulting tree has type int.  */
+   The resulting tree has type ptrdiff_t.  */
 
 static tree
 pointer_diff (location_t loc, tree op0, tree op1)
 {
   tree restype = ptrdiff_type_node;
   tree result, inttype;
 
   addr_space_t as0 = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (op0)));
   addr_space_t as1 = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (op1)));
   tree target_type = TREE_TYPE (TREE_TYPE (op0));
@@ -3824,23 +3824,21 @@ pointer_diff (location_t loc, tree op0,
 	     "pointer of type %<void *%> used in subtraction");
   if (TREE_CODE (target_type) == FUNCTION_TYPE)
     pedwarn (loc, OPT_Wpointer_arith,
 	     "pointer to a function used in subtraction");
 
   /* First do the subtraction as integers;
      then drop through to build the divide operator.
      Do not do default conversions on the minus operator
      in case restype is a short type.  */
 
-  op0 = build_binary_op (loc,
-			 MINUS_EXPR, convert (inttype, op0),
-			 convert (inttype, op1), false);
+  op0 = build2_loc (loc, POINTER_DIFF_EXPR, inttype, op0, op1);
   /* This generates an error if op1 is pointer to incomplete type.  */
   if (!COMPLETE_OR_VOID_TYPE_P (TREE_TYPE (TREE_TYPE (orig_op1))))
     error_at (loc, "arithmetic on pointer to an incomplete type");
 
   op1 = c_size_in_bytes (target_type);
 
   if (pointer_to_zero_sized_aggr_p (TREE_TYPE (orig_op1)))
     error_at (loc, "arithmetic on pointer to an empty aggregate");
 
   /* Divide by the size, in easiest possible way.  */
Index: gcc/c-family/c-pretty-print.c
===================================================================
--- gcc/c-family/c-pretty-print.c	(revision 253536)
+++ gcc/c-family/c-pretty-print.c	(working copy)
@@ -1869,20 +1869,21 @@ c_pretty_printer::multiplicative_express
       additive-expression - multiplicative-expression   */
 
 static void
 pp_c_additive_expression (c_pretty_printer *pp, tree e)
 {
   enum tree_code code = TREE_CODE (e);
   switch (code)
     {
     case POINTER_PLUS_EXPR:
     case PLUS_EXPR:
+    case POINTER_DIFF_EXPR:
     case MINUS_EXPR:
       pp_c_additive_expression (pp, TREE_OPERAND (e, 0));
       pp_c_whitespace (pp);
       if (code == PLUS_EXPR || code == POINTER_PLUS_EXPR)
 	pp_plus (pp);
       else
 	pp_minus (pp);
       pp_c_whitespace (pp);
       pp->multiplicative_expression (TREE_OPERAND (e, 1));
       break;
@@ -2285,20 +2286,21 @@ c_pretty_printer::expression (tree e)
     case NE_EXPR:
       pp_c_equality_expression (this, e);
       break;
 
     case COND_EXPR:
       conditional_expression (e);
       break;
 
     case POINTER_PLUS_EXPR:
     case PLUS_EXPR:
+    case POINTER_DIFF_EXPR:
     case MINUS_EXPR:
       pp_c_additive_expression (this, e);
       break;
 
     case MODIFY_EXPR:
     case INIT_EXPR:
       assignment_expression (e);
       break;
 
     case COMPOUND_EXPR:
Index: gcc/cfgexpand.c
===================================================================
--- gcc/cfgexpand.c	(revision 253536)
+++ gcc/cfgexpand.c	(working copy)
@@ -4597,20 +4597,21 @@ expand_debug_expr (tree exp)
 	    /* We always sign-extend, regardless of the signedness of
 	       the operand, because the operand is always unsigned
 	       here even if the original C expression is signed.  */
 	    op1 = simplify_gen_unary (SIGN_EXTEND, op0_mode, op1, op1_mode);
 	}
       /* Fall through.  */
     case PLUS_EXPR:
       return simplify_gen_binary (PLUS, mode, op0, op1);
 
     case MINUS_EXPR:
+    case POINTER_DIFF_EXPR:
       return simplify_gen_binary (MINUS, mode, op0, op1);
 
     case MULT_EXPR:
       return simplify_gen_binary (MULT, mode, op0, op1);
 
     case RDIV_EXPR:
     case TRUNC_DIV_EXPR:
     case EXACT_DIV_EXPR:
       if (unsignedp)
 	return simplify_gen_binary (UDIV, mode, op0, op1);
Index: gcc/cp/constexpr.c
===================================================================
--- gcc/cp/constexpr.c	(revision 253536)
+++ gcc/cp/constexpr.c	(working copy)
@@ -4265,20 +4265,21 @@ cxx_eval_constant_expression (const cons
 	      return t;
 	    op1 = TREE_OPERAND (t, 1);
 	    r = cxx_eval_constant_expression (ctx, op1,
 					      lval, non_constant_p, overflow_p,
 					      jump_target);
 	  }
       }
       break;
 
     case POINTER_PLUS_EXPR:
+    case POINTER_DIFF_EXPR:
     case PLUS_EXPR:
     case MINUS_EXPR:
     case MULT_EXPR:
     case TRUNC_DIV_EXPR:
     case CEIL_DIV_EXPR:
     case FLOOR_DIV_EXPR:
     case ROUND_DIV_EXPR:
     case TRUNC_MOD_EXPR:
     case CEIL_MOD_EXPR:
     case ROUND_MOD_EXPR:
@@ -5499,20 +5500,21 @@ potential_constant_expression_1 (tree t,
 	    && TYPE_POLYMORPHIC_P (TREE_TYPE (e)))
           {
             if (flags & tf_error)
               error_at (loc, "typeid-expression is not a constant expression "
 			"because %qE is of polymorphic type", e);
             return false;
           }
         return true;
       }
 
+    case POINTER_DIFF_EXPR:
     case MINUS_EXPR:
       want_rval = true;
       goto binary;
 
     case LT_EXPR:
     case LE_EXPR:
     case GT_EXPR:
     case GE_EXPR:
     case EQ_EXPR:
     case NE_EXPR:
Index: gcc/cp/cp-gimplify.c
===================================================================
--- gcc/cp/cp-gimplify.c	(revision 253536)
+++ gcc/cp/cp-gimplify.c	(working copy)
@@ -2205,20 +2205,21 @@ cp_fold (tree x)
     case POSTINCREMENT_EXPR:
     case INIT_EXPR:
     case PREDECREMENT_EXPR:
     case PREINCREMENT_EXPR:
     case COMPOUND_EXPR:
     case MODIFY_EXPR:
       rval_ops = false;
       /* FALLTHRU */
     case POINTER_PLUS_EXPR:
     case PLUS_EXPR:
+    case POINTER_DIFF_EXPR:
     case MINUS_EXPR:
     case MULT_EXPR:
     case TRUNC_DIV_EXPR:
     case CEIL_DIV_EXPR:
     case FLOOR_DIV_EXPR:
     case ROUND_DIV_EXPR:
     case TRUNC_MOD_EXPR:
     case CEIL_MOD_EXPR:
     case ROUND_MOD_EXPR:
     case RDIV_EXPR:
Index: gcc/cp/error.c
===================================================================
--- gcc/cp/error.c	(revision 253536)
+++ gcc/cp/error.c	(working copy)
@@ -2221,20 +2221,24 @@ dump_expr (cxx_pretty_printer *pp, tree
 	 default argument.  Note we may have cleared out the first
 	 operand in expand_expr, so don't go killing ourselves.  */
       if (TREE_OPERAND (t, 1))
 	dump_expr (pp, TREE_OPERAND (t, 1), flags | TFF_EXPR_IN_PARENS);
       break;
 
     case POINTER_PLUS_EXPR:
       dump_binary_op (pp, "+", t, flags);
       break;
 
+    case POINTER_DIFF_EXPR:
+      dump_binary_op (pp, "-", t, flags);
+      break;
+
     case INIT_EXPR:
     case MODIFY_EXPR:
       dump_binary_op (pp, assignment_operator_name_info[NOP_EXPR].name,
 		      t, flags);
       break;
 
     case PLUS_EXPR:
     case MINUS_EXPR:
     case MULT_EXPR:
     case TRUNC_DIV_EXPR:
Index: gcc/cp/typeck.c
===================================================================
--- gcc/cp/typeck.c	(revision 253536)
+++ gcc/cp/typeck.c	(working copy)
@@ -4305,20 +4305,21 @@ cp_build_binary_op (location_t location,
               converted = 1;
               break;
             }
           default:
             break;
         }
     }
 
   switch (code)
     {
+    case POINTER_DIFF_EXPR:
     case MINUS_EXPR:
       /* Subtraction of two similar pointers.
 	 We must subtract them as integers, then divide by object size.  */
       if (code0 == POINTER_TYPE && code1 == POINTER_TYPE
 	  && same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (type0),
 							TREE_TYPE (type1)))
 	return pointer_diff (location, op0, op1,
 			     common_pointer_type (type0, type1), complain);
       /* In all other cases except pointer - int, the usual arithmetic
 	 rules apply.  */
@@ -5397,25 +5398,21 @@ pointer_diff (location_t loc, tree op0,
       if (complain & tf_error)
 	permerror (loc, "ISO C++ forbids using pointer to "
 		   "a method in subtraction");
       else
 	return error_mark_node;
     }
 
   /* First do the subtraction as integers;
      then drop through to build the divide operator.  */
 
-  op0 = cp_build_binary_op (loc,
-			    MINUS_EXPR,
-			    cp_convert (restype, op0, complain),
-			    cp_convert (restype, op1, complain),
-			    complain);
+  op0 = build2_loc (loc, POINTER_DIFF_EXPR, restype, op0, op1);
 
   /* This generates an error if op1 is a pointer to an incomplete type.  */
   if (!COMPLETE_TYPE_P (TREE_TYPE (TREE_TYPE (op1))))
     {
       if (complain & tf_error)
 	error_at (loc, "invalid use of a pointer to an incomplete type in "
 		  "pointer arithmetic");
       else
 	return error_mark_node;
     }
Index: gcc/doc/generic.texi
===================================================================
--- gcc/doc/generic.texi	(revision 253536)
+++ gcc/doc/generic.texi	(working copy)
@@ -1217,20 +1217,21 @@ the byte offset of the field, but should
 @tindex RSHIFT_EXPR
 @tindex BIT_IOR_EXPR
 @tindex BIT_XOR_EXPR
 @tindex BIT_AND_EXPR
 @tindex TRUTH_ANDIF_EXPR
 @tindex TRUTH_ORIF_EXPR
 @tindex TRUTH_AND_EXPR
 @tindex TRUTH_OR_EXPR
 @tindex TRUTH_XOR_EXPR
 @tindex POINTER_PLUS_EXPR
+@tindex POINTER_DIFF_EXPR
 @tindex PLUS_EXPR
 @tindex MINUS_EXPR
 @tindex MULT_EXPR
 @tindex MULT_HIGHPART_EXPR
 @tindex RDIV_EXPR
 @tindex TRUNC_DIV_EXPR
 @tindex FLOOR_DIV_EXPR
 @tindex CEIL_DIV_EXPR
 @tindex ROUND_DIV_EXPR
 @tindex TRUNC_MOD_EXPR
@@ -1406,22 +1407,27 @@ always of @code{BOOLEAN_TYPE} or @code{I
 These nodes represent logical and, logical or, and logical exclusive or.
 They are strict; both arguments are always evaluated.  There are no
 corresponding operators in C or C++, but the front end will sometimes
 generate these expressions anyhow, if it can tell that strictness does
 not matter.  The type of the operands and that of the result are
 always of @code{BOOLEAN_TYPE} or @code{INTEGER_TYPE}.
 
 @item POINTER_PLUS_EXPR
 This node represents pointer arithmetic.  The first operand is always
 a pointer/reference type.  The second operand is always an unsigned
-integer type compatible with sizetype.  This is the only binary
-arithmetic operand that can operate on pointer types.
+integer type compatible with sizetype.  This and POINTER_DIFF_EXPR are
+the only binary arithmetic operators that can operate on pointer types.
+
+@item POINTER_DIFF_EXPR
+This node represents pointer subtraction.  The two operands always
+have pointer/reference type.  The second operand is always an unsigned
+integer type compatible with sizetype.  It returns a signed integer.
 
 @item PLUS_EXPR
 @itemx MINUS_EXPR
 @itemx MULT_EXPR
 These nodes represent various binary arithmetic operations.
 Respectively, these operations are addition, subtraction (of the second
 operand from the first) and multiplication.  Their operands may have
 either integral or floating type, but there will never be case in which
 one operand is of floating type and the other is of integral type.
 
Index: gcc/expr.c
===================================================================
--- gcc/expr.c	(revision 253536)
+++ gcc/expr.c	(working copy)
@@ -8539,20 +8539,21 @@ expand_expr_real_2 (sepops ops, rtx targ
 	  if (op1 == const0_rtx)
 	    return op0;
 	  goto binop2;
 	}
 
       expand_operands (treeop0, treeop1,
 		       subtarget, &op0, &op1, modifier);
       return REDUCE_BIT_FIELD (simplify_gen_binary (PLUS, mode, op0, op1));
 
     case MINUS_EXPR:
+    case POINTER_DIFF_EXPR:
     do_minus:
       /* For initializers, we are allowed to return a MINUS of two
 	 symbolic constants.  Here we handle all cases when both operands
 	 are constant.  */
       /* Handle difference of two symbolic constants,
 	 for the sake of an initializer.  */
       if ((modifier == EXPAND_SUM || modifier == EXPAND_INITIALIZER)
 	  && really_constant_p (treeop0)
 	  && really_constant_p (treeop1))
 	{
Index: gcc/fold-const.c
===================================================================
--- gcc/fold-const.c	(revision 253536)
+++ gcc/fold-const.c	(working copy)
@@ -1130,20 +1130,25 @@ const_binop (enum tree_code code, tree a
     return NULL_TREE;
 
   STRIP_NOPS (arg1);
   STRIP_NOPS (arg2);
 
   if (TREE_CODE (arg1) == INTEGER_CST && TREE_CODE (arg2) == INTEGER_CST)
     {
       if (code == POINTER_PLUS_EXPR)
 	return int_const_binop (PLUS_EXPR,
 				arg1, fold_convert (TREE_TYPE (arg1), arg2));
+      /* FIXME.  */
+      if (code == POINTER_DIFF_EXPR)
+	return int_const_binop (MINUS_EXPR,
+				fold_convert (ptrdiff_type_node, arg1),
+				fold_convert (ptrdiff_type_node, arg2));
 
       return int_const_binop (code, arg1, arg2);
     }
 
   if (TREE_CODE (arg1) == REAL_CST && TREE_CODE (arg2) == REAL_CST)
     {
       machine_mode mode;
       REAL_VALUE_TYPE d1;
       REAL_VALUE_TYPE d2;
       REAL_VALUE_TYPE value;
@@ -8816,24 +8821,23 @@ fold_addr_of_array_ref_difference (locat
   /* If the bases are array references as well, recurse.  If the bases
      are pointer indirections compute the difference of the pointers.
      If the bases are equal, we are set.  */
   if ((TREE_CODE (base0) == ARRAY_REF
        && TREE_CODE (base1) == ARRAY_REF
        && (base_offset
 	   = fold_addr_of_array_ref_difference (loc, type, base0, base1)))
       || (INDIRECT_REF_P (base0)
 	  && INDIRECT_REF_P (base1)
 	  && (base_offset
-	        = fold_binary_loc (loc, MINUS_EXPR, type,
-				   fold_convert (type, TREE_OPERAND (base0, 0)),
-				   fold_convert (type,
-						 TREE_OPERAND (base1, 0)))))
+	        = fold_binary_loc (loc, POINTER_DIFF_EXPR, type,
+				   TREE_OPERAND (base0, 0),
+				   TREE_OPERAND (base1, 0))))
       || operand_equal_p (base0, base1, OEP_ADDRESS_OF))
     {
       tree op0 = fold_convert_loc (loc, type, TREE_OPERAND (aref0, 1));
       tree op1 = fold_convert_loc (loc, type, TREE_OPERAND (aref1, 1));
       tree esz = fold_convert_loc (loc, type, array_ref_element_size (aref0));
       tree diff = fold_build2_loc (loc, MINUS_EXPR, type, op0, op1);
       return fold_build2_loc (loc, PLUS_EXPR, type,
 			      base_offset,
 			      fold_build2_loc (loc, MULT_EXPR, type,
 					       diff, esz));
@@ -9691,21 +9695,39 @@ fold_binary_loc (location_t loc,
 		}
 
 	      return
 		fold_convert_loc (loc, type, associate_trees (loc, var0, con0,
 							      code, atype));
 	    }
 	}
 
       return NULL_TREE;
 
+    case POINTER_DIFF_EXPR:
     case MINUS_EXPR:
+      /* Fold &a[i] - &a[j] to i-j.  */
+      if (TREE_CODE (arg0) == ADDR_EXPR
+	  && TREE_CODE (TREE_OPERAND (arg0, 0)) == ARRAY_REF
+	  && TREE_CODE (arg1) == ADDR_EXPR
+	  && TREE_CODE (TREE_OPERAND (arg1, 0)) == ARRAY_REF)
+        {
+	  tree tem = fold_addr_of_array_ref_difference (loc, type,
+							TREE_OPERAND (arg0, 0),
+							TREE_OPERAND (arg1, 0));
+	  if (tem)
+	    return tem;
+	}
+
+      /* Further transformations are not for pointers.  */
+      if (code == POINTER_DIFF_EXPR)
+	return NULL_TREE;
+
       /* (-A) - B -> (-B) - A  where B is easily negated and we can swap.  */
       if (TREE_CODE (arg0) == NEGATE_EXPR
 	  && negate_expr_p (op1))
 	return fold_build2_loc (loc, MINUS_EXPR, type,
 				negate_expr (op1),
 				fold_convert_loc (loc, type,
 						  TREE_OPERAND (arg0, 0)));
 
       /* Fold __complex__ ( x, 0 ) - __complex__ ( 0, y ) to
 	 __complex__ ( x, -y ).  This is not the same for SNaNs or if
@@ -9749,33 +9771,20 @@ fold_binary_loc (location_t loc,
 	  && ! TYPE_OVERFLOW_SANITIZED (type)
 	  && ((FLOAT_TYPE_P (type)
                /* Avoid this transformation if B is a positive REAL_CST.  */
 	       && (TREE_CODE (op1) != REAL_CST
 		   || REAL_VALUE_NEGATIVE (TREE_REAL_CST (op1))))
 	      || INTEGRAL_TYPE_P (type)))
 	return fold_build2_loc (loc, PLUS_EXPR, type,
 				fold_convert_loc (loc, type, arg0),
 				negate_expr (op1));
 
-      /* Fold &a[i] - &a[j] to i-j.  */
-      if (TREE_CODE (arg0) == ADDR_EXPR
-	  && TREE_CODE (TREE_OPERAND (arg0, 0)) == ARRAY_REF
-	  && TREE_CODE (arg1) == ADDR_EXPR
-	  && TREE_CODE (TREE_OPERAND (arg1, 0)) == ARRAY_REF)
-        {
-	  tree tem = fold_addr_of_array_ref_difference (loc, type,
-							TREE_OPERAND (arg0, 0),
-							TREE_OPERAND (arg1, 0));
-	  if (tem)
-	    return tem;
-	}
-
       if (FLOAT_TYPE_P (type)
 	  && flag_unsafe_math_optimizations
 	  && (TREE_CODE (arg0) == RDIV_EXPR || TREE_CODE (arg0) == MULT_EXPR)
 	  && (TREE_CODE (arg1) == RDIV_EXPR || TREE_CODE (arg1) == MULT_EXPR)
 	  && (tem = distribute_real_division (loc, code, type, arg0, arg1)))
 	return tem;
 
       /* Handle (A1 * C1) - (A2 * C2) with A1, A2 or C1, C2 being the same or
 	 one.  Make sure the type is not saturating and has the signedness of
 	 the stripped operands, as fold_plusminus_mult_expr will re-associate.
Index: gcc/match.pd
===================================================================
--- gcc/match.pd	(revision 253536)
+++ gcc/match.pd	(working copy)
@@ -117,20 +117,23 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
 
 /* Simplify x - x.
    This is unsafe for certain floats even in non-IEEE formats.
    In IEEE, it is unsafe because it does wrong for NaNs.
    Also note that operand_equal_p is always false if an operand
    is volatile.  */
 (simplify
  (minus @0 @0)
  (if (!FLOAT_TYPE_P (type) || !HONOR_NANS (type))
   { build_zero_cst (type); }))
+(simplify
+ (pointer_diff @@0 @0)
+ { build_zero_cst (type); })
 
 (simplify
  (mult @0 integer_zerop@1)
  @1)
 
 /* Maybe fold x * 0 to 0.  The expressions aren't the same
    when x is NaN, since x * 0 is also NaN.  Nor are they the
    same in modes with signed zeros, since multiplying a
    negative value by 0 gives -0, not +0.  */
 (simplify
@@ -1377,20 +1380,27 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
      tem5 = ptr1 + tem4;
    and produce
      tem5 = ptr2;  */
 (simplify
   (pointer_plus @0 (convert?@2 (minus@3 (convert @1) (convert @0))))
   /* Conditionally look through a sign-changing conversion.  */
   (if (TYPE_PRECISION (TREE_TYPE (@2)) == TYPE_PRECISION (TREE_TYPE (@3))
        && ((GIMPLE && useless_type_conversion_p (type, TREE_TYPE (@1)))
 	    || (GENERIC && type == TREE_TYPE (@1))))
    @1))
+(simplify
+  (pointer_plus @0 (convert?@2 (pointer_diff@3 @1 @@0)))
+  /* Conditionally look through a sign-changing conversion.  */
+  (if (TYPE_PRECISION (TREE_TYPE (@2)) == TYPE_PRECISION (TREE_TYPE (@3))
+       && ((GIMPLE && useless_type_conversion_p (type, TREE_TYPE (@1)))
+	    || (GENERIC && type == TREE_TYPE (@1))))
+   @1))
 
 /* Pattern match
      tem = (sizetype) ptr;
      tem = tem & algn;
      tem = -tem;
      ... = ptr p+ tem;
    and produce the simpler and easier to analyze with respect to alignment
      ... = ptr & ~algn;  */
 (simplify
   (pointer_plus @0 (negate (bit_and (convert @0) INTEGER_CST@1)))
@@ -1403,20 +1413,34 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
  (if (tree_nop_conversion_p (type, TREE_TYPE (@0)))
   (with { HOST_WIDE_INT diff; }
    (if (ptr_difference_const (@0, @1, &diff))
     { build_int_cst_type (type, diff); }))))
 (simplify
  (minus (convert @0) (convert ADDR_EXPR@1))
  (if (tree_nop_conversion_p (type, TREE_TYPE (@0)))
   (with { HOST_WIDE_INT diff; }
    (if (ptr_difference_const (@0, @1, &diff))
     { build_int_cst_type (type, diff); }))))
+(simplify
+ (pointer_diff (convert?@2 ADDR_EXPR@0) (convert?@3 @1))
+ (if (tree_nop_conversion_p (TREE_TYPE(@2), TREE_TYPE (@0))
+      && tree_nop_conversion_p (TREE_TYPE(@3), TREE_TYPE (@1)))
+  (with { HOST_WIDE_INT diff; }
+   (if (ptr_difference_const (@0, @1, &diff))
+    { build_int_cst_type (type, diff); }))))
+(simplify
+ (pointer_diff (convert?@2 @0) (convert?@3 ADDR_EXPR@1))
+ (if (tree_nop_conversion_p (TREE_TYPE(@2), TREE_TYPE (@0))
+      && tree_nop_conversion_p (TREE_TYPE(@3), TREE_TYPE (@1)))
+  (with { HOST_WIDE_INT diff; }
+   (if (ptr_difference_const (@0, @1, &diff))
+    { build_int_cst_type (type, diff); }))))
 
 /* If arg0 is derived from the address of an object or function, we may
    be able to fold this expression using the object or function's
    alignment.  */
 (simplify
  (bit_and (convert? @0) INTEGER_CST@1)
  (if (POINTER_TYPE_P (TREE_TYPE (@0))
       && tree_nop_conversion_p (type, TREE_TYPE (@0)))
   (with
    {
@@ -1599,20 +1623,26 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
 	 || (INTEGRAL_TYPE_P (TREE_TYPE (@0))
 	     && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@0)))
 	 /* For pointer types, if the conversion of A to the
 	    final type requires a sign- or zero-extension,
 	    then we have to punt - it is not defined which
 	    one is correct.  */
 	 || (POINTER_TYPE_P (TREE_TYPE (@0))
 	     && TREE_CODE (@1) == INTEGER_CST
 	     && tree_int_cst_sign_bit (@1) == 0))
      (convert @1))))
+   (simplify
+    (pointer_diff (pointer_plus @@0 @1) @0)
+    /* The second argument of pointer_plus must be interpreted as signed, and
+       thus sign-extended if necessary.  */
+    (with { tree stype = signed_type_for (TREE_TYPE (@1)); }
+     (convert (convert:stype @1))))
 
   /* (T)P - (T)(P + A) -> -(T) A */
   (for add (plus pointer_plus)
    (simplify
     (minus (convert @0)
      (convert (add @@0 @1)))
     (if (element_precision (type) <= element_precision (TREE_TYPE (@1))
 	 /* For integer types, if A has a smaller type
 	    than T the result depends on the possible
 	    overflow in P + A.
@@ -1623,20 +1653,26 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
 	 || (INTEGRAL_TYPE_P (TREE_TYPE (@0))
 	     && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@0)))
 	 /* For pointer types, if the conversion of A to the
 	    final type requires a sign- or zero-extension,
 	    then we have to punt - it is not defined which
 	    one is correct.  */
 	 || (POINTER_TYPE_P (TREE_TYPE (@0))
 	     && TREE_CODE (@1) == INTEGER_CST
 	     && tree_int_cst_sign_bit (@1) == 0))
      (negate (convert @1)))))
+   (simplify
+    (pointer_diff @0 (pointer_plus @@0 @1))
+    /* The second argument of pointer_plus must be interpreted as signed, and
+       thus sign-extended if necessary.  */
+    (with { tree stype = signed_type_for (TREE_TYPE (@1)); }
+     (negate (convert (convert:stype @1)))))
 
   /* (T)(P + A) - (T)(P + B) -> (T)A - (T)B */
   (for add (plus pointer_plus)
    (simplify
     (minus (convert (add @@0 @1))
      (convert (add @0 @2)))
     (if (element_precision (type) <= element_precision (TREE_TYPE (@1))
 	 /* For integer types, if A has a smaller type
 	    than T the result depends on the possible
 	    overflow in P + A.
@@ -1649,20 +1685,26 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
 	 /* For pointer types, if the conversion of A to the
 	    final type requires a sign- or zero-extension,
 	    then we have to punt - it is not defined which
 	    one is correct.  */
 	 || (POINTER_TYPE_P (TREE_TYPE (@0))
 	     && TREE_CODE (@1) == INTEGER_CST
 	     && tree_int_cst_sign_bit (@1) == 0
 	     && TREE_CODE (@2) == INTEGER_CST
 	     && tree_int_cst_sign_bit (@2) == 0))
      (minus (convert @1) (convert @2)))))))
+   (simplify
+    (pointer_diff (pointer_plus @@0 @1) (pointer_plus @0 @2))
+    /* The second argument of pointer_plus must be interpreted as signed, and
+       thus sign-extended if necessary.  */
+    (with { tree stype = signed_type_for (TREE_TYPE (@1)); }
+     (minus (convert (convert:stype @1)) (convert (convert:stype @2)))))
 
 
 /* Simplifications of MIN_EXPR, MAX_EXPR, fmin() and fmax().  */
 
 (for minmax (min max FMIN FMAX)
  (simplify
   (minmax @0 @0)
   @0))
 /* min(max(x,y),y) -> y.  */
 (simplify
@@ -2639,20 +2681,25 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
 /* Transform comparisons of the form X - Y CMP 0 to X CMP Y.
    ??? The transformation is valid for the other operators if overflow
    is undefined for the type, but performing it here badly interacts
    with the transformation in fold_cond_expr_with_comparison which
    attempts to synthetize ABS_EXPR.  */
 (for cmp (eq ne)
  (simplify
   (cmp (minus@2 @0 @1) integer_zerop)
   (if (single_use (@2))
    (cmp @0 @1))))
+(for cmp (eq ne)
+ (simplify
+  (cmp (pointer_diff@2 @0 @1) integer_zerop)
+  (if (single_use (@2))
+   (cmp @0 @1))))
 
 /* Transform comparisons of the form X * C1 CMP 0 to X CMP 0 in the
    signed arithmetic case.  That form is created by the compiler
    often enough for folding it to be of value.  One example is in
    computing loop trip counts after Operator Strength Reduction.  */
 (for cmp (simple_comparison)
      scmp (swapped_simple_comparison)
  (simplify
   (cmp (mult@3 @0 INTEGER_CST@1) integer_zerop@2)
   /* Handle unfolded multiplication by zero.  */
Index: gcc/optabs-tree.c
===================================================================
--- gcc/optabs-tree.c	(revision 253536)
+++ gcc/optabs-tree.c	(working copy)
@@ -216,20 +216,21 @@ optab_for_tree_code (enum tree_code code
 
   trapv = INTEGRAL_TYPE_P (type) && TYPE_OVERFLOW_TRAPS (type);
   switch (code)
     {
     case POINTER_PLUS_EXPR:
     case PLUS_EXPR:
       if (TYPE_SATURATING (type))
 	return TYPE_UNSIGNED (type) ? usadd_optab : ssadd_optab;
       return trapv ? addv_optab : add_optab;
 
+    case POINTER_DIFF_EXPR:
     case MINUS_EXPR:
       if (TYPE_SATURATING (type))
 	return TYPE_UNSIGNED (type) ? ussub_optab : sssub_optab;
       return trapv ? subv_optab : sub_optab;
 
     case MULT_EXPR:
       if (TYPE_SATURATING (type))
 	return TYPE_UNSIGNED (type) ? usmul_optab : ssmul_optab;
       return trapv ? smulv_optab : smul_optab;
 
Index: gcc/tree-cfg.c
===================================================================
--- gcc/tree-cfg.c	(revision 253536)
+++ gcc/tree-cfg.c	(working copy)
@@ -3973,20 +3973,39 @@ verify_gimple_assign_binary (gassign *st
 	    error ("type mismatch in pointer plus expression");
 	    debug_generic_stmt (lhs_type);
 	    debug_generic_stmt (rhs1_type);
 	    debug_generic_stmt (rhs2_type);
 	    return true;
 	  }
 
 	return false;
       }
 
+    case POINTER_DIFF_EXPR:
+      {
+	if (!POINTER_TYPE_P (rhs1_type)
+	    || !POINTER_TYPE_P (rhs2_type)
+	    // || !useless_type_conversion_p (rhs2_type, rhs1_type)
+	    // || !useless_type_conversion_p (ptrdiff_type_node, lhs_type))
+	    || TREE_CODE (lhs_type) != INTEGER_TYPE
+	    || TYPE_UNSIGNED (lhs_type))
+	  {
+	    error ("type mismatch in pointer diff expression");
+	    debug_generic_stmt (lhs_type);
+	    debug_generic_stmt (rhs1_type);
+	    debug_generic_stmt (rhs2_type);
+	    return true;
+	  }
+
+	return false;
+      }
+
     case TRUTH_ANDIF_EXPR:
     case TRUTH_ORIF_EXPR:
     case TRUTH_AND_EXPR:
     case TRUTH_OR_EXPR:
     case TRUTH_XOR_EXPR:
 
       gcc_unreachable ();
 
     case LT_EXPR:
     case LE_EXPR:
Index: gcc/tree-inline.c
===================================================================
--- gcc/tree-inline.c	(revision 253536)
+++ gcc/tree-inline.c	(working copy)
@@ -3914,20 +3914,21 @@ estimate_operator_cost (enum tree_code c
       return 0;
 
     /* Assign cost of 1 to usual operations.
        ??? We may consider mapping RTL costs to this.  */
     case COND_EXPR:
     case VEC_COND_EXPR:
     case VEC_PERM_EXPR:
 
     case PLUS_EXPR:
     case POINTER_PLUS_EXPR:
+    case POINTER_DIFF_EXPR:
     case MINUS_EXPR:
     case MULT_EXPR:
     case MULT_HIGHPART_EXPR:
     case FMA_EXPR:
 
     case ADDR_SPACE_CONVERT_EXPR:
     case FIXED_CONVERT_EXPR:
     case FIX_TRUNC_EXPR:
 
     case NEGATE_EXPR:
Index: gcc/tree-pretty-print.c
===================================================================
--- gcc/tree-pretty-print.c	(revision 253536)
+++ gcc/tree-pretty-print.c	(working copy)
@@ -2299,20 +2299,21 @@ dump_generic_node (pretty_printer *pp, t
       pp_greater (pp);
       break;
 
       /* Binary arithmetic and logic expressions.  */
     case WIDEN_SUM_EXPR:
     case WIDEN_MULT_EXPR:
     case MULT_EXPR:
     case MULT_HIGHPART_EXPR:
     case PLUS_EXPR:
     case POINTER_PLUS_EXPR:
+    case POINTER_DIFF_EXPR:
     case MINUS_EXPR:
     case TRUNC_DIV_EXPR:
     case CEIL_DIV_EXPR:
     case FLOOR_DIV_EXPR:
     case ROUND_DIV_EXPR:
     case TRUNC_MOD_EXPR:
     case CEIL_MOD_EXPR:
     case FLOOR_MOD_EXPR:
     case ROUND_MOD_EXPR:
     case RDIV_EXPR:
@@ -3534,20 +3535,21 @@ op_code_prio (enum tree_code code)
     case LROTATE_EXPR:
     case RROTATE_EXPR:
     case VEC_WIDEN_LSHIFT_HI_EXPR:
     case VEC_WIDEN_LSHIFT_LO_EXPR:
     case WIDEN_LSHIFT_EXPR:
       return 11;
 
     case WIDEN_SUM_EXPR:
     case PLUS_EXPR:
     case POINTER_PLUS_EXPR:
+    case POINTER_DIFF_EXPR:
     case MINUS_EXPR:
       return 12;
 
     case VEC_WIDEN_MULT_HI_EXPR:
     case VEC_WIDEN_MULT_LO_EXPR:
     case WIDEN_MULT_EXPR:
     case DOT_PROD_EXPR:
     case WIDEN_MULT_PLUS_EXPR:
     case WIDEN_MULT_MINUS_EXPR:
     case MULT_EXPR:
@@ -3720,20 +3722,21 @@ op_symbol_code (enum tree_code code)
       return "w+";
 
     case WIDEN_MULT_EXPR:
       return "w*";
 
     case MULT_HIGHPART_EXPR:
       return "h*";
 
     case NEGATE_EXPR:
     case MINUS_EXPR:
+    case POINTER_DIFF_EXPR:
       return "-";
 
     case BIT_NOT_EXPR:
       return "~";
 
     case TRUTH_NOT_EXPR:
       return "!";
 
     case MULT_EXPR:
     case INDIRECT_REF:
Index: gcc/tree-vrp.c
===================================================================
--- gcc/tree-vrp.c	(revision 253536)
+++ gcc/tree-vrp.c	(working copy)
@@ -3104,29 +3104,29 @@ extract_range_from_binary_expr (value_ra
 	set_value_range (&n_vr0, VR_RANGE, op0, op0, NULL);
 
       extract_range_from_binary_expr_1 (vr, code, expr_type, &n_vr0, &vr1);
     }
 
   /* If we didn't derive a range for MINUS_EXPR, and
      op1's range is ~[op0,op0] or vice-versa, then we
      can derive a non-null range.  This happens often for
      pointer subtraction.  */
   if (vr->type == VR_VARYING
-      && code == MINUS_EXPR
+      && (code == MINUS_EXPR || code == POINTER_DIFF_EXPR)
       && TREE_CODE (op0) == SSA_NAME
       && ((vr0.type == VR_ANTI_RANGE
 	   && vr0.min == op1
 	   && vr0.min == vr0.max)
 	  || (vr1.type == VR_ANTI_RANGE
 	      && vr1.min == op0
 	      && vr1.min == vr1.max)))
-      set_value_range_to_nonnull (vr, TREE_TYPE (op0));
+      set_value_range_to_nonnull (vr, expr_type);
 }
 
 /* Extract range information from a unary operation CODE based on
    the range of its operand *VR0 with type OP0_TYPE with resulting type TYPE.
    The resulting range is stored in *VR.  */
 
 void
 extract_range_from_unary_expr (value_range *vr,
 			       enum tree_code code, tree type,
 			       value_range *vr0_, tree op0_type)
Index: gcc/tree.def
===================================================================
--- gcc/tree.def	(revision 253536)
+++ gcc/tree.def	(working copy)
@@ -669,20 +669,24 @@ DEFTREECODE (PLACEHOLDER_EXPR, "placehol
 
 /* Simple arithmetic.  */
 DEFTREECODE (PLUS_EXPR, "plus_expr", tcc_binary, 2)
 DEFTREECODE (MINUS_EXPR, "minus_expr", tcc_binary, 2)
 DEFTREECODE (MULT_EXPR, "mult_expr", tcc_binary, 2)
 
 /* Pointer addition.  The first operand is always a pointer and the
    second operand is an integer of type sizetype.  */
 DEFTREECODE (POINTER_PLUS_EXPR, "pointer_plus_expr", tcc_binary, 2)
 
+/* Pointer subtraction.  The two arguments are pointers, and the result
+   is a signed integer.  */
+DEFTREECODE (POINTER_DIFF_EXPR, "pointer_diff_expr", tcc_binary, 2)
+
 /* Highpart multiplication.  For an integral type with precision B,
    returns bits [2B-1, B] of the full 2*B product.  */
 DEFTREECODE (MULT_HIGHPART_EXPR, "mult_highpart_expr", tcc_binary, 2)
 
 /* Division for integer result that rounds the quotient toward zero.  */
 DEFTREECODE (TRUNC_DIV_EXPR, "trunc_div_expr", tcc_binary, 2)
 
 /* Division for integer result that rounds it toward plus infinity.  */
 DEFTREECODE (CEIL_DIV_EXPR, "ceil_div_expr", tcc_binary, 2)
 
Index: gcc/varasm.c
===================================================================
--- gcc/varasm.c	(revision 253536)
+++ gcc/varasm.c	(working copy)
@@ -4606,20 +4606,21 @@ initializer_constant_valid_p_1 (tree val
       else
       /* Support narrowing pointer differences.  */
 	ret = narrowing_initializer_constant_valid_p (value, endtype, NULL);
       if (cache)
 	{
 	  cache[0] = value;
 	  cache[1] = ret;
 	}
       return ret;
 
+    case POINTER_DIFF_EXPR:
     case MINUS_EXPR:
       if (TREE_CODE (endtype) == REAL_TYPE)
 	return NULL_TREE;
       if (cache && cache[0] == value)
 	return cache[1];
       if (! INTEGRAL_TYPE_P (endtype)
 	  || TYPE_PRECISION (endtype) >= TYPE_PRECISION (TREE_TYPE (value)))
 	{
 	  tree ncache[4] = { NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE };
 	  tree valid0

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]