Commit 227858d1 by Diego Novillo

[multiple changes]

2005-06-01  Diego Novillo  <dnovillo@redhat.com>

	PR 14341, PR 21332, PR 20701, PR 21029, PR 21086, PR 21090
	PR 21289, PR 21348, PR 21367, PR 21368, PR 21458.
	* fold-const.c (invert_tree_comparison): Make extern.
	* tree-flow.h (enum value_range_type): Move to tree-ssa-propagate.
	(struct value_range_def): Limewise.
	(get_value_range): Remove.
	(dump_value_range): Remove.
	(dump_all_value_ranges): Remove.
	(debug_all_value_ranges): Remove.
	(vrp_evaluate_conditional): Declare.
	* tree-ssa-propagate.c (struct prop_stats_d): Add field
	num_pred_folded.
	(substitute_and_fold): Add argument use_ranges_p.
	Update all callers.
	If use_ranges_p is true, call fold_predicate_in to fold
	predicates using range information.
	Ignore ASSERT_EXPRs.
	Change debugging output to only show statements that have been
	folded.
	(replace_phi_args_in): Move debugging output code from
	substitute and fold.
	(fold_predicate_in): New local function.
	* tree-ssa-propagate.h (enum value_range_type): Move from
	tree-flow.h.
	(struct value_range_d): Likewise.
	Add field 'equiv'.
	(value_range_t): Rename from value_range.
	* tree-vrp.c (found_in_subgraph): Rename from found.
	(get_opposite_operand): Remove.
	(struct assert_locus_d): Declare.
	(assert_locus_t): Declare.
	(need_assert_for): Declare.
	(asserts_for): Declare.
	(blocks_visited): Declare.
	(vr_value): Declare.
	(set_value_range): Add argument 'equiv'.
	Don't drop to VARYING ranges that cover all values in the
	type.
	Make deep copy of equivalence set 'equiv'.
	(copy_value_range): New local function.
	(set_value_range_to_undefined): New local function.
	(compare_values): Return -2 if either value has overflowed.
	(range_includes_zero_p): New local function.
	(extract_range_from_assert): Flip the predicate code if the
	name being asserted is on the RHS of the predicate.
	Avoid creating unnecessary symbolic ranges if the comparison
	includes another name with a known numeric range.
	Update the equivalnce set of the new range when asserting
	EQ_EXPR predicates.
	(extract_range_from_ssa_name): Update the equivalence set of
	the new range with VAR.
	(extract_range_from_binary_expr): Also handle TRUTH_*_EXPR.
	If -fwrapv is used, set the resulting range to VARYING if the
	operation overflows.  Otherwise, use TYPE_MIN_VALUE and
	TYPE_MAX_VALUE to represent -INF and +INF.
	Fix handling of *_DIV_EXPR.
	(extract_range_from_unary_expr): Handle MINUS_EXPR and
	ABS_EXPR properly by switching the range around if necessary.
	(extract_range_from_comparison): New local function.
	(extract_range_from_expr): Call it.
	(adjust_range_with_scev): Do not adjust the range if using
	wrapping arithmetic (-fwrapv).
	(dump_value_range): Also show equivalence set.
	Show -INF and +INF for TYPE_MIN_VALUE and TYPE_MAX_VALUE.
	(build_assert_expr_for): Also build ASSERT_EXPR for EQ_EXPR.
	(infer_value_range): Change return value to bool.
	Add arguments 'comp_code_p' and 'val_p'.
	Do not attempt to infer ranges from statements that may throw.
	Store the comparison code in comp_code_p.
	Store the other operand to be used in the predicate in val_p.
	(dump_asserts_for): New.
	(debug_asserts_for): New.
	(dump_all_asserts): New.
	(debug_all_asserts): New.
	(register_new_assert_for): New.
	(register_edge_assert_for): New.
	(find_conditional_asserts): New.
	(find_assert_locations): New.
	(process_assert_insertions_for): New.
	(process_assert_insertions): New.
	(insert_range_assertions): Initialize found_in_subgraph,
	blocks_visited, need_assert_for and asserts_for.
	Call find_assert_locations and process_assert_insertions.
	(remove_range_assertions): Add more documentation.
	(vrp_initialize): Change return type to void.
	Do not try to guess if running VRP is worth it.
	(compare_name_with_value): New.
	(compare_names): New.
	(vrp_evaluate_conditional): Add argument 'use_equiv_p'.  If
	use_equiv_p is true, call compare_names and
	compare_name_with_value to compare all the ranges for every
	name in the equivalence set of the predicate operands.
	Update all callers.
	(vrp_meet): Try harder not to derive a VARYING range.
	If two values meet, the resulting equivalence set is the
	intersection of the two equivalence sets.
	(vrp_visit_phi_node): Call copy_value_range to get the current
	range information of the LHS.
	(vrp_finalize): Create a value vector representing all the
	names that ended up with exactly one value in their range.
	Call substitute_and_fold.
	(execute_vrp): Document equivalence sets in ranges.
	* tree.h (SSA_NAME_VALUE_RANGE): Remove.
	(struct tree_ssa_name): Remove field value_range.
	(invert_tree_comparison): Declare.

testsuite/ChangeLog

