[PATCH][0/N][RFC] Change POINTER_PLUS_EXPR offset type requirements

Richard Guenther rguenther@suse.de
Mon Jul 11 12:17:00 GMT 2011


This is the first patch in a series of patches that will eventually lead
to changed requirements for the POINTER_PLUS_EXPR offset operand.  The
first and foremost goal is to reduce the number of sizetyped computations
in our IL (with sizetype being that oddball type that is unsigned
but sign-extended).  The following patch goes for a canonical type
precision for the offset operand (matching the precision of sizetype)
but allows both signed (preferred) and unsigned offsets.

The patch introduces several wrappers around the concept of
valid offset types to be able to convert users without actually
switching the implementations to a different set of types.

The abstractions include

 - ptrofftype_p (t) - whether t is a valid type for operand 1 of ppe
 - convert_to_ptrofftype (t) - shortcut for the fold_convert (...)
     pattern, allows for advanced promotion rules
 - common_ptrofftype (t) - needed for the rare case when you combine
     two pointer-plus-expr offsets
 - fold_build_pointer_plus[_hwi] - for the common pattern that
     first converts the offset to a proper type and then builds
     a pointer-plus-expr (or builds an offset tree from a HWI calculation)

The patch actually provides implementations for the desired final
set of types.

Thus, comments on the abstraction itself and the (choice of) final
implementation welcome.

I suppose the fold_build_pointer_plus* one is least controversical
so I'll start with singling out that and its uses.

Thanks,
Richard.

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

	* expr.c (expand_expr_real_2): Extend the POINTER_PLUS_EXPR offset
	operand to pointer precision.
	* tree-cfg.c (verify_expr): Use ptrofftype_p for POINTER_PLUS_EXPR
	offset verification.
	(verify_gimple_assign_binary): Likewise.
	* tree.c (build2_stat): Likewise.
	(build_common_tree_nodes): Build ptrofftype and uptrofftype.
	* tree.h (enum size_type_kind): Add PTROFFTYPE and UPTROFFTYPE.
	(ptrofftype): Define.
	(uptrofftype): Likewise.
	(convert_to_ptrofftype_loc): New helper function.
	(convert_to_ptrofftype): Define.
	(common_ptrofftype): New helper function.
	(ptrofftype_p): Likewise.
	(fold_build_pointer_plus_loc): New helper function.
	(fold_build_pointer_plus_hwi_loc): Likewise.
	(fold_build_pointer_plus): Define.
	(fold_build_pointer_plus_hwi): Likewise.
	* tree.def (POINTER_PLUS_EXPR): Adjust documentation.

Index: trunk/gcc/expr.c
===================================================================
*** trunk.orig/gcc/expr.c	2011-07-11 11:48:46.000000000 +0200
--- trunk/gcc/expr.c	2011-07-11 12:57:40.000000000 +0200
*************** expand_expr_real_2 (sepops ops, rtx targ
*** 7428,7442 ****
        }
  
      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
--- 7428,7439 ----
        }
  
      case POINTER_PLUS_EXPR:
