aboutsummaryrefslogtreecommitdiff
path: root/gcc/tree-ssa-ccp.c
diff options
context:
space:
mode:
authorJan Hubicka <jh@suse.cz>2007-05-01 13:18:01 +0200
committerJan Hubicka <hubicka@gcc.gnu.org>2007-05-01 11:18:01 +0000
commitfe9821b88c042f37973f4ab2866a52dcb676446c (patch)
treebd72595e8b02806708c943137cbe687e4482667d /gcc/tree-ssa-ccp.c
parent8b11009bad1b794283984fc806198e3cf29dbed3 (diff)
downloadgcc-fe9821b88c042f37973f4ab2866a52dcb676446c.zip
gcc-fe9821b88c042f37973f4ab2866a52dcb676446c.tar.gz
gcc-fe9821b88c042f37973f4ab2866a52dcb676446c.tar.bz2
tree.h (maybe_fold_offset_to_component_ref): Remove.
* tree.h (maybe_fold_offset_to_component_ref): Remove. (maybe_fold_offset_to_reference): Declare. * fold-const.c (fold_unary): Do not fold (type *)&A into &A->field_of_type_and_offset_0 * tree-ssa-ccp.c (maybe_fold_offset_to_array_ref): When base type size is unknown, give up. (maybe_fold_offset_to_component_ref): Ignore firelds with unknown offsets. (maybe_fold_offset_to_reference): New. (maybe_fold_stmt_indirect): Use it. (fold_stmt_r): Fold (type *)&A+offset into A->field_if_type_and_offset. * gimplify.c (gimplify_conversion): Canonicalize conversions to field references. (gimplify_expr): Likewise for plus_expr. From-SVN: r124323
Diffstat (limited to 'gcc/tree-ssa-ccp.c')
-rw-r--r--gcc/tree-ssa-ccp.c111
1 files changed, 90 insertions, 21 deletions
diff --git a/gcc/tree-ssa-ccp.c b/gcc/tree-ssa-ccp.c
index 9c9d847..6c94755 100644
--- a/gcc/tree-ssa-ccp.c
+++ b/gcc/tree-ssa-ccp.c
@@ -1587,6 +1587,8 @@ maybe_fold_offset_to_array_ref (tree base, tree offset, tree orig_type)
Otherwise, compute the offset as an index by using a division. If the
division isn't exact, then don't do anything. */
elt_size = TYPE_SIZE_UNIT (elt_type);
+ if (!elt_size)
+ return NULL;
if (integer_zerop (offset))
{
if (TREE_CODE (elt_size) != INTEGER_CST)
@@ -1647,12 +1649,11 @@ maybe_fold_offset_to_array_ref (tree base, tree offset, tree orig_type)
}
-/* A subroutine of fold_stmt_r. Attempts to fold *(S+O) to S.X.
+/* Attempt to fold *(S+O) to S.X.
BASE is a record type. OFFSET is a byte displacement. ORIG_TYPE
is the desired result type. */
-/* ??? This doesn't handle class inheritance. */
-tree
+static tree
maybe_fold_offset_to_component_ref (tree record_type, tree base, tree offset,
tree orig_type, bool base_is_ptr)
{
@@ -1679,6 +1680,8 @@ maybe_fold_offset_to_component_ref (tree record_type, tree base, tree offset,
if (DECL_BIT_FIELD (f))
continue;
+ if (!DECL_FIELD_OFFSET (f))
+ continue;
field_offset = byte_position (f);
if (TREE_CODE (field_offset) != INTEGER_CST)
continue;
@@ -1766,6 +1769,69 @@ maybe_fold_offset_to_component_ref (tree record_type, tree base, tree offset,
orig_type, false);
}
+/* Attempt to express (ORIG_TYPE)BASE+OFFSET as BASE->field_of_orig_type
+ or BASE[index] or by combination of those.
+
+ Before attempting the conversion strip off existing ADDR_EXPRs and
+ handled component refs. */
+
+tree
+maybe_fold_offset_to_reference (tree base, tree offset, tree orig_type)
+{
+ tree ret;
+ tree type;
+ bool base_is_ptr = true;
+
+ STRIP_NOPS (base);
+ if (TREE_CODE (base) == ADDR_EXPR)
+ {
+ base_is_ptr = false;
+
+ base = TREE_OPERAND (base, 0);
+
+ /* Handle case where existing COMPONENT_REF pick e.g. wrong field of union,
+ so it needs to be removed and new COMPONENT_REF constructed.
+ The wrong COMPONENT_REF are often constructed by folding the
+ (type *)&object within the expression (type *)&object+offset */
+ if (handled_component_p (base) && 0)
+ {
+ HOST_WIDE_INT sub_offset, size, maxsize;
+ tree newbase;
+ newbase = get_ref_base_and_extent (base, &sub_offset,
+ &size, &maxsize);
+ gcc_assert (newbase);
+ gcc_assert (!(sub_offset & (BITS_PER_UNIT - 1)));
+ if (size == maxsize)
+ {
+ base = newbase;
+ if (sub_offset)
+ offset = int_const_binop (PLUS_EXPR, offset,
+ build_int_cst (TREE_TYPE (offset),
+ sub_offset / BITS_PER_UNIT), 1);
+ }
+ }
+ if (lang_hooks.types_compatible_p (orig_type, TREE_TYPE (base))
+ && integer_zerop (offset))
+ return base;
+ type = TREE_TYPE (base);
+ }
+ else
+ {
+ base_is_ptr = true;
+ if (!POINTER_TYPE_P (TREE_TYPE (base)))
+ return NULL_TREE;
+ type = TREE_TYPE (TREE_TYPE (base));
+ }
+ ret = maybe_fold_offset_to_component_ref (type, base, offset,
+ orig_type, base_is_ptr);
+ if (!ret)
+ {
+ if (base_is_ptr)
+ base = build1 (INDIRECT_REF, type, base);
+ ret = maybe_fold_offset_to_array_ref (base, offset, orig_type);
+ }
+ return ret;
+}
/* A subroutine of fold_stmt_r. Attempt to simplify *(BASE+OFFSET).
Return the simplified expression, or NULL if nothing could be done. */
@@ -1802,6 +1868,8 @@ maybe_fold_stmt_indirect (tree expr, tree base, tree offset)
if (TREE_CODE (base) == ADDR_EXPR)
{
+ tree base_addr = base;
+
/* Strip the ADDR_EXPR. */
base = TREE_OPERAND (base, 0);
@@ -1810,24 +1878,11 @@ maybe_fold_stmt_indirect (tree expr, tree base, tree offset)
&& ccp_decl_initial_min_invariant (DECL_INITIAL (base)))
return DECL_INITIAL (base);
- /* Try folding *(&B+O) to B[X]. */
- t = maybe_fold_offset_to_array_ref (base, offset, TREE_TYPE (expr));
- if (t)
- return t;
-
/* Try folding *(&B+O) to B.X. */
- t = maybe_fold_offset_to_component_ref (TREE_TYPE (base), base, offset,
- TREE_TYPE (expr), false);
+ t = maybe_fold_offset_to_reference (base_addr, offset,
+ TREE_TYPE (expr));
if (t)
return t;
-
- /* Fold *&B to B. We can only do this if EXPR is the same type
- as BASE. We can't do this if EXPR is the element type of an array
- and BASE is the array. */
- if (integer_zerop (offset)
- && lang_hooks.types_compatible_p (TREE_TYPE (base),
- TREE_TYPE (expr)))
- return base;
}
else
{
@@ -1856,9 +1911,8 @@ maybe_fold_stmt_indirect (tree expr, tree base, tree offset)
/* Try folding *(B+O) to B->X. Still an improvement. */
if (POINTER_TYPE_P (TREE_TYPE (base)))
{
- t = maybe_fold_offset_to_component_ref (TREE_TYPE (TREE_TYPE (base)),
- base, offset,
- TREE_TYPE (expr), true);
+ t = maybe_fold_offset_to_reference (base, offset,
+ TREE_TYPE (expr));
if (t)
return t;
}
@@ -2020,6 +2074,21 @@ fold_stmt_r (tree *expr_p, int *walk_subtrees, void *data)
integer_zero_node);
break;
+ case NOP_EXPR:
+ t = walk_tree (&TREE_OPERAND (expr, 0), fold_stmt_r, data, NULL);
+ if (t)
+ return t;
+ *walk_subtrees = 0;
+
+ if (POINTER_TYPE_P (TREE_TYPE (expr))
+ && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (expr, 0)))
+ && (t = maybe_fold_offset_to_reference
+ (TREE_OPERAND (expr, 0),
+ integer_zero_node,
+ TREE_TYPE (TREE_TYPE (expr)))))
+ t = build_fold_addr_expr_with_type (t, TREE_TYPE (expr));
+ break;
+
/* ??? Could handle more ARRAY_REFs here, as a variant of INDIRECT_REF.
We'd only want to bother decomposing an existing ARRAY_REF if
the base array is found to have another offset contained within.