[patch] Use get_inner_reference in ivopts

Zdenek Dvorak rakdver@atrey.karlin.mff.cuni.cz
Wed Sep 15 09:13:00 GMT 2004


Hello,

this patch replaces uses of peel_address by get_inner_reference.  It
also improves fold so that it is able to fold things like
&a[i].x - &a[i].y that are often produced by ivopts.

Bootstrapped & regtested on i686 and x86_64.

Zdenek

	* fold-const.c (fold): Fold difference of addresses.
	(ptr_difference_const): Moved from tree-ssa-loop-ivopts, based on
	get_inner_reference.
	* tree-ssa-loop-ivopts.c (peel_address): Removed.
	(ptr_difference_const): Moved to fold-const.c.
	(split_address_cost): Use get_inner_reference instead of peel_address.
	(ptr_difference_cost): Change type of diff to HOST_WIDE_INT.
	* tree.h (ptr_difference_const): Export.

Index: fold-const.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/fold-const.c,v
retrieving revision 1.458
diff -c -3 -p -r1.458 fold-const.c
*** fold-const.c	14 Sep 2004 12:21:41 -0000	1.458
--- fold-const.c	14 Sep 2004 21:19:18 -0000
*************** fold (tree expr)
*** 6966,6971 ****
--- 6966,6983 ----
  	      || (INTEGRAL_TYPE_P (type) && flag_wrapv && !flag_trapv)))
  	return fold (build2 (PLUS_EXPR, type, arg0, negate_expr (arg1)));
  
+       /* Try folding difference of addresses.  */
+       {
+ 	HOST_WIDE_INT diff;
+ 
+ 	if (TREE_CODE (arg0) == ADDR_EXPR
+ 	    && TREE_CODE (arg1) == ADDR_EXPR
+ 	    && ptr_difference_const (TREE_OPERAND (arg0, 0),
+ 				     TREE_OPERAND (arg1, 0),
+ 				     &diff))
+ 	  return build_int_cst_type (type, diff);
+       }
+ 
        if (TREE_CODE (arg0) == MULT_EXPR
  	  && TREE_CODE (arg1) == MULT_EXPR
  	  && (INTEGRAL_TYPE_P (type) || flag_unsafe_math_optimizations))
*************** round_down (tree value, int divisor)
*** 10668,10670 ****
--- 10680,10730 ----
  
    return value;
  }
+ 
+ /* Returns true if addresses of E1 and E2 differ by a constant, false
+    otherwise.  If they do, &E1 - &E2 is stored in *DIFF.  */
+ 
+ bool
+ ptr_difference_const (tree e1, tree e2, HOST_WIDE_INT *diff)
+ {
+   tree core1, core2;
+   HOST_WIDE_INT bitsize1, bitsize2;
+   HOST_WIDE_INT bitpos1, bitpos2;
+   tree toffset1, toffset2, tdiff, type;
+   enum machine_mode mode1, mode2;
+   int unsignedp1, unsignedp2, volatilep1, volatilep2;
+   
+   core1 = get_inner_reference (e1, &bitsize1, &bitpos1, &toffset1, &mode1,
+ 			       &unsignedp1, &volatilep1);
+   core2 = get_inner_reference (e2, &bitsize2, &bitpos2, &toffset2, &mode2,
+ 			       &unsignedp2, &volatilep2);
+ 
+   if (bitpos1 % BITS_PER_UNIT != 0
+       || bitpos2 % BITS_PER_UNIT != 0
+       || !operand_equal_p (core1, core2, 0))
+     return false;
+ 
+   if (toffset1 && toffset2)
+     {
+       type = TREE_TYPE (toffset1);
+       if (type != TREE_TYPE (toffset2))
+ 	toffset2 = fold_convert (type, toffset2);
+ 
+       tdiff = fold (build2 (MINUS_EXPR, type, toffset1, toffset2));
+       if (!host_integerp (tdiff, 0))
+ 	return false;
+ 
+       *diff = tree_low_cst (tdiff, 0);
+     }
+   else if (toffset1 || toffset2)
+     {
+       /* If only one of the offsets is non-constant, the difference cannot
+ 	 be a constant.  */
+       return false;
+     }
+   else
+     *diff = 0;
+ 
+   *diff += (bitpos1 - bitpos2) / BITS_PER_UNIT;
+   return true;
+ }
Index: tree-ssa-loop-ivopts.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-ssa-loop-ivopts.c,v
retrieving revision 2.9
diff -c -3 -p -r2.9 tree-ssa-loop-ivopts.c
*** tree-ssa-loop-ivopts.c	10 Sep 2004 08:56:36 -0000	2.9
--- tree-ssa-loop-ivopts.c	14 Sep 2004 21:19:18 -0000
*************** force_var_cost (struct ivopts_data *data
*** 2500,2597 ****
    return target_spill_cost;
  }
  