!       /* Extend/truncate the offset operand to pointer width according
!          to its signedness.  */
!       if (TYPE_PRECISION (type) != TYPE_PRECISION (TREE_TYPE (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-07-11 11:48:46.000000000 +0200
--- trunk/gcc/tree-cfg.c	2011-07-11 12:12:42.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 a ptrofftype.  */
!       if (!ptrofftype_p (TREE_TYPE (TREE_OPERAND (t, 1))))
  	{
  	  error ("invalid operand to pointer plus, second operand is not an "
! 		 "integer type of appropriate width");
  	  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)
! 	    || !ptrofftype_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-07-11 11:48:46.000000000 +0200
--- trunk/gcc/tree.c	2011-07-11 12:14:13.000000000 +0200
*************** build2_stat (enum tree_code code, tree t
*** 3776,3789 ****
        /* When sizetype precision doesn't match that of pointers
           we need to be able to build explicit extensions or truncations
  	 of the offset argument.  */
!       && TYPE_PRECISION (sizetype) == TYPE_PRECISION (tt))
      gcc_assert (TREE_CODE (arg0) == INTEGER_CST
  		&& TREE_CODE (arg1) == INTEGER_CST);
  
    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;
--- 3776,3788 ----
        /* When sizetype precision doesn't match that of pointers
           we need to be able to build explicit extensions or truncations
  	 of the offset argument.  */
!       && TYPE_PRECISION (ptrofftype) == TYPE_PRECISION (tt))
      gcc_assert (TREE_CODE (arg0) == INTEGER_CST
  		&& TREE_CODE (arg1) == INTEGER_CST);
  
    if (code == POINTER_PLUS_EXPR && arg0 && arg1 && tt)
      gcc_assert (POINTER_TYPE_P (tt) && POINTER_TYPE_P (TREE_TYPE (arg0))
! 		&& ptrofftype_p (TREE_TYPE (arg1)));
  
    t = make_node_stat (code PASS_MEM_STAT);
    TREE_TYPE (t) = tt;
*************** build_common_tree_nodes (bool signed_cha
*** 9179,9184 ****
--- 9178,9190 ----
  
    initialize_sizetypes ();
  
+   /* The pointer offset type is of the same width as sizetype
+      but signed and not of TYPE_IS_SIZETYPE kind.  */
+   ptrofftype = make_signed_type (TYPE_PRECISION (sizetype));
+   TYPE_NAME (ptrofftype) = get_identifier ("ptrofftype");
+   uptrofftype = make_unsigned_type (TYPE_PRECISION (sizetype));
+   TYPE_NAME (uptrofftype) = get_identifier ("uptrofftype");
+ 
    /* Define both `signed char' and `unsigned char'.  */
    signed_char_type_node = make_signed_type (CHAR_TYPE_SIZE);
    TYPE_STRING_FLAG (signed_char_type_node) = 1;
Index: trunk/gcc/tree.def
===================================================================
*** trunk.orig/gcc/tree.def	2011-07-11 11:48:46.000000000 +0200
--- trunk/gcc/tree.def	2011-07-11 12:11:11.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,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 precision ptrofftype.  */
  DEFTREECODE (POINTER_PLUS_EXPR, "pointer_plus_expr", tcc_binary, 2)
  
  /* Division for integer result that rounds the quotient toward zero.  */
Index: trunk/gcc/tree.h
===================================================================
*** trunk.orig/gcc/tree.h	2011-07-11 11:59:51.000000000 +0200
--- trunk/gcc/tree.h	2011-07-11 13:01:08.000000000 +0200
*************** enum size_type_kind
*** 4725,4730 ****
--- 4725,4732 ----
    SSIZETYPE,		/* Signed representation of sizes in bytes.  */
    BITSIZETYPE,		/* Normal representation of sizes in bits.  */
    SBITSIZETYPE,		/* Signed representation of sizes in bits.  */
+   PTROFFTYPE,		/* Representation of pointer offsets.  */
+   UPTROFFTYPE,		/* Unsigned representation of pointer offsets.  */
    TYPE_KIND_LAST};
  
  extern GTY(()) tree sizetype_tab[(int) TYPE_KIND_LAST];
*************** extern GTY(()) tree sizetype_tab[(int) T
*** 4733,4738 ****
--- 4735,4742 ----
  #define bitsizetype sizetype_tab[(int) BITSIZETYPE]
  #define ssizetype sizetype_tab[(int) SSIZETYPE]
  #define sbitsizetype sizetype_tab[(int) SBITSIZETYPE]
+ #define ptrofftype sizetype_tab[(int) PTROFFTYPE]
+ #define uptrofftype sizetype_tab[(int) UPTROFFTYPE]
  
  extern tree size_int_kind (HOST_WIDE_INT, enum size_type_kind);
  #define size_binop(CODE,T1,T2)\
*************** truth_value_p (enum tree_code code)
*** 5316,5321 ****
--- 5320,5381 ----
  	  || code == TRUTH_XOR_EXPR || code == TRUTH_NOT_EXPR);
  }
  
+ /* Return whether TYPE is a type suitable for an offset for
+    a POINTER_PLUS_EXPR.  */
+ static inline bool
+ ptrofftype_p (tree type)
+ {
+   return (INTEGRAL_TYPE_P (type)
+ 	  && TYPE_PRECISION (type) == TYPE_PRECISION (ptrofftype));
+ }
+ 
+ /* Return OFF converted to a pointer offset type suitable as offset for
+    POINTER_PLUS_EXPR.  Use location LOC for this conversion.  */
+ static inline tree
+ convert_to_ptrofftype_loc (location_t loc, tree off)
+ {
+   tree type = TREE_TYPE (off);
+   /* Do sign-preserving truncation and always extend to signed.  */
+   return fold_convert_loc (loc,
+ 			   TYPE_PRECISION (type) >= TYPE_PRECISION (ptrofftype)
+ 			   && TYPE_UNSIGNED (type) ? uptrofftype : ptrofftype,
+ 			   off);
+ }
+ #define convert_to_ptrofftype(t) convert_to_ptrofftype_loc (UNKNOWN_LOCATION, t)
+ 
+ /* For two pointer offset types return a common type that should be used
+    for arithmetic on them.  */
+ static inline tree
+ common_ptrofftype (tree type1, tree type2)
+ {
+   /* If any type is unsigned return an unsigned type, otherwise use the
+      signed variant.  */
+   if (TYPE_UNSIGNED (type2))
+     return type2;
+   else
+     return type1;
+ }
+ 
+ /* Build and fold a POINTER_PLUS_EXPR at LOC offsetting PTR by OFF.  */
+ static inline tree
+ fold_build_pointer_plus_loc (location_t loc, tree ptr, tree off)
+ {
+   return fold_build2_loc (loc, POINTER_PLUS_EXPR, TREE_TYPE (ptr),
+ 			  ptr, convert_to_ptrofftype_loc (loc, off));
+ }
+ #define fold_build_pointer_plus(p,o) \
+ 	fold_build_pointer_plus_loc (UNKNOWN_LOCATION, p, o)
+ 
+ /* Build and fold a POINTER_PLUS_EXPR at LOC offsetting PTR by OFF.  */
+ static inline tree
+ fold_build_pointer_plus_hwi_loc (location_t loc, tree ptr, HOST_WIDE_INT off)
+ {
+   return fold_build2_loc (loc, POINTER_PLUS_EXPR, TREE_TYPE (ptr),
+ 			  ptr, build_int_cst (ptrofftype, off));
+ }
+ #define fold_build_pointer_plus_hwi(p,o) \
+ 	fold_build_pointer_plus_hwi_loc (UNKNOWN_LOCATION, p, o)
+ 
  
  /* In builtins.c */
  extern tree fold_call_expr (location_t, tree, bool);
Index: trunk/gcc/gimple.c
===================================================================
*** trunk.orig/gcc/gimple.c	2011-07-11 12:41:15.000000000 +0200
--- trunk/gcc/gimple.c	2011-07-11 12:57:59.000000000 +0200
*************** gimple_asm_clobbers_memory_p (const_gimp
*** 5501,5504 ****
--- 5501,5505 ----
  
    return false;
  }
+ 
  #include "gt-gimple.h"



More information about the Gcc-patches mailing list