[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