From: Richard Biener Date: Tue, 24 Jan 2017 11:30:44 +0000 (+0000) Subject: Backport PRs 71848, 77646, 77648, 77879, 78188 X-Git-Tag: releases/gcc-5.5.0~563 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a88596b249b590252f0886febb200261b3a28089;p=thirdparty%2Fgcc.git Backport PRs 71848, 77646, 77648, 77879, 78188 2017-01-24 Richard Biener Backport from mainline 2016-09-20 Richard Biener PR tree-optimization/77646 * tree-ssa-sccvn.c (visit_reference_op_call): Always value-number a VDEF. * gcc.dg/torture/pr77646.c: New testcase. 2016-11-05 David Edelsohn Richard Biener PR bootstrap/78188 PR c++/71848 * ipa-comdats.c (pass_ipa_comdats::gate): Require HAVE_COMDAT_GROUP. * g++.dg/ipa/pr78188.C: New test. 2016-09-21 Richard Biener PR tree-optimization/77648 * tree-ssa-structalias.c (process_constraint): Handle all DEREF with complex RHS. (make_transitive_closure_constraints): Adjust comment. (make_any_offset_constraints): New function. (handle_rhs_call): Make sure to first expand a pointer to all subfields before transitively closing it. (handle_const_call): Likewise. Properly expand returned pointers as well. (handle_pure_call): Likewise. * gcc.dg/torture/pr77648-1.c: New testcase. * gcc.dg/torture/pr77648-2.c: Likewise. 2016-10-07 Richard Biener PR tree-optimization/77879 * tree-ssa-structalias.c (handle_const_call): Properly handle NRV return slots. (handle_pure_call): Likewise. From-SVN: r244864 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index a132be1c9b8c..c6875f40bf90 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,39 @@ +2017-01-24 Richard Biener + + Backport from mainline + 2016-09-20 Richard Biener + + PR tree-optimization/77646 + * tree-ssa-sccvn.c (visit_reference_op_call): Always value-number + a VDEF. + + 2016-11-05 David Edelsohn + Richard Biener + + PR bootstrap/78188 + PR c++/71848 + * ipa-comdats.c (pass_ipa_comdats::gate): Require HAVE_COMDAT_GROUP. + + 2016-09-21 Richard Biener + + PR tree-optimization/77648 + * tree-ssa-structalias.c (process_constraint): Handle all DEREF + with complex RHS. + (make_transitive_closure_constraints): Adjust comment. + (make_any_offset_constraints): New function. + (handle_rhs_call): Make sure to first expand a pointer to all + subfields before transitively closing it. + (handle_const_call): Likewise. Properly expand returned + pointers as well. + (handle_pure_call): Likewise. + + 2016-10-07 Richard Biener + + PR tree-optimization/77879 + * tree-ssa-structalias.c (handle_const_call): Properly handle + NRV return slots. + (handle_pure_call): Likewise. + 2017-01-24 Richard Biener Backport from mainline diff --git a/gcc/ipa-comdats.c b/gcc/ipa-comdats.c index 3e6fc1d030ea..d4726753a94e 100644 --- a/gcc/ipa-comdats.c +++ b/gcc/ipa-comdats.c @@ -433,7 +433,7 @@ public: bool pass_ipa_comdats::gate (function *) { - return optimize; + return HAVE_COMDAT_GROUP && optimize; } } // anon namespace diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 25255d437c5e..6b1b2983358d 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,24 @@ +2017-01-24 Richard Biener + + Backport from mainline + 2016-09-20 Richard Biener + + PR tree-optimization/77646 + * gcc.dg/torture/pr77646.c: New testcase. + + 2016-11-05 David Edelsohn + Richard Biener + + PR bootstrap/78188 + PR c++/71848 + * g++.dg/ipa/pr78188.C: New test. + + 2016-09-21 Richard Biener + + PR tree-optimization/77648 + * gcc.dg/torture/pr77648-1.c: New testcase. + * gcc.dg/torture/pr77648-2.c: Likewise. + 2017-01-24 Richard Biener Backport from mainline diff --git a/gcc/testsuite/g++.dg/ipa/pr78188.C b/gcc/testsuite/g++.dg/ipa/pr78188.C new file mode 100644 index 000000000000..f6ee654471e0 --- /dev/null +++ b/gcc/testsuite/g++.dg/ipa/pr78188.C @@ -0,0 +1,20 @@ +// { dg-do compile } +// { dg-options "-O2 -fno-exceptions" } + +int a; +static void __attribute__((noinline)) foo () { a = 1; } +static void __attribute__((noinline)) foo2 () { a = 2; } + +struct X +{ + virtual void bar (int i) { if (!i) { foo (); __builtin_abort (); } } +}; + +void baz (int i) +{ + if (!i) + { foo2 (); __builtin_abort (); } +} + +X xx; + diff --git a/gcc/testsuite/gcc.dg/torture/pr77646.c b/gcc/testsuite/gcc.dg/torture/pr77646.c new file mode 100644 index 000000000000..1b1990037bf1 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr77646.c @@ -0,0 +1,21 @@ +/* { dg-do compile } */ + +struct e { + int (*f)(); + void (*g)(); +} * c; +int a; +void *h(); +typedef struct { struct e j; } k; +int l() { return a; } +const struct e b = {l}; +void m() +{ + k *d = h(); + d->j = b; + c = (struct e *)d; + struct e *i = c; + if (i->f(c)) + while (i->f(c)) + i->g(); +} diff --git a/gcc/testsuite/gcc.dg/torture/pr77648-1.c b/gcc/testsuite/gcc.dg/torture/pr77648-1.c new file mode 100644 index 000000000000..3597e2ed4567 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr77648-1.c @@ -0,0 +1,24 @@ +/* { dg-do run } */ + +struct S { int *p; int *q; }; + +int **__attribute__((noinline,noclone,pure)) foo (struct S *s) +{ + int tem; + __asm__ ("" : "=g" (tem) : "g" (s->p)); + return &s->q; +} + +int main() +{ + struct S s; + int i = 1, j = 2; + int **x; + s.p = &i; + s.q = &j; + x = foo (&s); + **x = 7; + if (j != 7) + __builtin_abort (); + return 0; +} diff --git a/gcc/testsuite/gcc.dg/torture/pr77648-2.c b/gcc/testsuite/gcc.dg/torture/pr77648-2.c new file mode 100644 index 000000000000..1c3734d34d8b --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr77648-2.c @@ -0,0 +1,22 @@ +/* { dg-do run } */ + +struct S { int *p; int *q; }; + +int **__attribute__((noinline,noclone,const)) foo (struct S *s) +{ + return &s->q; +} + +int main() +{ + struct S s; + int i = 1, j = 2; + int **x; + s.p = &i; + s.q = &j; + x = foo (&s); + **x = 7; + if (j != 7) + __builtin_abort (); + return 0; +} diff --git a/gcc/tree-ssa-sccvn.c b/gcc/tree-ssa-sccvn.c index db554d6fea31..349bae7b0e43 100644 --- a/gcc/tree-ssa-sccvn.c +++ b/gcc/tree-ssa-sccvn.c @@ -2980,6 +2980,10 @@ visit_reference_op_call (tree lhs, gcall *stmt) { if (vnresult->result_vdef && vdef) changed |= set_ssa_val_to (vdef, vnresult->result_vdef); + else if (vdef) + /* If the call was discovered to be pure or const reflect + that as far as possible. */ + changed |= set_ssa_val_to (vdef, vuse_ssa_val (gimple_vuse (stmt))); if (!vnresult->result && lhs) vnresult->result = lhs; diff --git a/gcc/tree-ssa-structalias.c b/gcc/tree-ssa-structalias.c index bf1b989d8373..d1eaae2f5c42 100644 --- a/gcc/tree-ssa-structalias.c +++ b/gcc/tree-ssa-structalias.c @@ -3037,7 +3037,7 @@ process_constraint (constraint_t t) process_constraint (new_constraint (tmplhs, rhs)); process_constraint (new_constraint (lhs, tmplhs)); } - else if (rhs.type == ADDRESSOF && lhs.type == DEREF) + else if ((rhs.type != SCALAR || rhs.offset != 0) && lhs.type == DEREF) { /* Split into tmp = &rhs, *lhs = tmp */ struct constraint_expr tmplhs; @@ -3756,7 +3756,7 @@ make_transitive_closure_constraints (varinfo_t vi) { struct constraint_expr lhs, rhs; - /* VAR = *VAR; */ + /* VAR = *(VAR + UNKNOWN); */ lhs.type = SCALAR; lhs.var = vi->id; lhs.offset = 0; @@ -3766,6 +3766,23 @@ make_transitive_closure_constraints (varinfo_t vi) process_constraint (new_constraint (lhs, rhs)); } +/* Add constraints to that the solution of VI has all subvariables added. */ + +static void +make_any_offset_constraints (varinfo_t vi) +{ + struct constraint_expr lhs, rhs; + + /* VAR = VAR + UNKNOWN; */ + lhs.type = SCALAR; + lhs.var = vi->id; + lhs.offset = 0; + rhs.type = SCALAR; + rhs.var = vi->id; + rhs.offset = UNKNOWN_OFFSET; + process_constraint (new_constraint (lhs, rhs)); +} + /* Temporary storage for fake var decls. */ struct obstack fake_var_decl_obstack; @@ -3910,15 +3927,12 @@ handle_rhs_call (gcall *stmt, vec *results) && (flags & EAF_NOESCAPE)) { varinfo_t uses = get_call_use_vi (stmt); + varinfo_t tem = new_var_info (NULL_TREE, "callarg"); + make_constraint_to (tem->id, arg); + make_any_offset_constraints (tem); if (!(flags & EAF_DIRECT)) - { - varinfo_t tem = new_var_info (NULL_TREE, "callarg"); - make_constraint_to (tem->id, arg); - make_transitive_closure_constraints (tem); - make_copy_constraint (uses, tem->id); - } - else - make_constraint_to (uses->id, arg); + make_transitive_closure_constraints (tem); + make_copy_constraint (uses, tem->id); returns_uses = true; } else if (flags & EAF_NOESCAPE) @@ -3928,6 +3942,7 @@ handle_rhs_call (gcall *stmt, vec *results) varinfo_t clobbers = get_call_clobber_vi (stmt); varinfo_t tem = new_var_info (NULL_TREE, "callarg"); make_constraint_to (tem->id, arg); + make_any_offset_constraints (tem); if (!(flags & EAF_DIRECT)) make_transitive_closure_constraints (tem); make_copy_constraint (uses, tem->id); @@ -3953,7 +3968,7 @@ handle_rhs_call (gcall *stmt, vec *results) if (returns_uses) { rhsc.var = get_call_use_vi (stmt)->id; - rhsc.offset = 0; + rhsc.offset = UNKNOWN_OFFSET; rhsc.type = SCALAR; results->safe_push (rhsc); } @@ -4056,30 +4071,58 @@ handle_const_call (gcall *stmt, vec *results) { struct constraint_expr rhsc; unsigned int k; + bool need_uses = false; /* Treat nested const functions the same as pure functions as far as the static chain is concerned. */ if (gimple_call_chain (stmt)) { varinfo_t uses = get_call_use_vi (stmt); - make_transitive_closure_constraints (uses); make_constraint_to (uses->id, gimple_call_chain (stmt)); + need_uses = true; + } + + /* And if we applied NRV the address of the return slot escapes as well. */ + if (gimple_call_return_slot_opt_p (stmt) + && gimple_call_lhs (stmt) != NULL_TREE + && TREE_ADDRESSABLE (TREE_TYPE (gimple_call_lhs (stmt)))) + { + varinfo_t uses = get_call_use_vi (stmt); + auto_vec tmpc; + get_constraint_for_address_of (gimple_call_lhs (stmt), &tmpc); + make_constraints_to (uses->id, tmpc); + need_uses = true; + } + + if (need_uses) + { + varinfo_t uses = get_call_use_vi (stmt); + make_any_offset_constraints (uses); + make_transitive_closure_constraints (uses); rhsc.var = uses->id; rhsc.offset = 0; rhsc.type = SCALAR; results->safe_push (rhsc); } - /* May return arguments. */ + /* May return offsetted arguments. */ + varinfo_t tem = NULL; + if (gimple_call_num_args (stmt) != 0) + tem = new_var_info (NULL_TREE, "callarg"); for (k = 0; k < gimple_call_num_args (stmt); ++k) { tree arg = gimple_call_arg (stmt, k); auto_vec argc; - unsigned i; - struct constraint_expr *argp; get_constraint_for_rhs (arg, &argc); - FOR_EACH_VEC_ELT (argc, i, argp) - results->safe_push (*argp); + make_constraints_to (tem->id, argc); + } + if (tem) + { + ce_s ce; + ce.type = SCALAR; + ce.var = tem->id; + ce.offset = UNKNOWN_OFFSET; + results->safe_push (ce); } /* May return addresses of globals. */ @@ -4106,6 +4149,7 @@ handle_pure_call (gcall *stmt, vec *results) if (!uses) { uses = get_call_use_vi (stmt); + make_any_offset_constraints (uses); make_transitive_closure_constraints (uses); } make_constraint_to (uses->id, arg); @@ -4117,11 +4161,28 @@ handle_pure_call (gcall *stmt, vec *results) if (!uses) { uses = get_call_use_vi (stmt); + make_any_offset_constraints (uses); make_transitive_closure_constraints (uses); } make_constraint_to (uses->id, gimple_call_chain (stmt)); } + /* And if we applied NRV the address of the return slot. */ + if (gimple_call_return_slot_opt_p (stmt) + && gimple_call_lhs (stmt) != NULL_TREE + && TREE_ADDRESSABLE (TREE_TYPE (gimple_call_lhs (stmt)))) + { + if (!uses) + { + uses = get_call_use_vi (stmt); + make_any_offset_constraints (uses); + make_transitive_closure_constraints (uses); + } + auto_vec tmpc; + get_constraint_for_address_of (gimple_call_lhs (stmt), &tmpc); + make_constraints_to (uses->id, tmpc); + } + /* Pure functions may return call-used and nonlocal memory. */ if (uses) {