diff options
author | dberlin <dberlin@138bc75d-0d04-0410-961f-82ee72b054a4> | 2005-05-16 01:12:07 +0000 |
---|---|---|
committer | dberlin <dberlin@138bc75d-0d04-0410-961f-82ee72b054a4> | 2005-05-16 01:12:07 +0000 |
commit | f0c13a343d486f428f8c7eb41d0e1c8a7f0b2f86 (patch) | |
tree | 9ae1ca4cfd3a16282eccd4a1235eecbb784104c3 | |
parent | e3feb2af3138cba10396fab975f553e986304d08 (diff) | |
download | gcc-f0c13a343d486f428f8c7eb41d0e1c8a7f0b2f86.tar.gz |
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.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@99759 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r-- | gcc/ChangeLog | 25 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-cse-1.c | 6 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-10.c | 14 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-11.c | 21 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-12.c | 27 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-13.c | 26 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-9.c | 13 | ||||
-rw-r--r-- | gcc/tree-ssa-pre.c | 281 | ||||
-rw-r--r-- | gcc/tree-vn.c | 26 |
9 files changed, 419 insertions, 20 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index ef16d8ba29e..24444470364 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -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'. diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-cse-1.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-cse-1.c index 82687d71913..5bbfd3d17fb 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-cse-1.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-cse-1.c @@ -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" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-10.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-10.c new file mode 100644 index 00000000000..127caa6cd6b --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-10.c @@ -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" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-11.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-11.c new file mode 100644 index 00000000000..26c47b1830b --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-11.c @@ -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" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-12.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-12.c new file mode 100644 index 00000000000..fd80e3d8d50 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-12.c @@ -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" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-13.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-13.c new file mode 100644 index 00000000000..dfce46b9907 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-13.c @@ -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" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-9.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-9.c new file mode 100644 index 00000000000..32e37b99703 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-9.c @@ -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" } } */ diff --git a/gcc/tree-ssa-pre.c b/gcc/tree-ssa-pre.c index 0494774b608..859bf096210 100644 --- a/gcc/tree-ssa-pre.c +++ b/gcc/tree-ssa-pre.c @@ -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 */ }; diff --git a/gcc/tree-vn.c b/gcc/tree-vn.c index 5f003720e4d..e46fafaf308 100644 --- a/gcc/tree-vn.c +++ b/gcc/tree-vn.c @@ -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); |