This implements my idea of how POINTER_PLUS_EXPR should end up being
changed.  This addresses two things, 1) reduce the use of sizetype
nodes, 2) properly handle targets where sizeof (void *) != sizeof 
(sizetype).  Especially 2) is important as currently we lose information
about the signedness of the offset and thus have no idea on whether
to sign- or zero-extend.

The following patch just implements the different checking and
handles the desired semantics during expansion.  It does not yet
touch the various places that build POINTER_PLUS_EXPRs (in fact,
a sizetype offset operand is still valid).  A final transition
will be as tedious as the original patch introducing POINTER_PLUS_EXPRs,
but the obvious starting points are the frontends and fold.  Partial
transitions will of course also eventually expose issues with
this new design.  Like, how do we fold (p + short a) + unsigned int b.
Straight-forward answer: as p + ((uintptr_t)a + (uintptr_t)b).  Which
we eventually can narrow again if we know sth about the value-ranges
of a and b (remember, overflow in ptr + offset is undefined).

Comments?

Thanks,
Richard.

2011-06-17  Richard Guenther  <rguent...@suse.de>

        * expr.c (expand_expr_real_2): Extend the POINTER_PLUS_EXPR offset
        operand to pointer precision.
        * tree-cfg.c (verify_expr): Allow arbitrary integral types
        for the POINTER_PLUS_EXPR offset operand.
        (verify_gimple_assign_binary): Likewise.
        * tree.c (build2_stat): Likewise.
        * tree.def (POINTER_PLUS_EXPR): Adjust documentation.

Index: trunk/gcc/expr.c
===================================================================
*** trunk.orig/gcc/expr.c       2011-06-16 16:56:02.000000000 +0200
--- trunk/gcc/expr.c    2011-06-17 11:33:52.000000000 +0200
*************** expand_expr_real_2 (sepops ops, rtx targ
*** 7422,7436 ****
        }
  
      case POINTER_PLUS_EXPR:
!       /* Even though the sizetype mode and the pointer's mode can be different
!          expand is able to handle this correctly and get the correct result 
out
!          of the PLUS_EXPR code.  */
!       /* Make sure to sign-extend the sizetype offset in a POINTER_PLUS_EXPR
!          if sizetype precision is smaller than pointer precision.  */
!       if (TYPE_PRECISION (sizetype) < TYPE_PRECISION (type))
!       treeop1 = fold_convert_loc (loc, type,
!                                   fold_convert_loc (loc, ssizetype,
!                                                     treeop1));
      case PLUS_EXPR:
        /* If we are adding a constant, a VAR_DECL that is sp, fp, or ap, and
         something else, make sure we add the register to the constant and
--- 7422,7433 ----
        }
  
      case POINTER_PLUS_EXPR:
!       /* Extend/truncate the offset operand to pointer width according
!          to its signedness.  */
!       if (TYPE_PRECISION (type) != TYPE_PRECISION (treeop1))
!       treeop1 = fold_convert_loc (loc, type, treeop1);
! 
!       /* Fallthru.  */
      case PLUS_EXPR:
        /* If we are adding a constant, a VAR_DECL that is sp, fp, or ap, and
         something else, make sure we add the register to the constant and
Index: trunk/gcc/tree-cfg.c
===================================================================
*** trunk.orig/gcc/tree-cfg.c   2011-06-16 16:55:45.000000000 +0200
--- trunk/gcc/tree-cfg.c        2011-06-17 11:35:17.000000000 +0200
*************** verify_expr (tree *tp, int *walk_subtree
*** 2845,2857 ****
          error ("invalid operand to pointer plus, first operand is not a 
pointer");
          return t;
        }
!       /* Check to make sure the second operand is an integer with type of
!        sizetype.  */
!       if (!useless_type_conversion_p (sizetype,
!                                    TREE_TYPE (TREE_OPERAND (t, 1))))
        {
          error ("invalid operand to pointer plus, second operand is not an "
!                "integer with type of sizetype");
          return t;
        }
        /* FALLTHROUGH */
--- 2845,2855 ----
          error ("invalid operand to pointer plus, first operand is not a 
pointer");
          return t;
        }
!       /* Check to make sure the second operand is an integer.  */
!       if (!INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (t, 1))))
        {
          error ("invalid operand to pointer plus, second operand is not an "
!                "integer type");
          return t;
        }
        /* FALLTHROUGH */
*************** verify_gimple_assign_binary (gimple stmt
*** 3609,3615 ****
  do_pointer_plus_expr_check:
        if (!POINTER_TYPE_P (rhs1_type)
            || !useless_type_conversion_p (lhs_type, rhs1_type)
!           || !useless_type_conversion_p (sizetype, rhs2_type))
          {
            error ("type mismatch in pointer plus expression");
            debug_generic_stmt (lhs_type);
--- 3607,3613 ----
  do_pointer_plus_expr_check:
        if (!POINTER_TYPE_P (rhs1_type)
            || !useless_type_conversion_p (lhs_type, rhs1_type)
!           || !INTEGRAL_TYPE_P (rhs2_type))
          {
            error ("type mismatch in pointer plus expression");
            debug_generic_stmt (lhs_type);
Index: trunk/gcc/tree.c
===================================================================
*** trunk.orig/gcc/tree.c       2011-06-16 16:55:45.000000000 +0200
--- trunk/gcc/tree.c    2011-06-17 11:29:35.000000000 +0200
*************** build2_stat (enum tree_code code, tree t
*** 3779,3786 ****
  
    if (code == POINTER_PLUS_EXPR && arg0 && arg1 && tt)
      gcc_assert (POINTER_TYPE_P (tt) && POINTER_TYPE_P (TREE_TYPE (arg0))
!               && INTEGRAL_TYPE_P (TREE_TYPE (arg1))
!               && useless_type_conversion_p (sizetype, TREE_TYPE (arg1)));
  
    t = make_node_stat (code PASS_MEM_STAT);
    TREE_TYPE (t) = tt;
--- 3779,3785 ----
  
    if (code == POINTER_PLUS_EXPR && arg0 && arg1 && tt)
      gcc_assert (POINTER_TYPE_P (tt) && POINTER_TYPE_P (TREE_TYPE (arg0))
!               && INTEGRAL_TYPE_P (TREE_TYPE (arg1)));
  
    t = make_node_stat (code PASS_MEM_STAT);
    TREE_TYPE (t) = tt;
Index: trunk/gcc/tree.def
===================================================================
*** trunk.orig/gcc/tree.def     2011-06-16 14:49:31.000000000 +0200
--- trunk/gcc/tree.def  2011-06-17 11:41:04.000000000 +0200
*************** DEFTREECODE (MINUS_EXPR, "minus_expr", t
*** 610,616 ****
  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)
  
  /* Division for integer result that rounds the quotient toward zero.  */
--- 610,617 ----
  DEFTREECODE (MULT_EXPR, "mult_expr", tcc_binary, 2)
  
  /* Pointer addition.  The first operand is always a pointer and the
!    second operand is an integer.  The second operand is implicitly
!    extended to the width of the first operand.  */
  DEFTREECODE (POINTER_PLUS_EXPR, "pointer_plus_expr", tcc_binary, 2)
  
  /* Division for integer result that rounds the quotient toward zero.  */

Reply via email to