Hi! 5 further backports to 7 branch, bootstrapped/regtested on x86_64-linux and i686-linux, committed to branch.
Jakub
2017-12-22 Jakub Jelinek <ja...@redhat.com> Backported from mainline 2017-12-19 Jakub Jelinek <ja...@redhat.com> PR ipa/82801 PR ipa/83346 * ipa-inline.c (flatten_remove_node_hook): New function. (ipa_inline): Keep only nodes with flatten attribute at the end of the array in the order from ipa_reverse_postorder, only walk that portion of array for flattening, if there is more than one such node, temporarily register a removal hook and ignore removed nodes. * g++.dg/ipa/pr82801.C: New test. --- gcc/ipa-inline.c (revision 255804) +++ gcc/ipa-inline.c (revision 255805) @@ -2338,6 +2338,19 @@ dump_inline_stats (void) (int) reason[i][1], reason_freq[i].to_double (), reason[i][0]); } +/* Called when node is removed. */ + +static void +flatten_remove_node_hook (struct cgraph_node *node, void *data) +{ + if (lookup_attribute ("flatten", DECL_ATTRIBUTES (node->decl)) == NULL) + return; + + hash_set<struct cgraph_node *> *removed + = (hash_set<struct cgraph_node *> *) data; + removed->add (node); +} + /* Decide on the inlining. We do so in the topological order to avoid expenses on updating data structures. */ @@ -2347,7 +2360,7 @@ ipa_inline (void) struct cgraph_node *node; int nnodes; struct cgraph_node **order; - int i; + int i, j; int cold; bool remove_functions = false; @@ -2380,26 +2393,56 @@ ipa_inline (void) if (dump_file) fprintf (dump_file, "\nFlattening functions:\n"); + /* First shrink order array, so that it only contains nodes with + flatten attribute. */ + for (i = nnodes - 1, j = i; i >= 0; i--) + { + node = order[i]; + if (lookup_attribute ("flatten", + DECL_ATTRIBUTES (node->decl)) != NULL) + order[j--] = order[i]; + } + + /* After the above loop, order[j + 1] ... order[nnodes - 1] contain + nodes with flatten attribute. If there is more than one such + node, we need to register a node removal hook, as flatten_function + could remove other nodes with flatten attribute. See PR82801. */ + struct cgraph_node_hook_list *node_removal_hook_holder = NULL; + hash_set<struct cgraph_node *> *flatten_removed_nodes = NULL; + if (j < nnodes - 2) + { + flatten_removed_nodes = new hash_set<struct cgraph_node *>; + node_removal_hook_holder + = symtab->add_cgraph_removal_hook (&flatten_remove_node_hook, + flatten_removed_nodes); + } + /* In the first pass handle functions to be flattened. Do this with a priority so none of our later choices will make this impossible. */ - for (i = nnodes - 1; i >= 0; i--) + for (i = nnodes - 1; i > j; i--) { node = order[i]; + if (flatten_removed_nodes + && flatten_removed_nodes->contains (node)) + continue; /* Handle nodes to be flattened. Ideally when processing callees we stop inlining at the entry of cycles, possibly cloning that entry point and try to flatten itself turning it into a self-recursive function. */ - if (lookup_attribute ("flatten", - DECL_ATTRIBUTES (node->decl)) != NULL) - { - if (dump_file) - fprintf (dump_file, - "Flattening %s\n", node->name ()); - flatten_function (node, false); - } + if (dump_file) + fprintf (dump_file, "Flattening %s\n", node->name ()); + flatten_function (node, false); } + + if (j < nnodes - 2) + { + symtab->remove_cgraph_removal_hook (node_removal_hook_holder); + delete flatten_removed_nodes; + } + free (order); + if (dump_file) dump_overall_stats (); @@ -2411,7 +2454,6 @@ ipa_inline (void) inline functions and virtual functions so we really know what is called once. */ symtab->remove_unreachable_nodes (dump_file); - free (order); /* Inline functions with a property that after inlining into all callers the code size will shrink because the out-of-line copy is eliminated. --- gcc/testsuite/g++.dg/ipa/pr82801.C (nonexistent) +++ gcc/testsuite/g++.dg/ipa/pr82801.C (revision 255805) @@ -0,0 +1,20 @@ +// PR ipa/82801 +// { dg-do compile } +// { dg-options "-O2 -Wno-attributes" } + +template<int> +struct A { A () {} }; +struct B { double foo () const; }; + +__attribute__((always_inline, flatten)) +double B::foo () const +{ + A<1> v; + return 0.0; +} + +int +main () +{ + return 0; +}
2017-12-22 Jakub Jelinek <ja...@redhat.com> Backported from mainline 2017-12-21 Jakub Jelinek <ja...@redhat.com> PR tree-optimization/83521 * tree-ssa-phiopt.c (factor_out_conditional_conversion): Use gimple_build_assign without code on result of fold_build1 (VIEW_CONVERT_EXPR, ...), as it might not create a VIEW_CONVERT_EXPR. * gcc.dg/pr83521.c: New test. --- gcc/tree-ssa-phiopt.c (revision 255951) +++ gcc/tree-ssa-phiopt.c (revision 255952) @@ -548,8 +548,12 @@ factor_out_conditional_conversion (edge /* Create the conversion stmt and insert it. */ if (convert_code == VIEW_CONVERT_EXPR) - temp = fold_build1 (VIEW_CONVERT_EXPR, TREE_TYPE (result), temp); - new_stmt = gimple_build_assign (result, convert_code, temp); + { + temp = fold_build1 (VIEW_CONVERT_EXPR, TREE_TYPE (result), temp); + new_stmt = gimple_build_assign (result, temp); + } + else + new_stmt = gimple_build_assign (result, convert_code, temp); gsi = gsi_after_labels (gimple_bb (phi)); gsi_insert_before (&gsi, new_stmt, GSI_SAME_STMT); --- gcc/testsuite/gcc.dg/pr83521.c (nonexistent) +++ gcc/testsuite/gcc.dg/pr83521.c (revision 255952) @@ -0,0 +1,10 @@ +/* PR tree-optimization/83521 */ +/* { dg-do compile } */ +/* { dg-options "-O1 -fno-tree-forwprop" } */ + +int +foo (unsigned int x, int y) +{ + int *z = (int *)&x; + return (y == 0) ? y : *z; +}
2017-12-22 Jakub Jelinek <ja...@redhat.com> Backported from mainline 2017-12-21 Jakub Jelinek <ja...@redhat.com> PR tree-optimization/83523 * tree-ssa-math-opts.c (is_widening_mult_p): Return false if for INTEGER_TYPE TYPE_OVERFLOW_TRAPS. (convert_mult_to_fma): Likewise. * g++.dg/tree-ssa/pr83523.C: New test. --- gcc/tree-ssa-math-opts.c (revision 255952) +++ gcc/tree-ssa-math-opts.c (revision 255953) @@ -3074,8 +3074,12 @@ is_widening_mult_p (gimple *stmt, { tree type = TREE_TYPE (gimple_assign_lhs (stmt)); - if (TREE_CODE (type) != INTEGER_TYPE - && TREE_CODE (type) != FIXED_POINT_TYPE) + if (TREE_CODE (type) == INTEGER_TYPE) + { + if (TYPE_OVERFLOW_TRAPS (type)) + return false; + } + else if (TREE_CODE (type) != FIXED_POINT_TYPE) return false; if (!is_widening_mult_rhs_p (type, gimple_assign_rhs1 (stmt), type1_out, @@ -3443,7 +3447,8 @@ convert_mult_to_fma (gimple *mul_stmt, t /* We don't want to do bitfield reduction ops. */ if (INTEGRAL_TYPE_P (type) && (TYPE_PRECISION (type) - != GET_MODE_PRECISION (TYPE_MODE (type)))) + != GET_MODE_PRECISION (TYPE_MODE (type)) + || TYPE_OVERFLOW_TRAPS (type))) return false; /* If the target doesn't support it, don't generate it. We assume that --- gcc/testsuite/g++.dg/tree-ssa/pr83523.C (nonexistent) +++ gcc/testsuite/g++.dg/tree-ssa/pr83523.C (revision 255953) @@ -0,0 +1,25 @@ +// PR tree-optimization/83523 +// { dg-do compile } +// { dg-options "-O2 -fexceptions -fnon-call-exceptions -ftrapv" } + +#ifdef __SIZEOF_INT128__ +typedef __int128 T; +typedef long long int U; +#else +typedef long long int T; +typedef int U; +#endif + +struct S { S (); ~S (); }; +void bar (); + +T +foo (U x, U y) +{ + T z = x; + S s; + bar (); + z *= y; + bar (); + return z; +}
2017-12-22 Jakub Jelinek <ja...@redhat.com> Backported from mainline 2017-12-21 Jakub Jelinek <ja...@redhat.com> PR rtl-optimization/80747 PR rtl-optimization/83512 * cfgrtl.c (force_nonfallthru_and_redirect): When splitting succ edge from ENTRY, copy partition from e->dest to the newly created bb. * bb-reorder.c (reorder_basic_blocks_simple): If last_tail is ENTRY, use BB_PARTITION of its successor block as current_partition. Don't copy partition when splitting succ edge from ENTRY. * gcc.dg/pr80747.c: New test. * gcc.dg/pr83512.c: New test. --- gcc/bb-reorder.c (revision 255953) +++ gcc/bb-reorder.c (revision 255954) @@ -2405,7 +2405,10 @@ reorder_basic_blocks_simple (void) basic_block last_tail = (basic_block) ENTRY_BLOCK_PTR_FOR_FN (cfun)->aux; - int current_partition = BB_PARTITION (last_tail); + int current_partition + = BB_PARTITION (last_tail == ENTRY_BLOCK_PTR_FOR_FN (cfun) + ? EDGE_SUCC (ENTRY_BLOCK_PTR_FOR_FN (cfun), 0)->dest + : last_tail); bool need_another_pass = true; for (int pass = 0; pass < 2 && need_another_pass; pass++) @@ -2446,7 +2449,6 @@ reorder_basic_blocks_simple (void) { force_nonfallthru (e); e->src->aux = ENTRY_BLOCK_PTR_FOR_FN (cfun)->aux; - BB_COPY_PARTITION (e->src, e->dest); } } --- gcc/cfgrtl.c (revision 255953) +++ gcc/cfgrtl.c (revision 255954) @@ -1542,6 +1542,9 @@ force_nonfallthru_and_redirect (edge e, basic_block bb = create_basic_block (BB_HEAD (e->dest), NULL, ENTRY_BLOCK_PTR_FOR_FN (cfun)); + /* Make sure new block ends up in correct hot/cold section. */ + BB_COPY_PARTITION (bb, e->dest); + /* Change the existing edge's source to be the new block, and add a new edge from the entry block to the new block. */ e->src = bb; --- gcc/testsuite/gcc.dg/pr83512.c (nonexistent) +++ gcc/testsuite/gcc.dg/pr83512.c (revision 255954) @@ -0,0 +1,16 @@ +/* PR rtl-optimization/83512 */ +/* { dg-do compile } */ +/* { dg-options "-O2 -freorder-blocks-algorithm=simple" } */ + +int a; + +void +foo (int *x) +{ + for (;;) + { + for (*x = 0; *x < 1; *x++) + ; + ++a; + } +} --- gcc/testsuite/gcc.dg/pr80747.c (nonexistent) +++ gcc/testsuite/gcc.dg/pr80747.c (revision 255954) @@ -0,0 +1,18 @@ +/* PR rtl-optimization/80747 */ +/* { dg-do compile } */ +/* { dg-options "-fprofile-use -freorder-blocks-and-partition -O1 -foptimize-sibling-calls" } */ + +int +foo (int a) +{ + int r; + if (a & 1) + r = foo (a - 1); + else if (a) + r = foo (a - 2); + else + return 0; + if (r) + r = r; + return r; +}
2017-12-22 Jakub Jelinek <ja...@redhat.com> Backported from mainline 2017-12-21 Jakub Jelinek <ja...@redhat.com> PR c/83448 * gimple-ssa-sprintf.c (maybe_warn): Don't call set_caret_index if navail is >= dir.len. * gcc.c-torture/compile/pr83448.c: New test. * gcc.dg/tree-ssa/builtin-snprintf-warn-4.c: New test. --- gcc/gimple-ssa-sprintf.c (revision 255959) +++ gcc/gimple-ssa-sprintf.c (revision 255960) @@ -2466,7 +2466,8 @@ maybe_warn (substring_loc &dirloc, locat /* For plain character directives (i.e., the format string itself) but not others, point the caret at the first character that's past the end of the destination. */ - dirloc.set_caret_index (dirloc.get_caret_idx () + navail); + if (navail < dir.len) + dirloc.set_caret_index (dirloc.get_caret_idx () + navail); } if (*dir.beg == '\0') @@ -2594,7 +2595,8 @@ maybe_warn (substring_loc &dirloc, locat /* For plain character directives (i.e., the format string itself) but not others, point the caret at the first character that's past the end of the destination. */ - dirloc.set_caret_index (dirloc.get_caret_idx () + navail); + if (navail < dir.len) + dirloc.set_caret_index (dirloc.get_caret_idx () + navail); } if (*dir.beg == '\0') --- gcc/testsuite/gcc.c-torture/compile/pr83448.c (nonexistent) +++ gcc/testsuite/gcc.c-torture/compile/pr83448.c (revision 255960) @@ -0,0 +1,15 @@ +/* PR c/83448 */ + +char *a; +int b; + +void +foo (void) +{ + for (;;) + { + if (b < 0) + foo (); + __builtin_snprintf (a, b, "%*s", b, ""); + } +} --- gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-warn-4.c (nonexistent) +++ gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-warn-4.c (revision 255960) @@ -0,0 +1,46 @@ +/* PR c/83448 */ +/* { dg-do compile } */ +/* { dg-options "-O2 -Wformat-truncation -fdiagnostics-show-caret" } */ + +extern int snprintf (char *, __SIZE_TYPE__, const char *, ...); + +void +foo (char *a, char *b, char *c, int d, int e) +{ + snprintf (a, 7, "abc\\\123 efg"); + /* { dg-warning "directive output truncated writing 9 bytes into a region of size 7" "" { target *-*-* } .-1 } + { dg-message ".snprintf. output 10 bytes into a destination of size 7" "note" { target *-*-* } .-2 } + { dg-begin-multiline-output "" } + snprintf (a, 7, "abc\\\123 efg"); + ~~~~~~~~~~~^~ + { dg-end-multiline-output "" } + { dg-begin-multiline-output "note" } + snprintf (a, 7, "abc\\\123 efg"); + ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + { dg-end-multiline-output "" } */ + d &= 63; + d += 10; + snprintf (b, 7, "a%dbcdefg", d); + /* { dg-warning "'bcdefg' directive output truncated writing 6 bytes into a region of size 4" "" { target *-*-* } .-1 } + { dg-message ".snprintf. output 10 bytes into a destination of size 7" "note" { target *-*-* } .-2 } + { dg-begin-multiline-output "" } + snprintf (b, 7, "a%dbcdefg", d); + ~~~~^~ + { dg-end-multiline-output "" } + { dg-begin-multiline-output "note" } + snprintf (b, 7, "a%dbcdefg", d); + ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + { dg-end-multiline-output "" } */ + e &= 127; + snprintf (c, 7, "a%dbcdefgh", e); + /* { dg-warning "'bcdefgh' directive output truncated writing 7 bytes into a region of size between 3 and 5" "" { target *-*-* } .-1 } + { dg-message ".snprintf. output between 10 and 12 bytes into a destination of size 7" "note" { target *-*-* } .-2 } + { dg-begin-multiline-output "" } + snprintf (c, 7, "a%dbcdefgh", e); + ~~~~~^~ + { dg-end-multiline-output "" } + { dg-begin-multiline-output "note" } + snprintf (c, 7, "a%dbcdefgh", e); + ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + { dg-end-multiline-output "" } */ +}