- /* Peels a single layer of ADDR.  If DIFF is not NULL, do it only if the
-    offset is constant and add the offset to DIFF.  */
- 
- static tree
- peel_address (tree addr, unsigned HOST_WIDE_INT *diff)
- {
-   tree off, size;
-   HOST_WIDE_INT bit_offset;
- 
-   switch (TREE_CODE (addr))
-     {
-     case SSA_NAME:
-     case INDIRECT_REF:
-     case BIT_FIELD_REF:
-     case VAR_DECL:
-     case PARM_DECL:
-     case RESULT_DECL:
-     case STRING_CST:
-     case REALPART_EXPR:
-     case IMAGPART_EXPR:
-       return NULL_TREE;
- 
-     case COMPONENT_REF:
-       off = DECL_FIELD_BIT_OFFSET (TREE_OPERAND (addr, 1));
-       bit_offset = TREE_INT_CST_LOW (off);
- 
-       gcc_assert ((bit_offset % BITS_PER_UNIT) == 0);
-       
-       if (diff)
- 	*diff += bit_offset / BITS_PER_UNIT;
- 
-       return TREE_OPERAND (addr, 0);
- 
-     case VIEW_CONVERT_EXPR:
-       return TREE_OPERAND (addr, 0);
- 
-     case ARRAY_REF:
-       off = TREE_OPERAND (addr, 1);
- 
-       if (diff)
- 	{
- 	  if (!cst_and_fits_in_hwi (off))
- 	    return NULL_TREE;
- 
- 	  size = TYPE_SIZE_UNIT (TREE_TYPE (addr));
- 	  if (!cst_and_fits_in_hwi (size))
- 	    return NULL_TREE;
- 
- 	  *diff += TREE_INT_CST_LOW (off) * TREE_INT_CST_LOW (size);
- 	}
- 
-       return TREE_OPERAND (addr, 0);
- 
-     default:
-       gcc_unreachable ();
-     }
- }
- 
- /* Checks whether E1 and E2 have constant difference, and if they do,
-    store it in *DIFF.  */
- 
- static bool
- ptr_difference_const (tree e1, tree e2, unsigned HOST_WIDE_INT *diff)
- {
-   int d1 = 0, d2 = 0;
-   tree x;
-   unsigned HOST_WIDE_INT delta1 = 0, delta2 = 0;
- 
-   /* Find depths of E1 and E2.  */
-   for (x = e1; x; x = peel_address (x, NULL))
-     d1++;
-   for (x = e2; x; x = peel_address (x, NULL))
-     d2++;
- 
-   for (; e1 && d1 > d2; e1 = peel_address (e1, &delta1))
-     d1--;
-   for (; e2 && d2 > d1; e2 = peel_address (e2, &delta2))
-     d2--;
- 
-   while (e1 && e2 && !operand_equal_p (e1, e2, 0))
-     {
-       e1 = peel_address (e1, &delta1);
-       e2 = peel_address (e2, &delta1);
-     }
- 
-   if (!e1 || !e2)
-     return false;
- 
-   *diff = delta1 - delta2;
-   return true;
- }
- 
  /* Estimates cost of expressing address ADDR  as var + symbol + offset.  The
     value of offset is added to OFFSET, SYMBOL_PRESENT and VAR_PRESENT are set
     to false if the corresponding part is missing.  DEPENDS_ON is a set of the
--- 2500,2505 ----
*************** split_address_cost (struct ivopts_data *
*** 2602,2622 ****
  		    tree addr, bool *symbol_present, bool *var_present,
  		    unsigned HOST_WIDE_INT *offset, bitmap *depends_on)
  {
!   tree core = addr;
! 
!   while (core
! 	 && TREE_CODE (core) != VAR_DECL)
!     core = peel_address (core, offset);
  
!   if (!core)
      {
        *symbol_present = false;
        *var_present = true;
        fd_ivopts_data = data;
        walk_tree (&addr, find_depends, depends_on, NULL);
        return target_spill_cost;
!     }  
! 	  
    if (TREE_STATIC (core)
        || DECL_EXTERNAL (core))
      {
--- 2510,2537 ----
  		    tree addr, bool *symbol_present, bool *var_present,
  		    unsigned HOST_WIDE_INT *offset, bitmap *depends_on)
  {
!   tree core;
!   HOST_WIDE_INT bitsize;
!   HOST_WIDE_INT bitpos;
!   tree toffset;
!   enum machine_mode mode;
!   int unsignedp, volatilep;
!   
!   core = get_inner_reference (addr, &bitsize, &bitpos, &toffset, &mode,
! 			      &unsignedp, &volatilep);
  
!   if (toffset != 0
!       || bitpos % BITS_PER_UNIT != 0
!       || TREE_CODE (core) != VAR_DECL)
      {
        *symbol_present = false;
        *var_present = true;
        fd_ivopts_data = data;
        walk_tree (&addr, find_depends, depends_on, NULL);
        return target_spill_cost;
!     }
! 
!   *offset += bitpos / BITS_PER_UNIT;
    if (TREE_STATIC (core)
        || DECL_EXTERNAL (core))
      {
*************** ptr_difference_cost (struct ivopts_data 
*** 2641,2647 ****
  		     tree e1, tree e2, bool *symbol_present, bool *var_present,
  		     unsigned HOST_WIDE_INT *offset, bitmap *depends_on)
  {
!   unsigned HOST_WIDE_INT diff = 0;
    unsigned cost;
  
    gcc_assert (TREE_CODE (e1) == ADDR_EXPR);
--- 2556,2562 ----
  		     tree e1, tree e2, bool *symbol_present, bool *var_present,
  		     unsigned HOST_WIDE_INT *offset, bitmap *depends_on)
  {
!   HOST_WIDE_INT diff = 0;
    unsigned cost;
  
    gcc_assert (TREE_CODE (e1) == ADDR_EXPR);
Index: tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree.h,v
retrieving revision 1.621
diff -c -3 -p -r1.621 tree.h
*** tree.h	13 Sep 2004 20:27:05 -0000	1.621
--- tree.h	14 Sep 2004 21:19:18 -0000
*************** extern tree constant_boolean_node (int, 
*** 3464,3469 ****
--- 3464,3471 ----
  extern bool tree_swap_operands_p (tree, tree, bool);
  extern enum tree_code swap_tree_comparison (enum tree_code);
  
+ extern bool ptr_difference_const (tree, tree, HOST_WIDE_INT *);
+ 
  /* In builtins.c */
  extern tree fold_builtin (tree, bool);
  extern tree fold_builtin_fputs (tree, bool, bool, tree);



More information about the Gcc-patches mailing list