2005-06-01  Diego Novillo  <dnovillo@redhat.com>

	PR 14341, PR 21332, PR 20701, PR 21086, PR 21090
	PR 21289, PR 21348, PR 21367, PR 21368, PR 21458.
	* gcc.dg/tree-ssa/pr14341.c: New test.
	* gcc.dg/tree-ssa/pr14841.c: New test.
	* gcc.dg/tree-ssa/pr20701.c: New test.
	* gcc.dg/tree-ssa/pr21086.c: New test.
	* gcc.dg/tree-ssa/pr21090.c: New test.
	* gcc.dg/tree-ssa/pr21332.c: New test.
	* gcc.dg/tree-ssa/pr21458.c: New test.
	* gcc.dg/tree-ssa/pr21658.c: New test.
	* gcc.dg/tree-ssa/vrp01.c: New test.
	* gcc.dg/tree-ssa/vrp02.c: New test.
	* gcc.dg/tree-ssa/vrp03.c: New test.
	* gcc.dg/tree-ssa/vrp04.c: New test.
	* gcc.dg/tree-ssa/vrp05.c: New test.
	* gcc.dg/tree-ssa/vrp06.c: New test.
	* gcc.dg/tree-ssa/vrp07.c: New test.
	* gcc.dg/tree-ssa/vrp08.c: New test.
	* gcc.dg/tree-ssa/vrp09.c: New test.
	* gcc.dg/tree-ssa/vrp10.c: New test.
	* gcc.dg/tree-ssa/vrp11.c: New test.
	* gcc.dg/tree-ssa/vrp12.c: New test.
	* gcc.dg/tree-ssa/vrp13.c: New test.

2005-06-01  Alexandre Oliva  <aoliva@redhat.com>

	PR 21029
	* gcc.dg/tree-ssa/pr21029.c: New test.

