Commit 99f536cc by Richard Guenther Committed by Richard Biener

tree.h (maybe_fold_offset_to_address): Declare.

2008-08-13  Richard Guenther  <rguenther@suse.de>

	* tree.h (maybe_fold_offset_to_address): Declare.
	* tree-ssa-ccp.c (surely_varying_stmt_p): Fix typo in last commit.
	(ccp_fold): Handle pointer conversions the same as fold_stmt.
	Likewise for POINTER_PLUS_EXPR.
	(maybe_fold_offset_to_reference): Enable disabled code.
	(maybe_fold_offset_to_address): New function.
	(fold_stmt_r): Use it.
	(fold_gimple_assign): Likewise.
	* gimplify.c (gimplify_conversion): Use maybe_fold_offset_to_address.
	(gimplify_expr): Likewise.

	* gcc.dg/tree-ssa/ssa-ccp-21.c: New testcase.
	* gcc.dg/tree-ssa/ssa-ccp-22.c: Likewise.
	* gcc.dg/tree-ssa/ssa-ccp-23.c: Likewise.

From-SVN: r139061
parent e3f05c4e
2008-08-13 Richard Guenther <rguenther@suse.de>
* tree.h (maybe_fold_offset_to_address): Declare.
* tree-ssa-ccp.c (surely_varying_stmt_p): Fix typo in last commit.
(ccp_fold): Handle pointer conversions the same as fold_stmt.
Likewise for POINTER_PLUS_EXPR.
(maybe_fold_offset_to_reference): Enable disabled code.
(maybe_fold_offset_to_address): New function.
(fold_stmt_r): Use it.
(fold_gimple_assign): Likewise.
* gimplify.c (gimplify_conversion): Use maybe_fold_offset_to_address.
(gimplify_expr): Likewise.
2008-08-13 Manuel Lopez-Ibanez <manu@gcc.gnu.org>
* toplev.h (pedwarn_at): Fix declaration.
......
......@@ -1842,17 +1842,13 @@ gimplify_conversion (tree *expr_p)
/* 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
if (CONVERT_EXPR_P (*expr_p)
&& POINTER_TYPE_P (TREE_TYPE (*expr_p))
&& POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (*expr_p, 0)))
&& (tem = maybe_fold_offset_to_reference
&& (tem = maybe_fold_offset_to_address
(TREE_OPERAND (*expr_p, 0),
integer_zero_node, TREE_TYPE (TREE_TYPE (*expr_p)))))
{
tree ptr_type = build_pointer_type (TREE_TYPE (tem));
if (useless_type_conversion_p (TREE_TYPE (*expr_p), ptr_type))
*expr_p = build_fold_addr_expr_with_type (tem, ptr_type);
}
integer_zero_node, TREE_TYPE (*expr_p))) != NULL_TREE)
*expr_p = tem;
/* If we still have a conversion at the toplevel,
then canonicalize some constructs. */
......@@ -6735,30 +6731,24 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
The second is gimple immediate saving a need for extra statement.
*/
if (TREE_CODE (TREE_OPERAND (*expr_p, 1)) == INTEGER_CST
&& (tmp = maybe_fold_offset_to_reference
&& (tmp = maybe_fold_offset_to_address
(TREE_OPERAND (*expr_p, 0), TREE_OPERAND (*expr_p, 1),
TREE_TYPE (TREE_TYPE (*expr_p)))))
{
tree ptr_type = build_pointer_type (TREE_TYPE (tmp));
if (useless_type_conversion_p (TREE_TYPE (*expr_p), ptr_type))
{
*expr_p = build_fold_addr_expr_with_type (tmp, ptr_type);
break;
}
}
TREE_TYPE (*expr_p))))
{
*expr_p = tmp;
break;
}
/* Convert (void *)&a + 4 into (void *)&a[1]. */
if (TREE_CODE (TREE_OPERAND (*expr_p, 0)) == NOP_EXPR
&& TREE_CODE (TREE_OPERAND (*expr_p, 1)) == INTEGER_CST
&& POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (*expr_p,
0),0)))
&& (tmp = maybe_fold_offset_to_reference
&& (tmp = maybe_fold_offset_to_address
(TREE_OPERAND (TREE_OPERAND (*expr_p, 0), 0),
TREE_OPERAND (*expr_p, 1),
TREE_TYPE (TREE_TYPE
(TREE_OPERAND (TREE_OPERAND (*expr_p, 0),
0))))))
TREE_TYPE (TREE_OPERAND (TREE_OPERAND (*expr_p, 0),
0)))))
{
tmp = build_fold_addr_expr (tmp);
*expr_p = fold_convert (TREE_TYPE (*expr_p), tmp);
break;
}
......
2008-08-13 Richard Guenther <rguenther@suse.de>
* gcc.dg/tree-ssa/ssa-ccp-21.c: New testcase.
* gcc.dg/tree-ssa/ssa-ccp-22.c: Likewise.
* gcc.dg/tree-ssa/ssa-ccp-23.c: Likewise.
2008-08-13 Samuel Tardieu <sam@rfc1149.net>
PR ada/36777
......
/* { dg-do compile } */
/* { dg-options "-O -fdump-tree-ccp1" } */
struct A {
struct B {
int i;
} b;
} a;
int foo (void)
{
struct B *p = &a.b;
struct A *q = (struct A *) p;
return q->b.i;
}
int bar (void)
{
struct A *p = &a;
struct B *q = (struct B *) p;
return q->i;
}
/* { dg-final { scan-tree-dump-times "a.b.i" 2 "ccp1" } } */
/* { dg-final { cleanup-tree-dump "ccp1" } } */
/* { dg-do compile } */
/* { dg-options "-O -fdump-tree-ccp1" } */
/* Make sure we propagate through builtins. */
int foo (unsigned b)
{
unsigned t = -1;
int x = b <= t;
long l = __builtin_expect (x, 0);
return l;
}
/* { dg-final { scan-tree-dump "return 1;" "ccp1" } } */
/* { dg-final { cleanup-tree-dump "ccp1" } } */
/* { dg-do compile } */
/* { dg-options "-O -fdump-tree-ccp1" } */
/* Make sure we propagate through POINTER_PLUS_EXPRs. */
struct A {
int i[2];
} a;
int foo (void)
{
struct A *p = &a;
int *q = (int *)p;
int *x = q + 1;
return *x;
}
/* { dg-final { scan-tree-dump "a.i\\\[1\\\]" "ccp1" } } */
/* { dg-final { cleanup-tree-dump "ccp1" } } */
......@@ -630,7 +630,7 @@ surely_varying_stmt_p (gimple stmt)
tree fndecl;
if (!gimple_call_lhs (stmt)
|| ((fndecl = gimple_call_fndecl (stmt)) != NULL_TREE
&& DECL_BUILT_IN (fndecl)))
&& !DECL_BUILT_IN (fndecl)))
return true;
}
......@@ -988,18 +988,26 @@ ccp_fold (gimple stmt)
useless_type_conversion_p places for pointer type conversions
do not apply here. Substitution later will only substitute to
allowed places. */
if ((subcode == NOP_EXPR || subcode == CONVERT_EXPR)
&& ((POINTER_TYPE_P (TREE_TYPE (lhs))
&& POINTER_TYPE_P (TREE_TYPE (op0))
/* Do not allow differences in volatile qualification
as this might get us confused as to whether a
propagation destination statement is volatile
or not. See PR36988. */
&& (TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (lhs)))
== TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (op0)))))
|| useless_type_conversion_p (TREE_TYPE (lhs),
TREE_TYPE (op0))))
return op0;
if (IS_CONVERT_EXPR_CODE_P (subcode)
&& POINTER_TYPE_P (TREE_TYPE (lhs))
&& POINTER_TYPE_P (TREE_TYPE (op0))
/* Do not allow differences in volatile qualification
as this might get us confused as to whether a
propagation destination statement is volatile
or not. See PR36988. */
&& (TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (lhs)))
== TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (op0)))))
{
tree tem;
/* Still try to generate a constant of correct type. */
if (!useless_type_conversion_p (TREE_TYPE (lhs),
TREE_TYPE (op0))
&& ((tem = maybe_fold_offset_to_address
(op0, integer_zero_node, TREE_TYPE (lhs)))
!= NULL_TREE))
return tem;
return op0;
}
return fold_unary (subcode, gimple_expr_type (stmt), op0);
}
......@@ -1025,6 +1033,18 @@ ccp_fold (gimple stmt)
op1 = val->value;
}
/* Fold &foo + CST into an invariant reference if possible. */
if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR
&& TREE_CODE (op0) == ADDR_EXPR
&& TREE_CODE (op1) == INTEGER_CST)
{
tree lhs = gimple_assign_lhs (stmt);
tree tem = maybe_fold_offset_to_address (op0, op1,
TREE_TYPE (lhs));
if (tem != NULL_TREE)
return tem;
}
return fold_binary (subcode, gimple_expr_type (stmt), op0, op1);
}
......@@ -1948,15 +1968,15 @@ maybe_fold_offset_to_reference (tree base, tree offset, tree orig_type)
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)
if (handled_component_p (base))
{
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)
if (size == maxsize
&& !(sub_offset & (BITS_PER_UNIT - 1)))
{
base = newbase;
if (sub_offset)
......@@ -1988,6 +2008,63 @@ maybe_fold_offset_to_reference (tree base, tree offset, tree orig_type)
return ret;
}
/* 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 component refs. */
tree
maybe_fold_offset_to_address (tree addr, tree offset, tree orig_type)
{
tree t;
gcc_assert (POINTER_TYPE_P (TREE_TYPE (addr))
&& POINTER_TYPE_P (orig_type));
t = maybe_fold_offset_to_reference (addr, offset, TREE_TYPE (orig_type));
if (t != NULL_TREE)
{
tree orig = addr;
tree ptr_type;
/* For __builtin_object_size to function correctly we need to
make sure not to fold address arithmetic so that we change
reference from one array to another. This would happen for
example for
struct X { char s1[10]; char s2[10] } s;
char *foo (void) { return &s.s2[-4]; }
where we need to avoid generating &s.s1[6]. As the C and
C++ frontends create different initial trees
(char *) &s.s1 + -4 vs. &s.s1[-4] we have to do some
sophisticated comparisons here. Note that checking for the
condition after the fact is easier than trying to avoid doing
the folding. */
STRIP_NOPS (orig);
if (TREE_CODE (orig) == ADDR_EXPR)
orig = TREE_OPERAND (orig, 0);
if ((TREE_CODE (orig) == ARRAY_REF
|| (TREE_CODE (orig) == COMPONENT_REF
&& TREE_CODE (TREE_TYPE (TREE_OPERAND (orig, 1))) == ARRAY_TYPE))
&& (TREE_CODE (t) == ARRAY_REF
|| (TREE_CODE (t) == COMPONENT_REF
&& TREE_CODE (TREE_TYPE (TREE_OPERAND (t, 1))) == ARRAY_TYPE))
&& !operand_equal_p (TREE_CODE (orig) == ARRAY_REF
? TREE_OPERAND (orig, 0) : orig,
TREE_CODE (t) == ARRAY_REF
? TREE_OPERAND (t, 0) : t, 0))
return NULL_TREE;
ptr_type = build_pointer_type (TREE_TYPE (t));
if (!useless_type_conversion_p (orig_type, ptr_type))
return NULL_TREE;
return build_fold_addr_expr_with_type (t, ptr_type);
}
return NULL_TREE;
}
/* A subroutine of fold_stmt_r. Attempt to simplify *(BASE+OFFSET).
Return the simplified expression, or NULL if nothing could be done. */
......@@ -2223,16 +2300,10 @@ fold_stmt_r (tree *expr_p, int *walk_subtrees, void *data)
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)))))
{
tree ptr_type = build_pointer_type (TREE_TYPE (t));
if (!useless_type_conversion_p (TREE_TYPE (expr), ptr_type))
return NULL_TREE;
t = build_fold_addr_expr_with_type (t, ptr_type);
}
&& (t = maybe_fold_offset_to_address (TREE_OPERAND (expr, 0),
integer_zero_node,
TREE_TYPE (TREE_TYPE (expr)))))
return t;
break;
/* ??? Could handle more ARRAY_REFs here, as a variant of INDIRECT_REF.
......@@ -2715,15 +2786,10 @@ fold_gimple_assign (gimple_stmt_iterator *si)
&& POINTER_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (stmt))))
{
tree type = gimple_expr_type (stmt);
tree t = maybe_fold_offset_to_reference (gimple_assign_rhs1 (stmt),
integer_zero_node,
TREE_TYPE (type));
tree t = maybe_fold_offset_to_address (gimple_assign_rhs1 (stmt),
integer_zero_node, type);
if (t)
{
tree ptr_type = build_pointer_type (TREE_TYPE (t));
if (useless_type_conversion_p (type, ptr_type))
return build_fold_addr_expr_with_type (t, ptr_type);
}
return t;
}
break;
......
......@@ -4744,6 +4744,7 @@ extern void fold_undefer_overflow_warnings (bool, const_gimple, int);
extern void fold_undefer_and_ignore_overflow_warnings (void);
extern bool fold_deferring_overflow_warnings_p (void);
extern tree maybe_fold_offset_to_reference (tree, tree, tree);
extern tree maybe_fold_offset_to_address (tree, tree, tree);
extern tree maybe_fold_stmt_addition (tree, tree, tree);
extern tree force_fit_type_double (tree, unsigned HOST_WIDE_INT, HOST_WIDE_INT,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment