diff options
author | Jan Hubicka <jh@suse.cz> | 2007-05-01 13:18:01 +0200 |
---|---|---|
committer | Jan Hubicka <hubicka@gcc.gnu.org> | 2007-05-01 11:18:01 +0000 |
commit | fe9821b88c042f37973f4ab2866a52dcb676446c (patch) | |
tree | bd72595e8b02806708c943137cbe687e4482667d /gcc | |
parent | 8b11009bad1b794283984fc806198e3cf29dbed3 (diff) | |
download | gcc-fe9821b88c042f37973f4ab2866a52dcb676446c.tar.gz |
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')
-rw-r--r-- | gcc/ChangeLog | 17 | ||||
-rw-r--r-- | gcc/fold-const.c | 7 | ||||
-rw-r--r-- | gcc/gimplify.c | 27 | ||||
-rw-r--r-- | gcc/tree-ssa-ccp.c | 111 | ||||
-rw-r--r-- | gcc/tree.h | 3 |
5 files changed, 135 insertions, 30 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 2230102974d..88d090a6ec8 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,20 @@ +2007-05-01 Jan Hubicka <jh@suse.cz> + + * 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. + 2007-05-01 Zdenek Dvorak <dvorakz@suse.cz> * tree-ssa-loop-ivopts.c (rewrite_use_nonlinear_expr): Use diff --git a/gcc/fold-const.c b/gcc/fold-const.c index 7a8afcdbe87..6311be7e084 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -7748,13 +7748,6 @@ fold_unary (enum tree_code code, tree type, tree op0) return fold_convert (type, build_fold_addr_expr (base)); } - /* Convert (type *)&A into &A->field_of_type_and_offset_0. */ - if (TREE_CODE (op0) == ADDR_EXPR && POINTER_TYPE_P (type) - && (tem = maybe_fold_offset_to_component_ref - (TREE_TYPE (TREE_OPERAND (op0, 0)), TREE_OPERAND (op0, 0), - integer_zero_node, TREE_TYPE (type), false))) - return build_fold_addr_expr_with_type (tem, type); - if ((TREE_CODE (op0) == MODIFY_EXPR || TREE_CODE (op0) == GIMPLE_MODIFY_STMT) && TREE_CONSTANT (GENERIC_TREE_OPERAND (op0, 1)) diff --git a/gcc/gimplify.c b/gcc/gimplify.c index 0b6ec34d974..805c3020272 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -1617,6 +1617,7 @@ canonicalize_addr_expr (tree *expr_p) static enum gimplify_status gimplify_conversion (tree *expr_p) { + tree tem; gcc_assert (TREE_CODE (*expr_p) == NOP_EXPR || TREE_CODE (*expr_p) == CONVERT_EXPR); @@ -1627,6 +1628,17 @@ gimplify_conversion (tree *expr_p) if (tree_ssa_useless_type_conversion (*expr_p)) *expr_p = TREE_OPERAND (*expr_p, 0); + /* Attempt to avoid NOP_EXPR by producing reference to a subtype. + For example this fold (subclass *)&A into &A->subclass avoiding + a need for statement. */ + if (TREE_CODE (*expr_p) == NOP_EXPR + && POINTER_TYPE_P (TREE_TYPE (*expr_p)) + && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (*expr_p, 0))) + && (tem = maybe_fold_offset_to_reference + (TREE_OPERAND (*expr_p, 0), + integer_zero_node, TREE_TYPE (TREE_TYPE (*expr_p))))) + *expr_p = build_fold_addr_expr_with_type (tem, TREE_TYPE (*expr_p)); + /* If we still have a conversion at the toplevel, then canonicalize some constructs. */ if (TREE_CODE (*expr_p) == NOP_EXPR || TREE_CODE (*expr_p) == CONVERT_EXPR) @@ -5857,6 +5869,21 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p, ret = GS_ALL_DONE; break; + case PLUS_EXPR: + /* Convert ((type *)A)+offset into &A->field_of_type_and_offset. + The second is gimple immediate saving a need for extra statement. + */ + if (POINTER_TYPE_P (TREE_TYPE (*expr_p)) + && TREE_CODE (TREE_OPERAND (*expr_p, 1)) == INTEGER_CST + && (tmp = maybe_fold_offset_to_reference + (TREE_OPERAND (*expr_p, 0), TREE_OPERAND (*expr_p, 1), + TREE_TYPE (TREE_TYPE (*expr_p))))) + { + *expr_p = build_fold_addr_expr_with_type (tmp, + TREE_TYPE (*expr_p)); + break; + } + /* FALLTHRU */ default: switch (TREE_CODE_CLASS (TREE_CODE (*expr_p))) { diff --git a/gcc/tree-ssa-ccp.c b/gcc/tree-ssa-ccp.c index 9c9d847eed6..6c9475540fe 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. diff --git a/gcc/tree.h b/gcc/tree.h index c076fc1aa7a..3059d402804 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -4422,8 +4422,7 @@ extern void fold_defer_overflow_warnings (void); extern void fold_undefer_overflow_warnings (bool, tree, int); extern void fold_undefer_and_ignore_overflow_warnings (void); extern bool fold_deferring_overflow_warnings_p (void); -extern tree maybe_fold_offset_to_component_ref (tree, tree, tree, - tree, bool); +extern tree maybe_fold_offset_to_reference (tree, tree, tree); extern tree force_fit_type_double (tree, unsigned HOST_WIDE_INT, HOST_WIDE_INT, int, bool); |