From-SVN: r100478
parent 292a398f
2005-06-01 Diego Novillo <dnovillo@redhat.com>
PR 14341, PR 21332, PR 20701, PR 21029, PR 21086, PR 21090
PR 21289, PR 21348, PR 21367, PR 21368, PR 21458.
* fold-const.c (invert_tree_comparison): Make extern.
* tree-flow.h (enum value_range_type): Move to tree-ssa-propagate.
(struct value_range_def): Limewise.
(get_value_range): Remove.
(dump_value_range): Remove.
(dump_all_value_ranges): Remove.
(debug_all_value_ranges): Remove.
(vrp_evaluate_conditional): Declare.
* tree-ssa-propagate.c (struct prop_stats_d): Add field
num_pred_folded.
(substitute_and_fold): Add argument use_ranges_p.
Update all callers.
If use_ranges_p is true, call fold_predicate_in to fold
predicates using range information.
Ignore ASSERT_EXPRs.
Change debugging output to only show statements that have been
folded.
(replace_phi_args_in): Move debugging output code from
substitute and fold.
(fold_predicate_in): New local function.
* tree-ssa-propagate.h (enum value_range_type): Move from
tree-flow.h.
(struct value_range_d): Likewise.
Add field 'equiv'.
(value_range_t): Rename from value_range.
* tree-vrp.c (found_in_subgraph): Rename from found.
(get_opposite_operand): Remove.
(struct assert_locus_d): Declare.
(assert_locus_t): Declare.
(need_assert_for): Declare.
(asserts_for): Declare.
(blocks_visited): Declare.
(vr_value): Declare.
(set_value_range): Add argument 'equiv'.
Don't drop to VARYING ranges that cover all values in the
type.
Make deep copy of equivalence set 'equiv'.
(copy_value_range): New local function.
(set_value_range_to_undefined): New local function.
(compare_values): Return -2 if either value has overflowed.
(range_includes_zero_p): New local function.
(extract_range_from_assert): Flip the predicate code if the
name being asserted is on the RHS of the predicate.
Avoid creating unnecessary symbolic ranges if the comparison
includes another name with a known numeric range.
Update the equivalnce set of the new range when asserting
EQ_EXPR predicates.
(extract_range_from_ssa_name): Update the equivalence set of
the new range with VAR.
(extract_range_from_binary_expr): Also handle TRUTH_*_EXPR.
If -fwrapv is used, set the resulting range to VARYING if the
operation overflows. Otherwise, use TYPE_MIN_VALUE and
TYPE_MAX_VALUE to represent -INF and +INF.
Fix handling of *_DIV_EXPR.
(extract_range_from_unary_expr): Handle MINUS_EXPR and
ABS_EXPR properly by switching the range around if necessary.
(extract_range_from_comparison): New local function.
(extract_range_from_expr): Call it.
(adjust_range_with_scev): Do not adjust the range if using
wrapping arithmetic (-fwrapv).
(dump_value_range): Also show equivalence set.
Show -INF and +INF for TYPE_MIN_VALUE and TYPE_MAX_VALUE.
(build_assert_expr_for): Also build ASSERT_EXPR for EQ_EXPR.
(infer_value_range): Change return value to bool.
Add arguments 'comp_code_p' and 'val_p'.
Do not attempt to infer ranges from statements that may throw.
Store the comparison code in comp_code_p.
Store the other operand to be used in the predicate in val_p.
(dump_asserts_for): New.
(debug_asserts_for): New.
(dump_all_asserts): New.
(debug_all_asserts): New.
(register_new_assert_for): New.
(register_edge_assert_for): New.
(find_conditional_asserts): New.
(find_assert_locations): New.
(process_assert_insertions_for): New.
(process_assert_insertions): New.
(insert_range_assertions): Initialize found_in_subgraph,
blocks_visited, need_assert_for and asserts_for.
Call find_assert_locations and process_assert_insertions.
(remove_range_assertions): Add more documentation.
(vrp_initialize): Change return type to void.
Do not try to guess if running VRP is worth it.
(compare_name_with_value): New.
(compare_names): New.
(vrp_evaluate_conditional): Add argument 'use_equiv_p'. If
use_equiv_p is true, call compare_names and
compare_name_with_value to compare all the ranges for every
name in the equivalence set of the predicate operands.
Update all callers.
(vrp_meet): Try harder not to derive a VARYING range.
If two values meet, the resulting equivalence set is the
intersection of the two equivalence sets.
(vrp_visit_phi_node): Call copy_value_range to get the current
range information of the LHS.
(vrp_finalize): Create a value vector representing all the
names that ended up with exactly one value in their range.
Call substitute_and_fold.
(execute_vrp): Document equivalence sets in ranges.
* tree.h (SSA_NAME_VALUE_RANGE): Remove.
(struct tree_ssa_name): Remove field value_range.
(invert_tree_comparison): Declare.
2005-06-01 Daniel Berlin <dberlin@dberlin.org> 2005-06-01 Daniel Berlin <dberlin@dberlin.org>
Fix PR tree-optimization/21839 Fix PR tree-optimization/21839
......
...@@ -89,7 +89,6 @@ static tree negate_expr (tree); ...@@ -89,7 +89,6 @@ static tree negate_expr (tree);
static tree split_tree (tree, enum tree_code, tree *, tree *, tree *, int); static tree split_tree (tree, enum tree_code, tree *, tree *, tree *, int);
static tree associate_trees (tree, tree, enum tree_code, tree); static tree associate_trees (tree, tree, enum tree_code, tree);
static tree const_binop (enum tree_code, tree, tree, int); static tree const_binop (enum tree_code, tree, tree, int);
static enum tree_code invert_tree_comparison (enum tree_code, bool);
static enum comparison_code comparison_to_compcode (enum tree_code); static enum comparison_code comparison_to_compcode (enum tree_code);
static enum tree_code compcode_to_comparison (enum comparison_code); static enum tree_code compcode_to_comparison (enum comparison_code);
static tree combine_comparisons (enum tree_code, enum tree_code, static tree combine_comparisons (enum tree_code, enum tree_code,
...@@ -2119,7 +2118,7 @@ pedantic_non_lvalue (tree x) ...@@ -2119,7 +2118,7 @@ pedantic_non_lvalue (tree x)
comparisons, except for NE_EXPR and EQ_EXPR, so we receive a machine mode comparisons, except for NE_EXPR and EQ_EXPR, so we receive a machine mode
as well: if reversing the comparison is unsafe, return ERROR_MARK. */ as well: if reversing the comparison is unsafe, return ERROR_MARK. */
static enum tree_code enum tree_code
invert_tree_comparison (enum tree_code code, bool honor_nans) invert_tree_comparison (enum tree_code code, bool honor_nans)
{ {
if (honor_nans && flag_trapping_math) if (honor_nans && flag_trapping_math)
......
2005-06-01 Diego Novillo <dnovillo@redhat.com>
PR 14341, PR 21332, PR 20701, PR 21086, PR 21090
PR 21289, PR 21348, PR 21367, PR 21368, PR 21458.
* gcc.dg/tree-ssa/pr14341.c: New test.
* gcc.dg/tree-ssa/pr14841.c: New test.
* gcc.dg/tree-ssa/pr20701.c: New test.
* gcc.dg/tree-ssa/pr21086.c: New test.
* gcc.dg/tree-ssa/pr21090.c: New test.
* gcc.dg/tree-ssa/pr21332.c: New test.
* gcc.dg/tree-ssa/pr21458.c: New test.
* gcc.dg/tree-ssa/pr21658.c: New test.
* gcc.dg/tree-ssa/vrp01.c: New test.
* gcc.dg/tree-ssa/vrp02.c: New test.
* gcc.dg/tree-ssa/vrp03.c: New test.
* gcc.dg/tree-ssa/vrp04.c: New test.
* gcc.dg/tree-ssa/vrp05.c: New test.
* gcc.dg/tree-ssa/vrp06.c: New test.
* gcc.dg/tree-ssa/vrp07.c: New test.
* gcc.dg/tree-ssa/vrp08.c: New test.
* gcc.dg/tree-ssa/vrp09.c: New test.
* gcc.dg/tree-ssa/vrp10.c: New test.
* gcc.dg/tree-ssa/vrp11.c: New test.
* gcc.dg/tree-ssa/vrp12.c: New test.
* gcc.dg/tree-ssa/vrp13.c: New test.
2005-06-01 Alexandre Oliva <aoliva@redhat.com>
PR 21029
* gcc.dg/tree-ssa/pr21029.c: New test.
2005-06-01 Roger Sayle <roger@eyesopen.com> 2005-06-01 Roger Sayle <roger@eyesopen.com>
* gfortran.dg/logint-1.f: New test case. * gfortran.dg/logint-1.f: New test case.
......
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-vrp" } */
void fn_call (int);
int h(int, int);
void t()
{
int i;
int x;
for( i = 0; i < 100000000; i++ ){
fn_call (i < 100000000);
}
}
/* { dg-final { scan-tree-dump-times "fn_call \\(1\\)" 1 "vrp" } } */
/* { dg-final { cleanup-tree-dump "vrp" } } */
...@@ -25,5 +25,5 @@ foo (void) ...@@ -25,5 +25,5 @@ foo (void)
link_error (); link_error ();
} }
/* { dg-final { scan-tree-dump-times "with if \\(0\\)" 1 "store_ccp"} } */ /* { dg-final { scan-tree-dump-times "Folded statement: if " 1 "store_ccp"} } */
/* { dg-final { cleanup-tree-dump "store_ccp" } } */ /* { dg-final { cleanup-tree-dump "store_ccp" } } */
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-vrp" } */
typedef struct {
int code;
} *rtx;
int
can_combine_p (rtx insn, rtx elt)
{
rtx set;
set = 0;
if (insn->code == 3)
set = insn;
else
{
set = elt;
if (set == 0)
return 0;
}
if (set == 0)
return 1;
return 0;
}
/* { dg-final { scan-tree-dump-times "Folding predicate.*to 0" 1 "vrp" } } */
/* { dg-final { cleanup-tree-dump "vrp" } } */
/* { dg-do run } */
/* { dg-options "-O2 -fwrapv" } */
/* PR tree-optimization/21029
f() used to get optimized to an infinite loop by tree-vrp, because
j is assumed to be non-negative. Even though the conversion from
unsigned to signed has unspecified results if the expression value
is not representable in the signed type, the compiler itself (e.g.,
the Ada front end) depends on wrap-around behavior. */
unsigned int f(void) {
unsigned char i = 123;
signed char j;
do
if ((j = (signed char) i) < 0)
break;
else
i++;
while (1);
return i;
}
/* Now let's torture it a bit further. Narrowing conversions need
similar treatment. */
unsigned int f1 (void) {
unsigned short i = 123;
signed char j;
do
if ((j = (signed char) i) < 0)
break;
else
i++;
while (1);
return i;
}
/* And so do widening conversions. */
unsigned int f2 (void) {
unsigned char i = 123;
signed short j;
do
if ((j = (signed short) (signed char) i) < 0)
break;
else
i++;
while (1);
return i;
}
/* Check same-sign truncations with an increment that turns into
decrements. */
unsigned int f3 (void) {
signed short i = 5;
signed char j;
do
if ((j = (signed char) i) < 0)
break;
else
i += 255;
while (1);
return i;
}
/* Check that the truncation above doesn't confuse the result of the
test after a widening conversion. */
unsigned int f4 (void) {
signed short i = -123;
signed int j;
do
if ((j = (signed int) (signed char) i) > 0)
break;
else
i += 255;
while (1);
return i;
}
/* Even if we omit the widening truncation, the narrowing truncation
is implementation-defined. */
unsigned int f5 (void) {
signed long i = -123;
signed char j;
do
if ((j = (signed char) i) > 0)
break;
else
i += 255;
while (1);
return i;
}
int main (void) {
f ();
f1 ();
f2 ();
f3 ();
f4 ();
f5 ();
return 0;
}
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-vrp" } */
int
foo (int *p)
{
int a = *p;
int b = p != 0;
*p = b;
if (b)
return a;
else
return 0;
}
/* { dg-final { scan-tree-dump-times "Folding predicate " 2 "vrp" } } */
/* { dg-final { cleanup-tree-dump "vrp" } } */
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-vrp" } */
int g, h;
int
foo (int a)
{
int *p;
if (a)
p = &g;
else
p = &h;
if (p != 0)
return 1;
else
return 0;
}
/* { dg-final { scan-tree-dump-times "Folding predicate.*to 1" 1 "vrp" } } */
/* { dg-final { cleanup-tree-dump "vrp" } } */
/* { dg-do run } */
/* { dg-options "-O2" } */
// this testcase fails also on amd64:
extern void abort (void);
int f ()
{
return -1;
}
int main ()
{
int b, c, i;
b = 0;
c = f ();
if (c <= 0)
{
c = -c;
for (i = 0; i < c; i++)
b = 1;
if (!b)
abort ();
}
return 0;
}
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-vrp" } */
extern void g (void);
extern void bar (int);
int
foo (int a)
{
int i;
for (i = 1; i < 100; i++)
{
if (i)
g ();
}
}
/* { dg-final { scan-tree-dump-times "Folding predicate.*to 1" 1 "vrp" } } */
/* { dg-final { cleanup-tree-dump "vrp" } } */
...@@ -17,5 +17,5 @@ f (void) ...@@ -17,5 +17,5 @@ f (void)
link_error (); link_error ();
} }
/* { dg-final { scan-tree-dump-times "with if \\(0\\)" 1 "ccp"} } */ /* { dg-final { scan-tree-dump-times "Folded statement: if " 1 "ccp"} } */
/* { dg-final { cleanup-tree-dump "ccp" } } */ /* { dg-final { cleanup-tree-dump "ccp" } } */
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-vrp" } */
foo (int *p, int i)
{
int x;
if (i > 10)
{
if (p)
{
x = *p;
p = 0;
}
}
else
p = 0;
/* This should be folded to if (1), but only if we insert an
assertion on the ELSE edge from the inner 'if (p)'. */
if (p == 0)
return x + 1;
return i;
}
/* { dg-final { scan-tree-dump-times "Folding predicate p_.*to 1" 1 "vrp" } } */
/* { dg-final { cleanup-tree-dump "vrp" } } */
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-vrp" } */
struct A
{
int a;
int b;
};
foo (struct A *p, struct A *q)
{
int x = p->a;
if (p == q)
return q->a;
/* We should fold this to 'if (1)' but the assertion for 'p == q'
was overwriting the assertion 'p != 0' from the first dereference
of 'p'. */
if (p)
return x + p->b;
}
/* { dg-final { scan-tree-dump-times "Folding predicate p_.*to 1" 1 "vrp" } } */
/* { dg-final { cleanup-tree-dump "vrp" } } */
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-vrp" } */
struct A
{
int a;
int b;
};
foo (struct A *p, struct A *q)
{
int *r = 0;
if (p)
{
if (p == q)
{
/* This should be folded to 'if (1)' because q is [p, p]
and p is ~[0, 0]. */
if (q)
r = &q->a;
/* This should be folded to 'if (1)' because q should be
~[0, 0] and thus &q->a should be ~[0, 0]. */
if (r)
return 5;
}
}
return q->a;
}
/* { dg-final { scan-tree-dump-times "Folding predicate q_.*to 1" 1 "vrp" } } */
/* { dg-final { scan-tree-dump-times "Folding predicate r_.*to 1" 1 "vrp" } } */
/* { dg-final { cleanup-tree-dump "vrp" } } */
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-vrp" } */
foo (int a, int b)
{
if (a == b)
/* This should be folded to if (1) */
if (a == b)
return a + b;
}
/* { dg-final { scan-tree-dump-times "Folding predicate a_.*to 1" 1 "vrp" } } */
/* { dg-final { cleanup-tree-dump "vrp" } } */
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-vrp" } */
foo (int k, int j)
{
if (k >= 10)
{
if (j > k)
{
/* We should fold this to if (1). */
if (j > 0)
return j;
}
}
return j;
}
/* { dg-final { scan-tree-dump-times "Folding predicate j_.*to 1" 1 "vrp" } } */
/* { dg-final { cleanup-tree-dump "vrp" } } */
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-vrp" } */
foo (int i, int j, int a)
{
if (i >= 10)
if (i <= 30)
if (i == j)
{
a--;
/* This should fold to 'if (0)'. */
if (i < 0)
i = baz ();
/* This should fold to 'if (1)'. */
if (j > 0)
a--;
/* This should fold to 'if (0)'. */
if (i != j)
return 0;
}
return i + a + j;
}
/* { dg-final { scan-tree-dump-times "Folding predicate i_.*to 0" 1 "vrp" } } */
/* { dg-final { scan-tree-dump-times "Folding predicate j_.*to 1" 1 "vrp" } } */
/* { dg-final { scan-tree-dump-times "Folding predicate i_.*to 0" 1 "vrp" } } */
/* { dg-final { cleanup-tree-dump "vrp" } } */
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-vrp-details" } */
foo (int i, int *p)
{
int j;
if (i > 10)
{
if (p)
{
j = *p;
/* This should be folded to if (1) because of the parent 'if
(p)'. But the dereference of p above does not need an
assertion. */
if (p)
return j + 1;
}
}
else
{
j = *p - 3;
/* This should be folded to if (0), because p has just been
dereferenced. But we were not inserting enough ASSERT_EXPRs
to figure it out. */
if (!p)
return j - 4;
}
return i;
}
/* { dg-final { scan-tree-dump-times "Folding predicate p_.*to 1" 1 "vrp" } } */
/* { dg-final { scan-tree-dump-times "Folding predicate p_.*to 0" 1 "vrp" } } */
/* { dg-final { scan-tree-dump-times "PREDICATE: p_\[0-9\] ne_expr 0B" 2 "vrp" } } */
/* { dg-final { cleanup-tree-dump "vrp" } } */
/* { dg-do compile } */
/* { dg-options "-O2 -fno-tree-fre -fdump-tree-vrp-details" } */
/* Compile with -fno-tree-fre -O2 to prevent CSEing *p. */
foo (int a, int *p)
{
int x = *p + 2;
int y = *p - 1;
int z = *p + 9;
/* This should be folded to if (1), but only one ASSERT_EXPR should
be inserted. */
if (p)
a = x + y + z;
else
a = x - y;
return a;
}
/* { dg-final { scan-tree-dump-times "Folding predicate p_.*to 1" 1 "vrp" } } */
/* { dg-final { scan-tree-dump-times "PREDICATE: p_. ne_expr 0" 1 "vrp" } } */
/* { dg-final { cleanup-tree-dump "vrp" } } */
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-vrp" } */
foo (int *p)
{
int x = baz ();
if (p == 0)
goto L78;
else
{
x = *p;
/* This should be folded to if (1). */
if (p)
x = x + 1;
L78:
/* This should not be folded to if (1). */
if (p)
{
x = baz (*p);
/* This should be folded to if (1). */
if (p)
return x + 3;
}
return x - 3;
}
}
/* { dg-final { scan-tree-dump-times "Folding predicate p_.. != 0B to 1" 2 "vrp" } } */
/* { dg-final { cleanup-tree-dump "vrp" } } */
/* { dg-do run } */
/* { dg-options "-O2" } */
extern void abort (void);
foo (int k, int j)
{
if (k >= 10)
{
if (j > k)
{
/* We should fold this to if (0). */
if (j < 10)
abort ();
}
}
return j;
}
main()
{
foo (10, 3);
return 0;
}
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-vrp" } */
foo (int k, int j, int z)
{
if (k > z)
{
if (j > k)
{
/* We should fold this to if (1). */
if (j > z)
return j;
}
}
return j;
}
/* { dg-final { scan-tree-dump-times "Folding predicate.*to 1" 1 "vrp" } } */
/* { dg-final { cleanup-tree-dump "vrp" } } */
/* { dg-do link } */
/* { dg-options -O2 } */
foo (int i)
{
int x;
x = i;
if (i < -10)
{
x = __builtin_abs (i);
/* VRP was incorrectly folding this to if (1). */
if (x < 0)
link_error ();
}
return x;
}
main()
{
foo (-30);
}
/* { dg-do run } */
/* { dg-options -O2 } */
extern void abort (void);
foo (int i, int j)
{
int k;
/* [-INF, -1] / [1, +INF] should not give [-1, -1]. */
if (i <= -1)
if (j >= 1)
{
k = i / j;
if (k == -1)
abort ();
return k;
}
/* [-20, -10] / [2, 10] should give [-10, -1]. */
if (i >= -20)
if (i <= -10)
if (j >= 2)
if (j <= 10)
{
k = i / j;
if (k < -10)
link_error ();
if (k > -1)
link_error ();
return k;
}
/* [-20, -10] / [-10, -2] should give [1, 10]. */
if (i >= -20)
if (i <= -10)
if (j >= -10)
if (j <= -2)
{
k = i / j;
if (k < 1)
link_error ();
if (k > 10)
link_error ();
return k;
}
/* [-20, 10] / [2, 10] should give [-10, 5]. */
if (i >= -20)
if (i <= 10)
if (j >= 2)
if (j <= 10)
{
k = i / j;
if (k < -10)
link_error ();
if (k > 5)
link_error ();
return k;
}
/* [-20, 10] / [-10, -2] should give [-5, 10]. */
if (i >= -20)
if (i <= 10)
if (j >= -10)
if (j <= -2)
{
k = i / j;
if (k < -5)
link_error ();
if (k > 10)
link_error ();
return k;
}
/* [10, 20] / [2, 10] should give [1, 10]. */
if (i >= 10)
if (i <= 20)
if (j >= 2)
if (j <= 10)
{
k = i / j;
if (k < 1)
link_error ();
if (k > 10)
link_error ();
return k;
}
/* [10, 20] / [-10, -2] should give [-10, -1]. */
if (i >= 10)
if (i <= 20)
if (j >= -10)
if (j <= -2)
{
k = i / j;
if (k > -1)
link_error ();
if (k < -10)
link_error ();
return k;
}
abort ();
}
main()
{
if (foo (-10, 5) != -2)
abort ();
if (foo (-16, 4) != -4)
abort ();
if (foo (-15, -5) != 3)
abort ();
if (foo (8, 2) != 4)
abort ();
if (foo (10, -2) != -5)
abort ();
if (foo (20, 5) != 4)
abort ();
if (foo (15, -3) != -5)
abort ();
return 0;
}
...@@ -83,34 +83,6 @@ struct ptr_info_def GTY(()) ...@@ -83,34 +83,6 @@ struct ptr_info_def GTY(())
}; };
/* Types of value ranges. */
enum value_range_type { VR_UNDEFINED, VR_RANGE, VR_ANTI_RANGE, VR_VARYING };
/* Ranges of values that can be associated with an SSA_NAME after VRP
has executed. */
struct value_range_def GTY(())
{
/* Lattice value represented by this range. */
enum value_range_type type;
/* Minimum and maximum values represented by this range. These
values are _CST nodes that should be interpreted as follows:
- If TYPE == VR_UNDEFINED then MIN and MAX must be NULL.
- If TYPE == VR_RANGE then MIN holds the minimum value and
MAX holds the maximum value of the range [MIN, MAX].
- If TYPE == ANTI_RANGE the variable is known to NOT
take any values in the range [MIN, MAX]. */
tree min;
tree max;
};
typedef struct value_range_def value_range;
/*--------------------------------------------------------------------------- /*---------------------------------------------------------------------------
Tree annotations stored in tree_common.ann Tree annotations stored in tree_common.ann
---------------------------------------------------------------------------*/ ---------------------------------------------------------------------------*/
...@@ -619,12 +591,8 @@ bool fold_stmt_inplace (tree); ...@@ -619,12 +591,8 @@ bool fold_stmt_inplace (tree);
tree widen_bitfield (tree, tree, tree); tree widen_bitfield (tree, tree, tree);
/* In tree-vrp.c */ /* In tree-vrp.c */
value_range *get_value_range (tree);
void dump_value_range (FILE *, value_range *);
void debug_value_range (value_range *);
void dump_all_value_ranges (FILE *);
void debug_all_value_ranges (void);
bool expr_computes_nonzero (tree); bool expr_computes_nonzero (tree);
tree vrp_evaluate_conditional (tree, bool);
/* In tree-ssa-dom.c */ /* In tree-ssa-dom.c */
extern void dump_dominator_optimization_stats (FILE *); extern void dump_dominator_optimization_stats (FILE *);
......
...@@ -580,7 +580,7 @@ static void ...@@ -580,7 +580,7 @@ static void
ccp_finalize (void) ccp_finalize (void)
{ {
/* Perform substitutions based on the known constant values. */ /* Perform substitutions based on the known constant values. */
substitute_and_fold (const_val); substitute_and_fold (const_val, false);
free (const_val); free (const_val);
} }
......
...@@ -894,7 +894,7 @@ fini_copy_prop (void) ...@@ -894,7 +894,7 @@ fini_copy_prop (void)
copy_of[i].value = get_last_copy_of (var); copy_of[i].value = get_last_copy_of (var);
} }
substitute_and_fold (copy_of); substitute_and_fold (copy_of, false);
free (cached_last_copy_of); free (cached_last_copy_of);
free (copy_of); free (copy_of);
......
...@@ -773,6 +773,7 @@ struct prop_stats_d ...@@ -773,6 +773,7 @@ struct prop_stats_d
{ {
long num_const_prop; long num_const_prop;
long num_copy_prop; long num_copy_prop;
long num_pred_folded;
}; };
static struct prop_stats_d prop_stats; static struct prop_stats_d prop_stats;
...@@ -964,6 +965,11 @@ static void ...@@ -964,6 +965,11 @@ static void
replace_phi_args_in (tree phi, prop_value_t *prop_value) replace_phi_args_in (tree phi, prop_value_t *prop_value)
{ {
int i; int i;
bool replaced = false;
tree prev_phi = NULL;
if (dump_file && (dump_flags & TDF_DETAILS))
prev_phi = unshare_expr (phi);
for (i = 0; i < PHI_NUM_ARGS (phi); i++) for (i = 0; i < PHI_NUM_ARGS (phi); i++)
{ {
...@@ -981,6 +987,7 @@ replace_phi_args_in (tree phi, prop_value_t *prop_value) ...@@ -981,6 +987,7 @@ replace_phi_args_in (tree phi, prop_value_t *prop_value)
prop_stats.num_copy_prop++; prop_stats.num_copy_prop++;
propagate_value (PHI_ARG_DEF_PTR (phi, i), val); propagate_value (PHI_ARG_DEF_PTR (phi, i), val);
replaced = true;
/* If we propagated a copy and this argument flows /* If we propagated a copy and this argument flows
through an abnormal edge, update the replacement through an abnormal edge, update the replacement
...@@ -991,19 +998,79 @@ replace_phi_args_in (tree phi, prop_value_t *prop_value) ...@@ -991,19 +998,79 @@ replace_phi_args_in (tree phi, prop_value_t *prop_value)
} }
} }
} }
if (replaced && dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "Folded PHI node: ");
print_generic_stmt (dump_file, prev_phi, TDF_SLIM);
fprintf (dump_file, " into: ");
print_generic_stmt (dump_file, phi, TDF_SLIM);
fprintf (dump_file, "\n");
}
}
/* If STMT has a predicate whose value can be computed using the value
range information computed by VRP, compute its value and return true.
Otherwise, return false. */
static bool
fold_predicate_in (tree stmt)
{
tree *pred_p = NULL;
tree val;
if (TREE_CODE (stmt) == MODIFY_EXPR
&& COMPARISON_CLASS_P (TREE_OPERAND (stmt, 1)))
pred_p = &TREE_OPERAND (stmt, 1);
else if (TREE_CODE (stmt) == COND_EXPR)
pred_p = &COND_EXPR_COND (stmt);
else
return false;
val = vrp_evaluate_conditional (*pred_p, true);
if (val)
{
if (dump_file)
{
fprintf (dump_file, "Folding predicate ");
print_generic_expr (dump_file, *pred_p, 0);
fprintf (dump_file, " to ");
print_generic_expr (dump_file, val, 0);
fprintf (dump_file, "\n");
}
prop_stats.num_pred_folded++;
*pred_p = val;
return true;
}
return false;
} }
/* Perform final substitution and folding of propagated values. */ /* Perform final substitution and folding of propagated values.
PROP_VALUE[I] contains the single value that should be substituted
at every use of SSA name N_I. If PROP_VALUE is NULL, no values are
substituted.
If USE_RANGES_P is true, statements that contain predicate
expressions are evaluated with a call to vrp_evaluate_conditional.
This will only give meaningful results when called from tree-vrp.c
(the information used by vrp_evaluate_conditional is built by the
VRP pass). */
void void
substitute_and_fold (prop_value_t *prop_value) substitute_and_fold (prop_value_t *prop_value, bool use_ranges_p)
{ {
basic_block bb; basic_block bb;
if (prop_value == NULL && !use_ranges_p)
return;
if (dump_file && (dump_flags & TDF_DETAILS)) if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, fprintf (dump_file, "\nSubstituing values and folding statements\n\n");
"\nSubstituing values and folding statements\n\n");
memset (&prop_stats, 0, sizeof (prop_stats)); memset (&prop_stats, 0, sizeof (prop_stats));
...@@ -1013,41 +1080,51 @@ substitute_and_fold (prop_value_t *prop_value) ...@@ -1013,41 +1080,51 @@ substitute_and_fold (prop_value_t *prop_value)
block_stmt_iterator i; block_stmt_iterator i;
tree phi; tree phi;
/* Propagate our known values into PHI nodes. */ /* Propagate known values into PHI nodes. */
for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi)) if (prop_value)
{ for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "Replaced ");
print_generic_stmt (dump_file, phi, TDF_SLIM);
}
replace_phi_args_in (phi, prop_value); replace_phi_args_in (phi, prop_value);
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, " with ");
print_generic_stmt (dump_file, phi, TDF_SLIM);
fprintf (dump_file, "\n");
}
}
for (i = bsi_start (bb); !bsi_end_p (i); bsi_next (&i)) for (i = bsi_start (bb); !bsi_end_p (i); bsi_next (&i))
{ {
bool replaced_address, did_replace; bool replaced_address, did_replace;
tree prev_stmt = NULL;
tree stmt = bsi_stmt (i); tree stmt = bsi_stmt (i);
/* Ignore ASSERT_EXPRs. They are used by VRP to generate
range information for names and they are discarded
afterwards. */
if (TREE_CODE (stmt) == MODIFY_EXPR
&& TREE_CODE (TREE_OPERAND (stmt, 1)) == ASSERT_EXPR)
continue;
/* Replace the statement with its folded version and mark it /* Replace the statement with its folded version and mark it
folded. */ folded. */
did_replace = false;
replaced_address = false;
if (dump_file && (dump_flags & TDF_DETAILS)) if (dump_file && (dump_flags & TDF_DETAILS))
prev_stmt = unshare_expr (stmt);
/* If we have range information, see if we can fold
predicate expressions. */
if (use_ranges_p)
did_replace = fold_predicate_in (stmt);
if (prop_value)
{ {
fprintf (dump_file, "Replaced "); /* Only replace real uses if we couldn't fold the
print_generic_stmt (dump_file, stmt, TDF_SLIM); statement using value range information (value range
information is not collected on virtuals, so we only
need to check this for real uses). */
if (!did_replace)
did_replace |= replace_uses_in (stmt, &replaced_address,
prop_value);
did_replace |= replace_vuses_in (stmt, &replaced_address,
prop_value);
} }
replaced_address = false; /* If we made a replacement, fold and cleanup the statement. */
did_replace = replace_uses_in (stmt, &replaced_address, prop_value);
did_replace |= replace_vuses_in (stmt, &replaced_address, prop_value);
if (did_replace) if (did_replace)
{ {
tree old_stmt = stmt; tree old_stmt = stmt;
...@@ -1068,13 +1145,15 @@ substitute_and_fold (prop_value_t *prop_value) ...@@ -1068,13 +1145,15 @@ substitute_and_fold (prop_value_t *prop_value)
rhs = get_rhs (stmt); rhs = get_rhs (stmt);
if (TREE_CODE (rhs) == ADDR_EXPR) if (TREE_CODE (rhs) == ADDR_EXPR)
recompute_tree_invarant_for_addr_expr (rhs); recompute_tree_invarant_for_addr_expr (rhs);
}
if (dump_file && (dump_flags & TDF_DETAILS)) if (dump_file && (dump_flags & TDF_DETAILS))
{ {
fprintf (dump_file, " with "); fprintf (dump_file, "Folded statement: ");
print_generic_stmt (dump_file, stmt, TDF_SLIM); print_generic_stmt (dump_file, prev_stmt, TDF_SLIM);
fprintf (dump_file, "\n"); fprintf (dump_file, " into: ");
print_generic_stmt (dump_file, stmt, TDF_SLIM);
fprintf (dump_file, "\n");
}
} }
} }
} }
...@@ -1085,6 +1164,9 @@ substitute_and_fold (prop_value_t *prop_value) ...@@ -1085,6 +1164,9 @@ substitute_and_fold (prop_value_t *prop_value)
prop_stats.num_const_prop); prop_stats.num_const_prop);
fprintf (dump_file, "Copies propagated: %6ld\n", fprintf (dump_file, "Copies propagated: %6ld\n",
prop_stats.num_copy_prop); prop_stats.num_copy_prop);
fprintf (dump_file, "Predicates folded: %6ld\n",
prop_stats.num_pred_folded);
} }
} }
#include "gt-tree-ssa-propagate.h" #include "gt-tree-ssa-propagate.h"
...@@ -73,6 +73,39 @@ struct prop_value_d { ...@@ -73,6 +73,39 @@ struct prop_value_d {
typedef struct prop_value_d prop_value_t; typedef struct prop_value_d prop_value_t;
/* Type of value ranges. See value_range_d for a description of these
types. */
enum value_range_type { VR_UNDEFINED, VR_RANGE, VR_ANTI_RANGE, VR_VARYING };
/* Range of values that can be associated with an SSA_NAME after VRP
has executed. */
struct value_range_d
{
/* Lattice value represented by this range. */
enum value_range_type type;
/* Minimum and maximum values represented by this range. These
values should be interpreted as follows:
- If TYPE is VR_UNDEFINED or VR_VARYING then MIN and MAX must
be NULL.
- If TYPE == VR_RANGE then MIN holds the minimum value and
MAX holds the maximum value of the range [MIN, MAX].
- If TYPE == ANTI_RANGE the variable is known to NOT
take any values in the range [MIN, MAX]. */
tree min;
tree max;
/* Set of SSA names whose value ranges are equivalent to this one.
This set is only valid when TYPE is VR_RANGE or VR_ANTI_RANGE. */
bitmap equiv;
};
typedef struct value_range_d value_range_t;
/* Call-back functions used by the value propagation engine. */ /* Call-back functions used by the value propagation engine. */
typedef enum ssa_prop_result (*ssa_prop_visit_stmt_fn) (tree, edge *, tree *); typedef enum ssa_prop_result (*ssa_prop_visit_stmt_fn) (tree, edge *, tree *);
typedef enum ssa_prop_result (*ssa_prop_visit_phi_fn) (tree); typedef enum ssa_prop_result (*ssa_prop_visit_phi_fn) (tree);
...@@ -87,6 +120,6 @@ bool stmt_makes_single_load (tree); ...@@ -87,6 +120,6 @@ bool stmt_makes_single_load (tree);
bool stmt_makes_single_store (tree); bool stmt_makes_single_store (tree);
prop_value_t *get_value_loaded_by (tree, prop_value_t *); prop_value_t *get_value_loaded_by (tree, prop_value_t *);
bool replace_uses_in (tree, bool *, prop_value_t *); bool replace_uses_in (tree, bool *, prop_value_t *);
void substitute_and_fold (prop_value_t *); void substitute_and_fold (prop_value_t *, bool);
#endif /* _TREE_SSA_PROPAGATE_H */ #endif /* _TREE_SSA_PROPAGATE_H */
...@@ -1338,17 +1338,12 @@ struct tree_exp GTY(()) ...@@ -1338,17 +1338,12 @@ struct tree_exp GTY(())
#define SSA_NAME_VALUE(N) \ #define SSA_NAME_VALUE(N) \
SSA_NAME_CHECK (N)->ssa_name.value_handle SSA_NAME_CHECK (N)->ssa_name.value_handle
/* Range information for SSA_NAMEs. */
#define SSA_NAME_VALUE_RANGE(N) \
SSA_NAME_CHECK (N)->ssa_name.value_range
/* Auxiliary pass-specific data. */ /* Auxiliary pass-specific data. */
#define SSA_NAME_AUX(N) \ #define SSA_NAME_AUX(N) \
SSA_NAME_CHECK (N)->ssa_name.aux SSA_NAME_CHECK (N)->ssa_name.aux
#ifndef _TREE_FLOW_H #ifndef _TREE_FLOW_H
struct ptr_info_def; struct ptr_info_def;
struct value_range_def;
#endif #endif
...@@ -1386,9 +1381,6 @@ struct tree_ssa_name GTY(()) ...@@ -1386,9 +1381,6 @@ struct tree_ssa_name GTY(())
as well. */ as well. */
tree value_handle; tree value_handle;
/* Value range information. */
struct value_range_def *value_range;
/* Auxiliary information stored with the ssa name. */ /* Auxiliary information stored with the ssa name. */
PTR GTY((skip)) aux; PTR GTY((skip)) aux;
...@@ -3601,6 +3593,7 @@ extern bool tree_swap_operands_p (tree, tree, bool); ...@@ -3601,6 +3593,7 @@ extern bool tree_swap_operands_p (tree, tree, bool);
extern enum tree_code swap_tree_comparison (enum tree_code); extern enum tree_code swap_tree_comparison (enum tree_code);
extern bool ptr_difference_const (tree, tree, HOST_WIDE_INT *); extern bool ptr_difference_const (tree, tree, HOST_WIDE_INT *);
extern enum tree_code invert_tree_comparison (enum tree_code, bool);
/* In builtins.c */ /* In builtins.c */
extern tree fold_builtin (tree, tree, bool); extern tree fold_builtin (tree, tree, bool);
......
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