mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-02-23 18:39:48 +08:00
tree-ssa-dom.c (simplify_rhs_and_lookup_avail_expr): No longer simplify DIV, MOD or ABS expressions using VRP information.
* tree-ssa-dom.c (simplify_rhs_and_lookup_avail_expr): No longer simplify DIV, MOD or ABS expressions using VRP information. Remove WALK_DATA parameter. Prototype and all callers updated. (eliminate_redundant_computations): Remove WALK_DATA parameter. Prototype and all callers updated. (optimize_stmt): WALK_DATA parameter is now unused. * tree-vrp.c (local_fold): New function. Like fold, but strips useless type conversions in the result. (simplify_using_ranges): New function, largely cribbed from tree-ssa-dom.c::simplify_rhs_and_lookup_avail_expr. (vrp_finalize): Call simplify_using_ranges. * gcc.dg/tree-ssa/20030807-10.c: VRP is now expected to perform the desired transformations. * gcc.dg/tree-ssa/20030806-6.c: Similarly. * gcc.dg/tree-ssa/20040514-2.c: Similarly. From-SVN: r100909
This commit is contained in:
parent
2b5554f3c0
commit
a513fe886b
@ -1,3 +1,18 @@
|
||||
2005-06-13 Jeff Law <law@redhat.com>
|
||||
|
||||
* tree-ssa-dom.c (simplify_rhs_and_lookup_avail_expr): No longer
|
||||
simplify DIV, MOD or ABS expressions using VRP information.
|
||||
Remove WALK_DATA parameter. Prototype and all callers updated.
|
||||
(eliminate_redundant_computations): Remove WALK_DATA parameter.
|
||||
Prototype and all callers updated.
|
||||
(optimize_stmt): WALK_DATA parameter is now unused.
|
||||
|
||||
* tree-vrp.c (local_fold): New function. Like fold, but
|
||||
strips useless type conversions in the result.
|
||||
(simplify_using_ranges): New function, largely cribbed from
|
||||
tree-ssa-dom.c::simplify_rhs_and_lookup_avail_expr.
|
||||
(vrp_finalize): Call simplify_using_ranges.
|
||||
|
||||
2005-06-13 Mark Mitchell <mark@codesourcery.com>
|
||||
|
||||
* config/i386/x86-64.h (ASM_SPEC): Explicitly pass --64 to the
|
||||
|
@ -1,3 +1,10 @@
|
||||
2005-06-13 Jeff Law <law@redhat.com>
|
||||
|
||||
* gcc.dg/tree-ssa/20030807-10.c: VRP is now expected to
|
||||
perform the desired transformations.
|
||||
* gcc.dg/tree-ssa/20030806-6.c: Similarly.
|
||||
* gcc.dg/tree-ssa/20040514-2.c: Similarly.
|
||||
|
||||
2005-06-13 Tobias Schl"uter <tobias.schlueter@physik.uni-muenchen.de>
|
||||
|
||||
PR fortran/22038
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O1 -fdump-tree-dom3" } */
|
||||
/* { dg-options "-O2 -fdump-tree-vrp" } */
|
||||
|
||||
|
||||
extern const unsigned char mode_size[];
|
||||
@ -18,9 +18,9 @@ subreg_highpart_offset (outermode, innermode)
|
||||
}
|
||||
|
||||
/* There should be one mask with the value 3. */
|
||||
/* { dg-final { scan-tree-dump-times " \& 3" 1 "dom3"} } */
|
||||
/* { dg-final { scan-tree-dump-times " \& 3" 1 "vrp"} } */
|
||||
|
||||
/* There should be one right shift by 2 places. */
|
||||
/* { dg-final { scan-tree-dump-times " >> 2" 1 "dom3"} } */
|
||||
/* { dg-final { scan-tree-dump-times " >> 2" 1 "vrp"} } */
|
||||
|
||||
/* { dg-final { cleanup-tree-dump "dom3" } } */
|
||||
/* { dg-final { cleanup-tree-dump "vrp" } } */
|
||||
|
@ -1,8 +1,8 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O1 -fdump-tree-dom3" } */
|
||||
/* { dg-options "-O2 -fdump-tree-vrp" } */
|
||||
|
||||
|
||||
static void
|
||||
void
|
||||
foo (distance, i, j)
|
||||
int distance[13][13];
|
||||
int i, j;
|
||||
@ -11,7 +11,7 @@ foo (distance, i, j)
|
||||
distance[i][0] = ((distance[i][j]) < 0 ? -(distance[i][j]) : (distance[i][j]));
|
||||
}
|
||||
|
||||
static void
|
||||
void
|
||||
foo2 (distance, i, j)
|
||||
int distance[13][13];
|
||||
int i, j;
|
||||
@ -20,7 +20,7 @@ foo2 (distance, i, j)
|
||||
distance[i][0] = ((distance[i][j]) < 0 ? -(distance[i][j]) : (distance[i][j]));
|
||||
}
|
||||
|
||||
static void
|
||||
void
|
||||
foo3 (distance, i, j)
|
||||
int distance[13][13];
|
||||
int i, j;
|
||||
@ -29,7 +29,7 @@ foo3 (distance, i, j)
|
||||
distance[i][0] = ((distance[i][j]) < 0 ? -(distance[i][j]) : (distance[i][j]));
|
||||
}
|
||||
|
||||
static void
|
||||
void
|
||||
foo4 (distance, i, j)
|
||||
double distance[13][13];
|
||||
int i, j;
|
||||
@ -39,5 +39,5 @@ foo4 (distance, i, j)
|
||||
}
|
||||
|
||||
/* There should be no ABS_EXPR. */
|
||||
/* { dg-final { scan-tree-dump-times "ABS_EXPR " 0 "dom3"} } */
|
||||
/* { dg-final { cleanup-tree-dump "dom3" } } */
|
||||
/* { dg-final { scan-tree-dump-times "ABS_EXPR " 0 "vrp"} } */
|
||||
/* { dg-final { cleanup-tree-dump "vrp" } } */
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O1 -fdump-tree-dom3" } */
|
||||
/* { dg-options "-O2 -fdump-tree-phiopt1" } */
|
||||
int
|
||||
foo2 (distance, i, j)
|
||||
int distance;
|
||||
@ -12,7 +12,6 @@ foo2 (distance, i, j)
|
||||
}
|
||||
|
||||
/* There should be one ABS_EXPR and no conditionals. */
|
||||
/* { dg-final { scan-tree-dump-times "ABS_EXPR " 1 "dom3"} } */
|
||||
/* { dg-final { scan-tree-dump-times "if " 0 "dom3"} } */
|
||||
/* { dg-final { scan-tree-dump-times "ABS_EXPR " 1 "phiopt1"} } */
|
||||
/* { dg-final { scan-tree-dump-times "if " 0 "phiopt1"} } */
|
||||
|
||||
/* { dg-final { cleanup-tree-dump "dom3" } } */
|
||||
|
@ -272,8 +272,7 @@ static void record_cond (tree, tree);
|
||||
static void record_const_or_copy (tree, tree);
|
||||
static void record_equality (tree, tree);
|
||||
static tree update_rhs_and_lookup_avail_expr (tree, tree, bool);
|
||||
static tree simplify_rhs_and_lookup_avail_expr (struct dom_walk_data *,
|
||||
tree, int);
|
||||
static tree simplify_rhs_and_lookup_avail_expr (tree, int);
|
||||
static tree simplify_cond_and_lookup_avail_expr (tree, stmt_ann_t, int);
|
||||
static tree simplify_switch_and_lookup_avail_expr (tree, int);
|
||||
static tree find_equivalent_equality_comparison (tree);
|
||||
@ -281,8 +280,7 @@ static void record_range (tree, basic_block);
|
||||
static bool extract_range_from_cond (tree, tree *, tree *, int *);
|
||||
static void record_equivalences_from_phis (basic_block);
|
||||
static void record_equivalences_from_incoming_edge (basic_block);
|
||||
static bool eliminate_redundant_computations (struct dom_walk_data *,
|
||||
tree, stmt_ann_t);
|
||||
static bool eliminate_redundant_computations (tree, stmt_ann_t);
|
||||
static void record_equivalences_from_stmt (tree, int, stmt_ann_t);
|
||||
static void thread_across_edge (struct dom_walk_data *, edge);
|
||||
static void dom_opt_finalize_block (struct dom_walk_data *, basic_block);
|
||||
@ -1715,8 +1713,7 @@ simple_iv_increment_p (tree stmt)
|
||||
the hash table and return the result. Otherwise return NULL. */
|
||||
|
||||
static tree
|
||||
simplify_rhs_and_lookup_avail_expr (struct dom_walk_data *walk_data,
|
||||
tree stmt, int insert)
|
||||
simplify_rhs_and_lookup_avail_expr (tree stmt, int insert)
|
||||
{
|
||||
tree rhs = TREE_OPERAND (stmt, 1);
|
||||
enum tree_code rhs_code = TREE_CODE (rhs);
|
||||
@ -1840,127 +1837,6 @@ simplify_rhs_and_lookup_avail_expr (struct dom_walk_data *walk_data,
|
||||
dont_fold_assoc:;
|
||||
}
|
||||
|
||||
/* Transform TRUNC_DIV_EXPR and TRUNC_MOD_EXPR into RSHIFT_EXPR
|
||||
and BIT_AND_EXPR respectively if the first operand is greater
|
||||
than zero and the second operand is an exact power of two. */
|
||||
if ((rhs_code == TRUNC_DIV_EXPR || rhs_code == TRUNC_MOD_EXPR)
|
||||
&& INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (rhs, 0)))
|
||||
&& integer_pow2p (TREE_OPERAND (rhs, 1)))
|
||||
{
|
||||
tree val;
|
||||
tree op = TREE_OPERAND (rhs, 0);
|
||||
|
||||
if (TYPE_UNSIGNED (TREE_TYPE (op)))
|
||||
{
|
||||
val = integer_one_node;
|
||||
}
|
||||
else
|
||||
{
|
||||
tree dummy_cond = walk_data->global_data;
|
||||
|
||||
if (! dummy_cond)
|
||||
{
|
||||
dummy_cond = build (GT_EXPR, boolean_type_node,
|
||||
op, integer_zero_node);
|
||||
dummy_cond = build (COND_EXPR, void_type_node,
|
||||
dummy_cond, NULL, NULL);
|
||||
walk_data->global_data = dummy_cond;
|
||||
}
|
||||
else
|
||||
{
|
||||
TREE_SET_CODE (COND_EXPR_COND (dummy_cond), GT_EXPR);
|
||||
TREE_OPERAND (COND_EXPR_COND (dummy_cond), 0) = op;
|
||||
TREE_OPERAND (COND_EXPR_COND (dummy_cond), 1)
|
||||
= integer_zero_node;
|
||||
}
|
||||
val = simplify_cond_and_lookup_avail_expr (dummy_cond, NULL, false);
|
||||
}
|
||||
|
||||
if (val && integer_onep (val))
|
||||
{
|
||||
tree t;
|
||||
tree op0 = TREE_OPERAND (rhs, 0);
|
||||
tree op1 = TREE_OPERAND (rhs, 1);
|
||||
|
||||
if (rhs_code == TRUNC_DIV_EXPR)
|
||||
t = build (RSHIFT_EXPR, TREE_TYPE (op0), op0,
|
||||
build_int_cst (NULL_TREE, tree_log2 (op1)));
|
||||
else
|
||||
t = build (BIT_AND_EXPR, TREE_TYPE (op0), op0,
|
||||
local_fold (build (MINUS_EXPR, TREE_TYPE (op1),
|
||||
op1, integer_one_node)));
|
||||
|
||||
result = update_rhs_and_lookup_avail_expr (stmt, t, insert);
|
||||
}
|
||||
}
|
||||
|
||||
/* Transform ABS (X) into X or -X as appropriate. */
|
||||
if (rhs_code == ABS_EXPR
|
||||
&& INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (rhs, 0))))
|
||||
{
|
||||
tree val;
|
||||
tree op = TREE_OPERAND (rhs, 0);
|
||||
tree type = TREE_TYPE (op);
|
||||
|
||||
if (TYPE_UNSIGNED (type))
|
||||
{
|
||||
val = integer_zero_node;
|
||||
}
|
||||
else
|
||||
{
|
||||
tree dummy_cond = walk_data->global_data;
|
||||
|
||||
if (! dummy_cond)
|
||||
{
|
||||
dummy_cond = build (LE_EXPR, boolean_type_node,
|
||||
op, integer_zero_node);
|
||||
dummy_cond = build (COND_EXPR, void_type_node,
|
||||
dummy_cond, NULL, NULL);
|
||||
walk_data->global_data = dummy_cond;
|
||||
}
|
||||
else
|
||||
{
|
||||
TREE_SET_CODE (COND_EXPR_COND (dummy_cond), LE_EXPR);
|
||||
TREE_OPERAND (COND_EXPR_COND (dummy_cond), 0) = op;
|
||||
TREE_OPERAND (COND_EXPR_COND (dummy_cond), 1)
|
||||
= build_int_cst (type, 0);
|
||||
}
|
||||
val = simplify_cond_and_lookup_avail_expr (dummy_cond, NULL, false);
|
||||
|
||||
if (!val)
|
||||
{
|
||||
TREE_SET_CODE (COND_EXPR_COND (dummy_cond), GE_EXPR);
|
||||
TREE_OPERAND (COND_EXPR_COND (dummy_cond), 0) = op;
|
||||
TREE_OPERAND (COND_EXPR_COND (dummy_cond), 1)
|
||||
= build_int_cst (type, 0);
|
||||
|
||||
val = simplify_cond_and_lookup_avail_expr (dummy_cond,
|
||||
NULL, false);
|
||||
|
||||
if (val)
|
||||
{
|
||||
if (integer_zerop (val))
|
||||
val = integer_one_node;
|
||||
else if (integer_onep (val))
|
||||
val = integer_zero_node;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (val
|
||||
&& (integer_onep (val) || integer_zerop (val)))
|
||||
{
|
||||
tree t;
|
||||
|
||||
if (integer_onep (val))
|
||||
t = build1 (NEGATE_EXPR, TREE_TYPE (op), op);
|
||||
else
|
||||
t = op;
|
||||
|
||||
result = update_rhs_and_lookup_avail_expr (stmt, t, insert);
|
||||
}
|
||||
}
|
||||
|
||||
/* Optimize *"foo" into 'f'. This is done here rather than
|
||||
in fold to avoid problems with stuff like &*"foo". */
|
||||
if (TREE_CODE (rhs) == INDIRECT_REF || TREE_CODE (rhs) == ARRAY_REF)
|
||||
@ -2602,8 +2478,7 @@ propagate_to_outgoing_edges (struct dom_walk_data *walk_data ATTRIBUTE_UNUSED,
|
||||
table. */
|
||||
|
||||
static bool
|
||||
eliminate_redundant_computations (struct dom_walk_data *walk_data,
|
||||
tree stmt, stmt_ann_t ann)
|
||||
eliminate_redundant_computations (tree stmt, stmt_ann_t ann)
|
||||
{
|
||||
tree *expr_p, def = NULL_TREE;
|
||||
bool insert = true;
|
||||
@ -2632,7 +2507,7 @@ eliminate_redundant_computations (struct dom_walk_data *walk_data,
|
||||
then try to simplify the RHS and lookup the new RHS in the
|
||||
hash table. */
|
||||
if (! cached_lhs && TREE_CODE (stmt) == MODIFY_EXPR)
|
||||
cached_lhs = simplify_rhs_and_lookup_avail_expr (walk_data, stmt, insert);
|
||||
cached_lhs = simplify_rhs_and_lookup_avail_expr (stmt, insert);
|
||||
/* Similarly if this is a COND_EXPR and we did not find its
|
||||
expression in the hash table, simplify the condition and
|
||||
try again. */
|
||||
@ -2955,8 +2830,8 @@ cprop_into_stmt (tree stmt)
|
||||
the variable in the LHS in the CONST_AND_COPIES table. */
|
||||
|
||||
static void
|
||||
optimize_stmt (struct dom_walk_data *walk_data, basic_block bb,
|
||||
block_stmt_iterator si)
|
||||
optimize_stmt (struct dom_walk_data *walk_data ATTRIBUTE_UNUSED,
|
||||
basic_block bb, block_stmt_iterator si)
|
||||
{
|
||||
stmt_ann_t ann;
|
||||
tree stmt, old_stmt;
|
||||
@ -3026,7 +2901,7 @@ optimize_stmt (struct dom_walk_data *walk_data, basic_block bb,
|
||||
|
||||
if (may_optimize_p)
|
||||
may_have_exposed_new_symbols
|
||||
|= eliminate_redundant_computations (walk_data, stmt, ann);
|
||||
|= eliminate_redundant_computations (stmt, ann);
|
||||
|
||||
/* Record any additional equivalences created by this statement. */
|
||||
if (TREE_CODE (stmt) == MODIFY_EXPR)
|
||||
|
139
gcc/tree-vrp.c
139
gcc/tree-vrp.c
@ -94,6 +94,21 @@ static sbitmap blocks_visited;
|
||||
of values that SSA name N_I may take. */
|
||||
static value_range_t **vr_value;
|
||||
|
||||
/* Local version of fold that doesn't introduce cruft. */
|
||||
|
||||
static tree
|
||||
local_fold (tree t)
|
||||
{
|
||||
t = fold (t);
|
||||
|
||||
/* Strip away useless type conversions. Both the NON_LVALUE_EXPR that
|
||||
may have been added by fold, and "useless" type conversions that might
|
||||
now be apparent due to propagation. */
|
||||
STRIP_USELESS_TYPE_CONVERSION (t);
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
/* Given a comparison code, return its opposite. Note that this is *not*
|
||||
the same as inverting its truth value (invert_tree_comparison). Here we
|
||||
just want to literally flip the comparison around.
|
||||
@ -3402,6 +3417,124 @@ varying:
|
||||
return SSA_PROP_VARYING;
|
||||
}
|
||||
|
||||
/* Walk through the IL simplifying expressions using knowledge
|
||||
gathered by VRP. */
|
||||
|
||||
static void
|
||||
simplify_using_ranges (void)
|
||||
{
|
||||
basic_block bb;
|
||||
|
||||
FOR_EACH_BB (bb)
|
||||
{
|
||||
block_stmt_iterator bsi;
|
||||
|
||||
for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
|
||||
{
|
||||
tree stmt = bsi_stmt (bsi);
|
||||
|
||||
if (TREE_CODE (stmt) == MODIFY_EXPR)
|
||||
{
|
||||
tree rhs = TREE_OPERAND (stmt, 1);
|
||||
enum tree_code rhs_code = TREE_CODE (rhs);
|
||||
|
||||
/* Transform TRUNC_DIV_EXPR and TRUNC_MOD_EXPR into RSHIFT_EXPR
|
||||
and BIT_AND_EXPR respectively if the first operand is greater
|
||||
than zero and the second operand is an exact power of two. */
|
||||
if ((rhs_code == TRUNC_DIV_EXPR || rhs_code == TRUNC_MOD_EXPR)
|
||||
&& INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (rhs, 0)))
|
||||
&& integer_pow2p (TREE_OPERAND (rhs, 1)))
|
||||
{
|
||||
tree val = NULL;
|
||||
tree op = TREE_OPERAND (rhs, 0);
|
||||
value_range_t *vr = get_value_range (TREE_OPERAND (rhs, 0));
|
||||
|
||||
if (TYPE_UNSIGNED (TREE_TYPE (op)))
|
||||
{
|
||||
val = integer_one_node;
|
||||
}
|
||||
else
|
||||
{
|
||||
val = compare_range_with_value (GT_EXPR, vr,
|
||||
integer_zero_node);
|
||||
}
|
||||
|
||||
if (val && integer_onep (val))
|
||||
{
|
||||
tree t;
|
||||
tree op0 = TREE_OPERAND (rhs, 0);
|
||||
tree op1 = TREE_OPERAND (rhs, 1);
|
||||
|
||||
if (rhs_code == TRUNC_DIV_EXPR)
|
||||
t = build (RSHIFT_EXPR, TREE_TYPE (op0), op0,
|
||||
build_int_cst (NULL_TREE, tree_log2 (op1)));
|
||||
else
|
||||
t = build (BIT_AND_EXPR, TREE_TYPE (op0), op0,
|
||||
local_fold (build (MINUS_EXPR,
|
||||
TREE_TYPE (op1),
|
||||
op1,
|
||||
integer_one_node)));
|
||||
|
||||
TREE_OPERAND (stmt, 1) = t;
|
||||
update_stmt (stmt);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Transform ABS (X) into X or -X as appropriate. */
|
||||
if (rhs_code == ABS_EXPR
|
||||
&& TREE_CODE (TREE_OPERAND (rhs, 0)) == SSA_NAME
|
||||
&& INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (rhs, 0))))
|
||||
{
|
||||
tree val = NULL;
|
||||
tree op = TREE_OPERAND (rhs, 0);
|
||||
tree type = TREE_TYPE (op);
|
||||
value_range_t *vr = get_value_range (TREE_OPERAND (rhs, 0));
|
||||
|
||||
if (TYPE_UNSIGNED (type))
|
||||
{
|
||||
val = integer_zero_node;
|
||||
}
|
||||
else if (vr)
|
||||
{
|
||||
val = compare_range_with_value (LE_EXPR, vr,
|
||||
integer_zero_node);
|
||||
if (!val)
|
||||
{
|
||||
val = compare_range_with_value (GE_EXPR, vr,
|
||||
integer_zero_node);
|
||||
|
||||
if (val)
|
||||
{
|
||||
if (integer_zerop (val))
|
||||
val = integer_one_node;
|
||||
else if (integer_onep (val))
|
||||
val = integer_zero_node;
|
||||
}
|
||||
}
|
||||
|
||||
if (val
|
||||
&& (integer_onep (val) || integer_zerop (val)))
|
||||
{
|
||||
tree t;
|
||||
|
||||
if (integer_onep (val))
|
||||
t = build1 (NEGATE_EXPR, TREE_TYPE (op), op);
|
||||
else
|
||||
t = op;
|
||||
|
||||
TREE_OPERAND (stmt, 1) = t;
|
||||
update_stmt (stmt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO. Simplify conditionals. */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Traverse all the blocks folding conditionals with known ranges. */
|
||||
|
||||
@ -3445,6 +3578,12 @@ vrp_finalize (void)
|
||||
|
||||
substitute_and_fold (single_val_range, true);
|
||||
|
||||
/* One could argue all simplifications should be done here
|
||||
rather than using substitute_and_fold since this code
|
||||
is going to have to perform a complete walk through the
|
||||
IL anyway. */
|
||||
simplify_using_ranges ();
|
||||
|
||||
/* Free allocated memory. */
|
||||
for (i = 0; i < num_ssa_names; i++)
|
||||
if (vr_value[i])
|
||||
|
Loading…
Reference in New Issue
Block a user