re PR tree-optimization/21576 (FRE does not eliminate a redundant builtin call.)
2005-05-15 Daniel Berlin <dberlin@dberlin.org> Fix PR tree-optimization/21576 * tree-ssa-pre.c (expression_node_pool): New pool. (comparison_node_pool): Ditto. (list_node_pool): Ditto. (pool_copy_list): New function. (phi_translate): Handle CALL_EXPR. (valid_in_set): Ditto. (create_expression_by_pieces): Ditto. (insert_into_preds_of_block): Ditto. (insert_aux): Ditto. (compute_avail): Ditto. (create_value_expr_from): Handle TREE_LIST and CALL_EXPR. (can_value_number_call): New function. (find_leader): Update comment. (init_pre): Create new pools. (fini_pre): Free new pools. (pass_pre): Add TODO_update_ssa for the future when we are going to need vops. * tree-vn.c (expressions_equal_p): Handle TREE_LIST. (set_value_handle): Ditto. (get_value_handle): Ditto. From-SVN: r99759
This commit is contained in:
parent
cea02b6e7e
commit
43da81be39
@ -1,3 +1,28 @@
|
||||
2005-05-15 Daniel Berlin <dberlin@dberlin.org>
|
||||
|
||||
Fix PR tree-optimization/21576
|
||||
|
||||
* tree-ssa-pre.c (expression_node_pool): New pool.
|
||||
(comparison_node_pool): Ditto.
|
||||
(list_node_pool): Ditto.
|
||||
(pool_copy_list): New function.
|
||||
(phi_translate): Handle CALL_EXPR.
|
||||
(valid_in_set): Ditto.
|
||||
(create_expression_by_pieces): Ditto.
|
||||
(insert_into_preds_of_block): Ditto.
|
||||
(insert_aux): Ditto.
|
||||
(compute_avail): Ditto.
|
||||
(create_value_expr_from): Handle TREE_LIST and CALL_EXPR.
|
||||
(can_value_number_call): New function.
|
||||
(find_leader): Update comment.
|
||||
(init_pre): Create new pools.
|
||||
(fini_pre): Free new pools.
|
||||
(pass_pre): Add TODO_update_ssa for the future when we are going
|
||||
to need vops.
|
||||
* tree-vn.c (expressions_equal_p): Handle TREE_LIST.
|
||||
(set_value_handle): Ditto.
|
||||
(get_value_handle): Ditto.
|
||||
|
||||
2005-05-15 Richard Earnshaw <richard.earnshaw@arm.com>
|
||||
|
||||
* arm.c (thumb_unexpanded_epilogue): Delete unused variable 'mode'.
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -fdump-tree-dom1-details" } */
|
||||
/* { dg-options "-O2 -fdump-tree-fre-details" } */
|
||||
int t(int a) __attribute__ ((const));
|
||||
void q (void);
|
||||
void
|
||||
@ -12,5 +12,5 @@ threading(int a,int b)
|
||||
}
|
||||
}
|
||||
/* We should thread the jump twice and eliminate it. */
|
||||
/* { dg-final { scan-tree-dump-times "Replaced.* t " 1 "dom1"} } */
|
||||
/* { dg-final { cleanup-tree-dump "dom1" } } */
|
||||
/* { dg-final { scan-tree-dump-times "Replaced.* t " 1 "fre"} } */
|
||||
/* { dg-final { cleanup-tree-dump "fre" } } */
|
||||
|
14
gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-10.c
Normal file
14
gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-10.c
Normal file
@ -0,0 +1,14 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -fno-tree-dominator-opts -fdump-tree-fre-stats" } */
|
||||
double cos (double);
|
||||
void link_error();
|
||||
void f(double a)
|
||||
{
|
||||
double b = cos (a);
|
||||
double c = cos (a);
|
||||
if (b != c)
|
||||
link_error();
|
||||
}
|
||||
|
||||
/* { dg-final { scan-tree-dump-times "Eliminated: 1" 1 "fre"} } */
|
||||
/* { dg-final { cleanup-tree-dump "fre" } } */
|
21
gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-11.c
Normal file
21
gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-11.c
Normal file
@ -0,0 +1,21 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -fdump-tree-pre-stats" } */
|
||||
double cos (double);
|
||||
double f(double a)
|
||||
{
|
||||
double b;
|
||||
double c,d;
|
||||
if (a < 2.0)
|
||||
{
|
||||
c = cos (a);
|
||||
}
|
||||
else
|
||||
{
|
||||
c = 1.0;
|
||||
}
|
||||
d = cos (a);
|
||||
return d + c;
|
||||
}
|
||||
|
||||
/* { dg-final { scan-tree-dump-times "Eliminated: 1" 1 "pre"} } */
|
||||
/* { dg-final { cleanup-tree-dump "pre" } } */
|
27
gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-12.c
Normal file
27
gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-12.c
Normal file
@ -0,0 +1,27 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -fdump-tree-pre-stats" } */
|
||||
double cos (double) __attribute__ ((const));
|
||||
double sin (double) __attribute__ ((const));
|
||||
double f(double a)
|
||||
{
|
||||
double b;
|
||||
double c,d;
|
||||
double (*fp) (double) __attribute__ ((const));
|
||||
/* Fully redundant call, but we need a phi node to merge the results. */
|
||||
if (a < 2.0)
|
||||
{
|
||||
fp = sin;
|
||||
c = fp (a);
|
||||
}
|
||||
else
|
||||
{
|
||||
c = 1.0;
|
||||
fp = cos;
|
||||
c = fp (a);
|
||||
}
|
||||
d = fp (a);
|
||||
return d + c;
|
||||
}
|
||||
|
||||
/* { dg-final { scan-tree-dump-times "Eliminated: 1" 1 "pre"} } */
|
||||
/* { dg-final { cleanup-tree-dump "pre" } } */
|
26
gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-13.c
Normal file
26
gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-13.c
Normal file
@ -0,0 +1,26 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -fdump-tree-pre-stats" } */
|
||||
double cos (double) __attribute__ ((const));
|
||||
double sin (double) __attribute__ ((const));
|
||||
double f(double a)
|
||||
{
|
||||
double b;
|
||||
double c,d;
|
||||
double (*fp) (double) __attribute__ ((const));
|
||||
/* Partially redundant call */
|
||||
if (a < 2.0)
|
||||
{
|
||||
fp = sin;
|
||||
c = fp (a);
|
||||
}
|
||||
else
|
||||
{
|
||||
c = 1.0;
|
||||
fp = cos;
|
||||
}
|
||||
d = fp (a);
|
||||
return d + c;
|
||||
}
|
||||
|
||||
/* { dg-final { scan-tree-dump-times "Eliminated: 1" 1 "pre"} } */
|
||||
/* { dg-final { cleanup-tree-dump "pre" } } */
|
13
gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-9.c
Normal file
13
gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-9.c
Normal file
@ -0,0 +1,13 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -fno-tree-dominator-opts -fdump-tree-fre-stats" } */
|
||||
int
|
||||
foo (unsigned long a)
|
||||
{
|
||||
int b = __builtin_clzl (a);
|
||||
int c = __builtin_clzl (a);
|
||||
if (b == c)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
/* { dg-final { scan-tree-dump-times "Eliminated: 1" 1 "fre"} } */
|
||||
/* { dg-final { cleanup-tree-dump "fre" } } */
|
@ -305,6 +305,9 @@ static alloc_pool value_set_node_pool;
|
||||
static alloc_pool binary_node_pool;
|
||||
static alloc_pool unary_node_pool;
|
||||
static alloc_pool reference_node_pool;
|
||||
static alloc_pool comparison_node_pool;
|
||||
static alloc_pool expression_node_pool;
|
||||
static alloc_pool list_node_pool;
|
||||
static bitmap_obstack grand_bitmap_obstack;
|
||||
|
||||
/* Set of blocks with statements that have had its EH information
|
||||
@ -855,6 +858,35 @@ fully_constant_expression (tree t)
|
||||
return t;
|
||||
}
|
||||
|
||||
/* Return a copy of a chain of nodes, chained through the TREE_CHAIN field.
|
||||
For example, this can copy a list made of TREE_LIST nodes.
|
||||
Allocates the nodes in list_node_pool*/
|
||||
|
||||
static tree
|
||||
pool_copy_list (tree list)
|
||||
{
|
||||
tree head;
|
||||
tree prev, next;
|
||||
|
||||
if (list == 0)
|
||||
return 0;
|
||||
head = pool_alloc (list_node_pool);
|
||||
|
||||
memcpy (head, list, tree_size (list));
|
||||
prev = head;
|
||||
|
||||
next = TREE_CHAIN (list);
|
||||
while (next)
|
||||
{
|
||||
TREE_CHAIN (prev) = pool_alloc (list_node_pool);
|
||||
memcpy (TREE_CHAIN (prev), next, tree_size (next));
|
||||
prev = TREE_CHAIN (prev);
|
||||
next = TREE_CHAIN (next);
|
||||
}
|
||||
return head;
|
||||
}
|
||||
|
||||
|
||||
/* Translate EXPR using phis in PHIBLOCK, so that it has the values of
|
||||
the phis in PRED. Return NULL if we can't find a leader for each
|
||||
part of the translated expression. */
|
||||
@ -879,6 +911,89 @@ phi_translate (tree expr, value_set_t set, basic_block pred,
|
||||
|
||||
switch (TREE_CODE_CLASS (TREE_CODE (expr)))
|
||||
{
|
||||
case tcc_expression:
|
||||
{
|
||||
if (TREE_CODE (expr) != CALL_EXPR)
|
||||
return NULL;
|
||||
else
|
||||
{
|
||||
tree oldop0 = TREE_OPERAND (expr, 0);
|
||||
tree oldarglist = TREE_OPERAND (expr, 1);
|
||||
tree oldop2 = TREE_OPERAND (expr, 2);
|
||||
tree newop0;
|
||||
tree newarglist;
|
||||
tree newop2 = NULL;
|
||||
tree oldwalker;
|
||||
tree newwalker;
|
||||
tree newexpr;
|
||||
bool listchanged = false;
|
||||
|
||||
/* Call expressions are kind of weird because they have an
|
||||
argument list. We don't want to value number the list
|
||||
as one value number, because that doesn't make much
|
||||
sense, and just breaks the support functions we call,
|
||||
which expect TREE_OPERAND (call_expr, 2) to be a
|
||||
TREE_LIST. */
|
||||
|
||||
newop0 = phi_translate (find_leader (set, oldop0),
|
||||
set, pred, phiblock);
|
||||
if (newop0 == NULL)
|
||||
return NULL;
|
||||
if (oldop2)
|
||||
{
|
||||
newop2 = phi_translate (find_leader (set, oldop2),
|
||||
set, pred, phiblock);
|
||||
if (newop2 == NULL)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* phi translate the argument list piece by piece.
|
||||
|
||||
We could actually build the list piece by piece here,
|
||||
but it's likely to not be worth the memory we will save,
|
||||
unless you have millions of call arguments. */
|
||||
|
||||
newarglist = pool_copy_list (oldarglist);
|
||||
for (oldwalker = oldarglist, newwalker = newarglist;
|
||||
oldwalker && newwalker;
|
||||
oldwalker = TREE_CHAIN (oldwalker),
|
||||
newwalker = TREE_CHAIN (newwalker))
|
||||
{
|
||||
|
||||
tree oldval = TREE_VALUE (oldwalker);
|
||||
tree newval;
|
||||
if (oldval)
|
||||
{
|
||||
newval = phi_translate (find_leader (set, oldval),
|
||||
set, pred, phiblock);
|
||||
if (newval == NULL)
|
||||
return NULL;
|
||||
if (newval != oldval)
|
||||
{
|
||||
listchanged = true;
|
||||
TREE_VALUE (newwalker) = get_value_handle (newval);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (listchanged)
|
||||
vn_lookup_or_add (newarglist, NULL);
|
||||
|
||||
if (listchanged || (newop0 != oldop0) || (oldop2 != newop2))
|
||||
{
|
||||
newexpr = pool_alloc (expression_node_pool);
|
||||
memcpy (newexpr, expr, tree_size (expr));
|
||||
TREE_OPERAND (newexpr, 0) = newop0 == oldop0 ? oldop0 : get_value_handle (newop0);
|
||||
TREE_OPERAND (newexpr, 1) = listchanged ? newarglist : oldarglist;
|
||||
TREE_OPERAND (newexpr, 2) = newop2 == oldop2 ? oldop2 : get_value_handle (newop2);
|
||||
create_tree_ann (newexpr);
|
||||
vn_lookup_or_add (newexpr, NULL);
|
||||
expr = newexpr;
|
||||
phi_trans_add (oldexpr, newexpr, pred);
|
||||
}
|
||||
}
|
||||
}
|
||||
return expr;
|
||||
|
||||
case tcc_reference:
|
||||
/* XXX: Until we have PRE of loads working, none will be ANTIC. */
|
||||
return NULL;
|
||||
@ -1084,10 +1199,10 @@ find_leader (value_set_t set, tree val)
|
||||
we have a leader for each part of the expression (if it consists of
|
||||
values), or the expression is an SSA_NAME.
|
||||
|
||||
NB: We never should run into a case where we have SSA_NAME +
|
||||
NB: We never should run into a case where we have SSA_NAME +
|
||||
SSA_NAME or SSA_NAME + value. The sets valid_in_set is called on,
|
||||
the ANTIC sets, will only ever have SSA_NAME's or binary value
|
||||
expression (IE VALUE1 + VALUE2) */
|
||||
the ANTIC sets, will only ever have SSA_NAME's or value expressions
|
||||
(IE VALUE1 + VALUE2, *VALUE1, VALUE1 < VALUE2) */
|
||||
|
||||
static bool
|
||||
valid_in_set (value_set_t set, tree expr)
|
||||
@ -1107,7 +1222,31 @@ valid_in_set (value_set_t set, tree expr)
|
||||
tree op1 = TREE_OPERAND (expr, 0);
|
||||
return set_contains_value (set, op1);
|
||||
}
|
||||
|
||||
case tcc_expression:
|
||||
{
|
||||
if (TREE_CODE (expr) == CALL_EXPR)
|
||||
{
|
||||
tree op0 = TREE_OPERAND (expr, 0);
|
||||
tree arglist = TREE_OPERAND (expr, 1);
|
||||
tree op2 = TREE_OPERAND (expr, 2);
|
||||
|
||||
/* Check the non-list operands first. */
|
||||
if (!set_contains_value (set, op0)
|
||||
|| (op2 && !set_contains_value (set, op2)))
|
||||
return false;
|
||||
|
||||
/* Now check the operands. */
|
||||
for (; arglist; arglist = TREE_CHAIN (arglist))
|
||||
{
|
||||
if (!set_contains_value (set, TREE_VALUE (arglist)))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
case tcc_reference:
|
||||
/* XXX: Until PRE of loads works, no reference nodes are ANTIC. */
|
||||
return false;
|
||||
@ -1189,7 +1328,7 @@ compute_antic_aux (basic_block block, bool block_has_abnormal_pred_edge)
|
||||
translate through. */
|
||||
else if (single_succ_p (block))
|
||||
{
|
||||
phi_translate_set (ANTIC_OUT, ANTIC_IN(single_succ (block)),
|
||||
phi_translate_set (ANTIC_OUT, ANTIC_IN (single_succ (block)),
|
||||
block, single_succ (block));
|
||||
}
|
||||
/* If we have multiple successors, we take the intersection of all of
|
||||
@ -1359,6 +1498,42 @@ create_expression_by_pieces (basic_block block, tree expr, tree stmts)
|
||||
|
||||
switch (TREE_CODE_CLASS (TREE_CODE (expr)))
|
||||
{
|
||||
case tcc_expression:
|
||||
{
|
||||
tree op0, op2;
|
||||
tree arglist;
|
||||
tree genop0, genop2;
|
||||
tree genarglist;
|
||||
tree walker, genwalker;
|
||||
|
||||
gcc_assert (TREE_CODE (expr) == CALL_EXPR);
|
||||
genop2 = NULL;
|
||||
|
||||
op0 = TREE_OPERAND (expr, 0);
|
||||
arglist = TREE_OPERAND (expr, 1);
|
||||
op2 = TREE_OPERAND (expr, 2);
|
||||
|
||||
genop0 = find_or_generate_expression (block, op0, stmts);
|
||||
genarglist = copy_list (arglist);
|
||||
for (walker = arglist, genwalker = genarglist;
|
||||
genwalker && walker;
|
||||
genwalker = TREE_CHAIN (genwalker), walker = TREE_CHAIN (walker))
|
||||
{
|
||||
TREE_VALUE (genwalker) = find_or_generate_expression (block,
|
||||
TREE_VALUE (walker),
|
||||
stmts);
|
||||
}
|
||||
|
||||
if (op2)
|
||||
genop2 = find_or_generate_expression (block, op2, stmts);
|
||||
folded = fold (build (TREE_CODE (expr), TREE_TYPE (expr),
|
||||
genop0, genarglist, genop2));
|
||||
break;
|
||||
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case tcc_binary:
|
||||
case tcc_comparison:
|
||||
{
|
||||
@ -1499,7 +1674,8 @@ insert_into_preds_of_block (basic_block block, value_set_node_t node,
|
||||
eprime = avail[bprime->index];
|
||||
if (BINARY_CLASS_P (eprime)
|
||||
|| COMPARISON_CLASS_P (eprime)
|
||||
|| UNARY_CLASS_P (eprime))
|
||||
|| UNARY_CLASS_P (eprime)
|
||||
|| TREE_CODE (eprime) == CALL_EXPR)
|
||||
{
|
||||
builtexpr = create_expression_by_pieces (bprime,
|
||||
eprime,
|
||||
@ -1613,7 +1789,8 @@ insert_aux (basic_block block)
|
||||
{
|
||||
if (BINARY_CLASS_P (node->expr)
|
||||
|| COMPARISON_CLASS_P (node->expr)
|
||||
|| UNARY_CLASS_P (node->expr))
|
||||
|| UNARY_CLASS_P (node->expr)
|
||||
|| TREE_CODE (node->expr) == CALL_EXPR)
|
||||
{
|
||||
tree *avail;
|
||||
tree val;
|
||||
@ -1817,17 +1994,55 @@ create_value_expr_from (tree expr, basic_block block, tree stmt)
|
||||
gcc_assert (TREE_CODE_CLASS (code) == tcc_unary
|
||||
|| TREE_CODE_CLASS (code) == tcc_binary
|
||||
|| TREE_CODE_CLASS (code) == tcc_comparison
|
||||
|| TREE_CODE_CLASS (code) == tcc_reference);
|
||||
|| TREE_CODE_CLASS (code) == tcc_reference
|
||||
|| TREE_CODE_CLASS (code) == tcc_expression
|
||||
|| TREE_CODE_CLASS (code) == tcc_exceptional);
|
||||
|
||||
if (TREE_CODE_CLASS (code) == tcc_unary)
|
||||
pool = unary_node_pool;
|
||||
else if (TREE_CODE_CLASS (code) == tcc_reference)
|
||||
pool = reference_node_pool;
|
||||
else
|
||||
else if (TREE_CODE_CLASS (code) == tcc_binary)
|
||||
pool = binary_node_pool;
|
||||
else if (TREE_CODE_CLASS (code) == tcc_comparison)
|
||||
pool = comparison_node_pool;
|
||||
else if (TREE_CODE_CLASS (code) == tcc_exceptional)
|
||||
{
|
||||
gcc_assert (code == TREE_LIST);
|
||||
pool = list_node_pool;
|
||||
}
|
||||
else
|
||||
{
|
||||
gcc_assert (code == CALL_EXPR);
|
||||
pool = expression_node_pool;
|
||||
}
|
||||
|
||||
vexpr = pool_alloc (pool);
|
||||
memcpy (vexpr, expr, tree_size (expr));
|
||||
|
||||
/* This case is only for TREE_LIST's that appear as part of
|
||||
CALL_EXPR's. Anything else is a bug, but we can't easily verify
|
||||
this, hence tihs comment. TREE_LIST is not handled by the
|
||||
general case below is because they don't have a fixed length, or
|
||||
operands, so you can't access purpose/value/chain through
|
||||
TREE_OPERAND macros. */
|
||||
|
||||
if (code == TREE_LIST)
|
||||
{
|
||||
tree temp = NULL_TREE;
|
||||
if (TREE_CHAIN (vexpr))
|
||||
temp = create_value_expr_from (TREE_CHAIN (vexpr), block, stmt);
|
||||
TREE_CHAIN (vexpr) = temp ? temp : TREE_CHAIN (vexpr);
|
||||
|
||||
/* This is the equivalent of inserting op into EXP_GEN like we
|
||||
do below */
|
||||
if (!is_undefined_value (TREE_VALUE (vexpr)))
|
||||
value_insert_into_set (EXP_GEN (block), TREE_VALUE (vexpr));
|
||||
|
||||
TREE_VALUE (vexpr) = vn_lookup_or_add (TREE_VALUE (vexpr), NULL);
|
||||
|
||||
return vexpr;
|
||||
}
|
||||
|
||||
for (i = 0; i < TREE_CODE_LENGTH (code); i++)
|
||||
{
|
||||
@ -1846,18 +2061,32 @@ create_value_expr_from (tree expr, basic_block block, tree stmt)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Recursively value-numberize reference ops */
|
||||
/* Recursively value-numberize reference ops and tree lists. */
|
||||
if (REFERENCE_CLASS_P (op))
|
||||
{
|
||||
tree tempop = create_value_expr_from (op, block, stmt);
|
||||
op = tempop ? tempop : op;
|
||||
val = vn_lookup_or_add (op, stmt);
|
||||
}
|
||||
else if (TREE_CODE (op) == TREE_LIST)
|
||||
{
|
||||
tree tempop;
|
||||
|
||||
gcc_assert (TREE_CODE (expr) == CALL_EXPR);
|
||||
tempop = create_value_expr_from (op, block, stmt);
|
||||
|
||||
op = tempop ? tempop : op;
|
||||
vn_lookup_or_add (op, NULL);
|
||||
/* Unlike everywhere else, we do *not* want to replace the
|
||||
TREE_LIST itself with a value number, because support
|
||||
functions we call will blow up. */
|
||||
val = op;
|
||||
}
|
||||
else
|
||||
/* Create a value handle for OP and add it to VEXPR. */
|
||||
val = vn_lookup_or_add (op, NULL);
|
||||
|
||||
if (!is_undefined_value (op))
|
||||
if (!is_undefined_value (op) && TREE_CODE (op) != TREE_LIST)
|
||||
value_insert_into_set (EXP_GEN (block), op);
|
||||
|
||||
if (TREE_CODE (val) == VALUE_HANDLE)
|
||||
@ -1870,6 +2099,22 @@ create_value_expr_from (tree expr, basic_block block, tree stmt)
|
||||
}
|
||||
|
||||
|
||||
/* Return true if we can value number a call. This is true if we have
|
||||
a pure or constant call. */
|
||||
static bool
|
||||
can_value_number_call (tree stmt)
|
||||
{
|
||||
tree call = get_call_expr_in (stmt);
|
||||
|
||||
/* This is a temporary restriction until we translate vuses through
|
||||
phi nodes. */
|
||||
if (!ZERO_SSA_OPERANDS (stmt, SSA_OP_ALL_VIRTUALS))
|
||||
return false;
|
||||
if (call_expr_flags (call) & (ECF_PURE | ECF_CONST))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Compute the AVAIL set for all basic blocks.
|
||||
|
||||
This function performs value numbering of the statements in each basic
|
||||
@ -1964,7 +2209,9 @@ compute_avail (void)
|
||||
if (UNARY_CLASS_P (rhs)
|
||||
|| BINARY_CLASS_P (rhs)
|
||||
|| COMPARISON_CLASS_P (rhs)
|
||||
|| REFERENCE_CLASS_P (rhs))
|
||||
|| REFERENCE_CLASS_P (rhs)
|
||||
|| (TREE_CODE (rhs) == CALL_EXPR
|
||||
&& can_value_number_call (stmt)))
|
||||
{
|
||||
/* For binary, unary, and reference expressions,
|
||||
create a duplicate expression with the operands
|
||||
@ -2245,6 +2492,12 @@ init_pre (bool do_fre)
|
||||
tree_code_size (NEGATE_EXPR), 30);
|
||||
reference_node_pool = create_alloc_pool ("Reference tree nodes",
|
||||
tree_code_size (ARRAY_REF), 30);
|
||||
expression_node_pool = create_alloc_pool ("Expression tree nodes",
|
||||
tree_code_size (CALL_EXPR), 30);
|
||||
list_node_pool = create_alloc_pool ("List tree nodes",
|
||||
tree_code_size (TREE_LIST), 30);
|
||||
comparison_node_pool = create_alloc_pool ("Comparison tree nodes",
|
||||
tree_code_size (EQ_EXPR), 30);
|
||||
FOR_ALL_BB (bb)
|
||||
{
|
||||
EXP_GEN (bb) = set_new (true);
|
||||
@ -2273,6 +2526,9 @@ fini_pre (bool do_fre)
|
||||
free_alloc_pool (binary_node_pool);
|
||||
free_alloc_pool (reference_node_pool);
|
||||
free_alloc_pool (unary_node_pool);
|
||||
free_alloc_pool (list_node_pool);
|
||||
free_alloc_pool (expression_node_pool);
|
||||
free_alloc_pool (comparison_node_pool);
|
||||
htab_delete (phi_translate_table);
|
||||
remove_fake_exit_edges ();
|
||||
|
||||
@ -2398,7 +2654,8 @@ struct tree_opt_pass pass_pre =
|
||||
0, /* properties_provided */
|
||||
0, /* properties_destroyed */
|
||||
0, /* todo_flags_start */
|
||||
TODO_dump_func | TODO_ggc_collect | TODO_verify_ssa, /* todo_flags_finish */
|
||||
TODO_update_ssa | TODO_dump_func | TODO_ggc_collect
|
||||
| TODO_verify_ssa, /* todo_flags_finish */
|
||||
0 /* letter */
|
||||
};
|
||||
|
||||
|
@ -119,9 +119,25 @@ expressions_equal_p (tree e1, tree e2)
|
||||
te1 = TREE_TYPE (e1);
|
||||
te2 = TREE_TYPE (e2);
|
||||
|
||||
if (TREE_CODE (e1) == TREE_CODE (e2)
|
||||
&& (te1 == te2 || lang_hooks.types_compatible_p (te1, te2))
|
||||
&& operand_equal_p (e1, e2, OEP_PURE_SAME))
|
||||
if (TREE_CODE (e1) == TREE_LIST && TREE_CODE (e2) == TREE_LIST)
|
||||
{
|
||||
tree lop1 = e1;
|
||||
tree lop2 = e2;
|
||||
for (lop1 = e1, lop2 = e2;
|
||||
lop1 || lop2;
|
||||
lop1 = TREE_CHAIN (lop1), lop2 = TREE_CHAIN (lop2))
|
||||
{
|
||||
if (!lop1 || !lop2)
|
||||
return false;
|
||||
if (!expressions_equal_p (TREE_VALUE (lop1), TREE_VALUE (lop2)))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
else if (TREE_CODE (e1) == TREE_CODE (e2)
|
||||
&& (te1 == te2 || lang_hooks.types_compatible_p (te1, te2))
|
||||
&& operand_equal_p (e1, e2, OEP_PURE_SAME))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
@ -166,7 +182,7 @@ set_value_handle (tree e, tree v)
|
||||
{
|
||||
if (TREE_CODE (e) == SSA_NAME)
|
||||
SSA_NAME_VALUE (e) = v;
|
||||
else if (EXPR_P (e) || DECL_P (e))
|
||||
else if (EXPR_P (e) || DECL_P (e) || TREE_CODE (e) == TREE_LIST)
|
||||
get_tree_ann (e)->common.value_handle = v;
|
||||
else
|
||||
/* Do nothing. Constants are their own value handles. */
|
||||
@ -271,7 +287,7 @@ get_value_handle (tree expr)
|
||||
|
||||
if (TREE_CODE (expr) == SSA_NAME)
|
||||
return SSA_NAME_VALUE (expr);
|
||||
else if (EXPR_P (expr) || DECL_P (expr))
|
||||
else if (EXPR_P (expr) || DECL_P (expr) || TREE_CODE (expr) == TREE_LIST)
|
||||
{
|
||||
tree_ann_t ann = tree_ann (expr);
|
||||
return ((ann) ? ann->common.value_handle : NULL_TREE);
|
||||
|
Loading…
Reference in New Issue
Block a user