From: Andrew Pinski Date: Mon, 20 Mar 2006 21:00:18 +0000 (+0000) Subject: re PR tree-optimization/26629 (tree load PRE does not work on array references) X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=e13f1c1432140a43edd23a50c3916fa41fadd610;p=gcc.git re PR tree-optimization/26629 (tree load PRE does not work on array references) 2006-03-20 Andrew Pinski PR tree-opt/26629 * tree-ssa-pre (phi_translate): Handle ARRAY_REF's operands. (valid_in_set): Handle ARRAY_REF. Change "if min_variant or VH" to asserts. (create_component_ref_by_pieces): Handle ARRAY_REF. (create_expression_by_pieces): Likewise. (can_PRE_operation): ARRAY_REFs can now be PRE'd. 2006-03-20 Andrew Pinski PR tree-opt/26629 * gcc.dg/tree-ssa/loadpre12.c: New test. * gcc.dg/tree-ssa/loadpre13.c: New test. * gcc.dg/tree-ssa/loadpre14.c: New test. * gcc.dg/tree-ssa/loadpre15.c: New test. * gcc.dg/tree-ssa/loadpre16.c: New test. * gcc.dg/tree-ssa/loadpre17.c: New test. * gcc.dg/tree-ssa/loadpre18.c: New test. * gcc.dg/tree-ssa/loadpre19.c: New test. * gcc.dg/tree-ssa/loadpre20.c: New test. * gcc.dg/tree-ssa/loadpre21.c: New test. * gcc.dg/tree-ssa/loadpre22.c: New test. From-SVN: r112227 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 9e31001c0c5..157a550c1bb 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,13 @@ +2006-03-20 Andrew Pinski + + PR tree-opt/26629 + * tree-ssa-pre (phi_translate): Handle ARRAY_REF's operands. + (valid_in_set): Handle ARRAY_REF. + Change "if min_variant or VH" to asserts. + (create_component_ref_by_pieces): Handle ARRAY_REF. + (create_expression_by_pieces): Likewise. + (can_PRE_operation): ARRAY_REFs can now be PRE'd. + 2006-03-20 David Edelsohn * genpreds.c (write_insn_extra_address_constraint): Argument `c' diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 736eca1d9b2..92e62fc66fa 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,18 @@ +2006-03-20 Andrew Pinski + + PR tree-opt/26629 + * gcc.dg/tree-ssa/loadpre12.c: New test. + * gcc.dg/tree-ssa/loadpre13.c: New test. + * gcc.dg/tree-ssa/loadpre14.c: New test. + * gcc.dg/tree-ssa/loadpre15.c: New test. + * gcc.dg/tree-ssa/loadpre16.c: New test. + * gcc.dg/tree-ssa/loadpre17.c: New test. + * gcc.dg/tree-ssa/loadpre18.c: New test. + * gcc.dg/tree-ssa/loadpre19.c: New test. + * gcc.dg/tree-ssa/loadpre20.c: New test. + * gcc.dg/tree-ssa/loadpre21.c: New test. + * gcc.dg/tree-ssa/loadpre22.c: New test. + 2006-03-19 Paul Thomas PR fortran/26741 diff --git a/gcc/testsuite/gcc.dg/tree-ssa/loadpre12.c b/gcc/testsuite/gcc.dg/tree-ssa/loadpre12.c new file mode 100644 index 00000000000..4a79c802b13 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/loadpre12.c @@ -0,0 +1,15 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-pre-stats" } */ +typedef int type[2]; +type *t; +int g(int); +int f(int tt) +{ + type *t1 = t; + if ((*t1)[0]) + (*t1)[0] = 2; + return g((*t1)[0]); +} + +/* { dg-final { scan-tree-dump-times "Eliminated: 1" 1 "pre" { xfail *-*-* } } } */ +/* { dg-final { cleanup-tree-dump "pre" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/loadpre13.c b/gcc/testsuite/gcc.dg/tree-ssa/loadpre13.c new file mode 100644 index 00000000000..420ad7162bc --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/loadpre13.c @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-pre-stats" } */ +int t[2]; +int g(int); +int f(int tt) +{ + if (t[0]) + t[0] = 2; + return g(t[0]); +} + +/* { 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/loadpre14.c b/gcc/testsuite/gcc.dg/tree-ssa/loadpre14.c new file mode 100644 index 00000000000..f4c06f264d3 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/loadpre14.c @@ -0,0 +1,19 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-pre-stats" } */ +typedef int type[2]; +int main(type *a, int argc) +{ + type c = {0, 1}; + int d, e; + + /* Should be able to eliminate the second load of *a along the main path. */ + d = (*a)[0]; + if (argc) + { + a = &c; + } + e = (*a)[0]; + return d + e; +} +/* { 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/loadpre15.c b/gcc/testsuite/gcc.dg/tree-ssa/loadpre15.c new file mode 100644 index 00000000000..3e3ff7c4535 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/loadpre15.c @@ -0,0 +1,19 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-pre-stats" } */ +typedef int type[2]; +int main(type *a, int argc, int t) +{ + type c = {0, 1}; + int d, e; + + /* Should be able to eliminate the second load of *a along the main path. */ + d = (*a)[t]; + if (argc) + { + a = &c; + } + e = (*a)[t]; + return d + e; +} +/* { 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/loadpre16.c b/gcc/testsuite/gcc.dg/tree-ssa/loadpre16.c new file mode 100644 index 00000000000..3702440f3d7 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/loadpre16.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-pre-stats" } */ +typedef int type[2]; +int main(type *a, int argc) +{ + int d, e; + + /* Should be able to eliminate the second load of *a along the main path. */ + d = (*a)[0]; + if (argc) + a++; + e = (*a)[0]; + return d + e; +} +/* { 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/loadpre17.c b/gcc/testsuite/gcc.dg/tree-ssa/loadpre17.c new file mode 100644 index 00000000000..93c530d5e57 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/loadpre17.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-pre-stats" } */ +typedef int type[2]; +int main(type *a, int argc) +{ + int d, e; + + /* Should be able to eliminate the second load of *a along the main path. */ + d = (*a)[argc]; + if (argc) + a++; + e = (*a)[argc]; + return d + e; +} +/* { 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/loadpre18.c b/gcc/testsuite/gcc.dg/tree-ssa/loadpre18.c new file mode 100644 index 00000000000..21a1d067008 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/loadpre18.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-pre-stats" } */ +typedef int type[2]; +int main(type *a, int argc) +{ + int d, e; + + /* Should be able to eliminate the second load of *a along the main path. */ + d = (*a)[argc]; + if (argc) + argc++; + e = (*a)[argc]; + return d + e; +} +/* { dg-final { scan-tree-dump-times "Eliminated: 1" 1 "pre" { xfail *-*-* } } } */ +/* { dg-final { cleanup-tree-dump "pre" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/loadpre19.c b/gcc/testsuite/gcc.dg/tree-ssa/loadpre19.c new file mode 100644 index 00000000000..62ded9a6d80 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/loadpre19.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-pre-stats" } */ +typedef int type[2]; +int main(type *a, int argc) +{ + int d, e; + + /* Should be able to eliminate the second load of *a along the main path. */ + d = (*a)[argc]; + if (!d) + argc++; + e = (*a)[argc]; + return e; +} +/* { 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/loadpre20.c b/gcc/testsuite/gcc.dg/tree-ssa/loadpre20.c new file mode 100644 index 00000000000..330b67a579f --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/loadpre20.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-pre-stats" } */ +typedef int type[2]; +int main(type *a, int argc) +{ + int d, e; + + /* Should be able to eliminate the second load of *a along the main path. */ + d = (*a)[argc]; + if (!d) + a++; + e = (*a)[argc]; + return e; +} +/* { 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/loadpre21.c b/gcc/testsuite/gcc.dg/tree-ssa/loadpre21.c new file mode 100644 index 00000000000..77caef6ded6 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/loadpre21.c @@ -0,0 +1,19 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-pre-stats" } */ +typedef int type[2]; +int main(type *a, int argc) +{ + int b; + int i; + int d, e; + + /* Should be able to hoist this out of the loop. */ + for (i = 0; i < argc; i++) + { + e = (*a)[0]; + } + return d + e; +} + +/* { 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/loadpre22.c b/gcc/testsuite/gcc.dg/tree-ssa/loadpre22.c new file mode 100644 index 00000000000..3c03c9b12f6 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/loadpre22.c @@ -0,0 +1,19 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-pre-stats" } */ +typedef int type[2]; +int main(type *a, int argc) +{ + int b; + int i; + int d, e; + + /* Should be able to hoist this out of the loop. */ + for (i = 0; i < argc; i++) + { + e = (*a)[argc]; + } + return d + e; +} + +/* { dg-final { scan-tree-dump-times "Eliminated: 1" 1 "pre"} } */ +/* { dg-final { cleanup-tree-dump "pre" } } */ diff --git a/gcc/tree-ssa-pre.c b/gcc/tree-ssa-pre.c index 305ee3e938b..eea38c3bca1 100644 --- a/gcc/tree-ssa-pre.c +++ b/gcc/tree-ssa-pre.c @@ -1177,32 +1177,78 @@ phi_translate (tree expr, value_set_t set, basic_block pred, case tcc_reference: { - tree oldop1 = TREE_OPERAND (expr, 0); - tree newop1; + tree oldop0 = TREE_OPERAND (expr, 0); + tree oldop1 = NULL; + tree newop0; + tree newop1 = NULL; + tree oldop2 = NULL; + tree newop2 = NULL; + tree oldop3 = NULL; + tree newop3 = NULL; tree newexpr; VEC (tree, gc) * oldvuses = NULL; VEC (tree, gc) * newvuses = NULL; if (TREE_CODE (expr) != INDIRECT_REF - && TREE_CODE (expr) != COMPONENT_REF) + && TREE_CODE (expr) != COMPONENT_REF + && TREE_CODE (expr) != ARRAY_REF) return NULL; - newop1 = phi_translate (find_leader (set, oldop1), + newop0 = phi_translate (find_leader (set, oldop0), set, pred, phiblock); - if (newop1 == NULL) + if (newop0 == NULL) return NULL; + + if (TREE_CODE (expr) == ARRAY_REF) + { + oldop1 = TREE_OPERAND (expr, 1); + newop1 = phi_translate (find_leader (set, oldop1), + set, pred, phiblock); + + if (newop1 == NULL) + return NULL; + oldop2 = TREE_OPERAND (expr, 2); + if (oldop2) + { + newop2 = phi_translate (find_leader (set, oldop2), + set, pred, phiblock); + + if (newop2 == NULL) + return NULL; + } + oldop3 = TREE_OPERAND (expr, 3); + if (oldop3) + { + newop3 = phi_translate (find_leader (set, oldop3), + set, pred, phiblock); + + if (newop3 == NULL) + return NULL; + } + } oldvuses = VALUE_HANDLE_VUSES (get_value_handle (expr)); if (oldvuses) newvuses = translate_vuses_through_block (oldvuses, pred); - - if (newop1 != oldop1 || newvuses != oldvuses) + + if (newop0 != oldop0 || newvuses != oldvuses + || newop1 != oldop1 + || newop2 != oldop2 + || newop3 != oldop3) { tree t; newexpr = pool_alloc (reference_node_pool); memcpy (newexpr, expr, tree_size (expr)); - TREE_OPERAND (newexpr, 0) = get_value_handle (newop1); + TREE_OPERAND (newexpr, 0) = get_value_handle (newop0); + if (TREE_CODE (expr) == ARRAY_REF) + { + TREE_OPERAND (newexpr, 1) = get_value_handle (newop1); + if (newop2) + TREE_OPERAND (newexpr, 2) = get_value_handle (newop2); + if (newop3) + TREE_OPERAND (newexpr, 3) = get_value_handle (newop3); + } t = fully_constant_expression (newexpr); @@ -1525,22 +1571,38 @@ valid_in_set (value_set_t set, tree expr, basic_block block) case tcc_reference: { if (TREE_CODE (expr) == INDIRECT_REF - || TREE_CODE (expr) == COMPONENT_REF) + || TREE_CODE (expr) == COMPONENT_REF + || TREE_CODE (expr) == ARRAY_REF) { tree op0 = TREE_OPERAND (expr, 0); - if (is_gimple_min_invariant (op0) - || TREE_CODE (op0) == VALUE_HANDLE) + gcc_assert (is_gimple_min_invariant (op0) + || TREE_CODE (op0) == VALUE_HANDLE); + if (!set_contains_value (set, op0)) + return false; + if (TREE_CODE (expr) == ARRAY_REF) { - bool retval = set_contains_value (set, op0); - if (retval) - { - return set_contains_value (ANTIC_SAFE_LOADS (block), - vh) - || !vuses_dies_in_block_x (VALUE_HANDLE_VUSES (vh), - block); - } - return false; - } + tree op1 = TREE_OPERAND (expr, 1); + tree op2 = TREE_OPERAND (expr, 2); + tree op3 = TREE_OPERAND (expr, 3); + gcc_assert (is_gimple_min_invariant (op1) + || TREE_CODE (op1) == VALUE_HANDLE); + if (!set_contains_value (set, op1)) + return false; + gcc_assert (!op2 || is_gimple_min_invariant (op2) + || TREE_CODE (op2) == VALUE_HANDLE); + if (op2 + && !set_contains_value (set, op2)) + return false; + gcc_assert (!op3 || is_gimple_min_invariant (op3) + || TREE_CODE (op3) == VALUE_HANDLE); + if (op3 + && !set_contains_value (set, op3)) + return false; + } + return set_contains_value (ANTIC_SAFE_LOADS (block), + vh) + || !vuses_dies_in_block_x (VALUE_HANDLE_VUSES (vh), + block); } } return false; @@ -2091,7 +2153,8 @@ can_PRE_operation (tree op) || COMPARISON_CLASS_P (op) || TREE_CODE (op) == INDIRECT_REF || TREE_CODE (op) == COMPONENT_REF - || TREE_CODE (op) == CALL_EXPR; + || TREE_CODE (op) == CALL_EXPR + || TREE_CODE (op) == ARRAY_REF; } @@ -2105,8 +2168,8 @@ static VEC(tree,heap) *inserted_exprs; to see which expressions need to be put into GC'able memory */ static VEC(tree, heap) *need_creation; -/* For COMPONENT_REF's, we can't have any intermediates for the - COMPONENT_REF or INDIRECT_REF portion, because we'd end up with +/* For COMPONENT_REF's and ARRAY_REF's, we can't have any intermediates for the + COMPONENT_REF or INDIRECT_REF or ARRAY_REF portion, because we'd end up with trying to rename aggregates into ssa form directly, which is a no no. @@ -2136,6 +2199,26 @@ create_component_ref_by_pieces (basic_block block, tree expr, tree stmts) switch TREE_CODE (genop) { + case ARRAY_REF: + { + tree op0; + tree op1, op2, op3; + op0 = create_component_ref_by_pieces (block, + TREE_OPERAND (genop, 0), + stmts); + op1 = TREE_OPERAND (genop, 1); + if (TREE_CODE (op1) == VALUE_HANDLE) + op1 = find_or_generate_expression (block, op1, stmts); + op2 = TREE_OPERAND (genop, 2); + if (op2 && TREE_CODE (op2) == VALUE_HANDLE) + op2 = find_or_generate_expression (block, op2, stmts); + op3 = TREE_OPERAND (genop, 3); + if (op3 && TREE_CODE (op3) == VALUE_HANDLE) + op3 = find_or_generate_expression (block, op3, stmts); + folded = build4 (ARRAY_REF, TREE_TYPE (genop), op0, op1, + op2, op3); + return folded; + } case COMPONENT_REF: { tree op0; @@ -2259,7 +2342,8 @@ create_expression_by_pieces (basic_block block, tree expr, tree stmts) break; case tcc_reference: { - if (TREE_CODE (expr) == COMPONENT_REF) + if (TREE_CODE (expr) == COMPONENT_REF + || TREE_CODE (expr) == ARRAY_REF) { folded = create_component_ref_by_pieces (block, expr, stmts); }