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> 2008-08-13 Manuel Lopez-Ibanez <manu@gcc.gnu.org>
* toplev.h (pedwarn_at): Fix declaration. * toplev.h (pedwarn_at): Fix declaration.
......
...@@ -1842,17 +1842,13 @@ gimplify_conversion (tree *expr_p) ...@@ -1842,17 +1842,13 @@ gimplify_conversion (tree *expr_p)
/* Attempt to avoid NOP_EXPR by producing reference to a subtype. /* Attempt to avoid NOP_EXPR by producing reference to a subtype.
For example this fold (subclass *)&A into &A->subclass avoiding For example this fold (subclass *)&A into &A->subclass avoiding
a need for statement. */ 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 (*expr_p))
&& POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (*expr_p, 0))) && 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), (TREE_OPERAND (*expr_p, 0),
integer_zero_node, TREE_TYPE (TREE_TYPE (*expr_p))))) integer_zero_node, TREE_TYPE (*expr_p))) != NULL_TREE)
{ *expr_p = tem;
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);
}
/* If we still have a conversion at the toplevel, /* If we still have a conversion at the toplevel,
then canonicalize some constructs. */ then canonicalize some constructs. */
...@@ -6735,30 +6731,24 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, ...@@ -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. The second is gimple immediate saving a need for extra statement.
*/ */
if (TREE_CODE (TREE_OPERAND (*expr_p, 1)) == INTEGER_CST 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_OPERAND (*expr_p, 0), TREE_OPERAND (*expr_p, 1),
TREE_TYPE (TREE_TYPE (*expr_p))))) TREE_TYPE (*expr_p))))
{ {
tree ptr_type = build_pointer_type (TREE_TYPE (tmp)); *expr_p = tmp;
if (useless_type_conversion_p (TREE_TYPE (*expr_p), ptr_type))
{
*expr_p = build_fold_addr_expr_with_type (tmp, ptr_type);
break; break;
} }
}
/* Convert (void *)&a + 4 into (void *)&a[1]. */ /* Convert (void *)&a + 4 into (void *)&a[1]. */
if (TREE_CODE (TREE_OPERAND (*expr_p, 0)) == NOP_EXPR if (TREE_CODE (TREE_OPERAND (*expr_p, 0)) == NOP_EXPR
&& TREE_CODE (TREE_OPERAND (*expr_p, 1)) == INTEGER_CST && TREE_CODE (TREE_OPERAND (*expr_p, 1)) == INTEGER_CST
&& POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (*expr_p, && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (*expr_p,
0),0))) 0),0)))
&& (tmp = maybe_fold_offset_to_reference && (tmp = maybe_fold_offset_to_address
(TREE_OPERAND (TREE_OPERAND (*expr_p, 0), 0), (TREE_OPERAND (TREE_OPERAND (*expr_p, 0), 0),
TREE_OPERAND (*expr_p, 1), TREE_OPERAND (*expr_p, 1),
TREE_TYPE (TREE_TYPE TREE_TYPE (TREE_OPERAND (TREE_OPERAND (*expr_p, 0),
(TREE_OPERAND (TREE_OPERAND (*expr_p, 0), 0)))))
0))))))
{ {
tmp = build_fold_addr_expr (tmp);
*expr_p = fold_convert (TREE_TYPE (*expr_p), tmp); *expr_p = fold_convert (TREE_TYPE (*expr_p), tmp);
break; 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> 2008-08-13 Samuel Tardieu <sam@rfc1149.net>
PR ada/36777 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) ...@@ -630,7 +630,7 @@ surely_varying_stmt_p (gimple stmt)
tree fndecl; tree fndecl;
if (!gimple_call_lhs (stmt) if (!gimple_call_lhs (stmt)
|| ((fndecl = gimple_call_fndecl (stmt)) != NULL_TREE || ((fndecl = gimple_call_fndecl (stmt)) != NULL_TREE
&& DECL_BUILT_IN (fndecl))) && !DECL_BUILT_IN (fndecl)))
return true; return true;
} }
...@@ -988,8 +988,8 @@ ccp_fold (gimple stmt) ...@@ -988,8 +988,8 @@ ccp_fold (gimple stmt)
useless_type_conversion_p places for pointer type conversions useless_type_conversion_p places for pointer type conversions
do not apply here. Substitution later will only substitute to do not apply here. Substitution later will only substitute to
allowed places. */ allowed places. */
if ((subcode == NOP_EXPR || subcode == CONVERT_EXPR) if (IS_CONVERT_EXPR_CODE_P (subcode)
&& ((POINTER_TYPE_P (TREE_TYPE (lhs)) && POINTER_TYPE_P (TREE_TYPE (lhs))
&& POINTER_TYPE_P (TREE_TYPE (op0)) && POINTER_TYPE_P (TREE_TYPE (op0))
/* Do not allow differences in volatile qualification /* Do not allow differences in volatile qualification
as this might get us confused as to whether a as this might get us confused as to whether a
...@@ -997,9 +997,17 @@ ccp_fold (gimple stmt) ...@@ -997,9 +997,17 @@ ccp_fold (gimple stmt)
or not. See PR36988. */ or not. See PR36988. */
&& (TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (lhs))) && (TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (lhs)))
== TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (op0))))) == TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (op0)))))
|| useless_type_conversion_p (TREE_TYPE (lhs), {
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 op0;
}
return fold_unary (subcode, gimple_expr_type (stmt), op0); return fold_unary (subcode, gimple_expr_type (stmt), op0);
} }
...@@ -1025,6 +1033,18 @@ ccp_fold (gimple stmt) ...@@ -1025,6 +1033,18 @@ ccp_fold (gimple stmt)
op1 = val->value; 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); 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) ...@@ -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. so it needs to be removed and new COMPONENT_REF constructed.
The wrong COMPONENT_REF are often constructed by folding the The wrong COMPONENT_REF are often constructed by folding the
(type *)&object within the expression (type *)&object+offset */ (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; HOST_WIDE_INT sub_offset, size, maxsize;
tree newbase; tree newbase;
newbase = get_ref_base_and_extent (base, &sub_offset, newbase = get_ref_base_and_extent (base, &sub_offset,
&size, &maxsize); &size, &maxsize);
gcc_assert (newbase); 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; base = newbase;
if (sub_offset) if (sub_offset)
...@@ -1988,6 +2008,63 @@ maybe_fold_offset_to_reference (tree base, tree offset, tree orig_type) ...@@ -1988,6 +2008,63 @@ maybe_fold_offset_to_reference (tree base, tree offset, tree orig_type)
return ret; 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). /* A subroutine of fold_stmt_r. Attempt to simplify *(BASE+OFFSET).
Return the simplified expression, or NULL if nothing could be done. */ 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) ...@@ -2223,16 +2300,10 @@ fold_stmt_r (tree *expr_p, int *walk_subtrees, void *data)
if (POINTER_TYPE_P (TREE_TYPE (expr)) if (POINTER_TYPE_P (TREE_TYPE (expr))
&& POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (expr, 0))) && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (expr, 0)))
&& (t = maybe_fold_offset_to_reference && (t = maybe_fold_offset_to_address (TREE_OPERAND (expr, 0),
(TREE_OPERAND (expr, 0),
integer_zero_node, integer_zero_node,
TREE_TYPE (TREE_TYPE (expr))))) TREE_TYPE (TREE_TYPE (expr)))))
{ return t;
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);
}
break; break;
/* ??? Could handle more ARRAY_REFs here, as a variant of INDIRECT_REF. /* ??? Could handle more ARRAY_REFs here, as a variant of INDIRECT_REF.
...@@ -2715,15 +2786,10 @@ fold_gimple_assign (gimple_stmt_iterator *si) ...@@ -2715,15 +2786,10 @@ fold_gimple_assign (gimple_stmt_iterator *si)
&& POINTER_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (stmt)))) && POINTER_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (stmt))))
{ {
tree type = gimple_expr_type (stmt); tree type = gimple_expr_type (stmt);
tree t = maybe_fold_offset_to_reference (gimple_assign_rhs1 (stmt), tree t = maybe_fold_offset_to_address (gimple_assign_rhs1 (stmt),
integer_zero_node, integer_zero_node, type);
TREE_TYPE (type));
if (t) if (t)
{ return 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);
}
} }
break; break;
......
...@@ -4744,6 +4744,7 @@ extern void fold_undefer_overflow_warnings (bool, const_gimple, int); ...@@ -4744,6 +4744,7 @@ extern void fold_undefer_overflow_warnings (bool, const_gimple, int);
extern void fold_undefer_and_ignore_overflow_warnings (void); extern void fold_undefer_and_ignore_overflow_warnings (void);
extern bool fold_deferring_overflow_warnings_p (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_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 maybe_fold_stmt_addition (tree, tree, tree);
extern tree force_fit_type_double (tree, unsigned HOST_WIDE_INT, HOST_WIDE_INT, 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