From f09a35532794c2d8287355209b9f6bb9c18ccb8f Mon Sep 17 00:00:00 2001 From: John Marino Date: Fri, 13 Mar 2015 14:20:38 +0100 Subject: [PATCH] Update gcc-50 to SVN version 221423 Last Changed Date: 2015-03-13 14:48:21 +0100 (Fri, 13 Mar 2015) --- contrib/gcc-5.0/LAST_UPDATED | 4 +- contrib/gcc-5.0/gcc/DATESTAMP | 2 +- contrib/gcc-5.0/gcc/asan.c | 2 + contrib/gcc-5.0/gcc/c-family/c-common.c | 11 +- contrib/gcc-5.0/gcc/c-family/c.opt | 10 + contrib/gcc-5.0/gcc/c/c-convert.c | 4 +- contrib/gcc-5.0/gcc/c/c-decl.c | 5 +- contrib/gcc-5.0/gcc/c/c-parser.c | 2 +- contrib/gcc-5.0/gcc/c/c-typeck.c | 35 +- contrib/gcc-5.0/gcc/cfgexpand.c | 31 +- contrib/gcc-5.0/gcc/cgraph.c | 79 +- contrib/gcc-5.0/gcc/cgraph.h | 30 +- contrib/gcc-5.0/gcc/config/i386/i386.c | 36 +- contrib/gcc-5.0/gcc/config/i386/i386.md | 44 +- .../gcc/config/i386/intelmic-mkoffload.c | 28 +- .../gcc-5.0/gcc/config/i386/linux-common.h | 38 + contrib/gcc-5.0/gcc/cp/call.c | 6 +- contrib/gcc-5.0/gcc/cp/cp-gimplify.c | 78 +- contrib/gcc-5.0/gcc/cp/decl.c | 13 +- contrib/gcc-5.0/gcc/cp/parser.c | 23 +- contrib/gcc-5.0/gcc/cp/pt.c | 8 +- contrib/gcc-5.0/gcc/doc/extend.texi | 166 +--- contrib/gcc-5.0/gcc/doc/invoke.texi | 240 +++++- contrib/gcc-5.0/gcc/dominance.c | 2 +- contrib/gcc-5.0/gcc/fold-const.c | 51 +- contrib/gcc-5.0/gcc/gcc.c | 5 + contrib/gcc-5.0/gcc/graph.c | 7 +- contrib/gcc-5.0/gcc/ipa-chkp.c | 57 +- contrib/gcc-5.0/gcc/ipa-devirt.c | 726 +++++++++++------- contrib/gcc-5.0/gcc/ipa-icf-gimple.c | 71 +- contrib/gcc-5.0/gcc/ipa-icf-gimple.h | 10 +- contrib/gcc-5.0/gcc/ipa-icf.c | 272 +++---- contrib/gcc-5.0/gcc/ipa-icf.h | 12 - contrib/gcc-5.0/gcc/ipa-inline-analysis.c | 37 +- contrib/gcc-5.0/gcc/ipa-utils.h | 2 +- contrib/gcc-5.0/gcc/lra-lives.c | 6 +- contrib/gcc-5.0/gcc/lto/lto.c | 17 +- contrib/gcc-5.0/gcc/omp-low.c | 4 +- contrib/gcc-5.0/gcc/simplify-rtx.c | 16 +- contrib/gcc-5.0/gcc/symtab.c | 103 +++ contrib/gcc-5.0/gcc/toplev.c | 12 +- contrib/gcc-5.0/gcc/tree-cfg.c | 36 +- contrib/gcc-5.0/gcc/tree-cfgcleanup.c | 58 +- contrib/gcc-5.0/gcc/tree-core.h | 3 +- contrib/gcc-5.0/gcc/tree-inline.c | 15 +- contrib/gcc-5.0/gcc/tree-parloops.c | 3 +- contrib/gcc-5.0/gcc/tree-sra.c | 2 +- contrib/gcc-5.0/gcc/tree-ssa-coalesce.c | 154 +++- contrib/gcc-5.0/gcc/tree-ssa-coalesce.h | 1 + contrib/gcc-5.0/gcc/tree-ssa-dom.c | 28 +- contrib/gcc-5.0/gcc/tree-ssa-forwprop.c | 22 + contrib/gcc-5.0/gcc/tree-ssa-pre.c | 24 +- contrib/gcc-5.0/gcc/tree-ssa-propagate.c | 32 +- contrib/gcc-5.0/gcc/tree-ssa-tail-merge.c | 2 +- contrib/gcc-5.0/gcc/tree-vect-data-refs.c | 59 +- contrib/gcc-5.0/gcc/tree-vect-stmts.c | 9 +- contrib/gcc-5.0/gcc/tree-vectorizer.c | 9 +- contrib/gcc-5.0/gcc/tree.h | 3 +- contrib/gcc-5.0/gcc/ubsan.c | 8 +- contrib/gcc-5.0/gcc/var-tracking.c | 8 +- contrib/gcc-5.0/gcc/varasm.c | 58 +- contrib/gcc-5.0/gcc/varpool.c | 8 +- .../gcc-5.0/libstdc++-v3/include/bits/regex.h | 86 ++- .../libstdc++-v3/include/bits/regex.tcc | 33 +- .../include/experimental/system_error | 2 +- 65 files changed, 1911 insertions(+), 1057 deletions(-) diff --git a/contrib/gcc-5.0/LAST_UPDATED b/contrib/gcc-5.0/LAST_UPDATED index 3a6f495175..d8c9337b10 100644 --- a/contrib/gcc-5.0/LAST_UPDATED +++ b/contrib/gcc-5.0/LAST_UPDATED @@ -1,2 +1,2 @@ -221261 -Last Changed Date: 2015-03-08 01:16:18 +0100 (Sun, 08 Mar 2015) +221423 +Last Changed Date: 2015-03-13 14:48:21 +0100 (Fri, 13 Mar 2015) diff --git a/contrib/gcc-5.0/gcc/DATESTAMP b/contrib/gcc-5.0/gcc/DATESTAMP index 0b9fb17858..ea0dd137c0 100644 --- a/contrib/gcc-5.0/gcc/DATESTAMP +++ b/contrib/gcc-5.0/gcc/DATESTAMP @@ -1 +1 @@ -20150308 +20150313 diff --git a/contrib/gcc-5.0/gcc/asan.c b/contrib/gcc-5.0/gcc/asan.c index b7c2b11ed5..9e4a629981 100644 --- a/contrib/gcc-5.0/gcc/asan.c +++ b/contrib/gcc-5.0/gcc/asan.c @@ -1820,6 +1820,8 @@ instrument_derefs (gimple_stmt_iterator *iter, tree t, { if (DECL_THREAD_LOCAL_P (inner)) return; + if (!ASAN_GLOBALS && is_global_var (inner)) + return; if (!TREE_STATIC (inner)) { /* Automatic vars in the current function will be always diff --git a/contrib/gcc-5.0/gcc/c-family/c-common.c b/contrib/gcc-5.0/gcc/c-family/c-common.c index 8c23e09196..456c61955c 100644 --- a/contrib/gcc-5.0/gcc/c-family/c-common.c +++ b/contrib/gcc-5.0/gcc/c-family/c-common.c @@ -1800,6 +1800,12 @@ warn_logical_not_parentheses (location_t location, enum tree_code code, || TREE_CODE (TREE_TYPE (rhs)) == BOOLEAN_TYPE) return; + /* Don't warn for !x == 0 or !y != 0, those are equivalent to + !(x == 0) or !(y != 0). */ + if ((code == EQ_EXPR || code == NE_EXPR) + && integer_zerop (rhs)) + return; + warning_at (location, OPT_Wlogical_not_parentheses, "logical not is only applied to the left hand side of " "comparison"); @@ -5452,11 +5458,10 @@ c_common_nodes_and_builtins (void) char name[25]; sprintf (name, "__int%d", int_n_data[i].bitsize); - record_builtin_type ((enum rid)(RID_FIRST_INT_N + i), xstrdup (name), + record_builtin_type ((enum rid)(RID_FIRST_INT_N + i), name, int_n_trees[i].signed_type); sprintf (name, "__int%d unsigned", int_n_data[i].bitsize); - record_builtin_type (RID_MAX, xstrdup (name), - int_n_trees[i].unsigned_type); + record_builtin_type (RID_MAX, name, int_n_trees[i].unsigned_type); } if (c_dialect_cxx ()) diff --git a/contrib/gcc-5.0/gcc/c-family/c.opt b/contrib/gcc-5.0/gcc/c-family/c.opt index b3c8ceedd2..2692fb5085 100644 --- a/contrib/gcc-5.0/gcc/c-family/c.opt +++ b/contrib/gcc-5.0/gcc/c-family/c.opt @@ -1041,6 +1041,16 @@ fchkp-instrument-marked-only C ObjC C++ ObjC++ LTO Report Var(flag_chkp_instrument_marked_only) Init(0) Instrument only functions marked with bnd_instrument attribute. +fchkp-use-wrappers +C ObjC C++ ObjC++ LTO Report Var(flag_chkp_use_wrappers) Init(1) +Transform instrumented builtin calls into calls to wrappers. + +static-libmpx +Driver + +static-libmpxwrappers +Driver + fcilkplus C ObjC C++ ObjC++ LTO Report Var(flag_cilkplus) Init(0) Enable Cilk Plus diff --git a/contrib/gcc-5.0/gcc/c/c-convert.c b/contrib/gcc-5.0/gcc/c/c-convert.c index 2cb53f748d..27fc3fc0e8 100644 --- a/contrib/gcc-5.0/gcc/c/c-convert.c +++ b/contrib/gcc-5.0/gcc/c/c-convert.c @@ -121,9 +121,7 @@ convert (tree type, tree expr) if (flag_sanitize & SANITIZE_FLOAT_CAST && TREE_CODE (TREE_TYPE (expr)) == REAL_TYPE && COMPLETE_TYPE_P (type) - && current_function_decl != NULL_TREE - && !lookup_attribute ("no_sanitize_undefined", - DECL_ATTRIBUTES (current_function_decl))) + && do_ubsan_in_current_function ()) { tree arg; if (in_late_binary_op) diff --git a/contrib/gcc-5.0/gcc/c/c-decl.c b/contrib/gcc-5.0/gcc/c/c-decl.c index 749785801e..c140837f13 100644 --- a/contrib/gcc-5.0/gcc/c/c-decl.c +++ b/contrib/gcc-5.0/gcc/c/c-decl.c @@ -5837,10 +5837,7 @@ grokdeclarator (const struct c_declarator *declarator, warn_variable_length_array (name, size); if (flag_sanitize & SANITIZE_VLA && decl_context == NORMAL - && current_function_decl != NULL_TREE - && !lookup_attribute ("no_sanitize_undefined", - DECL_ATTRIBUTES - (current_function_decl))) + && do_ubsan_in_current_function ()) { /* Evaluate the array size only once. */ size = c_save_expr (size); diff --git a/contrib/gcc-5.0/gcc/c/c-parser.c b/contrib/gcc-5.0/gcc/c/c-parser.c index ceb9e1a78e..5cc3892307 100644 --- a/contrib/gcc-5.0/gcc/c/c-parser.c +++ b/contrib/gcc-5.0/gcc/c/c-parser.c @@ -139,7 +139,7 @@ c_parse_init (void) /* We always create the symbols but they aren't always supported. */ char name[50]; sprintf (name, "__int%d", int_n_data[i].bitsize); - id = get_identifier (xstrdup (name)); + id = get_identifier (name); C_SET_RID_CODE (id, RID_FIRST_INT_N + i); C_IS_RESERVED_WORD (id) = 1; } diff --git a/contrib/gcc-5.0/gcc/c/c-typeck.c b/contrib/gcc-5.0/gcc/c/c-typeck.c index a3a9c7760c..ebe4c73589 100644 --- a/contrib/gcc-5.0/gcc/c/c-typeck.c +++ b/contrib/gcc-5.0/gcc/c/c-typeck.c @@ -3459,9 +3459,36 @@ parser_build_binary_op (location_t location, enum tree_code code, code1, arg1.value, code2, arg2.value); if (warn_logical_not_paren + && TREE_CODE_CLASS (code) == tcc_comparison && code1 == TRUTH_NOT_EXPR - && code2 != TRUTH_NOT_EXPR) - warn_logical_not_parentheses (location, code, arg2.value); + && code2 != TRUTH_NOT_EXPR + /* Avoid warning for !!x == y. */ + && (TREE_CODE (arg1.value) != NE_EXPR + || !integer_zerop (TREE_OPERAND (arg1.value, 1)))) + { + /* Avoid warning for !b == y where b has _Bool type. */ + tree t = integer_zero_node; + if (TREE_CODE (arg1.value) == EQ_EXPR + && integer_zerop (TREE_OPERAND (arg1.value, 1)) + && TREE_TYPE (TREE_OPERAND (arg1.value, 0)) == integer_type_node) + { + t = TREE_OPERAND (arg1.value, 0); + do + { + if (TREE_TYPE (t) != integer_type_node) + break; + if (TREE_CODE (t) == C_MAYBE_CONST_EXPR) + t = C_MAYBE_CONST_EXPR_EXPR (t); + else if (CONVERT_EXPR_P (t)) + t = TREE_OPERAND (t, 0); + else + break; + } + while (1); + } + if (TREE_CODE (TREE_TYPE (t)) != BOOLEAN_TYPE) + warn_logical_not_parentheses (location, code, arg2.value); + } /* Warn about comparisons against string literals, with the exception of testing for equality or inequality of a string literal with NULL. */ @@ -11229,9 +11256,7 @@ build_binary_op (location_t location, enum tree_code code, if ((flag_sanitize & (SANITIZE_SHIFT | SANITIZE_DIVIDE | SANITIZE_FLOAT_DIVIDE)) - && current_function_decl != 0 - && !lookup_attribute ("no_sanitize_undefined", - DECL_ATTRIBUTES (current_function_decl)) + && do_ubsan_in_current_function () && (doing_div_or_mod || doing_shift)) { /* OP0 and/or OP1 might have side-effects. */ diff --git a/contrib/gcc-5.0/gcc/cfgexpand.c b/contrib/gcc-5.0/gcc/cfgexpand.c index 569cd0d239..67be09fc7e 100644 --- a/contrib/gcc-5.0/gcc/cfgexpand.c +++ b/contrib/gcc-5.0/gcc/cfgexpand.c @@ -3921,6 +3921,31 @@ expand_debug_expr (tree exp) op1 = expand_debug_expr (TREE_OPERAND (exp, 1)); if (!op1) return NULL_RTX; + switch (TREE_CODE (exp)) + { + case LSHIFT_EXPR: + case RSHIFT_EXPR: + case LROTATE_EXPR: + case RROTATE_EXPR: + case WIDEN_LSHIFT_EXPR: + /* Ensure second operand isn't wider than the first one. */ + inner_mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 1))); + if (SCALAR_INT_MODE_P (inner_mode)) + { + machine_mode opmode = mode; + if (VECTOR_MODE_P (mode)) + opmode = GET_MODE_INNER (mode); + if (SCALAR_INT_MODE_P (opmode) + && (GET_MODE_PRECISION (opmode) + < GET_MODE_PRECISION (inner_mode))) + op1 = simplify_gen_subreg (opmode, op1, inner_mode, + subreg_lowpart_offset (opmode, + inner_mode)); + } + break; + default: + break; + } /* Fall through. */ unary: @@ -5124,13 +5149,11 @@ reorder_operands (basic_block bb) continue; /* Swap operands if the second one is more expensive. */ def0 = get_gimple_for_ssa_name (op0); - if (!def0) - continue; def1 = get_gimple_for_ssa_name (op1); if (!def1) continue; swap = false; - if (lattice[gimple_uid (def1)] > lattice[gimple_uid (def0)]) + if (!def0 || lattice[gimple_uid (def1)] > lattice[gimple_uid (def0)]) swap = true; if (swap) { @@ -5139,7 +5162,7 @@ reorder_operands (basic_block bb) fprintf (dump_file, "Swap operands in stmt:\n"); print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM); fprintf (dump_file, "Cost left opnd=%d, right opnd=%d\n", - lattice[gimple_uid (def0)], + def0 ? lattice[gimple_uid (def0)] : 0, lattice[gimple_uid (def1)]); } swap_ssa_operands (stmt, gimple_assign_rhs1_ptr (stmt), diff --git a/contrib/gcc-5.0/gcc/cgraph.c b/contrib/gcc-5.0/gcc/cgraph.c index b2109bd517..ede58bf5aa 100644 --- a/contrib/gcc-5.0/gcc/cgraph.c +++ b/contrib/gcc-5.0/gcc/cgraph.c @@ -663,7 +663,19 @@ cgraph_node::get_for_asmname (tree asmname) hashval_t cgraph_edge_hasher::hash (cgraph_edge *e) { - return htab_hash_pointer (e->call_stmt); + /* This is a really poor hash function, but it is what htab_hash_pointer + uses. */ + return (hashval_t) ((intptr_t)e->call_stmt >> 3); +} + +/* Returns a hash value for X (which really is a cgraph_edge). */ + +hashval_t +cgraph_edge_hasher::hash (gimple call_stmt) +{ + /* This is a really poor hash function, but it is what htab_hash_pointer + uses. */ + return (hashval_t) ((intptr_t)call_stmt >> 3); } /* Return nonzero if the call_stmt of of cgraph_edge X is stmt *Y. */ @@ -680,9 +692,8 @@ static inline void cgraph_update_edge_in_call_site_hash (cgraph_edge *e) { gimple call = e->call_stmt; - *e->caller->call_site_hash->find_slot_with_hash (call, - htab_hash_pointer (call), - INSERT) = e; + *e->caller->call_site_hash->find_slot_with_hash + (call, cgraph_edge_hasher::hash (call), INSERT) = e; } /* Add call graph edge E to call site hash of its caller. */ @@ -695,8 +706,7 @@ cgraph_add_edge_to_call_site_hash (cgraph_edge *e) if (e->speculative && e->indirect_unknown_callee) return; cgraph_edge **slot = e->caller->call_site_hash->find_slot_with_hash - (e->call_stmt, - htab_hash_pointer (e->call_stmt), INSERT); + (e->call_stmt, cgraph_edge_hasher::hash (e->call_stmt), INSERT); if (*slot) { gcc_assert (((cgraph_edge *)*slot)->speculative); @@ -718,8 +728,8 @@ cgraph_node::get_edge (gimple call_stmt) int n = 0; if (call_site_hash) - return call_site_hash->find_with_hash (call_stmt, - htab_hash_pointer (call_stmt)); + return call_site_hash->find_with_hash + (call_stmt, cgraph_edge_hasher::hash (call_stmt)); /* This loop may turn out to be performance problem. In such case adding hashtables into call nodes with very many edges is probably best @@ -782,7 +792,7 @@ cgraph_edge::set_call_stmt (gcall *new_stmt, bool update_speculative) && (!speculative || !indirect_unknown_callee)) { caller->call_site_hash->remove_elt_with_hash - (call_stmt, htab_hash_pointer (call_stmt)); + (call_stmt, cgraph_edge_hasher::hash (call_stmt)); } cgraph_edge *e = this; @@ -987,8 +997,8 @@ cgraph_edge::remove_caller (void) caller->callees = next_callee; } if (caller->call_site_hash) - caller->call_site_hash->remove_elt_with_hash (call_stmt, - htab_hash_pointer (call_stmt)); + caller->call_site_hash->remove_elt_with_hash + (call_stmt, cgraph_edge_hasher::hash (call_stmt)); } /* Put the edge onto the free list. */ @@ -1711,7 +1721,10 @@ cgraph_node::release_body (bool keep_arguments) DECL_INITIAL (decl) = error_mark_node; release_function_body (decl); if (lto_file_data) - lto_free_function_in_decl_state_for_node (this); + { + lto_free_function_in_decl_state_for_node (this); + lto_file_data = NULL; + } } /* Remove function from symbol table. */ @@ -1789,13 +1802,18 @@ cgraph_node::remove (void) n = cgraph_node::get (decl); if (!n || (!n->clones && !n->clone_of && !n->global.inlined_to - && (symtab->global_info_ready + && ((symtab->global_info_ready || in_lto_p) && (TREE_ASM_WRITTEN (n->decl) || DECL_EXTERNAL (n->decl) || !n->analyzed || (!flag_wpa && n->in_other_partition))))) release_body (); } + else + { + lto_free_function_in_decl_state_for_node (this); + lto_file_data = NULL; + } decl = NULL; if (call_site_hash) @@ -2415,7 +2433,7 @@ nonremovable_p (cgraph_node *node, void *) calls to THIS. */ bool -cgraph_node::can_remove_if_no_direct_calls_p (void) +cgraph_node::can_remove_if_no_direct_calls_p (bool will_inline) { struct ipa_ref *ref; @@ -2430,6 +2448,9 @@ cgraph_node::can_remove_if_no_direct_calls_p (void) return !call_for_symbol_and_aliases (nonremovable_p, NULL, true); } + if (will_inline && address_taken) + return false; + /* Otheriwse check if we can remove the symbol itself and then verify that only uses of the comdat groups are direct call to THIS or its aliases. */ @@ -2454,12 +2475,16 @@ cgraph_node::can_remove_if_no_direct_calls_p (void) /* If we see different symbol than THIS, be sure to check calls. */ if (next->ultimate_alias_target () != target) for (cgraph_edge *e = next->callers; e; e = e->next_caller) - if (e->caller->get_comdat_group () != get_comdat_group ()) + if (e->caller->get_comdat_group () != get_comdat_group () + || will_inline) return false; - for (int i = 0; next->iterate_referring (i, ref); i++) - if (ref->referring->get_comdat_group () != get_comdat_group ()) - return false; + /* If function is not being inlined, we care only about + references outside of the comdat group. */ + if (!will_inline) + for (int i = 0; next->iterate_referring (i, ref); i++) + if (ref->referring->get_comdat_group () != get_comdat_group ()) + return false; } return true; } @@ -2479,9 +2504,9 @@ cgraph_node::can_remove_if_no_direct_calls_p (void) linkonce section. */ bool -cgraph_node::will_be_removed_from_program_if_no_direct_calls_p (void) +cgraph_node::will_be_removed_from_program_if_no_direct_calls_p + (bool will_inline) { - struct ipa_ref *ref; gcc_assert (!global.inlined_to); if (DECL_EXTERNAL (decl)) return true; @@ -2496,6 +2521,9 @@ cgraph_node::will_be_removed_from_program_if_no_direct_calls_p (void) if (same_comdat_group && externally_visible) { struct cgraph_node *target = ultimate_alias_target (); + + if (will_inline && address_taken) + return true; for (cgraph_node *next = dyn_cast (same_comdat_group); next != this; next = dyn_cast (next->same_comdat_group)) @@ -2510,18 +2538,15 @@ cgraph_node::will_be_removed_from_program_if_no_direct_calls_p (void) be sure to check calls. */ if (next->ultimate_alias_target () != target) for (cgraph_edge *e = next->callers; e; e = e->next_caller) - if (e->caller->get_comdat_group () != get_comdat_group ()) + if (e->caller->get_comdat_group () != get_comdat_group () + || will_inline) return false; - - for (int i = 0; next->iterate_referring (i, ref); i++) - if (ref->referring->get_comdat_group () != get_comdat_group ()) - return false; } } return true; } else - return can_remove_if_no_direct_calls_p (); + return can_remove_if_no_direct_calls_p (will_inline); } @@ -3201,6 +3226,8 @@ cgraph_node::get_untransformed_body (void) lto_free_section_data (file_data, LTO_section_function_body, name, data, len); lto_free_function_in_decl_state_for_node (this); + /* Keep lto file data so ipa-inline-analysis knows about cross module + inlining. */ timevar_pop (TV_IPA_LTO_GIMPLE_IN); diff --git a/contrib/gcc-5.0/gcc/cgraph.h b/contrib/gcc-5.0/gcc/cgraph.h index c4f39bab4e..99af026d2d 100644 --- a/contrib/gcc-5.0/gcc/cgraph.h +++ b/contrib/gcc-5.0/gcc/cgraph.h @@ -289,6 +289,18 @@ public: /* Make DECL local. */ void make_decl_local (void); + /* Return desired alignment of the definition. This is NOT alignment useful + to access THIS, because THIS may be interposable and DECL_ALIGN should + be used instead. It however must be guaranteed when output definition + of THIS. */ + unsigned int definition_alignment (); + + /* Return true if alignment can be increased. */ + bool can_increase_alignment_p (); + + /* Increase alignment of symbol to ALIGN. */ + void increase_alignment (unsigned int align); + /* Return true if list contains an alias. */ bool has_aliases_p (void); @@ -776,6 +788,7 @@ struct cgraph_edge_hasher : ggc_hasher typedef gimple compare_type; static hashval_t hash (cgraph_edge *); + static hashval_t hash (gimple); static bool equal (cgraph_edge *, gimple); }; @@ -1098,16 +1111,23 @@ public: all uses of COMDAT function does not make it necessarily disappear from the program unless we are compiling whole program or we do LTO. In this case we know we win since dynamic linking will not really discard the - linkonce section. */ - bool will_be_removed_from_program_if_no_direct_calls_p (void); + linkonce section. + + If WILL_INLINE is true, assume that function will be inlined into all the + direct calls. */ + bool will_be_removed_from_program_if_no_direct_calls_p + (bool will_inline = false); /* Return true when function can be removed from callgraph - if all direct calls are eliminated. */ + if all direct calls and references are eliminated. The function does + not take into account comdat groups. */ bool can_remove_if_no_direct_calls_and_refs_p (void); /* Return true when function cgraph_node and its aliases can be removed from - callgraph if all direct calls are eliminated. */ - bool can_remove_if_no_direct_calls_p (void); + callgraph if all direct calls are eliminated. + If WILL_INLINE is true, assume that function will be inlined into all the + direct calls. */ + bool can_remove_if_no_direct_calls_p (bool will_inline = false); /* Return true when callgraph node is a function with Gimple body defined in current unit. Functions can also be define externally or they diff --git a/contrib/gcc-5.0/gcc/config/i386/i386.c b/contrib/gcc-5.0/gcc/config/i386/i386.c index ab8f03acdc..47deda7ce5 100644 --- a/contrib/gcc-5.0/gcc/config/i386/i386.c +++ b/contrib/gcc-5.0/gcc/config/i386/i386.c @@ -12931,30 +12931,26 @@ ix86_address_cost (rtx x, machine_mode, addr_space_t, bool) if (parts.index && GET_CODE (parts.index) == SUBREG) parts.index = SUBREG_REG (parts.index); - /* Attempt to minimize number of registers in the address. */ - if ((parts.base - && (!REG_P (parts.base) || REGNO (parts.base) >= FIRST_PSEUDO_REGISTER)) - || (parts.index - && (!REG_P (parts.index) - || REGNO (parts.index) >= FIRST_PSEUDO_REGISTER))) - cost++; - - /* When address base or index is "pic_offset_table_rtx" we don't increase - address cost. When a memopt with "pic_offset_table_rtx" is not invariant - itself it most likely means that base or index is not invariant. - Therefore only "pic_offset_table_rtx" could be hoisted out, which is not - profitable for x86. */ + /* Attempt to minimize number of registers in the address by increasing + address cost for each used register. We don't increase address cost + for "pic_offset_table_rtx". When a memopt with "pic_offset_table_rtx" + is not invariant itself it most likely means that base or index is not + invariant. Therefore only "pic_offset_table_rtx" could be hoisted out, + which is not profitable for x86. */ if (parts.base - && (current_pass->type == GIMPLE_PASS - || (!pic_offset_table_rtx - || REGNO (pic_offset_table_rtx) != REGNO(parts.base))) && (!REG_P (parts.base) || REGNO (parts.base) >= FIRST_PSEUDO_REGISTER) - && parts.index && (current_pass->type == GIMPLE_PASS - || (!pic_offset_table_rtx - || REGNO (pic_offset_table_rtx) != REGNO(parts.index))) + || !pic_offset_table_rtx + || !REG_P (parts.base) + || REGNO (pic_offset_table_rtx) != REGNO (parts.base))) + cost++; + + if (parts.index && (!REG_P (parts.index) || REGNO (parts.index) >= FIRST_PSEUDO_REGISTER) - && parts.base != parts.index) + && (current_pass->type == GIMPLE_PASS + || !pic_offset_table_rtx + || !REG_P (parts.index) + || REGNO (pic_offset_table_rtx) != REGNO (parts.index))) cost++; /* AMD-K6 don't like addresses with ModR/M set to 00_xxx_100b, diff --git a/contrib/gcc-5.0/gcc/config/i386/i386.md b/contrib/gcc-5.0/gcc/config/i386/i386.md index 8a80415b9a..1129b935a1 100644 --- a/contrib/gcc-5.0/gcc/config/i386/i386.md +++ b/contrib/gcc-5.0/gcc/config/i386/i386.md @@ -12678,18 +12678,52 @@ (set_attr "mode" "")]) ;; BMI2 instructions. -(define_insn "bmi2_bzhi_3" +(define_expand "bmi2_bzhi_3" + [(parallel + [(set (match_operand:SWI48 0 "register_operand") + (zero_extract:SWI48 + (match_operand:SWI48 1 "nonimmediate_operand") + (umin:SWI48 + (and:SWI48 (match_operand:SWI48 2 "register_operand") + (const_int 255)) + (match_dup 3)) + (const_int 0))) + (clobber (reg:CC FLAGS_REG))])] + "TARGET_BMI2" + "operands[3] = GEN_INT ( * BITS_PER_UNIT);") + +(define_insn "*bmi2_bzhi_3" [(set (match_operand:SWI48 0 "register_operand" "=r") - (and:SWI48 (lshiftrt:SWI48 (const_int -1) - (match_operand:SWI48 2 "register_operand" "r")) - (match_operand:SWI48 1 "nonimmediate_operand" "rm"))) + (zero_extract:SWI48 + (match_operand:SWI48 1 "nonimmediate_operand" "rm") + (umin:SWI48 + (and:SWI48 (match_operand:SWI48 2 "register_operand" "r") + (const_int 255)) + (match_operand:SWI48 3 "const_int_operand" "n")) + (const_int 0))) (clobber (reg:CC FLAGS_REG))] - "TARGET_BMI2" + "TARGET_BMI2 && INTVAL (operands[3]) == * BITS_PER_UNIT" "bzhi\t{%2, %1, %0|%0, %1, %2}" [(set_attr "type" "bitmanip") (set_attr "prefix" "vex") (set_attr "mode" "")]) +(define_mode_attr k [(SI "k") (DI "q")]) +(define_insn "*bmi2_bzhi_3_1" + [(set (match_operand:SWI48 0 "register_operand" "=r") + (zero_extract:SWI48 + (match_operand:SWI48 1 "nonimmediate_operand" "rm") + (umin:SWI48 + (zero_extend:SWI48 (match_operand:QI 2 "register_operand" "r")) + (match_operand:SWI48 3 "const_int_operand" "n")) + (const_int 0))) + (clobber (reg:CC FLAGS_REG))] + "TARGET_BMI2 && INTVAL (operands[3]) == * BITS_PER_UNIT" + "bzhi\t{%2, %1, %0|%0, %1, %2}" + [(set_attr "type" "bitmanip") + (set_attr "prefix" "vex") + (set_attr "mode" "")]) + (define_insn "bmi2_pdep_3" [(set (match_operand:SWI48 0 "register_operand" "=r") (unspec:SWI48 [(match_operand:SWI48 1 "register_operand" "r") diff --git a/contrib/gcc-5.0/gcc/config/i386/intelmic-mkoffload.c b/contrib/gcc-5.0/gcc/config/i386/intelmic-mkoffload.c index e6394e9a54..f93007c51f 100644 --- a/contrib/gcc-5.0/gcc/config/i386/intelmic-mkoffload.c +++ b/contrib/gcc-5.0/gcc/config/i386/intelmic-mkoffload.c @@ -22,13 +22,13 @@ #include "config.h" #include -#include "libgomp-plugin.h" #include "system.h" #include "coretypes.h" #include "obstack.h" #include "intl.h" #include "diagnostic.h" #include "collect-utils.h" +#include "intelmic-offload.h" const char tool_name[] = "intelmic mkoffload"; @@ -158,10 +158,21 @@ find_target_compiler (const char *name) bool found = false; char **paths = NULL; unsigned n_paths, i; - const char *collect_path = dirname (ASTRDUP (getenv ("COLLECT_GCC"))); - size_t len = strlen (collect_path) + 1 + strlen (name) + 1; - char *target_compiler = XNEWVEC (char, len); - sprintf (target_compiler, "%s/%s", collect_path, name); + char *target_compiler; + const char *collect_gcc = getenv ("COLLECT_GCC"); + const char *gcc_path = dirname (ASTRDUP (collect_gcc)); + const char *gcc_exec = basename (ASTRDUP (collect_gcc)); + + if (strcmp (gcc_exec, collect_gcc) == 0) + { + /* collect_gcc has no path, so it was found in PATH. Make sure we also + find accel-gcc in PATH. */ + target_compiler = XDUPVEC (char, name, strlen (name) + 1); + found = true; + goto out; + } + + target_compiler = concat (gcc_path, "/", name, NULL); if (access_check (target_compiler, X_OK) == 0) { found = true; @@ -171,7 +182,7 @@ find_target_compiler (const char *name) n_paths = parse_env_var (getenv ("COMPILER_PATH"), &paths); for (i = 0; i < n_paths; i++) { - len = strlen (paths[i]) + 1 + strlen (name) + 1; + size_t len = strlen (paths[i]) + 1 + strlen (name) + 1; target_compiler = XRESIZEVEC (char, target_compiler, len); sprintf (target_compiler, "%s/%s", paths[i], name); if (access_check (target_compiler, X_OK) == 0) @@ -346,7 +357,7 @@ generate_host_descr_file (const char *host_compiler) "init (void)\n" "{\n" " GOMP_offload_register (&__OFFLOAD_TABLE__, %d, __offload_target_data);\n" - "}\n", OFFLOAD_TARGET_TYPE_INTEL_MIC); + "}\n", GOMP_DEVICE_INTEL_MIC); fclose (src_file); unsigned new_argc = 0; @@ -483,8 +494,7 @@ main (int argc, char **argv) if (!host_compiler) fatal_error (input_location, "COLLECT_GCC must be set"); - const char *target_driver_name - = DEFAULT_REAL_TARGET_MACHINE "-accel-" DEFAULT_TARGET_MACHINE "-gcc"; + const char *target_driver_name = GCC_INSTALL_NAME; char *target_compiler = find_target_compiler (target_driver_name); if (target_compiler == NULL) fatal_error (input_location, "offload compiler %s not found", diff --git a/contrib/gcc-5.0/gcc/config/i386/linux-common.h b/contrib/gcc-5.0/gcc/config/i386/linux-common.h index f93d71d3ea..9c6560b695 100644 --- a/contrib/gcc-5.0/gcc/config/i386/linux-common.h +++ b/contrib/gcc-5.0/gcc/config/i386/linux-common.h @@ -53,3 +53,41 @@ along with GCC; see the file COPYING3. If not see GNU_USER_TARGET_ENDFILE_SPEC, \ GNU_USER_TARGET_MATHFILE_SPEC " " \ ANDROID_ENDFILE_SPEC) + +#ifndef LIBMPX_LIBS +#define LIBMPX_LIBS "\ + %:include(libmpx.spec)%(link_libmpx)" +#endif + +#ifndef LIBMPX_SPEC +#if defined(HAVE_LD_STATIC_DYNAMIC) +#define LIBMPX_SPEC "\ +%{mmpx:%{fcheck-pointer-bounds:\ + %{static:--whole-archive -lmpx --no-whole-archive" LIBMPX_LIBS "}\ + %{!static:%{static-libmpx:" LD_STATIC_OPTION " --whole-archive}\ + -lmpx %{static-libmpx:--no-whole-archive " LD_DYNAMIC_OPTION \ + LIBMPX_LIBS "}}}}" +#else +#define LIBMPX_SPEC "\ +%{mmpx:%{fcheck-pointer-bounds:-lmpx" LIBMPX_LIBS "}}" +#endif +#endif + +#ifndef LIBMPXWRAPPERS_SPEC +#if defined(HAVE_LD_STATIC_DYNAMIC) +#define LIBMPXWRAPPERS_SPEC "\ +%{mmpx:%{fcheck-pointer-bounds:%{!fno-chkp-use-wrappers:\ + %{static:-lmpxwrappers}\ + %{!static:%{static-libmpxwrappers:" LD_STATIC_OPTION " --whole-archive}\ + -lmpxwrappers %{static-libmpxwrappers:--no-whole-archive "\ + LD_DYNAMIC_OPTION "}}}}}" +#else +#define LIBMPXWRAPPERS_SPEC "\ +%{mmpx:%{fcheck-pointer-bounds:{!fno-chkp-use-wrappers:-lmpxwrappers}}}" +#endif +#endif + +#ifndef CHKP_SPEC +#define CHKP_SPEC "\ +%{!nostdlib:%{!nodefaultlibs:" LIBMPX_SPEC LIBMPXWRAPPERS_SPEC "}}" +#endif diff --git a/contrib/gcc-5.0/gcc/cp/call.c b/contrib/gcc-5.0/gcc/cp/call.c index 2b15185a89..fdd8436d53 100644 --- a/contrib/gcc-5.0/gcc/cp/call.c +++ b/contrib/gcc-5.0/gcc/cp/call.c @@ -8020,7 +8020,11 @@ build_new_method_call_1 (tree instance, tree fns, vec **args, that would be captured if the call turns out to be to a non-static member function. Do not actually capture it at this point. */ - first_mem_arg = maybe_resolve_dummy (instance, false); + if (DECL_CONSTRUCTOR_P (fn)) + /* Constructors don't use the enclosing 'this'. */ + first_mem_arg = instance; + else + first_mem_arg = maybe_resolve_dummy (instance, false); /* Get the high-water mark for the CONVERSION_OBSTACK. */ p = conversion_obstack_alloc (0); diff --git a/contrib/gcc-5.0/gcc/cp/cp-gimplify.c b/contrib/gcc-5.0/gcc/cp/cp-gimplify.c index 4233a64aef..70645b59b8 100644 --- a/contrib/gcc-5.0/gcc/cp/cp-gimplify.c +++ b/contrib/gcc-5.0/gcc/cp/cp-gimplify.c @@ -53,6 +53,8 @@ along with GCC; see the file COPYING3. If not see #include "target.h" #include "c-family/c-ubsan.h" #include "cilk.h" +#include "gimplify.h" +#include "gimple-expr.h" /* Forward declarations. */ @@ -528,6 +530,29 @@ gimplify_must_not_throw_expr (tree *expr_p, gimple_seq *pre_p) return GS_ALL_DONE; } +/* Return TRUE if an operand (OP) of a given TYPE being copied is + really just an empty class copy. + + Check that the operand has a simple form so that TARGET_EXPRs and + non-empty CONSTRUCTORs get reduced properly, and we leave the + return slot optimization alone because it isn't a copy. */ + +static bool +simple_empty_class_p (tree type, tree op) +{ + return + ((TREE_CODE (op) == COMPOUND_EXPR + && simple_empty_class_p (type, TREE_OPERAND (op, 1))) + || is_gimple_lvalue (op) + || INDIRECT_REF_P (op) + || (TREE_CODE (op) == CONSTRUCTOR + && CONSTRUCTOR_NELTS (op) == 0 + && !TREE_CLOBBER_P (op)) + || (TREE_CODE (op) == CALL_EXPR + && !CALL_EXPR_RETURN_SLOT_OPT (op))) + && is_really_empty_class (type); +} + /* Do C++-specific gimplification. Args are as for gimplify_expr. */ int @@ -597,6 +622,7 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p) return GS_OK; /* Otherwise fall through. */ case MODIFY_EXPR: + modify_expr_case: { if (fn_contains_cilk_spawn_p (cfun) && cilk_detect_spawn_and_unwrap (expr_p) @@ -616,31 +642,22 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p) TREE_OPERAND (*expr_p, 1) = build1 (VIEW_CONVERT_EXPR, TREE_TYPE (op0), op1); - else if ((is_gimple_lvalue (op1) || INDIRECT_REF_P (op1) - || (TREE_CODE (op1) == CONSTRUCTOR - && CONSTRUCTOR_NELTS (op1) == 0 - && !TREE_CLOBBER_P (op1)) - || (TREE_CODE (op1) == CALL_EXPR - && !CALL_EXPR_RETURN_SLOT_OPT (op1))) - && is_really_empty_class (TREE_TYPE (op0))) + else if (simple_empty_class_p (TREE_TYPE (op0), op1)) { - /* Remove any copies of empty classes. We check that the RHS - has a simple form so that TARGET_EXPRs and non-empty - CONSTRUCTORs get reduced properly, and we leave the return - slot optimization alone because it isn't a copy (FIXME so it - shouldn't be represented as one). - - Also drop volatile variables on the RHS to avoid infinite - recursion from gimplify_expr trying to load the value. */ - if (!TREE_SIDE_EFFECTS (op1)) - *expr_p = op0; - else if (TREE_THIS_VOLATILE (op1) - && (REFERENCE_CLASS_P (op1) || DECL_P (op1))) - *expr_p = build2 (COMPOUND_EXPR, TREE_TYPE (*expr_p), - build_fold_addr_expr (op1), op0); - else - *expr_p = build2 (COMPOUND_EXPR, TREE_TYPE (*expr_p), - op0, op1); + /* Remove any copies of empty classes. Also drop volatile + variables on the RHS to avoid infinite recursion from + gimplify_expr trying to load the value. */ + gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p, + is_gimple_lvalue, fb_lvalue); + if (TREE_SIDE_EFFECTS (op1)) + { + if (TREE_THIS_VOLATILE (op1) + && (REFERENCE_CLASS_P (op1) || DECL_P (op1))) + op1 = build_fold_addr_expr (op1); + + gimplify_and_add (op1, pre_p); + } + *expr_p = TREE_OPERAND (*expr_p, 0); } } ret = GS_OK; @@ -740,6 +757,19 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p) } break; + case RETURN_EXPR: + if (TREE_OPERAND (*expr_p, 0) + && (TREE_CODE (TREE_OPERAND (*expr_p, 0)) == INIT_EXPR + || TREE_CODE (TREE_OPERAND (*expr_p, 0)) == MODIFY_EXPR)) + { + expr_p = &TREE_OPERAND (*expr_p, 0); + code = TREE_CODE (*expr_p); + /* Avoid going through the INIT_EXPR case, which can + degrade INIT_EXPRs into AGGR_INIT_EXPRs. */ + goto modify_expr_case; + } + /* Fall through. */ + default: ret = (enum gimplify_status) c_gimplify_expr (expr_p, pre_p, post_p); break; diff --git a/contrib/gcc-5.0/gcc/cp/decl.c b/contrib/gcc-5.0/gcc/cp/decl.c index 83e060b4d1..e35e48436d 100644 --- a/contrib/gcc-5.0/gcc/cp/decl.c +++ b/contrib/gcc-5.0/gcc/cp/decl.c @@ -1922,7 +1922,9 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) { /* Per C++11 8.3.6/4, default arguments cannot be added in later declarations of a function template. */ - check_redeclaration_no_default_args (newdecl); + if (DECL_SOURCE_LOCATION (newdecl) + != DECL_SOURCE_LOCATION (olddecl)) + check_redeclaration_no_default_args (newdecl); check_default_args (newdecl); @@ -11227,11 +11229,10 @@ check_default_argument (tree decl, tree arg, tsubst_flags_t complain) LOOKUP_IMPLICIT); --cp_unevaluated_operand; - if (warn_zero_as_null_pointer_constant - && TYPE_PTR_OR_PTRMEM_P (decl_type) - && null_ptr_cst_p (arg) - && (complain & tf_warning) - && maybe_warn_zero_as_null_pointer_constant (arg, input_location)) + /* Avoid redundant -Wzero-as-null-pointer-constant warnings at + the call sites. */ + if (TYPE_PTR_OR_PTRMEM_P (decl_type) + && null_ptr_cst_p (arg)) return nullptr_node; /* [dcl.fct.default] diff --git a/contrib/gcc-5.0/gcc/cp/parser.c b/contrib/gcc-5.0/gcc/cp/parser.c index e0b455c88c..a209ee608f 100644 --- a/contrib/gcc-5.0/gcc/cp/parser.c +++ b/contrib/gcc-5.0/gcc/cp/parser.c @@ -8270,8 +8270,23 @@ cp_parser_binary_expression (cp_parser* parser, bool cast_p, c_inhibit_evaluation_warnings -= current.lhs == truthvalue_true_node; if (warn_logical_not_paren - && current.lhs_type == TRUTH_NOT_EXPR) - warn_logical_not_parentheses (current.loc, current.tree_type, rhs); + && TREE_CODE_CLASS (current.tree_type) == tcc_comparison + && current.lhs_type == TRUTH_NOT_EXPR + /* Avoid warning for !!x == y. */ + && (TREE_CODE (current.lhs) != NE_EXPR + || !integer_zerop (TREE_OPERAND (current.lhs, 1))) + && (TREE_CODE (current.lhs) != TRUTH_NOT_EXPR + || (TREE_CODE (TREE_OPERAND (current.lhs, 0)) != TRUTH_NOT_EXPR + /* Avoid warning for !b == y where b is boolean. */ + && (TREE_TYPE (TREE_OPERAND (current.lhs, 0)) == NULL_TREE + || (TREE_CODE (TREE_TYPE (TREE_OPERAND (current.lhs, 0))) + != BOOLEAN_TYPE)))) + /* Avoid warning for !!b == y where b is boolean. */ + && (!DECL_P (current.lhs) + || TREE_TYPE (current.lhs) == NULL_TREE + || TREE_CODE (TREE_TYPE (current.lhs)) != BOOLEAN_TYPE)) + warn_logical_not_parentheses (current.loc, current.tree_type, + maybe_constant_value (rhs)); overload = NULL; /* ??? Currently we pass lhs_type == ERROR_MARK and rhs_type == @@ -18299,7 +18314,9 @@ parsing_nsdmi (void) { /* We recognize NSDMI context by the context-less 'this' pointer set up by the function above. */ - if (current_class_ptr && DECL_CONTEXT (current_class_ptr) == NULL_TREE) + if (current_class_ptr + && TREE_CODE (current_class_ptr) == PARM_DECL + && DECL_CONTEXT (current_class_ptr) == NULL_TREE) return true; return false; } diff --git a/contrib/gcc-5.0/gcc/cp/pt.c b/contrib/gcc-5.0/gcc/cp/pt.c index 9a00d0d30e..ea82621199 100644 --- a/contrib/gcc-5.0/gcc/cp/pt.c +++ b/contrib/gcc-5.0/gcc/cp/pt.c @@ -20930,7 +20930,13 @@ dependent_type_p_r (tree type) return true; /* ... or any of the template arguments is a dependent type or an expression that is type-dependent or value-dependent. */ - else if (TYPE_TEMPLATE_INFO (type) + else if (CLASS_TYPE_P (type) && CLASSTYPE_TEMPLATE_INFO (type) + && (any_dependent_template_arguments_p + (INNERMOST_TEMPLATE_ARGS (CLASSTYPE_TI_ARGS (type))))) + return true; + /* For an alias template specialization, check the arguments both to the + class template and the alias template. */ + else if (alias_template_specialization_p (type) && (any_dependent_template_arguments_p (INNERMOST_TEMPLATE_ARGS (TYPE_TI_ARGS (type))))) return true; diff --git a/contrib/gcc-5.0/gcc/doc/extend.texi b/contrib/gcc-5.0/gcc/doc/extend.texi index eb818613ee..91b94f7b61 100644 --- a/contrib/gcc-5.0/gcc/doc/extend.texi +++ b/contrib/gcc-5.0/gcc/doc/extend.texi @@ -786,26 +786,6 @@ evaluated only once when using @code{__auto_type}, but twice if @code{typeof} is used. @end itemize -@emph{Compatibility Note:} In addition to @code{typeof}, GCC 2 supported -a more limited extension that permitted one to write - -@smallexample -typedef @var{T} = @var{expr}; -@end smallexample - -@noindent -with the effect of declaring @var{T} to have the type of the expression -@var{expr}. This extension does not work with GCC 3 (versions between -3.0 and 3.2 crash; 3.2.1 and later give an error). Code that -relies on it should be rewritten to use @code{typeof}: - -@smallexample -typedef typeof(@var{expr}) @var{T}; -@end smallexample - -@noindent -This works with all versions of GCC@. - @node Conditionals @section Conditionals with Omitted Operands @cindex conditional expressions, extensions @@ -1498,16 +1478,13 @@ structure or an element of an array. (However, these uses are permitted by GCC as extensions.) @end itemize -GCC versions before 3.0 allowed zero-length arrays to be statically -initialized, as if they were flexible arrays. In addition to those -cases that were useful, it also allowed initializations in situations -that would corrupt later data. Non-empty initialization of zero-length -arrays is now treated like any case where there are more initializer +Non-empty initialization of zero-length +arrays is treated like any case where there are more initializer elements than the array holds, in that a suitable warning about ``excess elements in array'' is given, and the excess elements (all of them, in this case) are ignored. -Instead GCC allows static initialization of flexible array members. +GCC allows static initialization of flexible array members. This is equivalent to defining a new structure containing the original structure followed by an array of sufficient size to contain the data. E.g.@: in the following, @code{f1} is constructed as if it were declared @@ -1729,9 +1706,10 @@ argument, these arguments are not macro expanded. @cindex escaped newlines @cindex newlines (escaped) -Recently, the preprocessor has relaxed its treatment of escaped -newlines. Previously, the newline had to immediately follow a -backslash. The current implementation allows whitespace in the form +The preprocessor treatment of escaped newlines is more relaxed +than that specified by the C90 standard, which requires the newline +to immediately follow a backslash. +GCC's implementation allows whitespace in the form of spaces, horizontal and vertical tabs, and form feeds between the backslash and the subsequent newline. The preprocessor issues a warning, but treats it as a valid escaped newline and combines the two @@ -1905,12 +1883,12 @@ In C, a compound literal designates an unnamed object with static or automatic storage duration. In C++, a compound literal designates a temporary object, which only lives until the end of its full-expression. As a result, well-defined C code that takes the -address of a subobject of a compound literal can be undefined in C++. +address of a subobject of a compound literal can be undefined in C++, +so the C++ compiler rejects the conversion of a temporary array to a pointer. For instance, if the array compound literal example above appeared inside a function, any subsequent use of @samp{foo} in C++ has undefined behavior because the lifetime of the array ends after the -declaration of @samp{foo}. As a result, the C++ compiler now rejects -the conversion of a temporary array to a pointer. +declaration of @samp{foo}. As an optimization, the C++ compiler sometimes gives array compound literals longer lifetimes: when the array either appears outside a @@ -2447,21 +2425,6 @@ function that calls a non-@code{const} function usually must not be @code{const}. It does not make sense for a @code{const} function to return @code{void}. -The attribute @code{const} is not implemented in GCC versions earlier -than 2.5. An alternative way to declare that a function has no side -effects, which works in the current version and in some older versions, -is as follows: - -@smallexample -typedef int intfn (); - -extern const intfn square; -@end smallexample - -@noindent -This approach does not work in GNU C++ from 2.6.0 on, since the language -specifies that the @samp{const} must be attached to the return value. - @item constructor @itemx destructor @itemx constructor (@var{priority}) @@ -2536,14 +2499,13 @@ On systems that support the @code{visibility} attribute, this attribute also implies ``default'' visibility. It is an error to explicitly specify any other visibility. -In previous versions of GCC, the @code{dllexport} attribute was ignored -for inlined functions, unless the @option{-fkeep-inline-functions} flag -had been used. The default behavior now is to emit all dllexported -inline functions; however, this can cause object file-size bloat, in -which case the old behavior can be restored by using -@option{-fno-keep-inline-dllexport}. +GCC's default behavior is to emit all inline functions with the +@code{dllexport} attribute. Since this can cause object file-size bloat, +you can use @option{-fno-keep-inline-dllexport}, which tells GCC to +ignore the attribute for inlined functions unless the +@option{-fkeep-inline-functions} flag is used instead. -The attribute is also ignored for undefined symbols. +The attribute is ignored for undefined symbols. When applied to C++ classes, the attribute marks defined non-inlined member functions and static data members as exports. Static consts @@ -2595,8 +2557,7 @@ the current translation unit. For Microsoft Windows targets the use of the @code{dllimport} attribute on functions is not necessary, but provides a small performance benefit by eliminating a thunk in the DLL@. The use of the -@code{dllimport} attribute on imported variables was required on older -versions of the GNU linker, but can now be avoided by passing the +@code{dllimport} attribute on imported variables can be avoided by passing the @option{--enable-auto-import} switch to the GNU linker. As with functions, using the attribute for a variable eliminates a thunk in the DLL@. @@ -2931,8 +2892,8 @@ void *memcpy (void *, const void *, size_t) __attribute__ ((ifunc ("resolve_memcpy"))); @end smallexample -Indirect functions cannot be weak, and require a recent binutils (at -least version 2.20.1), and GNU C library (at least version 2.11.1). +Indirect functions cannot be weak. Binutils version 2.20.1 or higher +and GNU C Library version 2.11.1 are required to use this feature. @item interrupt @cindex interrupt handler functions @@ -3573,28 +3534,13 @@ restored before calling the @code{noreturn} function. It does not make sense for a @code{noreturn} function to have a return type other than @code{void}. -The attribute @code{noreturn} is not implemented in GCC versions -earlier than 2.5. An alternative way to declare that a function does -not return, which works in the current version and in some older -versions, is as follows: - -@smallexample -typedef void voidfn (); - -volatile voidfn fatal; -@end smallexample - -@noindent -This approach does not work in GNU C++. - @item nothrow @cindex @code{nothrow} function attribute The @code{nothrow} attribute is used to inform the compiler that a function cannot throw an exception. For example, most functions in the standard C library can be guaranteed not to throw an exception with the notable exceptions of @code{qsort} and @code{bsearch} that -take function pointer arguments. The @code{nothrow} attribute is not -implemented in GCC versions earlier than 3.3. +take function pointer arguments. @item nosave_low_regs @cindex @code{nosave_low_regs} attribute @@ -3692,9 +3638,6 @@ Interesting non-pure functions are functions with infinite loops or those depending on volatile memory or other system resource, that may change between two consecutive calls (such as @code{feof} in a multithreading environment). -The attribute @code{pure} is not implemented in GCC versions earlier -than 2.96. - @item hot @cindex @code{hot} function attribute The @code{hot} attribute on a function is used to inform the compiler that @@ -3706,9 +3649,6 @@ improving locality. When profile feedback is available, via @option{-fprofile-use}, hot functions are automatically detected and this attribute is ignored. -The @code{hot} attribute on functions is not implemented in GCC versions -earlier than 4.3. - @item cold @cindex @code{cold} function attribute The @code{cold} attribute on functions is used to inform the compiler that @@ -3724,9 +3664,6 @@ of hot functions that do call marked functions in rare occasions. When profile feedback is available, via @option{-fprofile-use}, cold functions are automatically detected and this attribute is ignored. -The @code{cold} attribute on functions is not implemented in GCC versions -earlier than 4.3. - @item no_sanitize_address @itemx no_address_safety_analysis @cindex @code{no_sanitize_address} function attribute @@ -4660,9 +4597,6 @@ the path following the label is more likely than paths that are not so annotated. This attribute is used in cases where @code{__builtin_expect} cannot be used, for instance with computed goto or @code{asm goto}. -The @code{hot} attribute on labels is not implemented in GCC versions -earlier than 4.8. - @item cold @cindex @code{cold} label attribute The @code{cold} attribute on labels is used to inform the compiler that @@ -4670,9 +4604,6 @@ the path following the label is unlikely to be executed. This attribute is used in cases where @code{__builtin_expect} cannot be used, for instance with computed goto or @code{asm goto}. -The @code{cold} attribute on labels is not implemented in GCC versions -earlier than 4.8. - @end table @node Attribute Syntax @@ -5985,7 +5916,7 @@ main (void) If you replaced @code{short_a} with @code{short} in the variable declaration, the above program would abort when compiled with @option{-fstrict-aliasing}, which is on by default at @option{-O2} or -above in recent GCC versions. +above. @item visibility In C++, attribute visibility (@pxref{Function Attributes}) can also be @@ -7845,21 +7776,8 @@ static const char __func__[] = "function-name"; appeared, where function-name is the name of the lexically-enclosing function. This name is the unadorned name of the function. -@code{__FUNCTION__} is another name for @code{__func__}. Older -versions of GCC recognize only this name. However, it is not -standardized. For maximum portability, we recommend you use -@code{__func__}, but provide a fallback definition with the -preprocessor: - -@smallexample -#if __STDC_VERSION__ < 199901L -# if __GNUC__ >= 2 -# define __func__ __FUNCTION__ -# else -# define __func__ "" -# endif -#endif -@end smallexample +@code{__FUNCTION__} is another name for @code{__func__}, provided for +backward compatibility with old versions of GCC. In C, @code{__PRETTY_FUNCTION__} is yet another name for @code{__func__}. However, in C++, @code{__PRETTY_FUNCTION__} contains @@ -7897,13 +7815,9 @@ __FUNCTION__ = sub __PRETTY_FUNCTION__ = void a::sub(int) @end smallexample -These identifiers are not preprocessor macros. In GCC 3.3 and -earlier, in C only, @code{__FUNCTION__} and @code{__PRETTY_FUNCTION__} -were treated as string literals; they could be used to initialize -@code{char} arrays, and they could be concatenated with other string -literals. GCC 3.4 and later treat them as variables, like -@code{__func__}. In C++, @code{__FUNCTION__} and -@code{__PRETTY_FUNCTION__} have always been variables. +These identifiers are variables, not preprocessor macros, and may not +be used to initialize @code{char} arrays or be concatenated with other string +literals. @node Return Address @section Getting the Return or Frame Address of a Function @@ -9718,10 +9632,6 @@ not otherwise permitted in a static initializer (for example, @code{0 && foo ()}). GCC must be more conservative about evaluating the built-in in this case, because it has no opportunity to perform optimization. - -Previous versions of GCC did not accept this built-in in data -initializers. The earliest version where it is completely safe is -3.0.1. @end deftypefn @deftypefn {Built-in Function} long __builtin_expect (long @var{exp}, long @var{c}) @@ -17894,9 +17804,6 @@ if @code{attribute((optimize("STRING")))} was specified for that function. The parenthesis around the options is optional. @xref{Function Attributes}, for more information about the @code{optimize} attribute and the attribute syntax. - -The @samp{#pragma GCC optimize} pragma is not implemented in GCC -versions earlier than 4.4. @end table @table @code @@ -17910,9 +17817,6 @@ options. It is intended for include files where you temporarily want to switch to using a different @samp{#pragma GCC target} or @samp{#pragma GCC optimize} and then to pop back to the previous options. - -The @samp{#pragma GCC push_options} and @samp{#pragma GCC pop_options} -pragmas are not implemented in GCC versions earlier than 4.4. @end table @table @code @@ -17922,9 +17826,6 @@ pragmas are not implemented in GCC versions earlier than 4.4. This pragma clears the current @code{#pragma GCC target} and @code{#pragma GCC optimize} to use the default switches as specified on the command line. - -The @samp{#pragma GCC reset_options} pragma is not implemented in GCC -versions earlier than 4.4. @end table @node Loop-Specific Pragmas @@ -18557,14 +18458,11 @@ user with a way of explicitly directing the compiler to emit entities with vague linkage (and debugging information) in a particular translation unit. -@emph{Note:} As of GCC 2.7.2, these @code{#pragma}s are not useful in -most cases, because of COMDAT support and the ``key method'' heuristic +@emph{Note:} These @code{#pragma}s have been superceded as of GCC 2.7.2 +by COMDAT support and the ``key method'' heuristic mentioned in @ref{Vague Linkage}. Using them can actually cause your program to grow due to unnecessary out-of-line copies of inline -functions. Currently (3.4) the only benefit of these -@code{#pragma}s is reduced duplication of debugging information, and -that should be addressed soon on DWARF 2 targets with the use of -COMDAT groups. +functions. @table @code @item #pragma interface @@ -18608,12 +18506,6 @@ file. For example, in @file{allclass.cc}, giving just @samp{#pragma implementation} by itself is equivalent to @samp{#pragma implementation "allclass.h"}. -In versions of GNU C++ prior to 2.6.0 @file{allclass.h} was treated as -an implementation file whenever you would include it from -@file{allclass.cc} even if you never specified @samp{#pragma -implementation}. This was deemed to be more trouble than it was worth, -however, and disabled. - Use the string argument if you want a single implementation file to include code from multiple header files. (You must also use @samp{#include} to include the header file; @samp{#pragma diff --git a/contrib/gcc-5.0/gcc/doc/invoke.texi b/contrib/gcc-5.0/gcc/doc/invoke.texi index 67814d40d5..08ce074c26 100644 --- a/contrib/gcc-5.0/gcc/doc/invoke.texi +++ b/contrib/gcc-5.0/gcc/doc/invoke.texi @@ -302,6 +302,15 @@ Objective-C and Objective-C++ Dialects}. @gccoptlist{-d@var{letters} -dumpspecs -dumpmachine -dumpversion @gol -fsanitize=@var{style} -fsanitize-recover -fsanitize-recover=@var{style} @gol -fasan-shadow-offset=@var{number} -fsanitize-undefined-trap-on-error @gol +-fcheck-pointer-bounds -fchkp-check-incomplete-type @gol +-fchkp-first-field-has-own-bounds -fchkp-narrow-bounds @gol +-fchkp-narrow-to-innermost-array -fchkp-optimize @gol +-fchkp-use-fast-string-functions -fchkp-use-nochk-string-functions @gol +-fchkp-use-static-bounds -fchkp-use-static-const-bounds @gol +-fchkp-treat-zero-dynamic-size-as-infinite -fchkp-check-read @gol +-fchkp-check-read -fchkp-check-write -fchkp-store-bounds @gol +-fchkp-instrument-calls -fchkp-instrument-marked-only @gol +-fchkp-use-wrappers @gol -fdbg-cnt-list -fdbg-cnt=@var{counter-value-list} @gol -fdisable-ipa-@var{pass_name} @gol -fdisable-rtl-@var{pass_name} @gol @@ -477,6 +486,7 @@ Objective-C and Objective-C++ Dialects}. -nostartfiles -nodefaultlibs -nostdlib -pie -rdynamic @gol -s -static -static-libgcc -static-libstdc++ @gol -static-libasan -static-libtsan -static-liblsan -static-libubsan @gol +-static-libmpx -static-libmpxwrappers @gol -shared -shared-libgcc -symbolic @gol -T @var{script} -Wl,@var{option} -Xlinker @var{option} @gol -u @var{symbol} -z @var{keyword}} @@ -561,8 +571,8 @@ Objective-C and Objective-C++ Dialects}. @emph{AVR Options} @gccoptlist{-mmcu=@var{mcu} -maccumulate-args -mbranch-cost=@var{cost} @gol --mcall-prologues -mint8 -mno-interrupts -mrelax @gol --mstrict-X -mtiny-stack -Waddr-space-convert} +-mcall-prologues -mint8 -mn_flash=@var{size} -mno-interrupts @gol +-mrelax -mrmw -mstrict-X -mtiny-stack -Waddr-space-convert} @emph{Blackfin Options} @gccoptlist{-mcpu=@var{cpu}@r{[}-@var{sirevision}@r{]} @gol @@ -1767,17 +1777,15 @@ releases. @opindex fgnu89-inline The option @option{-fgnu89-inline} tells GCC to use the traditional GNU semantics for @code{inline} functions when in C99 mode. -@xref{Inline,,An Inline Function is As Fast As a Macro}. This option -is accepted and ignored by GCC versions 4.1.3 up to but not including -4.3. In GCC versions 4.3 and later it changes the behavior of GCC in -C99 mode. Using this option is roughly equivalent to adding the +@xref{Inline,,An Inline Function is As Fast As a Macro}. +Using this option is roughly equivalent to adding the @code{gnu_inline} function attribute to all inline functions (@pxref{Function Attributes}). The option @option{-fno-gnu89-inline} explicitly tells GCC to use the C99 semantics for @code{inline} when in C99 or gnu99 mode (i.e., it -specifies the default behavior). This option was first supported in -GCC 4.3. This option is not supported in @option{-std=c90} or +specifies the default behavior). +This option is not supported in @option{-std=c90} or @option{-std=gnu90} mode. The preprocessor macros @code{__GNUC_GNU_INLINE__} and @@ -2112,7 +2120,7 @@ See also @option{-Wabi}. @item -fabi-compat-version=@var{n} @opindex fabi-compat-version -Starting with GCC 4.5, on targets that support strong aliases, G++ +On targets that support strong aliases, G++ works around mangling changes by creating an alias with the correct mangled name when defining a symbol with an incorrect mangled name. This switch specifies which ABI version to use for the alias. @@ -2173,11 +2181,10 @@ deprecated, and may be removed in a future version of G++. Inject friend functions into the enclosing namespace, so that they are visible outside the scope of the class in which they are declared. Friend functions were documented to work this way in the old Annotated -C++ Reference Manual, and versions of G++ before 4.1 always worked -that way. However, in ISO C++ a friend function that is not declared +C++ Reference Manual. +However, in ISO C++ a friend function that is not declared in an enclosing scope can only be found using argument dependent -lookup. This option causes friends to be injected as they were in -earlier releases. +lookup. GCC defaults to the standard behavior. This option is for compatibility, and may be removed in a future release of G++. @@ -4536,8 +4543,7 @@ except when the same as the default promotion. @opindex Wno-declaration-after-statement Warn when a declaration is found after a statement in a block. This construct, known from C++, was introduced with ISO C99 and is by default -allowed in GCC@. It is not supported by ISO C90 and was not supported by -GCC versions before GCC 3.0. @xref{Mixed Declarations}. +allowed in GCC@. It is not supported by ISO C90. @xref{Mixed Declarations}. @item -Wundef @opindex Wundef @@ -5827,6 +5833,135 @@ a @code{libubsan} library routine. The advantage of this is that the @code{libubsan} library is not needed and is not linked in, so this is usable even in freestanding environments. +@item -fcheck-pointer-bounds +@opindex fcheck-pointer-bounds +@opindex fno-check-pointer-bounds +Enable Pointer Bounds Checker instrumentation. Each memory reference +is instrumented with checks of pointer used for memory access against +bounds associated with that pointer. Generated instrumentation may +be controlled by various @option{-fchkp-*} options. Currently there +is only Intel MPX based implementation available, thus i386 target +and @option{-mmpx} are required. MPX based instrumentation requires +a runtime library to enable MPX in a hardware and handle bounds +violation signals. By default when @option{-fcheck-pointer-bounds} +and @option{-mmpx} options are used to link a program, the GCC driver +links against @option{libmpx} runtime library. MPX based instrumentation +may be used for a debugging and also it may be included into a release +version to increase program security. Depending on usage you may +put different requirements to runtime library. Current version + of MPX runtime library is more oriented to be used as a debugging +tool. MPX runtime library usage implies @option{-lpthread}. See +also @option{-static-libmpx}. The runtime library behavior can be +influenced using various @env{CHKP_RT_*} environment variables. See +@uref{https://gcc.gnu.org/wiki/Intel%20MPX%20support%20in%20the%20GCC%20compiler} +for more details. + +@item -fchkp-check-incomplete-type +@opindex fchkp-check-incomplete-type +@opindex fno-chkp-check-incomplete-type +Generate pointer bounds checks for variables with incomplete type. +Enabled by default + +@item -fchkp-narrow-bounds +@opindex fchkp-narrow-bounds +@opindex fno-chkp-narrow-bounds +Controls bounds used by Pointer Bounds Checker for pointers to object +fields. If narrowing is enabled then field bounds are used. Otherwise +object bounds are used. See also @option{-fchkp-narrow-to-innermost-array} +and @option{-fchkp-first-field-has-own-bounds}. Enabled by default. + +@item -fchkp-first-field-has-own-bounds +@opindex fchkp-first-field-has-own-bounds +@opindex fno-chkp-first-field-has-own-bounds +Forces Pointer Bounds Checker to use narrowed bounds for address of the +first field in the structure. By default pointer to the first field has +the same bounds as pointer to the whole structure. + +@item -fchkp-narrow-to-innermost-array +@opindex fchkp-narrow-to-innermost-array +@opindex fno-chkp-narrow-to-innermost-array +Forces Pointer Bounds Checker to use bounds of the innermost arrays in +case of nested static arryas access. By default it is disabled and +bounds of the outermost array are used. + +@item -fchkp-optimize +@opindex fchkp-optimize +@opindex fno-chkp-optimize +Enables Pointer Bounds Checker optimizations. Enabled by default at +optimization levels @option{-O}, @option{-O2}, @option{-O3}. + +@item -fchkp-use-fast-string-functions +@opindex fchkp-use-fast-string-functions +@opindex fno-chkp-use-fast-string-functions +Allow to use @code{*_nobnd} versions of string functions (not copying bounds) +by Pointer Bounds Checker. Disabled by default. + +@item -fchkp-use-nochk-string-functions +@opindex fchkp-use-nochk-string-functions +@opindex fno-chkp-use-nochk-string-functions +Allow to use @code{*_nochk} versions of string functions (not checking bounds) +by Pointer Bounds Checker. Disabled by default. + +@item -fchkp-use-static-bounds +@opindex fchkp-use-static-bounds +@opindex fno-chkp-use-static-bounds +Allow Pointer Bounds Checker to generate static bounds holding +bounds of static variables. Enabled by default. + +@item -fchkp-use-static-const-bounds +@opindex fchkp-use-static-const-bounds +@opindex fno-chkp-use-static-const-bounds +Use statically initialized bounds for constant bounds instead of +generating them each time it is required. By default enabled when +@option{-fchkp-use-static-bounds} is enabled. + +@item -fchkp-treat-zero-dynamic-size-as-infinite +@opindex fchkp-treat-zero-dynamic-size-as-infinite +@opindex fno-chkp-treat-zero-dynamic-size-as-infinite +With this option zero size obtained dynamically for objects with +incomplete type will be treated as infinite by Pointer Bounds +Checker. It may be helpful if program is linked with a library +missing size information for some symbols. Disabled by default. + +@item -fchkp-check-read +@opindex fchkp-check-read +@opindex fno-chkp-check-read +Instructs Pointer Bounds Checker to generate checks for all read +accesses to memory. Enabled by default. + +@item -fchkp-check-write +@opindex fchkp-check-write +@opindex fno-chkp-check-write +Instructs Pointer Bounds Checker to generate checks for all write +accesses to memory. Enabled by default. + +@item -fchkp-store-bounds +@opindex fchkp-store-bounds +@opindex fno-chkp-store-bounds +Instructs Pointer Bounds Checker to generate bounds stores for +pointer writes. Enabled by default. + +@item -fchkp-instrument-calls +@opindex fchkp-instrument-calls +@opindex fno-chkp-instrument-calls +Instructs Pointer Bounds Checker to pass pointer bounds to calls. +Enabled by default. + +@item -fchkp-instrument-marked-only +@opindex fchkp-instrument-marked-only +@opindex fno-chkp-instrument-marked-only +Instructs Pointer Bounds Checker to instrument only functions +marked with @code{bnd_instrument} attribute. Disabled by default. + +@item -fchkp-use-wrappers +@opindex fchkp-use-wrappers +@opindex fno-chkp-use-wrappers +Allows Pointer Bounds Checker to replace calls to built-in function +with calls to wrapper functions. When the @option{-fchkp-use-wrappers} +is used to link a program, the GCC driver automatically links +agains @option{libmpxwrappers}. See also @option{-static-libmpxwrappers}. +Enabled by default. + @item -fdump-final-insns@r{[}=@var{file}@r{]} @opindex fdump-final-insns Dump the final internal representation (RTL) to @var{file}. If the @@ -7455,11 +7590,10 @@ machine-description macro @code{FRAME_POINTER_REQUIRED} controls whether a target machine supports this flag. @xref{Registers,,Register Usage, gccint, GNU Compiler Collection (GCC) Internals}. -Starting with GCC version 4.6, the default setting (when not optimizing for -size) for 32-bit GNU/Linux x86 and 32-bit Darwin x86 targets has been changed to -@option{-fomit-frame-pointer}. The default can be reverted to -@option{-fno-omit-frame-pointer} by configuring GCC with the -@option{--enable-frame-pointer} configure option. +The default setting (when not optimizing for +size) for 32-bit GNU/Linux x86 and 32-bit Darwin x86 targets is +@option{-fomit-frame-pointer}. You can configure GCC with the +@option{--enable-frame-pointer} configure option to change the default. Enabled at levels @option{-O}, @option{-O2}, @option{-O3}, @option{-Os}. @@ -8681,8 +8815,7 @@ from other functions. It is a more limited form of @option{-ftree-coalesce-vars}. This may harm debug information of such inlined variables, but it keeps variables of the inlined-into function apart from each other, such that they are more likely to -contain the expected values in a debugging session. This was the -default in GCC versions older than 4.7. +contain the expected values in a debugging session. @item -ftree-coalesce-vars @opindex ftree-coalesce-vars @@ -11136,6 +11269,27 @@ option is not used, then this links against the shared version of driver to link @file{libubsan} statically, without necessarily linking other libraries statically. +@item -static-libmpx +@opindex static-libmpx +When @option{-fcheck-pointer bounds} and @option{-mmpx} options are +used to link a program, the GCC driver automatically links against +@option{libmpx}. If @file{libmpx} is available as a shared library, +and the @option{-static} option is not used, then this links against +the shared version of @file{libmpx}. The @option{-static-libmpx} +option directs the GCC driver to link @file{libmpx} statically, +without necessarily linking other libraries statically. + +@item -static-libmpxwrappers +@opindex static-libmpxwrappers +When @option{-fcheck-pointer bounds}, @option{-mmpx} options are used and +@option{-fno-chkp-use-wrappers} option is not used to link a program, the +GCC driver automatically links against @option{libmpxwrappers}. If +@file{libmpxwrappers} is available as a shared library, and the +@option{-static} option is not used, then this links against the shared +version of @file{libmpxwrappers}. The @option{-static-libmpxwrappers} +option directs the GCC driver to link @file{libmpxwrappers} statically, +without necessarily linking other libraries statically. + @item -static-libstdc++ @opindex static-libstdc++ When the @command{g++} program is used to link a C++ program, it @@ -13349,6 +13503,11 @@ and @code{long long} is 4 bytes. Please note that this option does not conform to the C standards, but it results in smaller code size. +@item -mn-flash=@var{num} +@opindex mn-flash +Assume that the flash memory has a size of +@var{num} times 64@tie{}KiB. + @item -mno-interrupts @opindex mno-interrupts Generated code is not compatible with hardware interrupts. @@ -13358,8 +13517,9 @@ Code size is smaller. @opindex mrelax Try to replace @code{CALL} resp.@: @code{JMP} instruction by the shorter @code{RCALL} resp.@: @code{RJMP} instruction if applicable. -Setting @option{-mrelax} just adds the @option{--relax} option to the -linker command line when the linker is called. +Setting @option{-mrelax} just adds the @option{--mlink-relax} option to +the assembler's command line and the @option{--relax} option to the +linker's command line. Jump relaxing is performed by the linker because jump offsets are not known before code is located. Therefore, the assembler code generated by the @@ -13369,6 +13529,11 @@ differ from instructions in the assembler code. Relaxing must be turned on if linker stubs are needed, see the section on @code{EIND} and linker stubs below. +@item -mrmw +@opindex mrmw +Assume that the device supports the Read-Modify-Write +instructions @code{XCH}, @code{LAC}, @code{LAS} and @code{LAT}. + @item -msp8 @opindex msp8 Treat the stack pointer register as an 8-bit register, @@ -13609,13 +13774,18 @@ architecture and depends on the @option{-mmcu=@var{mcu}} option. Possible values are: @code{2}, @code{25}, @code{3}, @code{31}, @code{35}, -@code{4}, @code{5}, @code{51}, @code{6}, @code{102}, @code{104}, +@code{4}, @code{5}, @code{51}, @code{6} + +for @var{mcu}=@code{avr2}, @code{avr25}, @code{avr3}, @code{avr31}, +@code{avr35}, @code{avr4}, @code{avr5}, @code{avr51}, @code{avr6}, + +respectively and + +@code{100}, @code{102}, @code{104}, @code{105}, @code{106}, @code{107} -for @var{mcu}=@code{avr2}, @code{avr25}, @code{avr3}, -@code{avr31}, @code{avr35}, @code{avr4}, @code{avr5}, @code{avr51}, -@code{avr6}, @code{avrxmega2}, @code{avrxmega4}, @code{avrxmega5}, -@code{avrxmega6}, @code{avrxmega7}, respectively. +for @var{mcu}=@code{avrtiny}, @code{avrxmega2}, @code{avrxmega4}, +@code{avrxmega5}, @code{avrxmega6}, @code{avrxmega7}, respectively. If @var{mcu} specifies a device, this built-in macro is set accordingly. For example, with @option{-mmcu=atmega8} the macro is defined to @code{4}. @@ -13635,7 +13805,7 @@ the device name as from the AVR user manual. The difference between If @var{device} is not a device but only a core architecture like @samp{avr51}, this macro is not defined. -@item __AVR_DEVICE_NAME__ +@item __AVR_DEVICE_NAME__ Setting @option{-mmcu=@var{device}} defines this built-in macro to the device's name. For example, with @option{-mmcu=atmega8} the macro is defined to @code{atmega8}. @@ -19982,7 +20152,7 @@ The default is to not print debug information. Generate code that runs on @var{cpu-type}, which is the name of a system representing a certain processor type. Possible values for @var{cpu-type} are @samp{g5}, @samp{g6}, @samp{z900}, @samp{z990}, -@samp{z9-109}, @samp{z9-ec} and @samp{z10}. +@samp{z9-109}, @samp{z9-ec}, @samp{z10}, @samp{z196}, and @samp{zEC12}. When generating code using the instructions available on z/Architecture, the default is @option{-march=z900}. Otherwise, the default is @option{-march=g5}. @@ -20046,9 +20216,9 @@ The @var{stack-guard} option can only be used in conjunction with @var{stack-siz If the hotpatch option is enabled, a ``hot-patching'' function prologue is generated for all functions in the compilation unit. The funtion label is prepended with the given number of two-byte -Nop instructions (@var{pre-halfwords}, maximum 1000000). After +NOP instructions (@var{pre-halfwords}, maximum 1000000). After the label, 2 * @var{post-halfwords} bytes are appended, using the -larges nop like instructions the architecture allows (maximum +largest NOP like instructions the architecture allows (maximum 1000000). If both arguments are zero, hotpatching is disabled. @@ -23638,9 +23808,7 @@ available to be linked against from outside the shared object. @samp{protected} and @samp{internal} are pretty useless in real-world usage so the only other commonly used option is @samp{hidden}. The default if @option{-fvisibility} isn't specified is -@samp{default}, i.e., make every -symbol public---this causes the same behavior as previous versions of -GCC@. +@samp{default}, i.e., make every symbol public. A good explanation of the benefits offered by ensuring ELF symbols have the correct visibility is given by ``How To Write diff --git a/contrib/gcc-5.0/gcc/dominance.c b/contrib/gcc-5.0/gcc/dominance.c index 33d4ae4033..09c8c90eeb 100644 --- a/contrib/gcc-5.0/gcc/dominance.c +++ b/contrib/gcc-5.0/gcc/dominance.c @@ -982,7 +982,7 @@ nearest_common_dominator_for_set (enum cdi_direction dir, bitmap blocks) A_Dominated_by_B (node A, node B) { - return DFS_Number_In(A) >= DFS_Number_In(A) + return DFS_Number_In(A) >= DFS_Number_In(B) && DFS_Number_Out (A) <= DFS_Number_Out(B); } */ diff --git a/contrib/gcc-5.0/gcc/fold-const.c b/contrib/gcc-5.0/gcc/fold-const.c index 0834d47fa0..6d085b1858 100644 --- a/contrib/gcc-5.0/gcc/fold-const.c +++ b/contrib/gcc-5.0/gcc/fold-const.c @@ -2860,7 +2860,7 @@ operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags) case ADDR_EXPR: return operand_equal_p (TREE_OPERAND (arg0, 0), TREE_OPERAND (arg1, 0), TREE_CONSTANT (arg0) && TREE_CONSTANT (arg1) - ? OEP_CONSTANT_ADDRESS_OF : 0); + ? OEP_CONSTANT_ADDRESS_OF | OEP_ADDRESS_OF : 0); default: break; } @@ -2922,7 +2922,11 @@ operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags) switch (TREE_CODE (arg0)) { case INDIRECT_REF: - flags &= ~OEP_CONSTANT_ADDRESS_OF; + if (!(flags & OEP_ADDRESS_OF) + && (TYPE_ALIGN (TREE_TYPE (arg0)) + != TYPE_ALIGN (TREE_TYPE (arg1)))) + return 0; + flags &= ~(OEP_CONSTANT_ADDRESS_OF|OEP_ADDRESS_OF); return OP_SAME (0); case REALPART_EXPR: @@ -2930,30 +2934,35 @@ operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags) return OP_SAME (0); case TARGET_MEM_REF: - flags &= ~OEP_CONSTANT_ADDRESS_OF; - /* Require equal extra operands and then fall through to MEM_REF - handling of the two common operands. */ - if (!OP_SAME_WITH_NULL (2) - || !OP_SAME_WITH_NULL (3) - || !OP_SAME_WITH_NULL (4)) - return 0; - /* Fallthru. */ case MEM_REF: - flags &= ~OEP_CONSTANT_ADDRESS_OF; /* Require equal access sizes, and similar pointer types. We can have incomplete types for array references of variable-sized arrays from the Fortran frontend though. Also verify the types are compatible. */ - return ((TYPE_SIZE (TREE_TYPE (arg0)) == TYPE_SIZE (TREE_TYPE (arg1)) + if (!((TYPE_SIZE (TREE_TYPE (arg0)) == TYPE_SIZE (TREE_TYPE (arg1)) || (TYPE_SIZE (TREE_TYPE (arg0)) && TYPE_SIZE (TREE_TYPE (arg1)) && operand_equal_p (TYPE_SIZE (TREE_TYPE (arg0)), TYPE_SIZE (TREE_TYPE (arg1)), flags))) && types_compatible_p (TREE_TYPE (arg0), TREE_TYPE (arg1)) - && alias_ptr_types_compatible_p - (TREE_TYPE (TREE_OPERAND (arg0, 1)), - TREE_TYPE (TREE_OPERAND (arg1, 1))) - && OP_SAME (0) && OP_SAME (1)); + && ((flags & OEP_ADDRESS_OF) + || (alias_ptr_types_compatible_p + (TREE_TYPE (TREE_OPERAND (arg0, 1)), + TREE_TYPE (TREE_OPERAND (arg1, 1))) + && (MR_DEPENDENCE_CLIQUE (arg0) + == MR_DEPENDENCE_CLIQUE (arg1)) + && (MR_DEPENDENCE_BASE (arg0) + == MR_DEPENDENCE_BASE (arg1)) + && (TYPE_ALIGN (TREE_TYPE (arg0)) + == TYPE_ALIGN (TREE_TYPE (arg1))))))) + return 0; + flags &= ~(OEP_CONSTANT_ADDRESS_OF|OEP_ADDRESS_OF); + return (OP_SAME (0) && OP_SAME (1) + /* TARGET_MEM_REF require equal extra operands. */ + && (TREE_CODE (arg0) != TARGET_MEM_REF + || (OP_SAME_WITH_NULL (2) + && OP_SAME_WITH_NULL (3) + && OP_SAME_WITH_NULL (4)))); case ARRAY_REF: case ARRAY_RANGE_REF: @@ -2962,7 +2971,7 @@ operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags) may have different types but same value here. */ if (!OP_SAME (0)) return 0; - flags &= ~OEP_CONSTANT_ADDRESS_OF; + flags &= ~(OEP_CONSTANT_ADDRESS_OF|OEP_ADDRESS_OF); return ((tree_int_cst_equal (TREE_OPERAND (arg0, 1), TREE_OPERAND (arg1, 1)) || OP_SAME (1)) @@ -2975,13 +2984,13 @@ operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags) if (!OP_SAME_WITH_NULL (0) || !OP_SAME (1)) return 0; - flags &= ~OEP_CONSTANT_ADDRESS_OF; + flags &= ~(OEP_CONSTANT_ADDRESS_OF|OEP_ADDRESS_OF); return OP_SAME_WITH_NULL (2); case BIT_FIELD_REF: if (!OP_SAME (0)) return 0; - flags &= ~OEP_CONSTANT_ADDRESS_OF; + flags &= ~(OEP_CONSTANT_ADDRESS_OF|OEP_ADDRESS_OF); return OP_SAME (1) && OP_SAME (2); default: @@ -2992,6 +3001,10 @@ operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags) switch (TREE_CODE (arg0)) { case ADDR_EXPR: + return operand_equal_p (TREE_OPERAND (arg0, 0), + TREE_OPERAND (arg1, 0), + flags | OEP_ADDRESS_OF); + case TRUTH_NOT_EXPR: return OP_SAME (0); diff --git a/contrib/gcc-5.0/gcc/gcc.c b/contrib/gcc-5.0/gcc/gcc.c index 8a163a1c57..d956c36b15 100644 --- a/contrib/gcc-5.0/gcc/gcc.c +++ b/contrib/gcc-5.0/gcc/gcc.c @@ -812,6 +812,10 @@ proper position among the other output files. */ %{fvtable-verify=preinit: -lvtv -u_vtable_map_vars_start -u_vtable_map_vars_end}}" #endif +#ifndef CHKP_SPEC +#define CHKP_SPEC "" +#endif + /* -u* was put back because both BSD and SysV seem to support it. */ /* %{static:} simply prevents an error message if the target machine doesn't handle -static. */ @@ -832,6 +836,7 @@ proper position among the other output files. */ "%X %{o*} %{e*} %{N} %{n} %{r}\ %{s} %{t} %{u*} %{z} %{Z} %{!nostdlib:%{!nostartfiles:%S}} " VTABLE_VERIFICATION_SPEC " \ %{static:} %{L*} %(mfwrap) %(link_libgcc) " SANITIZER_EARLY_SPEC " %o\ + " CHKP_SPEC " \ %{fopenacc|fopenmp|ftree-parallelize-loops=*:%:include(libgomp.spec)%(link_gomp)}\ %{fcilkplus:%:include(libcilkrts.spec)%(link_cilkrts)}\ %{fgnu-tm:%:include(libitm.spec)%(link_itm)}\ diff --git a/contrib/gcc-5.0/gcc/graph.c b/contrib/gcc-5.0/gcc/graph.c index a1eb24c49c..5fb0d781bc 100644 --- a/contrib/gcc-5.0/gcc/graph.c +++ b/contrib/gcc-5.0/gcc/graph.c @@ -292,9 +292,10 @@ print_graph_cfg (const char *base, struct function *fun) pretty_printer graph_slim_pp; graph_slim_pp.buffer->stream = fp; pretty_printer *const pp = &graph_slim_pp; - pp_printf (pp, "subgraph \"%s\" {\n" - "\tcolor=\"black\";\n" - "\tlabel=\"%s\";\n", + pp_printf (pp, "subgraph \"cluster_%s\" {\n" + "\tstyle=\"dashed\";\n" + "\tcolor=\"black\";\n" + "\tlabel=\"%s ()\";\n", funcname, funcname); draw_cfg_nodes (pp, fun); draw_cfg_edges (pp, fun); diff --git a/contrib/gcc-5.0/gcc/ipa-chkp.c b/contrib/gcc-5.0/gcc/ipa-chkp.c index 0b857ffb8a..3bea06ab75 100644 --- a/contrib/gcc-5.0/gcc/ipa-chkp.c +++ b/contrib/gcc-5.0/gcc/ipa-chkp.c @@ -100,6 +100,44 @@ along with GCC; see the file COPYING3. If not see removed. */ #define CHKP_BOUNDS_OF_SYMBOL_PREFIX "__chkp_bounds_of_" +#define CHKP_WRAPPER_SYMBOL_PREFIX "__mpx_wrapper_" + +/* Return 1 calls to FNDECL should be replaced with + a call to wrapper function. */ +static bool +chkp_wrap_function (tree fndecl) +{ + if (!flag_chkp_use_wrappers) + return false; + + if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL) + { + switch (DECL_FUNCTION_CODE (fndecl)) + { + case BUILT_IN_STRLEN: + case BUILT_IN_STRCPY: + case BUILT_IN_STRNCPY: + case BUILT_IN_STPCPY: + case BUILT_IN_STPNCPY: + case BUILT_IN_STRCAT: + case BUILT_IN_STRNCAT: + case BUILT_IN_MEMCPY: + case BUILT_IN_MEMPCPY: + case BUILT_IN_MEMSET: + case BUILT_IN_MEMMOVE: + case BUILT_IN_BZERO: + case BUILT_IN_MALLOC: + case BUILT_IN_CALLOC: + case BUILT_IN_REALLOC: + return 1; + + default: + return 0; + } + } + + return false; +} /* Build a clone of FNDECL with a modified name. */ @@ -124,11 +162,20 @@ chkp_build_instrumented_fndecl (tree fndecl) because it conflicts with decl merging algorithms in LTO. Achieve the result by using transparent alias name for the instrumented version. */ - s = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (fndecl)); - s += ".chkp"; - new_name = get_identifier (s.c_str ()); - IDENTIFIER_TRANSPARENT_ALIAS (new_name) = 1; - TREE_CHAIN (new_name) = DECL_ASSEMBLER_NAME (fndecl); + if (chkp_wrap_function(fndecl)) + { + s = CHKP_WRAPPER_SYMBOL_PREFIX; + s += IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (fndecl)); + new_name = get_identifier (s.c_str ()); + } + else + { + s = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (fndecl)); + s += ".chkp"; + new_name = get_identifier (s.c_str ()); + IDENTIFIER_TRANSPARENT_ALIAS (new_name) = 1; + TREE_CHAIN (new_name) = DECL_ASSEMBLER_NAME (fndecl); + } SET_DECL_ASSEMBLER_NAME (new_decl, new_name); /* For functions with body versioning will make a copy of arguments. diff --git a/contrib/gcc-5.0/gcc/ipa-devirt.c b/contrib/gcc-5.0/gcc/ipa-devirt.c index fe29932c3e..c9d153c1b9 100644 --- a/contrib/gcc-5.0/gcc/ipa-devirt.c +++ b/contrib/gcc-5.0/gcc/ipa-devirt.c @@ -61,7 +61,7 @@ along with GCC; see the file COPYING3. If not see In the case of single inheritance, the virtual table is shared and BINFO_VTABLE of base BINFO is NULL. In the case of multiple inheritance the individual virtual tables are pointer to by - BINFO_VTABLE of base binfos (that differs of BINFO_VTABLE of + BINFO_VTABLE of base binfos (that differs of BINFO_VTABLE of binfo associated to the base type). BINFO lookup for a given base type and offset can be done by @@ -88,7 +88,7 @@ along with GCC; see the file COPYING3. If not see This means that the graph is not complete. Types with no methods are not inserted into the graph. Also types without virtual methods are not represented at all, though it may be easy to add this. - + The inheritance graph is represented as follows: Vertices are structures odr_type. Every odr_type may correspond @@ -213,7 +213,7 @@ static bool odr_violation_reported = false; static hash_set *cached_polymorphic_call_targets; /* The node of type inheritance graph. For each type unique in - One Definition Rule (ODR) sense, we produce one node linking all + One Definition Rule (ODR) sense, we produce one node linking all main variants of types equivalent to it, bases and derived types. */ struct GTY(()) odr_type_d @@ -272,7 +272,7 @@ type_all_ctors_visible_p (tree t) && symtab->state >= CONSTRUCTION /* We can not always use type_all_derivations_known_p. For function local types we must assume case where - the function is COMDAT and shared in between units. + the function is COMDAT and shared in between units. TODO: These cases are quite easy to get, but we need to keep track of C++ privatizing via -Wno-weak @@ -299,9 +299,10 @@ type_possibly_instantiated_p (tree t) return vnode && vnode->definition; } -/* One Definition Rule hashtable helpers. */ +/* Hash used to unify ODR types based on their mangled name and for anonymous + namespace types. */ -struct odr_hasher +struct odr_name_hasher { typedef odr_type_d value_type; typedef union tree_node compare_type; @@ -310,6 +311,16 @@ struct odr_hasher static inline void remove (value_type *); }; +/* Has used to unify ODR types based on their associated virtual table. + This hash is needed to keep -fno-lto-odr-type-merging to work and contains + only polymorphic types. Types with mangled names are inserted to both. */ + +struct odr_vtable_hasher:odr_name_hasher +{ + static inline hashval_t hash (const value_type *); + static inline bool equal (const value_type *, const compare_type *); +}; + /* Return type that was declared with T's name so that T is an qualified variant of it. */ @@ -323,10 +334,17 @@ main_odr_variant (const_tree t) return TYPE_MAIN_VARIANT (t); } -/* Produce hash based on type name. */ +static bool +can_be_name_hashed_p (tree t) +{ + return (!in_lto_p || type_in_anonymous_namespace_p (t) + || (TYPE_NAME (t) && DECL_ASSEMBLER_NAME_SET_P (TYPE_NAME (t)))); +} + +/* Hash type by its ODR name. */ static hashval_t -hash_type_name (tree t) +hash_odr_name (const_tree t) { gcc_checking_assert (main_odr_variant (t) == t); @@ -339,65 +357,91 @@ hash_type_name (tree t) if (type_in_anonymous_namespace_p (t)) return htab_hash_pointer (t); - /* ODR types have name specified. */ - if (TYPE_NAME (t) - && DECL_ASSEMBLER_NAME_SET_P (TYPE_NAME (t))) - return IDENTIFIER_HASH_VALUE (DECL_ASSEMBLER_NAME (TYPE_NAME (t))); + gcc_checking_assert (TYPE_NAME (t) + && DECL_ASSEMBLER_NAME_SET_P (TYPE_NAME (t))); + return IDENTIFIER_HASH_VALUE (DECL_ASSEMBLER_NAME (TYPE_NAME (t))); +} - /* For polymorphic types that was compiled with -fno-lto-odr-type-merging - we can simply hash the virtual table. */ - if (TREE_CODE (t) == RECORD_TYPE - && TYPE_BINFO (t) && BINFO_VTABLE (TYPE_BINFO (t))) - { - tree v = BINFO_VTABLE (TYPE_BINFO (t)); - hashval_t hash = 0; +/* Return the computed hashcode for ODR_TYPE. */ - if (TREE_CODE (v) == POINTER_PLUS_EXPR) - { - hash = TREE_INT_CST_LOW (TREE_OPERAND (v, 1)); - v = TREE_OPERAND (TREE_OPERAND (v, 0), 0); - } +inline hashval_t +odr_name_hasher::hash (const value_type *odr_type) +{ + return hash_odr_name (odr_type->type); +} + +static bool +can_be_vtable_hashed_p (tree t) +{ + /* vtable hashing can distinguish only main variants. */ + if (TYPE_MAIN_VARIANT (t) != t) + return false; + /* Anonymous namespace types are always handled by name hash. */ + if (type_in_anonymous_namespace_p (t)) + return false; + return (TREE_CODE (t) == RECORD_TYPE + && TYPE_BINFO (t) && BINFO_VTABLE (TYPE_BINFO (t))); +} + +/* Hash type by assembler name of its vtable. */ + +static hashval_t +hash_odr_vtable (const_tree t) +{ + tree v = BINFO_VTABLE (TYPE_BINFO (TYPE_MAIN_VARIANT (t))); + inchash::hash hstate; + + gcc_checking_assert (in_lto_p); + gcc_checking_assert (!type_in_anonymous_namespace_p (t)); + gcc_checking_assert (TREE_CODE (t) == RECORD_TYPE + && TYPE_BINFO (t) && BINFO_VTABLE (TYPE_BINFO (t))); + gcc_checking_assert (main_odr_variant (t) == t); - v = DECL_ASSEMBLER_NAME (v); - hash = iterative_hash_hashval_t (hash, htab_hash_pointer (v)); - return hash; + if (TREE_CODE (v) == POINTER_PLUS_EXPR) + { + add_expr (TREE_OPERAND (v, 1), hstate); + v = TREE_OPERAND (TREE_OPERAND (v, 0), 0); } - /* Builtin types may appear as main variants of ODR types and are unique. - Sanity check we do not get anything that looks non-builtin. */ - gcc_checking_assert (TREE_CODE (t) == INTEGER_TYPE - || TREE_CODE (t) == VOID_TYPE - || TREE_CODE (t) == COMPLEX_TYPE - || TREE_CODE (t) == REAL_TYPE - || TREE_CODE (t) == POINTER_TYPE); - return htab_hash_pointer (t); + hstate.add_wide_int (IDENTIFIER_HASH_VALUE (DECL_ASSEMBLER_NAME (v))); + return hstate.end (); } /* Return the computed hashcode for ODR_TYPE. */ inline hashval_t -odr_hasher::hash (const value_type *odr_type) +odr_vtable_hasher::hash (const value_type *odr_type) { - return hash_type_name (odr_type->type); + return hash_odr_vtable (odr_type->type); } /* For languages with One Definition Rule, work out if types are the same based on their name. - + This is non-trivial for LTO where minor differences in the type representation may have prevented type merging to merge two copies of otherwise equivalent type. Until we start streaming mangled type names, this function works - only for polymorphic types. */ + only for polymorphic types. + + When STRICT is true, we compare types by their names for purposes of + ODR violation warnings. When strict is false, we consider variants + equivalent, becuase it is all that matters for devirtualization machinery. +*/ bool -types_same_for_odr (const_tree type1, const_tree type2) +types_same_for_odr (const_tree type1, const_tree type2, bool strict) { gcc_checking_assert (TYPE_P (type1) && TYPE_P (type2)); type1 = main_odr_variant (type1); type2 = main_odr_variant (type2); + if (!strict) + { + type1 = TYPE_MAIN_VARIANT (type1); + type2 = TYPE_MAIN_VARIANT (type2); + } if (type1 == type2) return true; @@ -434,7 +478,8 @@ types_same_for_odr (const_tree type1, const_tree type2) if (TREE_CODE (type1) != TREE_CODE (type2)) return false; if (TREE_CODE (type1) == RECORD_TYPE - && (TYPE_BINFO (type1) == NULL_TREE) != (TYPE_BINFO (type1) == NULL_TREE)) + && (TYPE_BINFO (type1) == NULL_TREE) + != (TYPE_BINFO (type1) == NULL_TREE)) return false; if (TREE_CODE (type1) == RECORD_TYPE && TYPE_BINFO (type1) && (BINFO_VTABLE (TYPE_BINFO (type1)) == NULL_TREE) @@ -471,13 +516,16 @@ types_same_for_odr (const_tree type1, const_tree type2) /* Return true if we can decide on ODR equivalency. In non-LTO it is always decide, in LTO however it depends in the type has - ODR info attached. */ + ODR info attached. + + When STRICT is false, compare main variants. */ bool -types_odr_comparable (tree t1, tree t2) +types_odr_comparable (tree t1, tree t2, bool strict) { return (!in_lto_p - || main_odr_variant (t1) == main_odr_variant (t2) + || (strict ? main_odr_variant (t1) == main_odr_variant (t2) + : TYPE_MAIN_VARIANT (t1) == TYPE_MAIN_VARIANT (t2)) || (odr_type_p (t1) && odr_type_p (t2)) || (TREE_CODE (t1) == RECORD_TYPE && TREE_CODE (t2) == RECORD_TYPE && TYPE_BINFO (t1) && TYPE_BINFO (t2) @@ -494,29 +542,63 @@ types_must_be_same_for_odr (tree t1, tree t2) if (types_odr_comparable (t1, t2)) return types_same_for_odr (t1, t2); else - return main_odr_variant (t1) == main_odr_variant (t2); + return TYPE_MAIN_VARIANT (t1) == TYPE_MAIN_VARIANT (t2); } /* Compare types T1 and T2 and return true if they are equivalent. */ inline bool -odr_hasher::equal (const value_type *t1, const compare_type *ct2) +odr_name_hasher::equal (const value_type *o1, const compare_type *t2) { - tree t2 = const_cast (ct2); + tree t1 = o1->type; gcc_checking_assert (main_odr_variant (t2) == t2); - if (t1->type == t2) + gcc_checking_assert (main_odr_variant (t1) == t1); + if (t1 == t2) return true; if (!in_lto_p) return false; - return types_same_for_odr (t1->type, t2); + /* Check for anonymous namespaces. Those have !TREE_PUBLIC + on the corresponding TYPE_STUB_DECL. */ + if (type_in_anonymous_namespace_p (t1) + || type_in_anonymous_namespace_p (t2)) + return false; + gcc_checking_assert (DECL_ASSEMBLER_NAME (TYPE_NAME (t1))); + gcc_checking_assert (DECL_ASSEMBLER_NAME (TYPE_NAME (t2))); + return (DECL_ASSEMBLER_NAME (TYPE_NAME (t1)) + == DECL_ASSEMBLER_NAME (TYPE_NAME (t2))); +} + +/* Compare types T1 and T2 and return true if they are + equivalent. */ + +inline bool +odr_vtable_hasher::equal (const value_type *o1, const compare_type *t2) +{ + tree t1 = o1->type; + + gcc_checking_assert (main_odr_variant (t2) == t2); + gcc_checking_assert (main_odr_variant (t1) == t1); + gcc_checking_assert (in_lto_p); + t1 = TYPE_MAIN_VARIANT (t1); + t2 = TYPE_MAIN_VARIANT (t2); + if (t1 == t2) + return true; + tree v1 = BINFO_VTABLE (TYPE_BINFO (t1)); + tree v2 = BINFO_VTABLE (TYPE_BINFO (t2)); + return (operand_equal_p (TREE_OPERAND (v1, 1), + TREE_OPERAND (v2, 1), 0) + && DECL_ASSEMBLER_NAME + (TREE_OPERAND (TREE_OPERAND (v1, 0), 0)) + == DECL_ASSEMBLER_NAME + (TREE_OPERAND (TREE_OPERAND (v2, 0), 0))); } /* Free ODR type V. */ inline void -odr_hasher::remove (value_type *v) +odr_name_hasher::remove (value_type *v) { v->bases.release (); v->derived_types.release (); @@ -527,8 +609,10 @@ odr_hasher::remove (value_type *v) /* ODR type hash used to look up ODR type based on tree type node. */ -typedef hash_table odr_hash_type; +typedef hash_table odr_hash_type; static odr_hash_type *odr_hash; +typedef hash_table odr_vtable_hash_type; +static odr_vtable_hash_type *odr_vtable_hash; /* ODR types are also stored into ODR_TYPE vector to allow consistent walking. Bases appear before derived types. Vector is garbage collected @@ -573,9 +657,9 @@ odr_subtypes_equivalent_p (tree t1, tree t2, /* For ODR types be sure to compare their names. To support -wno-odr-type-merging we allow one type to be non-ODR and other ODR even though it is a violation. */ - if (types_odr_comparable (t1, t2)) + if (types_odr_comparable (t1, t2, true)) { - if (!types_same_for_odr (t1, t2)) + if (!types_same_for_odr (t1, t2, true)) return false; /* Limit recursion: If subtypes are ODR types and we know that they are same, be happy. */ @@ -681,7 +765,7 @@ compare_virtual_tables (varpool_node *prevailing, varpool_node *vtable) { /* Extra paranoia; compare the sizes. We do not have information about virtual inheritance offsets, so just be sure that these - match. + match. Do this as very last check so the not very informative error is not output too often. */ if (DECL_SIZE (prevailing->decl) != DECL_SIZE (vtable->decl)) @@ -692,7 +776,7 @@ compare_virtual_tables (varpool_node *prevailing, varpool_node *vtable) "one definition rule ", DECL_CONTEXT (vtable->decl))) { - inform (DECL_SOURCE_LOCATION + inform (DECL_SOURCE_LOCATION (TYPE_NAME (DECL_CONTEXT (prevailing->decl))), "the conflicting type defined in another translation " "unit has virtual table of different size"); @@ -718,10 +802,10 @@ compare_virtual_tables (varpool_node *prevailing, varpool_node *vtable) "one definition rule ", DECL_CONTEXT (vtable->decl))) { - inform (DECL_SOURCE_LOCATION + inform (DECL_SOURCE_LOCATION (TYPE_NAME (DECL_CONTEXT (prevailing->decl))), "the conflicting type defined in another translation " - "unit virtual table with different RTTI information"); + "unit with different RTTI information"); } return; } @@ -794,7 +878,7 @@ compare_virtual_tables (varpool_node *prevailing, varpool_node *vtable) { if (TREE_CODE (ref1->referred->decl) == FUNCTION_DECL) { - inform (DECL_SOURCE_LOCATION + inform (DECL_SOURCE_LOCATION (TYPE_NAME (DECL_CONTEXT (prevailing->decl))), "the conflicting type defined in another translation " "unit"); @@ -807,7 +891,7 @@ compare_virtual_tables (varpool_node *prevailing, varpool_node *vtable) ref2->referred->decl); } else - inform (DECL_SOURCE_LOCATION + inform (DECL_SOURCE_LOCATION (TYPE_NAME (DECL_CONTEXT (prevailing->decl))), "the conflicting type defined in another translation " "unit has virtual table table with different contents"); @@ -1312,32 +1396,45 @@ odr_types_equivalent_p (tree t1, tree t2, bool warn, bool *warned, /* TYPE is equivalent to VAL by ODR, but its tree representation differs from VAL->type. This may happen in LTO where tree merging did not merge - all variants of the same type. It may or may not mean the ODR violation. - Add it to the list of duplicates and warn on some violations. */ + all variants of the same type or due to ODR violation. + + Analyze and report ODR violations and add type to duplicate list. + If TYPE is more specified than VAL->type, prevail VAL->type. Also if + this is first time we see definition of a class return true so the + base types are analyzed. */ static bool add_type_duplicate (odr_type val, tree type) { bool build_bases = false; + bool prevail = false; + if (!val->types_set) val->types_set = new hash_set; /* Always prefer complete type to be the leader. */ if (!COMPLETE_TYPE_P (val->type) && COMPLETE_TYPE_P (type)) - build_bases = true; + { + prevail = true; + build_bases = TYPE_BINFO (type); + } else if (COMPLETE_TYPE_P (val->type) && !COMPLETE_TYPE_P (type)) ; else if (TREE_CODE (val->type) == ENUMERAL_TYPE && TREE_CODE (type) == ENUMERAL_TYPE && !TYPE_VALUES (val->type) && TYPE_VALUES (type)) - build_bases = true; + prevail = true; else if (TREE_CODE (val->type) == RECORD_TYPE && TREE_CODE (type) == RECORD_TYPE && TYPE_BINFO (type) && !TYPE_BINFO (val->type)) - build_bases = true; + { + gcc_assert (!val->bases.length ()); + build_bases = true; + prevail = true; + } - if (build_bases) + if (prevail) { tree tmp = type; @@ -1345,29 +1442,178 @@ add_type_duplicate (odr_type val, tree type) val->type = tmp; } - /* See if this duplicate is new. */ - if (!val->types_set->add (type)) + val->types_set->add (type); + + /* If we now have a mangled name, be sure to record it to val->type + so ODR hash can work. */ + + if (can_be_name_hashed_p (type) && !can_be_name_hashed_p (val->type)) + SET_DECL_ASSEMBLER_NAME (TYPE_NAME (val->type), + DECL_ASSEMBLER_NAME (TYPE_NAME (type))); + + bool merge = true; + bool base_mismatch = false; + unsigned int i; + bool warned = false; + hash_set visited; + + gcc_assert (in_lto_p); + vec_safe_push (val->types, type); + + /* First we compare memory layout. */ + if (!odr_types_equivalent_p (val->type, type, + !flag_ltrans && !val->odr_violated, + &warned, &visited)) { - bool merge = true; - bool base_mismatch = false; - unsigned int i; - bool warned = false; - hash_set visited; + merge = false; + odr_violation_reported = true; + val->odr_violated = true; + if (symtab->dump_file) + { + fprintf (symtab->dump_file, "ODR violation\n"); + + print_node (symtab->dump_file, "", val->type, 0); + putc ('\n',symtab->dump_file); + print_node (symtab->dump_file, "", type, 0); + putc ('\n',symtab->dump_file); + } + } + + /* Next sanity check that bases are the same. If not, we will end + up producing wrong answers. */ + if (COMPLETE_TYPE_P (type) && COMPLETE_TYPE_P (val->type) + && TREE_CODE (val->type) == RECORD_TYPE + && TREE_CODE (type) == RECORD_TYPE + && TYPE_BINFO (val->type) && TYPE_BINFO (type)) + { + if (BINFO_N_BASE_BINFOS (TYPE_BINFO (type)) + != BINFO_N_BASE_BINFOS (TYPE_BINFO (val->type))) + { + if (!warned && !val->odr_violated) + { + tree extra_base; + warn_odr (type, val->type, NULL, NULL, !warned, &warned, + "a type with the same name but different " + "number of polymorphic bases is " + "defined in another translation unit"); + if (BINFO_N_BASE_BINFOS (TYPE_BINFO (type)) + > BINFO_N_BASE_BINFOS (TYPE_BINFO (val->type))) + extra_base = BINFO_BASE_BINFO + (TYPE_BINFO (type), + BINFO_N_BASE_BINFOS (TYPE_BINFO (val->type))); + else + extra_base = BINFO_BASE_BINFO + (TYPE_BINFO (val->type), + BINFO_N_BASE_BINFOS (TYPE_BINFO (type))); + tree extra_base_type = BINFO_TYPE (extra_base); + inform (DECL_SOURCE_LOCATION (TYPE_NAME (extra_base_type)), + "the extra base is defined here"); + } + base_mismatch = true; + } + else + for (i = 0; i < BINFO_N_BASE_BINFOS (TYPE_BINFO (type)); i++) + { + tree base1 = BINFO_BASE_BINFO (TYPE_BINFO (type), i); + tree base2 = BINFO_BASE_BINFO (TYPE_BINFO (val->type), i); + tree type1 = BINFO_TYPE (base1); + tree type2 = BINFO_TYPE (base2); - gcc_assert (in_lto_p); - vec_safe_push (val->types, type); + if (types_odr_comparable (type1, type2)) + { + if (!types_same_for_odr (type1, type2)) + base_mismatch = true; + } + else + { + hash_set visited; + if (!odr_types_equivalent_p (type1, type2, false, NULL, + &visited)) + base_mismatch = true; + } + if (base_mismatch) + { + if (!warned && !val->odr_violated) + { + warn_odr (type, val->type, NULL, NULL, + !warned, &warned, + "a type with the same name but different base " + "type is defined in another translation unit"); + if (warned) + warn_types_mismatch (type1, type2); + } + break; + } + if (BINFO_OFFSET (base1) != BINFO_OFFSET (base2)) + { + base_mismatch = true; + if (!warned && !val->odr_violated) + warn_odr (type, val->type, NULL, NULL, + !warned, &warned, + "a type with the same name but different base " + "layout is defined in another translation unit"); + break; + } + /* One of bases is not of complete type. */ + if (!TYPE_BINFO (type1) != !TYPE_BINFO (type2)) + { + /* If we have a polymorphic type info specified for TYPE1 + but not for TYPE2 we possibly missed a base when recording + VAL->type earlier. + Be sure this does not happen. */ + gcc_assert (TYPE_BINFO (type2) + || !polymorphic_type_binfo_p (TYPE_BINFO (type1)) + || build_bases); + break; + } + /* One base is polymorphic and the other not. + This ought to be diagnosed earlier, but do not ICE in the + checking bellow. */ + else if (TYPE_BINFO (type1) + && polymorphic_type_binfo_p (TYPE_BINFO (type1)) + != polymorphic_type_binfo_p (TYPE_BINFO (type2))) + { + gcc_assert (val->odr_violated); + base_mismatch = true; + break; + } + } +#ifdef ENABLE_CHECKING + /* Sanity check that all bases will be build same way again. */ + if (!base_mismatch && val->bases.length ()) + { + unsigned int num_poly_bases = 0; + unsigned int j; - /* First we compare memory layout. */ - if (!odr_types_equivalent_p (val->type, type, - !flag_ltrans && !val->odr_violated, - &warned, &visited)) + for (i = 0; i < BINFO_N_BASE_BINFOS (TYPE_BINFO (type)); i++) + if (polymorphic_type_binfo_p (BINFO_BASE_BINFO + (TYPE_BINFO (type), i))) + num_poly_bases++; + gcc_assert (num_poly_bases == val->bases.length ()); + for (j = 0, i = 0; i < BINFO_N_BASE_BINFOS (TYPE_BINFO (type)); + i++) + if (polymorphic_type_binfo_p (BINFO_BASE_BINFO + (TYPE_BINFO (type), i))) + { + odr_type base = get_odr_type + (BINFO_TYPE + (BINFO_BASE_BINFO (TYPE_BINFO (type), + i)), + true); + gcc_assert (val->bases[j] == base); + j++; + } + } +#endif + if (base_mismatch) { merge = false; odr_violation_reported = true; val->odr_violated = true; + if (symtab->dump_file) { - fprintf (symtab->dump_file, "ODR violation\n"); + fprintf (symtab->dump_file, "ODR base violation\n"); print_node (symtab->dump_file, "", val->type, 0); putc ('\n',symtab->dump_file); @@ -1375,197 +1621,65 @@ add_type_duplicate (odr_type val, tree type) putc ('\n',symtab->dump_file); } } + } - /* Next sanity check that bases are the same. If not, we will end - up producing wrong answers. */ - if (COMPLETE_TYPE_P (type) && COMPLETE_TYPE_P (val->type) - && TREE_CODE (val->type) == RECORD_TYPE - && TREE_CODE (type) == RECORD_TYPE - && TYPE_BINFO (val->type) && TYPE_BINFO (type)) - { - if (BINFO_N_BASE_BINFOS (TYPE_BINFO (type)) - != BINFO_N_BASE_BINFOS (TYPE_BINFO (val->type))) - { - if (!warned && !val->odr_violated) - { - tree extra_base; - warn_odr (type, val->type, NULL, NULL, !warned, &warned, - "a type with the same name but different " - "number of polymorphic bases is " - "defined in another translation unit"); - if (BINFO_N_BASE_BINFOS (TYPE_BINFO (type)) - > BINFO_N_BASE_BINFOS (TYPE_BINFO (val->type))) - extra_base = BINFO_BASE_BINFO - (TYPE_BINFO (type), - BINFO_N_BASE_BINFOS (TYPE_BINFO (val->type))); - else - extra_base = BINFO_BASE_BINFO - (TYPE_BINFO (val->type), - BINFO_N_BASE_BINFOS (TYPE_BINFO (type))); - inform (DECL_SOURCE_LOCATION - (TYPE_NAME (DECL_CONTEXT (extra_base))), - "the extra base is defined here "); - } - base_mismatch = true; - } - else - for (i = 0; i < BINFO_N_BASE_BINFOS (TYPE_BINFO (type)); i++) - { - tree base1 = BINFO_BASE_BINFO (TYPE_BINFO (type), i); - tree base2 = BINFO_BASE_BINFO (TYPE_BINFO (val->type), i); - tree type1 = BINFO_TYPE (base1); - tree type2 = BINFO_TYPE (base2); - - if (types_odr_comparable (type1, type2)) - { - if (!types_same_for_odr (type1, type2)) - base_mismatch = true; - } - else - { - hash_set visited; - if (!odr_types_equivalent_p (type1, type2, false, NULL, - &visited)) - base_mismatch = true; - } - if (base_mismatch) - { - if (!warned && !val->odr_violated) - { - warn_odr (type, val->type, NULL, NULL, - !warned, &warned, - "a type with the same name but different base " - "type is defined in another translation unit"); - if (warned) - warn_types_mismatch (type1, type2); - } - break; - } - if (BINFO_OFFSET (base1) != BINFO_OFFSET (base2)) - { - base_mismatch = true; - if (!warned && !val->odr_violated) - warn_odr (type, val->type, NULL, NULL, - !warned, &warned, - "a type with the same name but different base " - "layout is defined in another translation unit"); - break; - } - /* One base is polymorphic and the other not. - This ought to be diagnosed earlier, but do not ICE in the - checking bellow. */ - if (!TYPE_BINFO (type1) != !TYPE_BINFO (type2) - || (TYPE_BINFO (type1) - && polymorphic_type_binfo_p (TYPE_BINFO (type1)) - != polymorphic_type_binfo_p (TYPE_BINFO (type2)))) - { - base_mismatch = true; - break; - } - } -#ifdef ENABLE_CHECKING - /* Sanity check that all bases will be build same way again. */ - if (!base_mismatch && val->bases.length ()) - { - unsigned int num_poly_bases = 0; - unsigned int j; - - for (i = 0; i < BINFO_N_BASE_BINFOS (TYPE_BINFO (type)); i++) - if (polymorphic_type_binfo_p (BINFO_BASE_BINFO - (TYPE_BINFO (type), i))) - num_poly_bases++; - gcc_assert (num_poly_bases == val->bases.length ()); - for (j = 0, i = 0; i < BINFO_N_BASE_BINFOS (TYPE_BINFO (type)); - i++) - if (polymorphic_type_binfo_p (BINFO_BASE_BINFO - (TYPE_BINFO (type), i))) - { - odr_type base = get_odr_type - (BINFO_TYPE - (BINFO_BASE_BINFO (TYPE_BINFO (type), - i)), - true); - gcc_assert (val->bases[j] == base); - j++; - } - } -#endif - if (base_mismatch) - { - merge = false; - odr_violation_reported = true; - val->odr_violated = true; + /* Regularize things a little. During LTO same types may come with + different BINFOs. Either because their virtual table was + not merged by tree merging and only later at decl merging or + because one type comes with external vtable, while other + with internal. We want to merge equivalent binfos to conserve + memory and streaming overhead. + + The external vtables are more harmful: they contain references + to external declarations of methods that may be defined in the + merged LTO unit. For this reason we absolutely need to remove + them and replace by internal variants. Not doing so will lead + to incomplete answers from possible_polymorphic_call_targets. + + FIXME: disable for now; because ODR types are now build during + streaming in, the variants do not need to be linked to the type, + yet. We need to do the merging in cleanup pass to be implemented + soon. */ + if (!flag_ltrans && merge + && 0 + && TREE_CODE (val->type) == RECORD_TYPE + && TREE_CODE (type) == RECORD_TYPE + && TYPE_BINFO (val->type) && TYPE_BINFO (type) + && TYPE_MAIN_VARIANT (type) == type + && TYPE_MAIN_VARIANT (val->type) == val->type + && BINFO_VTABLE (TYPE_BINFO (val->type)) + && BINFO_VTABLE (TYPE_BINFO (type))) + { + tree master_binfo = TYPE_BINFO (val->type); + tree v1 = BINFO_VTABLE (master_binfo); + tree v2 = BINFO_VTABLE (TYPE_BINFO (type)); - if (symtab->dump_file) - { - fprintf (symtab->dump_file, "ODR base violation\n"); - - print_node (symtab->dump_file, "", val->type, 0); - putc ('\n',symtab->dump_file); - print_node (symtab->dump_file, "", type, 0); - putc ('\n',symtab->dump_file); - } - } + if (TREE_CODE (v1) == POINTER_PLUS_EXPR) + { + gcc_assert (TREE_CODE (v2) == POINTER_PLUS_EXPR + && operand_equal_p (TREE_OPERAND (v1, 1), + TREE_OPERAND (v2, 1), 0)); + v1 = TREE_OPERAND (TREE_OPERAND (v1, 0), 0); + v2 = TREE_OPERAND (TREE_OPERAND (v2, 0), 0); } + gcc_assert (DECL_ASSEMBLER_NAME (v1) + == DECL_ASSEMBLER_NAME (v2)); - /* Regularize things a little. During LTO same types may come with - different BINFOs. Either because their virtual table was - not merged by tree merging and only later at decl merging or - because one type comes with external vtable, while other - with internal. We want to merge equivalent binfos to conserve - memory and streaming overhead. - - The external vtables are more harmful: they contain references - to external declarations of methods that may be defined in the - merged LTO unit. For this reason we absolutely need to remove - them and replace by internal variants. Not doing so will lead - to incomplete answers from possible_polymorphic_call_targets. - - FIXME: disable for now; because ODR types are now build during - streaming in, the variants do not need to be linked to the type, - yet. We need to do the merging in cleanup pass to be implemented - soon. */ - if (!flag_ltrans && merge - && 0 - && TREE_CODE (val->type) == RECORD_TYPE - && TREE_CODE (type) == RECORD_TYPE - && TYPE_BINFO (val->type) && TYPE_BINFO (type) - && TYPE_MAIN_VARIANT (type) == type - && TYPE_MAIN_VARIANT (val->type) == val->type - && BINFO_VTABLE (TYPE_BINFO (val->type)) - && BINFO_VTABLE (TYPE_BINFO (type))) + if (DECL_EXTERNAL (v1) && !DECL_EXTERNAL (v2)) { - tree master_binfo = TYPE_BINFO (val->type); - tree v1 = BINFO_VTABLE (master_binfo); - tree v2 = BINFO_VTABLE (TYPE_BINFO (type)); + unsigned int i; - if (TREE_CODE (v1) == POINTER_PLUS_EXPR) + set_type_binfo (val->type, TYPE_BINFO (type)); + for (i = 0; i < val->types->length (); i++) { - gcc_assert (TREE_CODE (v2) == POINTER_PLUS_EXPR - && operand_equal_p (TREE_OPERAND (v1, 1), - TREE_OPERAND (v2, 1), 0)); - v1 = TREE_OPERAND (TREE_OPERAND (v1, 0), 0); - v2 = TREE_OPERAND (TREE_OPERAND (v2, 0), 0); + if (TYPE_BINFO ((*val->types)[i]) + == master_binfo) + set_type_binfo ((*val->types)[i], TYPE_BINFO (type)); } - gcc_assert (DECL_ASSEMBLER_NAME (v1) - == DECL_ASSEMBLER_NAME (v2)); - - if (DECL_EXTERNAL (v1) && !DECL_EXTERNAL (v2)) - { - unsigned int i; - - set_type_binfo (val->type, TYPE_BINFO (type)); - for (i = 0; i < val->types->length (); i++) - { - if (TYPE_BINFO ((*val->types)[i]) - == master_binfo) - set_type_binfo ((*val->types)[i], TYPE_BINFO (type)); - } - BINFO_TYPE (TYPE_BINFO (type)) = val->type; - } - else - set_type_binfo (type, master_binfo); + BINFO_TYPE (TYPE_BINFO (type)) = val->type; } + else + set_type_binfo (type, master_binfo); } return build_bases; } @@ -1576,8 +1690,9 @@ add_type_duplicate (odr_type val, tree type) odr_type get_odr_type (tree type, bool insert) { - odr_type_d **slot; - odr_type val; + odr_type_d **slot = NULL; + odr_type_d **vtable_slot = NULL; + odr_type val = NULL; hashval_t hash; bool build_bases = false; bool insert_to_odr_array = false; @@ -1585,21 +1700,68 @@ get_odr_type (tree type, bool insert) type = main_odr_variant (type); - hash = hash_type_name (type); - slot = odr_hash->find_slot_with_hash (type, hash, - insert ? INSERT : NO_INSERT); - if (!slot) + gcc_checking_assert (can_be_name_hashed_p (type) + || can_be_vtable_hashed_p (type)); + + /* Lookup entry, first try name hash, fallback to vtable hash. */ + if (can_be_name_hashed_p (type)) + { + hash = hash_odr_name (type); + slot = odr_hash->find_slot_with_hash (type, hash, + insert ? INSERT : NO_INSERT); + } + if ((!slot || !*slot) && in_lto_p && can_be_vtable_hashed_p (type)) + { + hash = hash_odr_vtable (type); + vtable_slot = odr_vtable_hash->find_slot_with_hash (type, hash, + insert ? INSERT : NO_INSERT); + } + + if (!slot && !vtable_slot) return NULL; /* See if we already have entry for type. */ - if (*slot) + if ((slot && *slot) || (vtable_slot && *vtable_slot)) { - val = *slot; + if (slot && *slot) + { + val = *slot; +#ifdef ENABLE_CHECKING + if (in_lto_p && can_be_vtable_hashed_p (type)) + { + hash = hash_odr_vtable (type); + vtable_slot = odr_vtable_hash->find_slot_with_hash (type, hash, + NO_INSERT); + gcc_assert (!vtable_slot || *vtable_slot == *slot); + vtable_slot = NULL; + } +#endif + } + else if (*vtable_slot) + val = *vtable_slot; - /* With LTO we need to support multiple tree representation of - the same ODR type. */ - if (val->type != type) - build_bases = add_type_duplicate (val, type); + if (val->type != type + && (!val->types_set || !val->types_set->add (type))) + { + gcc_assert (insert); + /* We have type duplicate, but it may introduce vtable name or + mangled name; be sure to keep hashes in sync. */ + if (in_lto_p && can_be_vtable_hashed_p (type) + && (!vtable_slot || !*vtable_slot)) + { + if (!vtable_slot) + { + hash = hash_odr_vtable (type); + vtable_slot = odr_vtable_hash->find_slot_with_hash + (type, hash, INSERT); + gcc_checking_assert (!*vtable_slot || *vtable_slot == val); + } + *vtable_slot = val; + } + if (slot && !*slot) + *slot = val; + build_bases = add_type_duplicate (val, type); + } } else { @@ -1610,7 +1772,10 @@ get_odr_type (tree type, bool insert) val->anonymous_namespace = type_in_anonymous_namespace_p (type); build_bases = COMPLETE_TYPE_P (val->type); insert_to_odr_array = true; - *slot = val; + if (slot) + *slot = val; + if (vtable_slot) + *vtable_slot = val; } if (build_bases && TREE_CODE (type) == RECORD_TYPE && TYPE_BINFO (type) @@ -1664,7 +1829,11 @@ void register_odr_type (tree type) { if (!odr_hash) - odr_hash = new odr_hash_type (23); + { + odr_hash = new odr_hash_type (23); + if (in_lto_p) + odr_vtable_hash = new odr_vtable_hash_type (23); + } /* Arrange things to be nicer and insert main variants first. */ if (odr_type_p (TYPE_MAIN_VARIANT (type))) get_odr_type (TYPE_MAIN_VARIANT (type), true); @@ -1784,6 +1953,8 @@ build_type_inheritance_graph (void) timevar_push (TV_IPA_INHERITANCE); inheritance_dump_file = dump_begin (TDI_inheritance, &flags); odr_hash = new odr_hash_type (23); + if (in_lto_p) + odr_vtable_hash = new odr_vtable_hash_type (23); /* We reconstruct the graph starting of types of all methods seen in the the unit. */ @@ -2839,12 +3010,12 @@ dump_possible_polymorphic_call_targets (FILE *f, targets = possible_polymorphic_call_targets (otr_type, otr_token, ctx, &final, NULL, true); - gcc_assert (targets.length () <= len); if (targets.length () != len) { fprintf (f, " Speculative targets:"); dump_targets (f, targets); } + gcc_assert (targets.length () <= len); fprintf (f, "\n"); } @@ -3044,6 +3215,9 @@ ipa_devirt (void) if (!odr_types_ptr) return 0; + if (dump_file) + dump_type_inheritance_graph (dump_file); + /* We can output -Wsuggest-final-methods and -Wsuggest-final-types warnings. This is implemented by setting up final_warning_records that are updated by get_polymorphic_call_targets. diff --git a/contrib/gcc-5.0/gcc/ipa-icf-gimple.c b/contrib/gcc-5.0/gcc/ipa-icf-gimple.c index 4f1a8ce6e9..568407da2f 100644 --- a/contrib/gcc-5.0/gcc/ipa-icf-gimple.c +++ b/contrib/gcc-5.0/gcc/ipa-icf-gimple.c @@ -200,8 +200,22 @@ func_checker::compare_decl (tree t1, tree t2) && DECL_BY_REFERENCE (t1) != DECL_BY_REFERENCE (t2)) return return_false_with_msg ("DECL_BY_REFERENCE flags are different"); - if (!compatible_types_p (TREE_TYPE (t1), TREE_TYPE (t2), - m_compare_polymorphic)) + if (!compatible_types_p (TREE_TYPE (t1), TREE_TYPE (t2))) + return return_false (); + + /* TODO: we are actually too strict here. We only need to compare if + T1 can be used in polymorphic call. */ + if (TREE_ADDRESSABLE (t1) + && m_compare_polymorphic + && !compatible_polymorphic_types_p (TREE_TYPE (t1), TREE_TYPE (t2), + false)) + return return_false (); + + if ((t == VAR_DECL || t == PARM_DECL || t == RESULT_DECL) + && DECL_BY_REFERENCE (t1) + && m_compare_polymorphic + && !compatible_polymorphic_types_p (TREE_TYPE (t1), TREE_TYPE (t2), + true)) return return_false (); bool existed_p; @@ -215,11 +229,41 @@ func_checker::compare_decl (tree t1, tree t2) return true; } +/* Return true if T1 and T2 are same for purposes of ipa-polymorphic-call + analysis. COMPARE_PTR indicates if types of pointers needs to be + considered. */ + +bool +func_checker::compatible_polymorphic_types_p (tree t1, tree t2, + bool compare_ptr) +{ + gcc_assert (TREE_CODE (t1) != FUNCTION_TYPE && TREE_CODE (t1) != METHOD_TYPE); + + /* Pointer types generally give no information. */ + if (POINTER_TYPE_P (t1)) + { + if (!compare_ptr) + return true; + return func_checker::compatible_polymorphic_types_p (TREE_TYPE (t1), + TREE_TYPE (t2), + false); + } + + /* If types contain a polymorphic types, match them. */ + bool c1 = contains_polymorphic_type_p (t1); + bool c2 = contains_polymorphic_type_p (t2); + if (!c1 && !c2) + return true; + if (!c1 || !c2) + return return_false_with_msg ("one type is not polymorphic"); + if (!types_must_be_same_for_odr (t1, t2)) + return return_false_with_msg ("types are not same for ODR"); + return true; +} + /* Return true if types are compatible from perspective of ICF. */ bool -func_checker::compatible_types_p (tree t1, tree t2, - bool compare_polymorphic, - bool first_argument) +func_checker::compatible_types_p (tree t1, tree t2) { if (TREE_CODE (t1) != TREE_CODE (t2)) return return_false_with_msg ("different tree types"); @@ -233,23 +277,6 @@ func_checker::compatible_types_p (tree t1, tree t2, if (get_alias_set (t1) != get_alias_set (t2)) return return_false_with_msg ("alias sets are different"); - /* We call contains_polymorphic_type_p with this pointer type. */ - if (first_argument && TREE_CODE (t1) == POINTER_TYPE) - { - t1 = TREE_TYPE (t1); - t2 = TREE_TYPE (t2); - } - - if (compare_polymorphic) - if (contains_polymorphic_type_p (t1) || contains_polymorphic_type_p (t2)) - { - if (!contains_polymorphic_type_p (t1) || !contains_polymorphic_type_p (t2)) - return return_false_with_msg ("one type is not polymorphic"); - - if (!types_must_be_same_for_odr (t1, t2)) - return return_false_with_msg ("types are not same for ODR"); - } - return true; } diff --git a/contrib/gcc-5.0/gcc/ipa-icf-gimple.h b/contrib/gcc-5.0/gcc/ipa-icf-gimple.h index a52f8c33c9..53a1bfe3c1 100644 --- a/contrib/gcc-5.0/gcc/ipa-icf-gimple.h +++ b/contrib/gcc-5.0/gcc/ipa-icf-gimple.h @@ -226,12 +226,16 @@ public: /* Verifies that trees T1 and T2 do correspond. */ bool compare_variable_decl (tree t1, tree t2); + /* Return true if types are compatible for polymorphic call analysis. + COMPARE_PTR indicates if polymorphic type comparsion should be + done for pointers, too. */ + static bool compatible_polymorphic_types_p (tree t1, tree t2, + bool compare_ptr); + /* Return true if types are compatible from perspective of ICF. FIRST_ARGUMENT indicates if the comparison is called for first parameter of a function. */ - static bool compatible_types_p (tree t1, tree t2, - bool compare_polymorphic = true, - bool first_argument = false); + static bool compatible_types_p (tree t1, tree t2); private: diff --git a/contrib/gcc-5.0/gcc/ipa-icf.c b/contrib/gcc-5.0/gcc/ipa-icf.c index 7c4c852ed5..25b83062d3 100644 --- a/contrib/gcc-5.0/gcc/ipa-icf.c +++ b/contrib/gcc-5.0/gcc/ipa-icf.c @@ -406,6 +406,86 @@ sem_function::equals_wpa (sem_item *item, if (arg_types.length () != m_compared_func->arg_types.length ()) return return_false_with_msg ("different number of arguments"); + /* Compare special function DECL attributes. */ + if (DECL_FUNCTION_PERSONALITY (decl) + != DECL_FUNCTION_PERSONALITY (item->decl)) + return return_false_with_msg ("function personalities are different"); + + if (DECL_DISREGARD_INLINE_LIMITS (decl) + != DECL_DISREGARD_INLINE_LIMITS (item->decl)) + return return_false_with_msg ("DECL_DISREGARD_INLINE_LIMITS are different"); + + if (DECL_DECLARED_INLINE_P (decl) != DECL_DECLARED_INLINE_P (item->decl)) + return return_false_with_msg ("inline attributes are different"); + + if (DECL_IS_OPERATOR_NEW (decl) != DECL_IS_OPERATOR_NEW (item->decl)) + return return_false_with_msg ("operator new flags are different"); + + if (DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (decl) + != DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (item->decl)) + return return_false_with_msg ("intrument function entry exit " + "attributes are different"); + + if (DECL_NO_LIMIT_STACK (decl) != DECL_NO_LIMIT_STACK (item->decl)) + return return_false_with_msg ("no stack limit attributes are different"); + + if (DECL_CXX_CONSTRUCTOR_P (decl) != DECL_CXX_CONSTRUCTOR_P (item->decl)) + return return_false_with_msg ("DELC_CXX_CONSTRUCTOR mismatch"); + + if (DECL_CXX_DESTRUCTOR_P (decl) != DECL_CXX_DESTRUCTOR_P (item->decl)) + return return_false_with_msg ("DELC_CXX_DESTRUCTOR mismatch"); + + if (flags_from_decl_or_type (decl) != flags_from_decl_or_type (item->decl)) + return return_false_with_msg ("decl_or_type flags are different"); + + /* Do not match polymorphic constructors of different types. They calls + type memory location for ipa-polymorphic-call and we do not want + it to get confused by wrong type. */ + if (DECL_CXX_CONSTRUCTOR_P (decl) + && TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE) + { + if (TREE_CODE (TREE_TYPE (item->decl)) != METHOD_TYPE) + return return_false_with_msg ("DECL_CXX_CONSTURCTOR type mismatch"); + else if (!func_checker::compatible_polymorphic_types_p + (method_class_type (TREE_TYPE (decl)), + method_class_type (TREE_TYPE (item->decl)), false)) + return return_false_with_msg ("ctor polymorphic type mismatch"); + } + + /* Checking function TARGET and OPTIMIZATION flags. */ + cl_target_option *tar1 = target_opts_for_fn (decl); + cl_target_option *tar2 = target_opts_for_fn (item->decl); + + if (tar1 != tar2 && !cl_target_option_eq (tar1, tar2)) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "target flags difference"); + cl_target_option_print_diff (dump_file, 2, tar1, tar2); + } + + return return_false_with_msg ("Target flags are different"); + } + + cl_optimization *opt1 = opts_for_fn (decl); + cl_optimization *opt2 = opts_for_fn (item->decl); + + if (opt1 != opt2 && memcmp (opt1, opt2, sizeof(cl_optimization))) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "optimization flags difference"); + cl_optimization_print_diff (dump_file, 2, opt1, opt2); + } + + return return_false_with_msg ("optimization flags are different"); + } + + /* Result type checking. */ + if (!func_checker::compatible_types_p (result_type, + m_compared_func->result_type)) + return return_false_with_msg ("result types are different"); + /* Checking types of arguments. */ for (unsigned i = 0; i < arg_types.length (); i++) { @@ -413,13 +493,8 @@ sem_function::equals_wpa (sem_item *item, if (!arg_types[i] || !m_compared_func->arg_types[i]) return return_false_with_msg ("NULL argument type"); - /* Polymorphic comparison is executed just for non-leaf functions. */ - bool is_not_leaf = get_node ()->callees != NULL - || get_node ()->indirect_calls != NULL; - if (!func_checker::compatible_types_p (arg_types[i], - m_compared_func->arg_types[i], - is_not_leaf, i == 0)) + m_compared_func->arg_types[i])) return return_false_with_msg ("argument type is different"); if (POINTER_TYPE_P (arg_types[i]) && (TYPE_RESTRICT (arg_types[i]) @@ -427,11 +502,6 @@ sem_function::equals_wpa (sem_item *item, return return_false_with_msg ("argument restrict flag mismatch"); } - /* Result type checking. */ - if (!func_checker::compatible_types_p (result_type, - m_compared_func->result_type)) - return return_false_with_msg ("result types are different"); - if (node->num_references () != item->node->num_references ()) return return_false_with_msg ("different number of references"); @@ -439,6 +509,24 @@ sem_function::equals_wpa (sem_item *item, TREE_TYPE (item->decl)) != 1) return return_false_with_msg ("different type attributes"); + /* The type of THIS pointer type memory location for + ipa-polymorphic-call-analysis. */ + if (opt_for_fn (decl, flag_devirtualize) + && (TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE + || TREE_CODE (TREE_TYPE (item->decl)) == METHOD_TYPE) + && (!flag_ipa_cp + || ipa_is_param_used (IPA_NODE_REF (dyn_cast (node)), + 0)) + && compare_polymorphic_p ()) + { + if (TREE_CODE (TREE_TYPE (decl)) != TREE_CODE (TREE_TYPE (item->decl))) + return return_false_with_msg ("METHOD_TYPE and FUNCTION_TYPE mismatch"); + if (!func_checker::compatible_polymorphic_types_p + (method_class_type (TREE_TYPE (decl)), + method_class_type (TREE_TYPE (item->decl)), false)) + return return_false_with_msg ("THIS pointer ODR type mismatch"); + } + ipa_ref *ref = NULL, *ref2 = NULL; for (unsigned i = 0; node->iterate_reference (i, ref); i++) { @@ -520,45 +608,6 @@ sem_function::equals_private (sem_item *item, if (!equals_wpa (item, ignored_nodes)) return false; - /* Checking function TARGET and OPTIMIZATION flags. */ - cl_target_option *tar1 = target_opts_for_fn (decl); - cl_target_option *tar2 = target_opts_for_fn (m_compared_func->decl); - - if (tar1 != NULL && tar2 != NULL) - { - if (!cl_target_option_eq (tar1, tar2)) - { - if (dump_file && (dump_flags & TDF_DETAILS)) - { - fprintf (dump_file, "target flags difference"); - cl_target_option_print_diff (dump_file, 2, tar1, tar2); - } - - return return_false_with_msg ("Target flags are different"); - } - } - else if (tar1 != NULL || tar2 != NULL) - return return_false_with_msg ("Target flags are different"); - - cl_optimization *opt1 = opts_for_fn (decl); - cl_optimization *opt2 = opts_for_fn (m_compared_func->decl); - - if (opt1 != NULL && opt2 != NULL) - { - if (memcmp (opt1, opt2, sizeof(cl_optimization))) - { - if (dump_file && (dump_flags & TDF_DETAILS)) - { - fprintf (dump_file, "optimization flags difference"); - cl_optimization_print_diff (dump_file, 2, opt1, opt2); - } - - return return_false_with_msg ("optimization flags are different"); - } - } - else if (opt1 != NULL || opt2 != NULL) - return return_false_with_msg ("optimization flags are different"); - /* Checking function arguments. */ tree decl1 = DECL_ATTRIBUTES (decl); tree decl2 = DECL_ATTRIBUTES (m_compared_func->decl); @@ -598,7 +647,6 @@ sem_function::equals_private (sem_item *item, if (decl1 != decl2) return return_false(); - for (arg1 = DECL_ARGUMENTS (decl), arg2 = DECL_ARGUMENTS (m_compared_func->decl); arg1; arg1 = DECL_CHAIN (arg1), arg2 = DECL_CHAIN (arg2)) @@ -654,30 +702,6 @@ sem_function::equals_private (sem_item *item, if (!compare_phi_node (bb_sorted[i]->bb, m_compared_func->bb_sorted[i]->bb)) return return_false_with_msg ("PHI node comparison returns false"); - /* Compare special function DECL attributes. */ - if (DECL_FUNCTION_PERSONALITY (decl) != DECL_FUNCTION_PERSONALITY (item->decl)) - return return_false_with_msg ("function personalities are different"); - - if (DECL_DISREGARD_INLINE_LIMITS (decl) != DECL_DISREGARD_INLINE_LIMITS (item->decl)) - return return_false_with_msg ("DECL_DISREGARD_INLINE_LIMITS are different"); - - if (DECL_DECLARED_INLINE_P (decl) != DECL_DECLARED_INLINE_P (item->decl)) - return return_false_with_msg ("inline attributes are different"); - - if (DECL_IS_OPERATOR_NEW (decl) != DECL_IS_OPERATOR_NEW (item->decl)) - return return_false_with_msg ("operator new flags are different"); - - if (DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (decl) - != DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (item->decl)) - return return_false_with_msg ("intrument function entry exit " - "attributes are different"); - - if (DECL_NO_LIMIT_STACK (decl) != DECL_NO_LIMIT_STACK (item->decl)) - return return_false_with_msg ("no stack limit attributes are different"); - - if (flags_from_decl_or_type (decl) != flags_from_decl_or_type (item->decl)) - return return_false_with_msg ("decl_or_type flags are different"); - return result; } @@ -1224,10 +1248,20 @@ sem_function::hash_stmt (gimple stmt, inchash::hash &hstate) bool sem_function::compare_polymorphic_p (void) { - return get_node ()->callees != NULL - || get_node ()->indirect_calls != NULL - || m_compared_func->get_node ()->callees != NULL - || m_compared_func->get_node ()->indirect_calls != NULL; + struct cgraph_edge *e; + + if (!opt_for_fn (decl, flag_devirtualize)) + return false; + if (get_node ()->indirect_calls != NULL + || m_compared_func->get_node ()->indirect_calls != NULL) + return true; + /* TODO: We can do simple propagation determining what calls may lead to + a polymorphic call. */ + for (e = m_compared_func->get_node ()->callees; e; e = e->next_callee) + if (e->callee->definition + && opt_for_fn (e->callee->decl, flag_devirtualize)) + return true; + return false; } /* For a given call graph NODE, the function constructs new @@ -1382,41 +1416,6 @@ sem_function::bb_dict_test (vec *bb_dict, int source, int target) return (*bb_dict)[source] == target; } -/* Iterates all tree types in T1 and T2 and returns true if all types - are compatible. If COMPARE_POLYMORPHIC is set to true, - more strict comparison is executed. */ - -bool -sem_function::compare_type_list (tree t1, tree t2, bool compare_polymorphic) -{ - tree tv1, tv2; - tree_code tc1, tc2; - - if (!t1 && !t2) - return true; - - while (t1 != NULL && t2 != NULL) - { - tv1 = TREE_VALUE (t1); - tv2 = TREE_VALUE (t2); - - tc1 = TREE_CODE (tv1); - tc2 = TREE_CODE (tv2); - - if (tc1 == NOP_EXPR && tc2 == NOP_EXPR) - {} - else if (tc1 == NOP_EXPR || tc2 == NOP_EXPR) - return false; - else if (!func_checker::compatible_types_p (tv1, tv2, compare_polymorphic)) - return false; - - t1 = TREE_CHAIN (t1); - t2 = TREE_CHAIN (t2); - } - - return !(t1 || t2); -} - /* Semantic variable constructor that uses STACK as bitmap memory stack. */ @@ -1594,8 +1593,7 @@ sem_variable::equals (tree t1, tree t2) tree y1 = TREE_OPERAND (t1, 1); tree y2 = TREE_OPERAND (t2, 1); - if (!func_checker::compatible_types_p (TREE_TYPE (x1), TREE_TYPE (x2), - true)) + if (!func_checker::compatible_types_p (TREE_TYPE (x1), TREE_TYPE (x2))) return return_false (); /* Type of the offset on MEM_REF does not matter. */ @@ -1704,8 +1702,7 @@ sem_variable::equals (tree t1, tree t2) CASE_CONVERT: case VIEW_CONVERT_EXPR: - if (!func_checker::compatible_types_p (TREE_TYPE (t1), TREE_TYPE (t2), - true)) + if (!func_checker::compatible_types_p (TREE_TYPE (t1), TREE_TYPE (t2))) return return_false (); return sem_variable::equals (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0)); case ERROR_MARK: @@ -1882,40 +1879,6 @@ sem_variable::dump_to_file (FILE *file) fprintf (file, "\n\n"); } -/* Iterates though a constructor and identifies tree references - we are interested in semantic function equality. */ - -void -sem_variable::parse_tree_refs (tree t) -{ - switch (TREE_CODE (t)) - { - case CONSTRUCTOR: - { - unsigned length = vec_safe_length (CONSTRUCTOR_ELTS (t)); - - for (unsigned i = 0; i < length; i++) - parse_tree_refs(CONSTRUCTOR_ELT (t, i)->value); - - break; - } - case NOP_EXPR: - case ADDR_EXPR: - { - tree op = TREE_OPERAND (t, 0); - parse_tree_refs (op); - break; - } - case FUNCTION_DECL: - { - tree_refs.safe_push (t); - break; - } - default: - break; - } -} - unsigned int sem_item_optimizer::class_id = 0; sem_item_optimizer::sem_item_optimizer (): worklist (0), m_classes (0), @@ -2193,10 +2156,7 @@ sem_item_optimizer::filter_removed_items (void) { cgraph_node *cnode = static_cast (item)->get_node (); - bool no_body_function = in_lto_p && (cnode->alias || cnode->body_removed); - if (no_body_function || !opt_for_fn (item->decl, flag_ipa_icf_functions) - || DECL_CXX_CONSTRUCTOR_P (item->decl) - || DECL_CXX_DESTRUCTOR_P (item->decl)) + if (in_lto_p && (cnode->alias || cnode->body_removed)) remove_item (item); else filtered.safe_push (item); diff --git a/contrib/gcc-5.0/gcc/ipa-icf.h b/contrib/gcc-5.0/gcc/ipa-icf.h index 1481353388..c51bb4a429 100644 --- a/contrib/gcc-5.0/gcc/ipa-icf.h +++ b/contrib/gcc-5.0/gcc/ipa-icf.h @@ -353,11 +353,6 @@ private: corresponds to TARGET. */ bool bb_dict_test (vec *bb_dict, int source, int target); - /* Iterates all tree types in T1 and T2 and returns true if all types - are compatible. If COMPARE_POLYMORPHIC is set to true, - more strict comparison is executed. */ - bool compare_type_list (tree t1, tree t2, bool compare_polymorphic); - /* If cgraph edges E1 and E2 are indirect calls, verify that ICF flags are the same. */ bool compare_edge_flags (cgraph_edge *e1, cgraph_edge *e2); @@ -415,15 +410,8 @@ public: static sem_variable *parse (varpool_node *node, bitmap_obstack *stack); private: - /* Iterates though a constructor and identifies tree references - we are interested in semantic function equality. */ - void parse_tree_refs (tree t); - /* Compares trees T1 and T2 for semantic equality. */ static bool equals (tree t1, tree t2); - - /* Compare that symbol sections are either NULL or have same name. */ - bool compare_sections (sem_variable *alias); }; // class sem_variable class sem_item_optimizer; diff --git a/contrib/gcc-5.0/gcc/ipa-inline-analysis.c b/contrib/gcc-5.0/gcc/ipa-inline-analysis.c index d747163061..5707f6c960 100644 --- a/contrib/gcc-5.0/gcc/ipa-inline-analysis.c +++ b/contrib/gcc-5.0/gcc/ipa-inline-analysis.c @@ -3978,6 +3978,9 @@ check_callers (cgraph_node *node, int *max_callers) { ipa_ref *ref; + if (!node->can_remove_if_no_direct_calls_and_refs_p ()) + return true; + for (cgraph_edge *e = node->callers; e; e = e->next_caller) { (*max_callers)--; @@ -4007,23 +4010,13 @@ growth_likely_positive (struct cgraph_node *node, struct cgraph_edge *e; gcc_checking_assert (edge_growth > 0); + /* First quickly check if NODE is removable at all. */ if (DECL_EXTERNAL (node->decl)) return true; - /* Unlike for functions called once, we play unsafe with - COMDATs. We can allow that since we know functions - in consideration are small (and thus risk is small) and - moreover grow estimates already accounts that COMDAT - functions may or may not disappear when eliminated from - current unit. With good probability making aggressive - choice in all units is going to make overall program - smaller. */ - if (DECL_COMDAT (node->decl)) - { - if (!node->can_remove_if_no_direct_calls_p ()) - return true; - } - else if (!node->will_be_removed_from_program_if_no_direct_calls_p ()) + if (!node->can_remove_if_no_direct_calls_and_refs_p () + || node->address_taken) return true; + max_callers = inline_summaries->get (node)->size * 4 / edge_growth + 2; for (e = node->callers; e; e = e->next_caller) @@ -4039,6 +4032,22 @@ growth_likely_positive (struct cgraph_node *node, if (check_callers (dyn_cast (ref->referring), &max_callers)) return true; + /* Unlike for functions called once, we play unsafe with + COMDATs. We can allow that since we know functions + in consideration are small (and thus risk is small) and + moreover grow estimates already accounts that COMDAT + functions may or may not disappear when eliminated from + current unit. With good probability making aggressive + choice in all units is going to make overall program + smaller. */ + if (DECL_COMDAT (node->decl)) + { + if (!node->can_remove_if_no_direct_calls_p ()) + return true; + } + else if (!node->will_be_removed_from_program_if_no_direct_calls_p ()) + return true; + return estimate_growth (node) > 0; } diff --git a/contrib/gcc-5.0/gcc/ipa-utils.h b/contrib/gcc-5.0/gcc/ipa-utils.h index ea0f8b379f..d302456ae9 100644 --- a/contrib/gcc-5.0/gcc/ipa-utils.h +++ b/contrib/gcc-5.0/gcc/ipa-utils.h @@ -80,7 +80,7 @@ bool type_known_to_have_no_deriavations_p (tree); bool contains_polymorphic_type_p (const_tree); void register_odr_type (tree); bool types_must_be_same_for_odr (tree, tree); -bool types_odr_comparable (tree, tree); +bool types_odr_comparable (tree, tree, bool strict = false); cgraph_node *try_speculative_devirtualization (tree, HOST_WIDE_INT, ipa_polymorphic_call_context); diff --git a/contrib/gcc-5.0/gcc/lra-lives.c b/contrib/gcc-5.0/gcc/lra-lives.c index 9dfffb6f28..5d759ca73d 100644 --- a/contrib/gcc-5.0/gcc/lra-lives.c +++ b/contrib/gcc-5.0/gcc/lra-lives.c @@ -636,8 +636,12 @@ check_pseudos_live_through_calls (int regno) if (! sparseset_bit_p (pseudos_live_through_calls, regno)) return; sparseset_clear_bit (pseudos_live_through_calls, regno); + bool actual_call_used_reg_set_available_p + = !hard_reg_set_empty_p (lra_reg_info[regno].actual_call_used_reg_set); IOR_HARD_REG_SET (lra_reg_info[regno].conflict_hard_regs, - call_used_reg_set); + (actual_call_used_reg_set_available_p + ? lra_reg_info[regno].actual_call_used_reg_set + : call_used_reg_set)); for (hr = 0; hr < FIRST_PSEUDO_REGISTER; hr++) if (HARD_REGNO_CALL_PART_CLOBBERED (hr, PSEUDO_REGNO_MODE (regno))) diff --git a/contrib/gcc-5.0/gcc/lto/lto.c b/contrib/gcc-5.0/gcc/lto/lto.c index ce7e6b1974..760975fdf2 100644 --- a/contrib/gcc-5.0/gcc/lto/lto.c +++ b/contrib/gcc-5.0/gcc/lto/lto.c @@ -3118,13 +3118,20 @@ read_cgraph_and_symbols (unsigned nfiles, const char **fnames) fprintf (symtab->dump_file, "Before merging:\n"); symtab_node::dump_table (symtab->dump_file); } - lto_symtab_merge_symbols (); - /* Removal of unreachable symbols is needed to make verify_symtab to pass; - we are still having duplicated comdat groups containing local statics. - We could also just remove them while merging. */ - symtab->remove_unreachable_nodes (dump_file); + if (!flag_ltrans) + { + lto_symtab_merge_symbols (); + /* Removal of unreachable symbols is needed to make verify_symtab to pass; + we are still having duplicated comdat groups containing local statics. + We could also just remove them while merging. */ + symtab->remove_unreachable_nodes (dump_file); + } ggc_collect (); symtab->state = IPA_SSA; + /* FIXME: Technically all node removals happening here are useless, because + WPA should not stream them. */ + if (flag_ltrans) + symtab->remove_unreachable_nodes (dump_file); timevar_pop (TV_IPA_LTO_CGRAPH_MERGE); diff --git a/contrib/gcc-5.0/gcc/omp-low.c b/contrib/gcc-5.0/gcc/omp-low.c index 75d6707f19..2d64a74e3e 100644 --- a/contrib/gcc-5.0/gcc/omp-low.c +++ b/contrib/gcc-5.0/gcc/omp-low.c @@ -5514,8 +5514,8 @@ expand_omp_taskreg (struct omp_region *region) stmt = gsi_stmt (gsi); gcc_assert (stmt && (gimple_code (stmt) == GIMPLE_OMP_PARALLEL || gimple_code (stmt) == GIMPLE_OMP_TASK)); - gsi_remove (&gsi, true); e = split_block (entry_bb, stmt); + gsi_remove (&gsi, true); entry_bb = e->dest; single_succ_edge (entry_bb)->flags = EDGE_FALLTHRU; @@ -8889,8 +8889,8 @@ expand_omp_target (struct omp_region *region) stmt = gsi_stmt (gsi); gcc_assert (stmt && gimple_code (stmt) == gimple_code (entry_stmt)); - gsi_remove (&gsi, true); e = split_block (entry_bb, stmt); + gsi_remove (&gsi, true); entry_bb = e->dest; single_succ_edge (entry_bb)->flags = EDGE_FALLTHRU; diff --git a/contrib/gcc-5.0/gcc/simplify-rtx.c b/contrib/gcc-5.0/gcc/simplify-rtx.c index a003b4179a..5d1749829b 100644 --- a/contrib/gcc-5.0/gcc/simplify-rtx.c +++ b/contrib/gcc-5.0/gcc/simplify-rtx.c @@ -3555,7 +3555,21 @@ simplify_binary_operation_1 (enum rtx_code code, machine_mode mode, while (GET_MODE (vec) != mode && GET_CODE (vec) == VEC_CONCAT) { - HOST_WIDE_INT vec_size = GET_MODE_SIZE (GET_MODE (XEXP (vec, 0))); + HOST_WIDE_INT vec_size; + + if (CONST_INT_P (XEXP (vec, 0))) + { + /* vec_concat of two const_ints doesn't make sense with + respect to modes. */ + if (CONST_INT_P (XEXP (vec, 1))) + return 0; + + vec_size = GET_MODE_SIZE (GET_MODE (trueop0)) + - GET_MODE_SIZE (GET_MODE (XEXP (vec, 1))); + } + else + vec_size = GET_MODE_SIZE (GET_MODE (XEXP (vec, 0))); + if (offset < vec_size) vec = XEXP (vec, 0); else diff --git a/contrib/gcc-5.0/gcc/symtab.c b/contrib/gcc-5.0/gcc/symtab.c index a46ebd49ef..88e168bd19 100644 --- a/contrib/gcc-5.0/gcc/symtab.c +++ b/contrib/gcc-5.0/gcc/symtab.c @@ -1908,3 +1908,106 @@ symtab_node::address_matters_p () gcc_assert (!alias); return call_for_symbol_and_aliases (address_matters_1, NULL, true); } + +/* Return ture if symbol's alignment may be increased. */ + +bool +symtab_node::can_increase_alignment_p (void) +{ + symtab_node *target = ultimate_alias_target (); + + /* For now support only variables. */ + if (TREE_CODE (decl) != VAR_DECL) + return false; + + /* With -fno-toplevel-reorder we may have already output the constant. */ + if (TREE_ASM_WRITTEN (target->decl)) + return false; + + /* If target is already placed in an anchor, we can not touch its + alignment. */ + if (DECL_RTL_SET_P (target->decl) + && MEM_P (DECL_RTL (target->decl)) + && SYMBOL_REF_HAS_BLOCK_INFO_P (XEXP (DECL_RTL (target->decl), 0))) + return false; + + /* Constant pool entries may be shared. */ + if (DECL_IN_CONSTANT_POOL (target->decl)) + return false; + + /* We cannot change alignment of symbols that may bind to symbols + in other translation unit that may contain a definition with lower + alignment. */ + if (!decl_binds_to_current_def_p (decl)) + return false; + + /* When compiling partition, be sure the symbol is not output by other + partition. */ + if (flag_ltrans + && (target->in_other_partition + || target->get_partitioning_class () == SYMBOL_DUPLICATE)) + return false; + + /* Do not override the alignment as specified by the ABI when the used + attribute is set. */ + if (DECL_PRESERVE_P (decl) || DECL_PRESERVE_P (target->decl)) + return false; + + /* Do not override explicit alignment set by the user when an explicit + section name is also used. This is a common idiom used by many + software projects. */ + if (DECL_SECTION_NAME (target->decl) != NULL && !target->implicit_section) + return false; + + return true; +} + +/* Worker for symtab_node::increase_alignment. */ + +static bool +increase_alignment_1 (symtab_node *n, void *v) +{ + unsigned int align = (size_t)v; + if (DECL_ALIGN (n->decl) < align + && n->can_increase_alignment_p ()) + { + DECL_ALIGN (n->decl) = align; + DECL_USER_ALIGN (n->decl) = 1; + } + return false; +} + +/* Increase alignment of THIS to ALIGN. */ + +void +symtab_node::increase_alignment (unsigned int align) +{ + gcc_assert (can_increase_alignment_p () && align < MAX_OFILE_ALIGNMENT); + ultimate_alias_target()->call_for_symbol_and_aliases (increase_alignment_1, + (void *)(size_t) align, + true); + gcc_assert (DECL_ALIGN (decl) >= align); +} + +/* Helper for symtab_node::definition_alignment. */ + +static bool +get_alignment_1 (symtab_node *n, void *v) +{ + *((unsigned int *)v) = MAX (*((unsigned int *)v), DECL_ALIGN (n->decl)); + return false; +} + +/* Return desired alignment of the definition. This is NOT alignment useful + to access THIS, because THIS may be interposable and DECL_ALIGN should + be used instead. It however must be guaranteed when output definition + of THIS. */ + +unsigned int +symtab_node::definition_alignment () +{ + unsigned int align = 0; + gcc_assert (!alias); + call_for_symbol_and_aliases (get_alignment_1, &align, true); + return align; +} diff --git a/contrib/gcc-5.0/gcc/toplev.c b/contrib/gcc-5.0/gcc/toplev.c index 99cf180690..b06eed3e99 100644 --- a/contrib/gcc-5.0/gcc/toplev.c +++ b/contrib/gcc-5.0/gcc/toplev.c @@ -1375,7 +1375,17 @@ process_options (void) if (flag_check_pointer_bounds) { if (targetm.chkp_bound_mode () == VOIDmode) - error ("-fcheck-pointer-bounds is not supported for this target"); + { + error ("-fcheck-pointer-bounds is not supported for this target"); + flag_check_pointer_bounds = 0; + } + + if (flag_sanitize & SANITIZE_ADDRESS) + { + error ("-fcheck-pointer-bounds is not supported with " + "Address Sanitizer"); + flag_check_pointer_bounds = 0; + } } /* One region RA really helps to decrease the code size. */ diff --git a/contrib/gcc-5.0/gcc/tree-cfg.c b/contrib/gcc-5.0/gcc/tree-cfg.c index 006bc08bbc..0f5e428124 100644 --- a/contrib/gcc-5.0/gcc/tree-cfg.c +++ b/contrib/gcc-5.0/gcc/tree-cfg.c @@ -1703,7 +1703,8 @@ gimple_can_merge_blocks_p (basic_block a, basic_block b) if (!single_pred_p (b)) return false; - if (b == EXIT_BLOCK_PTR_FOR_FN (cfun)) + if (a == ENTRY_BLOCK_PTR_FOR_FN (cfun) + || b == EXIT_BLOCK_PTR_FOR_FN (cfun)) return false; /* If A ends by a statement causing exceptions or something similar, we @@ -5683,7 +5684,6 @@ gimple_split_block (basic_block bb, void *stmt) { gimple_stmt_iterator gsi; gimple_stmt_iterator gsi_tgt; - gimple act; gimple_seq list; basic_block new_bb; edge e; @@ -5697,26 +5697,16 @@ gimple_split_block (basic_block bb, void *stmt) FOR_EACH_EDGE (e, ei, new_bb->succs) e->src = new_bb; - if (stmt && gimple_code ((gimple) stmt) == GIMPLE_LABEL) - stmt = NULL; - - /* Move everything from GSI to the new basic block. */ - for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) + /* Get a stmt iterator pointing to the first stmt to move. */ + if (!stmt || gimple_code ((gimple) stmt) == GIMPLE_LABEL) + gsi = gsi_after_labels (bb); + else { - act = gsi_stmt (gsi); - if (gimple_code (act) == GIMPLE_LABEL) - continue; - - if (!stmt) - break; - - if (stmt == act) - { - gsi_next (&gsi); - break; - } + gsi = gsi_for_stmt ((gimple) stmt); + gsi_next (&gsi); } - + + /* Move everything from GSI to the new basic block. */ if (gsi_end_p (gsi)) return new_bb; @@ -8732,10 +8722,6 @@ execute_fixup_cfg (void) if (count_scale != REG_BR_PROB_BASE) compute_function_frequency (); - /* Dump a textual representation of the flowgraph. */ - if (dump_file) - gimple_dump_cfg (dump_file, dump_flags); - if (current_loops && (todo & TODO_cleanup_cfg)) loops_state_set (LOOPS_NEED_FIXUP); @@ -8748,7 +8734,7 @@ namespace { const pass_data pass_data_fixup_cfg = { GIMPLE_PASS, /* type */ - "*free_cfg_annotations", /* name */ + "fixup_cfg", /* name */ OPTGROUP_NONE, /* optinfo_flags */ TV_NONE, /* tv_id */ PROP_cfg, /* properties_required */ diff --git a/contrib/gcc-5.0/gcc/tree-cfgcleanup.c b/contrib/gcc-5.0/gcc/tree-cfgcleanup.c index 5c5c7bace7..e7122e33c2 100644 --- a/contrib/gcc-5.0/gcc/tree-cfgcleanup.c +++ b/contrib/gcc-5.0/gcc/tree-cfgcleanup.c @@ -625,35 +625,13 @@ fixup_noreturn_call (gimple stmt) update_stmt (stmt); } + /* Mark the call as altering control flow. */ + gimple_call_set_ctrl_altering (stmt, true); + return remove_fallthru_edge (bb->succs); } -/* Split basic blocks on calls in the middle of a basic block that are now - known not to return, and remove the unreachable code. */ - -static bool -split_bb_on_noreturn_calls (basic_block bb) -{ - bool changed = false; - gimple_stmt_iterator gsi; - - for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) - { - gimple stmt = gsi_stmt (gsi); - - if (!is_gimple_call (stmt)) - continue; - - if (gimple_call_noreturn_p (stmt)) - changed |= fixup_noreturn_call (stmt); - } - - if (changed) - bitmap_set_bit (cfgcleanup_altered_bbs, bb->index); - return changed; -} - /* Tries to cleanup cfg in basic block BB. Returns true if anything changes. */ @@ -672,8 +650,18 @@ cleanup_tree_cfg_bb (basic_block bb) if (single_succ_p (bb) && can_merge_blocks_p (bb, single_succ (bb))) { - merge_blocks (bb, single_succ (bb)); - return true; + /* If there is a merge opportunity with the predecessor + do nothing now but wait until we process the predecessor. + This happens when we visit BBs in a non-optimal order and + avoids quadratic behavior with adjusting stmts BB pointer. */ + if (single_pred_p (bb) + && can_merge_blocks_p (single_pred (bb), bb)) + ; + else + { + merge_blocks (bb, single_succ (bb)); + return true; + } } return retval; @@ -703,10 +691,7 @@ cleanup_tree_cfg_1 (void) { bb = BASIC_BLOCK_FOR_FN (cfun, i); if (bb) - { - retval |= cleanup_tree_cfg_bb (bb); - retval |= split_bb_on_noreturn_calls (bb); - } + retval |= cleanup_tree_cfg_bb (bb); } /* Now process the altered blocks, as long as any are available. */ @@ -722,10 +707,6 @@ cleanup_tree_cfg_1 (void) continue; retval |= cleanup_tree_cfg_bb (bb); - - /* Rerun split_bb_on_noreturn_calls, in case we have altered any noreturn - calls. */ - retval |= split_bb_on_noreturn_calls (bb); } end_recording_case_labels (); @@ -1111,9 +1092,12 @@ make_pass_merge_phi (gcc::context *ctxt) static unsigned int execute_cleanup_cfg_post_optimizing (void) { - unsigned int todo = 0; + unsigned int todo = execute_fixup_cfg (); if (cleanup_tree_cfg ()) - todo |= TODO_update_ssa; + { + todo &= ~TODO_cleanup_cfg; + todo |= TODO_update_ssa; + } maybe_remove_unreachable_handlers (); cleanup_dead_labels (); group_case_labels (); diff --git a/contrib/gcc-5.0/gcc/tree-core.h b/contrib/gcc-5.0/gcc/tree-core.h index 3aaf650ff7..ad1bb231eb 100644 --- a/contrib/gcc-5.0/gcc/tree-core.h +++ b/contrib/gcc-5.0/gcc/tree-core.h @@ -700,7 +700,8 @@ enum size_type_kind { enum operand_equal_flag { OEP_ONLY_CONST = 1, OEP_PURE_SAME = 2, - OEP_CONSTANT_ADDRESS_OF = 4 + OEP_CONSTANT_ADDRESS_OF = 4, + OEP_ADDRESS_OF = 8 }; /* Enum and arrays used for tree allocation stats. diff --git a/contrib/gcc-5.0/gcc/tree-inline.c b/contrib/gcc-5.0/gcc/tree-inline.c index d8abe03e40..83e43356f6 100644 --- a/contrib/gcc-5.0/gcc/tree-inline.c +++ b/contrib/gcc-5.0/gcc/tree-inline.c @@ -2805,7 +2805,9 @@ copy_cfg_body (copy_body_data * id, gcov_type count, int frequency_scale, maybe_move_debug_stmts_to_successors (id, (basic_block) bb->aux); /* Update call edge destinations. This can not be done before loop info is updated, because we may split basic blocks. */ - if (id->transform_call_graph_edges == CB_CGE_DUPLICATE) + if (id->transform_call_graph_edges == CB_CGE_DUPLICATE + && bb->index != ENTRY_BLOCK + && bb->index != EXIT_BLOCK) redirect_all_calls (id, (basic_block)bb->aux); ((basic_block)bb->aux)->aux = NULL; bb->aux = NULL; @@ -4777,18 +4779,19 @@ static bool gimple_expand_calls_inline (basic_block bb, copy_body_data *id) { gimple_stmt_iterator gsi; + bool inlined = false; - for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) + for (gsi = gsi_last_bb (bb); !gsi_end_p (gsi);) { gimple stmt = gsi_stmt (gsi); + gsi_prev (&gsi); if (is_gimple_call (stmt) - && !gimple_call_internal_p (stmt) - && expand_call_inline (bb, stmt, id)) - return true; + && !gimple_call_internal_p (stmt)) + inlined |= expand_call_inline (bb, stmt, id); } - return false; + return inlined; } diff --git a/contrib/gcc-5.0/gcc/tree-parloops.c b/contrib/gcc-5.0/gcc/tree-parloops.c index 5f7c1bc360..fbb9eebddc 100644 --- a/contrib/gcc-5.0/gcc/tree-parloops.c +++ b/contrib/gcc-5.0/gcc/tree-parloops.c @@ -1111,7 +1111,8 @@ create_call_for_reduction_1 (reduction_info **slot, struct clsn_data *clsn_data) /* Create phi node. */ bb = clsn_data->load_bb; - e = split_block (bb, t); + gsi = gsi_last_bb (bb); + e = split_block (bb, gsi_stmt (gsi)); new_bb = e->dest; tmp_load = create_tmp_var (TREE_TYPE (TREE_TYPE (addr))); diff --git a/contrib/gcc-5.0/gcc/tree-sra.c b/contrib/gcc-5.0/gcc/tree-sra.c index 3527a47256..a49e9504e1 100644 --- a/contrib/gcc-5.0/gcc/tree-sra.c +++ b/contrib/gcc-5.0/gcc/tree-sra.c @@ -1597,7 +1597,7 @@ build_ref_for_offset (location_t loc, tree base, HOST_WIDE_INT offset, misalign = (misalign + offset) & (align - 1); if (misalign != 0) align = (misalign & -misalign); - if (align < TYPE_ALIGN (exp_type)) + if (align != TYPE_ALIGN (exp_type)) exp_type = build_aligned_type (exp_type, align); mem_ref = fold_build2_loc (loc, MEM_REF, exp_type, base, off); diff --git a/contrib/gcc-5.0/gcc/tree-ssa-coalesce.c b/contrib/gcc-5.0/gcc/tree-ssa-coalesce.c index 1afeefef2e..dd6b9c04f8 100644 --- a/contrib/gcc-5.0/gcc/tree-ssa-coalesce.c +++ b/contrib/gcc-5.0/gcc/tree-ssa-coalesce.c @@ -59,6 +59,7 @@ along with GCC; see the file COPYING3. If not see #include "tree-ssa-live.h" #include "tree-ssa-coalesce.h" #include "diagnostic-core.h" +#include "timevar.h" /* This set of routines implements a coalesce_list. This is an object which @@ -1121,8 +1122,8 @@ create_outofssa_var_map (coalesce_list_p cl, bitmap used_in_copy) /* Attempt to coalesce ssa versions X and Y together using the partition - mapping in MAP and checking conflicts in GRAPH. Output any debug info to - DEBUG, if it is nun-NULL. */ + mapping in MAP and checking conflicts in GRAPH if not NULL. + Output any debug info to DEBUG, if it is nun-NULL. */ static inline bool attempt_coalesce (var_map map, ssa_conflicts_p graph, int x, int y, @@ -1154,7 +1155,8 @@ attempt_coalesce (var_map map, ssa_conflicts_p graph, int x, int y, fprintf (debug, " [map: %d, %d] ", p1, p2); - if (!ssa_conflicts_test_p (graph, p1, p2)) + if (!graph + || !ssa_conflicts_test_p (graph, p1, p2)) { var1 = partition_to_var (map, p1); var2 = partition_to_var (map, p2); @@ -1168,10 +1170,13 @@ attempt_coalesce (var_map map, ssa_conflicts_p graph, int x, int y, /* z is the new combined partition. Remove the other partition from the list, and merge the conflicts. */ - if (z == p1) - ssa_conflicts_merge (graph, p1, p2); - else - ssa_conflicts_merge (graph, p2, p1); + if (graph) + { + if (z == p1) + ssa_conflicts_merge (graph, p1, p2); + else + ssa_conflicts_merge (graph, p2, p1); + } if (debug) fprintf (debug, ": Success -> %d\n", z); @@ -1185,24 +1190,16 @@ attempt_coalesce (var_map map, ssa_conflicts_p graph, int x, int y, } -/* Attempt to Coalesce partitions in MAP which occur in the list CL using - GRAPH. Debug output is sent to DEBUG if it is non-NULL. */ +/* Perform all abnormal coalescing on MAP. + Debug output is sent to DEBUG if it is non-NULL. */ static void -coalesce_partitions (var_map map, ssa_conflicts_p graph, coalesce_list_p cl, - FILE *debug) +perform_abnormal_coalescing (var_map map, FILE *debug) { - int x = 0, y = 0; - tree var1, var2; - int cost; basic_block bb; edge e; edge_iterator ei; - /* First, coalesce all the copies across abnormal edges. These are not placed - in the coalesce list because they do not need to be sorted, and simply - consume extra memory/compilation time in large programs. */ - FOR_EACH_BB_FN (bb, cfun) { FOR_EACH_EDGE (e, ei, bb->preds) @@ -1226,11 +1223,23 @@ coalesce_partitions (var_map map, ssa_conflicts_p graph, coalesce_list_p cl, if (debug) fprintf (debug, "Abnormal coalesce: "); - if (!attempt_coalesce (map, graph, v1, v2, debug)) + if (!attempt_coalesce (map, NULL, v1, v2, debug)) fail_abnormal_edge_coalesce (v1, v2); } } } +} + +/* Attempt to Coalesce partitions in MAP which occur in the list CL using + GRAPH. Debug output is sent to DEBUG if it is non-NULL. */ + +static void +coalesce_partitions (var_map map, ssa_conflicts_p graph, coalesce_list_p cl, + FILE *debug) +{ + int x = 0, y = 0; + tree var1, var2; + int cost; /* Now process the items in the coalesce list. */ @@ -1285,6 +1294,11 @@ coalesce_ssa_name (void) var_map map; unsigned int i; +#ifdef ENABLE_CHECKING + /* Verify we can perform all must coalesces. */ + verify_ssa_coalescing (); +#endif + cl = create_coalesce_list (); map = create_outofssa_var_map (cl, used_in_copies); @@ -1341,6 +1355,15 @@ coalesce_ssa_name (void) return map; } + /* First, coalesce all the copies across abnormal edges. These are not placed + in the coalesce list because they do not need to be sorted, and simply + consume extra memory/compilation time in large programs. + Performing abnormal coalescing also needs no live/conflict computation + because it must succeed (but we lose checking that it indeed does). + Still for PR63155 this reduces memory usage from 10GB to zero. */ + perform_abnormal_coalescing (map, + ((dump_flags & TDF_DETAILS) ? dump_file : NULL)); + if (dump_file && (dump_flags & TDF_DETAILS)) dump_var_map (dump_file, map); @@ -1371,11 +1394,100 @@ coalesce_ssa_name (void) /* Now coalesce everything in the list. */ coalesce_partitions (map, graph, cl, - ((dump_flags & TDF_DETAILS) ? dump_file - : NULL)); + ((dump_flags & TDF_DETAILS) ? dump_file : NULL)); delete_coalesce_list (cl); ssa_conflicts_delete (graph); return map; } + + +/* Helper for verify_ssa_coalescing. Operates in two modes: + 1) scan the function for coalesces we must perform and store the + SSA names participating in USED_IN_COPIES + 2) scan the function for coalesces and verify they can be performed + under the constraints of GRAPH updating MAP in the process + FIXME: This can be extended to verify that the virtual operands + form a factored use-def chain (coalescing the active virtual use + with the virtual def at virtual def point). */ + +static void +verify_ssa_coalescing_worker (bitmap used_in_copies, + var_map map, ssa_conflicts_p graph) +{ + basic_block bb; + + FOR_EACH_BB_FN (bb, cfun) + { + edge e; + edge_iterator ei; + + FOR_EACH_EDGE (e, ei, bb->preds) + if (e->flags & EDGE_ABNORMAL) + { + gphi_iterator gsi; + for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); + gsi_next (&gsi)) + { + gphi *phi = gsi.phi (); + tree arg = PHI_ARG_DEF (phi, e->dest_idx); + if (SSA_NAME_IS_DEFAULT_DEF (arg) + && (!SSA_NAME_VAR (arg) + || TREE_CODE (SSA_NAME_VAR (arg)) != PARM_DECL)) + continue; + + tree res = PHI_RESULT (phi); + + int v1 = SSA_NAME_VERSION (res); + int v2 = SSA_NAME_VERSION (arg); + if (used_in_copies) + { + bitmap_set_bit (used_in_copies, v1); + bitmap_set_bit (used_in_copies, v2); + } + else + { + int p1 = var_to_partition (map, res); + int p2 = var_to_partition (map, arg); + if (p1 != p2) + { + if (ssa_conflicts_test_p (graph, p1, p2)) + fail_abnormal_edge_coalesce (v1, v2); + int z = var_union (map, + partition_to_var (map, p1), + partition_to_var (map, p2)); + if (z == p1) + ssa_conflicts_merge (graph, p1, p2); + else + ssa_conflicts_merge (graph, p2, p1); + } + } + } + } + } +} + +/* Verify that we can coalesce SSA names we must coalesce. */ + +DEBUG_FUNCTION void +verify_ssa_coalescing (void) +{ + auto_timevar tv (TV_TREE_SSA_VERIFY); + bitmap used_in_copies = BITMAP_ALLOC (NULL); + verify_ssa_coalescing_worker (used_in_copies, NULL, NULL); + if (bitmap_empty_p (used_in_copies)) + { + BITMAP_FREE (used_in_copies); + return; + } + var_map map = init_var_map (num_ssa_names); + partition_view_bitmap (map, used_in_copies, true); + BITMAP_FREE (used_in_copies); + tree_live_info_p liveinfo = calculate_live_ranges (map, false); + ssa_conflicts_p graph = build_ssa_conflict_graph (liveinfo); + delete_tree_live_info (liveinfo); + verify_ssa_coalescing_worker (NULL, map, graph); + ssa_conflicts_delete (graph); + delete_var_map (map); +} diff --git a/contrib/gcc-5.0/gcc/tree-ssa-coalesce.h b/contrib/gcc-5.0/gcc/tree-ssa-coalesce.h index 99b188a393..06c33bfc7e 100644 --- a/contrib/gcc-5.0/gcc/tree-ssa-coalesce.h +++ b/contrib/gcc-5.0/gcc/tree-ssa-coalesce.h @@ -21,5 +21,6 @@ along with GCC; see the file COPYING3. If not see #define GCC_TREE_SSA_COALESCE_H extern var_map coalesce_ssa_name (void); +extern void verify_ssa_coalescing (void); #endif /* GCC_TREE_SSA_COALESCE_H */ diff --git a/contrib/gcc-5.0/gcc/tree-ssa-dom.c b/contrib/gcc-5.0/gcc/tree-ssa-dom.c index d230ce1c7b..ea49eb7c3c 100644 --- a/contrib/gcc-5.0/gcc/tree-ssa-dom.c +++ b/contrib/gcc-5.0/gcc/tree-ssa-dom.c @@ -74,6 +74,7 @@ along with GCC; see the file COPYING3. If not see #include "tree-ssa-dom.h" #include "inchash.h" #include "gimplify.h" +#include "tree-cfgcleanup.h" /* This file implements optimizations on the dominator tree. */ @@ -246,6 +247,7 @@ static bool cfg_altered; /* Bitmap of blocks that have had EH statements cleaned. We should remove their dead edges eventually. */ static bitmap need_eh_cleanup; +static vec need_noreturn_fixup; /* Statistics for dominator optimizations. */ struct opt_stats_d @@ -885,6 +887,7 @@ pass_dominator::execute (function *fun) avail_exprs_stack.create (20); const_and_copies_stack.create (20); need_eh_cleanup = BITMAP_ALLOC (NULL); + need_noreturn_fixup.create (0); calculate_dominance_info (CDI_DOMINATORS); cfg_altered = false; @@ -967,6 +970,23 @@ pass_dominator::execute (function *fun) bitmap_clear (need_eh_cleanup); } + /* Fixup stmts that became noreturn calls. This may require splitting + blocks and thus isn't possible during the dominator walk or before + jump threading finished. Do this in reverse order so we don't + inadvertedly remove a stmt we want to fixup by visiting a dominating + now noreturn call first. */ + while (!need_noreturn_fixup.is_empty ()) + { + gimple stmt = need_noreturn_fixup.pop (); + if (dump_file && dump_flags & TDF_DETAILS) + { + fprintf (dump_file, "Fixing up noreturn call "); + print_gimple_stmt (dump_file, stmt, 0, 0); + fprintf (dump_file, "\n"); + } + fixup_noreturn_call (stmt); + } + statistics_counter_event (fun, "Redundant expressions eliminated", opt_stats.num_re); statistics_counter_event (fun, "Constants propagated", @@ -986,7 +1006,7 @@ pass_dominator::execute (function *fun) /* Free asserted bitmaps and stacks. */ BITMAP_FREE (need_eh_cleanup); - + need_noreturn_fixup.release (); avail_exprs_stack.release (); const_and_copies_stack.release (); @@ -2364,8 +2384,10 @@ optimize_stmt (basic_block bb, gimple_stmt_iterator si) gimple stmt, old_stmt; bool may_optimize_p; bool modified_p = false; + bool was_noreturn; old_stmt = stmt = gsi_stmt (si); + was_noreturn = is_gimple_call (stmt) && gimple_call_noreturn_p (stmt); if (dump_file && (dump_flags & TDF_DETAILS)) { @@ -2545,6 +2567,10 @@ optimize_stmt (basic_block bb, gimple_stmt_iterator si) if (dump_file && (dump_flags & TDF_DETAILS)) fprintf (dump_file, " Flagged to clear EH edges.\n"); } + + if (!was_noreturn + && is_gimple_call (stmt) && gimple_call_noreturn_p (stmt)) + need_noreturn_fixup.safe_push (stmt); } } diff --git a/contrib/gcc-5.0/gcc/tree-ssa-forwprop.c b/contrib/gcc-5.0/gcc/tree-ssa-forwprop.c index d8db20acd3..93f92f33a5 100644 --- a/contrib/gcc-5.0/gcc/tree-ssa-forwprop.c +++ b/contrib/gcc-5.0/gcc/tree-ssa-forwprop.c @@ -2141,6 +2141,7 @@ pass_forwprop::execute (function *fun) lattice.quick_grow_cleared (num_ssa_names); int *postorder = XNEWVEC (int, n_basic_blocks_for_fn (fun)); int postorder_num = inverted_post_order_compute (postorder); + auto_vec to_fixup; to_purge = BITMAP_ALLOC (NULL); for (int i = 0; i < postorder_num; ++i) { @@ -2340,6 +2341,8 @@ pass_forwprop::execute (function *fun) gimple stmt = gsi_stmt (gsi); gimple orig_stmt = stmt; bool changed = false; + bool was_noreturn = (is_gimple_call (stmt) + && gimple_call_noreturn_p (stmt)); /* Mark stmt as potentially needing revisiting. */ gimple_set_plf (stmt, GF_PLF_1, false); @@ -2350,6 +2353,9 @@ pass_forwprop::execute (function *fun) stmt = gsi_stmt (gsi); if (maybe_clean_or_replace_eh_stmt (orig_stmt, stmt)) bitmap_set_bit (to_purge, bb->index); + if (!was_noreturn + && is_gimple_call (stmt) && gimple_call_noreturn_p (stmt)) + to_fixup.safe_push (stmt); /* Cleanup the CFG if we simplified a condition to true or false. */ if (gcond *cond = dyn_cast (stmt)) @@ -2470,6 +2476,22 @@ pass_forwprop::execute (function *fun) free (postorder); lattice.release (); + /* Fixup stmts that became noreturn calls. This may require splitting + blocks and thus isn't possible during the walk. Do this + in reverse order so we don't inadvertedly remove a stmt we want to + fixup by visiting a dominating now noreturn call first. */ + while (!to_fixup.is_empty ()) + { + gimple stmt = to_fixup.pop (); + if (dump_file && dump_flags & TDF_DETAILS) + { + fprintf (dump_file, "Fixing up noreturn call "); + print_gimple_stmt (dump_file, stmt, 0, 0); + fprintf (dump_file, "\n"); + } + cfg_changed |= fixup_noreturn_call (stmt); + } + cfg_changed |= gimple_purge_all_dead_eh_edges (to_purge); BITMAP_FREE (to_purge); diff --git a/contrib/gcc-5.0/gcc/tree-ssa-pre.c b/contrib/gcc-5.0/gcc/tree-ssa-pre.c index 83b48df8b4..c985e79869 100644 --- a/contrib/gcc-5.0/gcc/tree-ssa-pre.c +++ b/contrib/gcc-5.0/gcc/tree-ssa-pre.c @@ -98,6 +98,7 @@ along with GCC; see the file COPYING3. If not see #include "ipa-prop.h" #include "tree-ssa-propagate.h" #include "ipa-utils.h" +#include "tree-cfgcleanup.h" /* TODO: @@ -3922,6 +3923,7 @@ compute_avail (void) /* Local state for the eliminate domwalk. */ static vec el_to_remove; +static vec el_to_fixup; static unsigned int el_todo; static vec el_avail; static vec el_avail_stack; @@ -4429,7 +4431,7 @@ eliminate_dom_walker::before_dom_children (basic_block b) /* When changing a call into a noreturn call, cfg cleanup is needed to fix up the noreturn call. */ if (!was_noreturn && gimple_call_noreturn_p (stmt)) - el_todo |= TODO_cleanup_cfg; + el_to_fixup.safe_push (stmt); } else { @@ -4529,6 +4531,7 @@ eliminate (bool do_pre) need_ab_cleanup = BITMAP_ALLOC (NULL); el_to_remove.create (0); + el_to_fixup.create (0); el_todo = 0; el_avail.create (num_ssa_names); el_avail_stack.create (0); @@ -4580,6 +4583,25 @@ eliminate (bool do_pre) } el_to_remove.release (); + /* Fixup stmts that became noreturn calls. This may require splitting + blocks and thus isn't possible during the dominator walk. Do this + in reverse order so we don't inadvertedly remove a stmt we want to + fixup by visiting a dominating now noreturn call first. */ + while (!el_to_fixup.is_empty ()) + { + stmt = el_to_fixup.pop (); + + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "Fixing up noreturn call "); + print_gimple_stmt (dump_file, stmt, 0, 0); + } + + if (fixup_noreturn_call (stmt)) + el_todo |= TODO_cleanup_cfg; + } + el_to_fixup.release (); + return el_todo; } diff --git a/contrib/gcc-5.0/gcc/tree-ssa-propagate.c b/contrib/gcc-5.0/gcc/tree-ssa-propagate.c index 8b82f9e208..c3f9d3e1cd 100644 --- a/contrib/gcc-5.0/gcc/tree-ssa-propagate.c +++ b/contrib/gcc-5.0/gcc/tree-ssa-propagate.c @@ -67,6 +67,7 @@ #include "value-prof.h" #include "domwalk.h" #include "cfgloop.h" +#include "tree-cfgcleanup.h" /* This file implements a generic value propagation engine based on the same propagation used by the SSA-CCP algorithm [1]. @@ -1071,11 +1072,13 @@ public: fold_fn (fold_fn_), do_dce (do_dce_), something_changed (false) { stmts_to_remove.create (0); + stmts_to_fixup.create (0); need_eh_cleanup = BITMAP_ALLOC (NULL); } ~substitute_and_fold_dom_walker () { stmts_to_remove.release (); + stmts_to_fixup.release (); BITMAP_FREE (need_eh_cleanup); } @@ -1087,6 +1090,7 @@ public: bool do_dce; bool something_changed; vec stmts_to_remove; + vec stmts_to_fixup; bitmap need_eh_cleanup; }; @@ -1125,7 +1129,6 @@ substitute_and_fold_dom_walker::before_dom_children (basic_block bb) { bool did_replace; gimple stmt = gsi_stmt (i); - gimple old_stmt; enum gimple_code code = gimple_code (stmt); /* Ignore ASSERT_EXPRs. They are used by VRP to generate @@ -1163,7 +1166,9 @@ substitute_and_fold_dom_walker::before_dom_children (basic_block bb) print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM); } - old_stmt = stmt; + gimple old_stmt = stmt; + bool was_noreturn = (is_gimple_call (stmt) + && gimple_call_noreturn_p (stmt)); /* Some statements may be simplified using propagator specific information. Do this before propagating @@ -1194,6 +1199,13 @@ substitute_and_fold_dom_walker::before_dom_children (basic_block bb) if (maybe_clean_or_replace_eh_stmt (old_stmt, stmt)) bitmap_set_bit (need_eh_cleanup, bb->index); + /* If we turned a not noreturn call into a noreturn one + schedule it for fixup. */ + if (!was_noreturn + && is_gimple_call (stmt) + && gimple_call_noreturn_p (stmt)) + stmts_to_fixup.safe_push (stmt); + if (is_gimple_assign (stmt) && (get_gimple_rhs_class (gimple_assign_rhs_code (stmt)) == GIMPLE_SINGLE_RHS)) @@ -1286,6 +1298,22 @@ substitute_and_fold (ssa_prop_get_value_fn get_value_fn, if (!bitmap_empty_p (walker.need_eh_cleanup)) gimple_purge_all_dead_eh_edges (walker.need_eh_cleanup); + /* Fixup stmts that became noreturn calls. This may require splitting + blocks and thus isn't possible during the dominator walk. Do this + in reverse order so we don't inadvertedly remove a stmt we want to + fixup by visiting a dominating now noreturn call first. */ + while (!walker.stmts_to_fixup.is_empty ()) + { + gimple stmt = walker.stmts_to_fixup.pop (); + if (dump_file && dump_flags & TDF_DETAILS) + { + fprintf (dump_file, "Fixing up noreturn call "); + print_gimple_stmt (dump_file, stmt, 0, 0); + fprintf (dump_file, "\n"); + } + fixup_noreturn_call (stmt); + } + statistics_counter_event (cfun, "Constants propagated", prop_stats.num_const_prop); statistics_counter_event (cfun, "Copies propagated", diff --git a/contrib/gcc-5.0/gcc/tree-ssa-tail-merge.c b/contrib/gcc-5.0/gcc/tree-ssa-tail-merge.c index 5d47813061..2c48cb619c 100644 --- a/contrib/gcc-5.0/gcc/tree-ssa-tail-merge.c +++ b/contrib/gcc-5.0/gcc/tree-ssa-tail-merge.c @@ -587,7 +587,7 @@ same_succ_def::equal (const value_type *e1, const compare_type *e2) if (!inverse_flags (e1, e2)) { for (i = 0; i < e1->succ_flags.length (); ++i) - if (e1->succ_flags[i] != e1->succ_flags[i]) + if (e1->succ_flags[i] != e2->succ_flags[i]) return 0; } diff --git a/contrib/gcc-5.0/gcc/tree-vect-data-refs.c b/contrib/gcc-5.0/gcc/tree-vect-data-refs.c index ffe83e2b2f..b308ac7ac6 100644 --- a/contrib/gcc-5.0/gcc/tree-vect-data-refs.c +++ b/contrib/gcc-5.0/gcc/tree-vect-data-refs.c @@ -758,12 +758,7 @@ vect_compute_data_ref_alignment (struct data_reference *dr) && TREE_CODE (TREE_OPERAND (base, 0)) == ADDR_EXPR) base = TREE_OPERAND (TREE_OPERAND (base, 0), 0); - /* Do not change the alignment of global variables here if - flag_section_anchors is enabled as we already generated - RTL for other functions. Most global variables should - have been aligned during the IPA increase_alignment pass. */ - if (!vect_can_force_dr_alignment_p (base, TYPE_ALIGN (vectype)) - || (TREE_STATIC (base) && flag_section_anchors)) + if (!vect_can_force_dr_alignment_p (base, TYPE_ALIGN (vectype))) { if (dump_enabled_p ()) { @@ -5703,58 +5698,10 @@ vect_can_force_dr_alignment_p (const_tree decl, unsigned int alignment) if (TREE_CODE (decl) != VAR_DECL) return false; - /* With -fno-toplevel-reorder we may have already output the constant. */ - if (TREE_ASM_WRITTEN (decl)) + if (decl_in_symtab_p (decl) + && !symtab_node::get (decl)->can_increase_alignment_p ()) return false; - /* Constant pool entries may be shared and not properly merged by LTO. */ - if (DECL_IN_CONSTANT_POOL (decl)) - return false; - - if (TREE_PUBLIC (decl) || DECL_EXTERNAL (decl)) - { - symtab_node *snode; - - /* We cannot change alignment of symbols that may bind to symbols - in other translation unit that may contain a definition with lower - alignment. */ - if (!decl_binds_to_current_def_p (decl)) - return false; - - /* When compiling partition, be sure the symbol is not output by other - partition. */ - snode = symtab_node::get (decl); - if (flag_ltrans - && (snode->in_other_partition - || snode->get_partitioning_class () == SYMBOL_DUPLICATE)) - return false; - } - - /* Do not override the alignment as specified by the ABI when the used - attribute is set. */ - if (DECL_PRESERVE_P (decl)) - return false; - - /* Do not override explicit alignment set by the user when an explicit - section name is also used. This is a common idiom used by many - software projects. */ - if (TREE_STATIC (decl) - && DECL_SECTION_NAME (decl) != NULL - && !symtab_node::get (decl)->implicit_section) - return false; - - /* If symbol is an alias, we need to check that target is OK. */ - if (TREE_STATIC (decl)) - { - tree target = symtab_node::get (decl)->ultimate_alias_target ()->decl; - if (target != decl) - { - if (DECL_PRESERVE_P (target)) - return false; - decl = target; - } - } - if (TREE_STATIC (decl)) return (alignment <= MAX_OFILE_ALIGNMENT); else diff --git a/contrib/gcc-5.0/gcc/tree-vect-stmts.c b/contrib/gcc-5.0/gcc/tree-vect-stmts.c index aa9d43f0fc..41ff80245e 100644 --- a/contrib/gcc-5.0/gcc/tree-vect-stmts.c +++ b/contrib/gcc-5.0/gcc/tree-vect-stmts.c @@ -4956,8 +4956,13 @@ ensure_base_align (stmt_vec_info stmt_info, struct data_reference *dr) tree vectype = STMT_VINFO_VECTYPE (stmt_info); tree base_decl = ((dataref_aux *)dr->aux)->base_decl; - DECL_ALIGN (base_decl) = TYPE_ALIGN (vectype); - DECL_USER_ALIGN (base_decl) = 1; + if (decl_in_symtab_p (base_decl)) + symtab_node::get (base_decl)->increase_alignment (TYPE_ALIGN (vectype)); + else + { + DECL_ALIGN (base_decl) = TYPE_ALIGN (vectype); + DECL_USER_ALIGN (base_decl) = 1; + } ((dataref_aux *)dr->aux)->base_misaligned = false; } } diff --git a/contrib/gcc-5.0/gcc/tree-vectorizer.c b/contrib/gcc-5.0/gcc/tree-vectorizer.c index 5d43720a37..415bffa14d 100644 --- a/contrib/gcc-5.0/gcc/tree-vectorizer.c +++ b/contrib/gcc-5.0/gcc/tree-vectorizer.c @@ -719,14 +719,7 @@ increase_alignment (void) if (vect_can_force_dr_alignment_p (decl, alignment)) { - DECL_ALIGN (decl) = TYPE_ALIGN (vectype); - DECL_USER_ALIGN (decl) = 1; - if (TREE_STATIC (decl)) - { - tree target = symtab_node::get (decl)->ultimate_alias_target ()->decl; - DECL_ALIGN (target) = TYPE_ALIGN (vectype); - DECL_USER_ALIGN (target) = 1; - } + vnode->increase_alignment (TYPE_ALIGN (vectype)); dump_printf (MSG_NOTE, "Increasing alignment of decl: "); dump_generic_expr (MSG_NOTE, TDF_SLIM, decl); dump_printf (MSG_NOTE, "\n"); diff --git a/contrib/gcc-5.0/gcc/tree.h b/contrib/gcc-5.0/gcc/tree.h index 8f93a512a7..4fcc272c75 100644 --- a/contrib/gcc-5.0/gcc/tree.h +++ b/contrib/gcc-5.0/gcc/tree.h @@ -4470,7 +4470,8 @@ extern tree block_ultimate_origin (const_tree); extern tree get_binfo_at_offset (tree, HOST_WIDE_INT, tree); extern bool virtual_method_call_p (tree); extern tree obj_type_ref_class (tree ref); -extern bool types_same_for_odr (const_tree type1, const_tree type2); +extern bool types_same_for_odr (const_tree type1, const_tree type2, + bool strict=false); extern bool contains_bitfld_component_ref_p (const_tree); extern bool type_in_anonymous_namespace_p (const_tree); extern bool block_may_fallthru (const_tree); diff --git a/contrib/gcc-5.0/gcc/ubsan.c b/contrib/gcc-5.0/gcc/ubsan.c index 38d98cfd4e..0e23d91974 100644 --- a/contrib/gcc-5.0/gcc/ubsan.c +++ b/contrib/gcc-5.0/gcc/ubsan.c @@ -864,6 +864,7 @@ ubsan_expand_null_ifn (gimple_stmt_iterator *gsip) /* Replace the UBSAN_NULL with a GIMPLE_COND stmt. */ gsi_replace (&gsi, g, false); + stmt = g; } if (check_align) @@ -1022,11 +1023,16 @@ ubsan_expand_objsize_ifn (gimple_stmt_iterator *gsi) /* Point GSI to next logical statement. */ *gsi = gsi_start_bb (fallthru_bb); + + /* Get rid of the UBSAN_OBJECT_SIZE call from the IR. */ + unlink_stmt_vdef (stmt); + gsi_remove (&gsi_orig, true); + return true; } /* Get rid of the UBSAN_OBJECT_SIZE call from the IR. */ unlink_stmt_vdef (stmt); - gsi_remove (&gsi_orig, true); + gsi_remove (gsi, true); return true; } diff --git a/contrib/gcc-5.0/gcc/var-tracking.c b/contrib/gcc-5.0/gcc/var-tracking.c index 9ec5d8bcf8..da4c61e7d5 100644 --- a/contrib/gcc-5.0/gcc/var-tracking.c +++ b/contrib/gcc-5.0/gcc/var-tracking.c @@ -1011,7 +1011,13 @@ use_narrower_mode (rtx x, machine_mode mode, machine_mode wmode) return simplify_gen_binary (GET_CODE (x), mode, op0, op1); case ASHIFT: op0 = use_narrower_mode (XEXP (x, 0), mode, wmode); - return simplify_gen_binary (ASHIFT, mode, op0, XEXP (x, 1)); + op1 = XEXP (x, 1); + /* Ensure shift amount is not wider than mode. */ + if (GET_MODE (op1) == VOIDmode) + op1 = lowpart_subreg (mode, op1, wmode); + else if (GET_MODE_PRECISION (mode) < GET_MODE_PRECISION (GET_MODE (op1))) + op1 = lowpart_subreg (mode, op1, GET_MODE (op1)); + return simplify_gen_binary (ASHIFT, mode, op0, op1); default: gcc_unreachable (); } diff --git a/contrib/gcc-5.0/gcc/varasm.c b/contrib/gcc-5.0/gcc/varasm.c index 8173207b49..752dccf935 100644 --- a/contrib/gcc-5.0/gcc/varasm.c +++ b/contrib/gcc-5.0/gcc/varasm.c @@ -659,7 +659,7 @@ function_section_1 (tree decl, bool force_cold) else return targetm.asm_out.select_section (decl, freq == NODE_FREQUENCY_UNLIKELY_EXECUTED, - DECL_ALIGN (decl)); + symtab_node::get (decl)->definition_alignment ()); #else if (targetm.asm_out.function_section) section = targetm.asm_out.function_section (decl, freq, startup, exit); @@ -1630,35 +1630,30 @@ default_ctor_section_asm_out_constructor (rtx symbol, void notice_global_symbol (tree decl) { - const char **type = &first_global_object_name; + const char **t = &first_global_object_name; if (first_global_object_name || !TREE_PUBLIC (decl) || DECL_EXTERNAL (decl) || !DECL_NAME (decl) + || (TREE_CODE (decl) == VAR_DECL && DECL_HARD_REGISTER (decl)) || (TREE_CODE (decl) != FUNCTION_DECL && (TREE_CODE (decl) != VAR_DECL || (DECL_COMMON (decl) && (DECL_INITIAL (decl) == 0 - || DECL_INITIAL (decl) == error_mark_node)))) - || !MEM_P (DECL_RTL (decl))) + || DECL_INITIAL (decl) == error_mark_node))))) return; /* We win when global object is found, but it is useful to know about weak symbol as well so we can produce nicer unique names. */ if (DECL_WEAK (decl) || DECL_ONE_ONLY (decl) || flag_shlib) - type = &weak_global_object_name; + t = &weak_global_object_name; - if (!*type) + if (!*t) { - const char *p; - const char *name; - rtx decl_rtl = DECL_RTL (decl); - - p = targetm.strip_name_encoding (XSTR (XEXP (decl_rtl, 0), 0)); - name = ggc_strdup (p); - - *type = name; + tree id = DECL_ASSEMBLER_NAME (decl); + ultimate_transparent_alias_target (&id); + *t = ggc_strdup (targetm.strip_name_encoding (IDENTIFIER_POINTER (id))); } } @@ -1740,6 +1735,8 @@ assemble_start_function (tree decl, const char *fnname) if (CONSTANT_POOL_BEFORE_FUNCTION) output_constant_pool (fnname, decl); + align = symtab_node::get (decl)->definition_alignment (); + /* Make sure the not and cold text (code) sections are properly aligned. This is necessary here in the case where the function has both hot and cold sections, because we don't want to re-set @@ -1750,7 +1747,7 @@ assemble_start_function (tree decl, const char *fnname) first_function_block_is_cold = false; switch_to_section (unlikely_text_section ()); - assemble_align (DECL_ALIGN (decl)); + assemble_align (align); ASM_OUTPUT_LABEL (asm_out_file, crtl->subsections.cold_section_label); /* When the function starts with a cold section, we need to explicitly @@ -1760,7 +1757,7 @@ assemble_start_function (tree decl, const char *fnname) && BB_PARTITION (ENTRY_BLOCK_PTR_FOR_FN (cfun)->next_bb) == BB_COLD_PARTITION) { switch_to_section (text_section); - assemble_align (DECL_ALIGN (decl)); + assemble_align (align); ASM_OUTPUT_LABEL (asm_out_file, crtl->subsections.hot_section_label); hot_label_written = true; first_function_block_is_cold = true; @@ -1777,7 +1774,7 @@ assemble_start_function (tree decl, const char *fnname) ASM_OUTPUT_LABEL (asm_out_file, crtl->subsections.hot_section_label); /* Tell assembler to move to target machine's alignment for functions. */ - align = floor_log2 (DECL_ALIGN (decl) / BITS_PER_UNIT); + align = floor_log2 (align / BITS_PER_UNIT); if (align > 0) { ASM_OUTPUT_ALIGN (asm_out_file, align); @@ -1931,17 +1928,18 @@ assemble_string (const char *p, int size) /* A noswitch_section_callback for lcomm_section. */ static bool -emit_local (tree decl ATTRIBUTE_UNUSED, +emit_local (tree decl, const char *name ATTRIBUTE_UNUSED, unsigned HOST_WIDE_INT size ATTRIBUTE_UNUSED, unsigned HOST_WIDE_INT rounded ATTRIBUTE_UNUSED) { + int align = symtab_node::get (decl)->definition_alignment (); #if defined ASM_OUTPUT_ALIGNED_DECL_LOCAL ASM_OUTPUT_ALIGNED_DECL_LOCAL (asm_out_file, decl, name, - size, DECL_ALIGN (decl)); + size, align); return true; #elif defined ASM_OUTPUT_ALIGNED_LOCAL - ASM_OUTPUT_ALIGNED_LOCAL (asm_out_file, name, size, DECL_ALIGN (decl)); + ASM_OUTPUT_ALIGNED_LOCAL (asm_out_file, name, size, align); return true; #else ASM_OUTPUT_LOCAL (asm_out_file, name, size, rounded); @@ -3295,7 +3293,12 @@ build_constant_desc (tree exp) /* Now construct the SYMBOL_REF and the MEM. */ if (use_object_blocks_p ()) { - section *sect = get_constant_section (exp, DECL_ALIGN (decl)); + int align = (TREE_CODE (decl) == CONST_DECL + || (TREE_CODE (decl) == VAR_DECL + && DECL_IN_CONSTANT_POOL (decl)) + ? DECL_ALIGN (decl) + : symtab_node::get (decl)->definition_alignment ()); + section *sect = get_constant_section (exp, align); symbol = create_block_symbol (ggc_strdup (label), get_block_for_section (sect), -1); } @@ -3423,7 +3426,6 @@ output_constant_def_contents (rtx symbol) { tree decl = SYMBOL_REF_DECL (symbol); tree exp = DECL_INITIAL (decl); - unsigned int align; bool asan_protected = false; /* Make sure any other constants whose addresses appear in EXP @@ -3449,7 +3451,11 @@ output_constant_def_contents (rtx symbol) place_block_symbol (symbol); else { - align = DECL_ALIGN (decl); + int align = (TREE_CODE (decl) == CONST_DECL + || (TREE_CODE (decl) == VAR_DECL + && DECL_IN_CONSTANT_POOL (decl)) + ? DECL_ALIGN (decl) + : symtab_node::get (decl)->definition_alignment ()); switch_to_section (get_constant_section (exp, align)); if (align > BITS_PER_UNIT) ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT)); @@ -7159,6 +7165,7 @@ place_block_symbol (rtx symbol) else if (TREE_CONSTANT_POOL_ADDRESS_P (symbol)) { decl = SYMBOL_REF_DECL (symbol); + gcc_checking_assert (DECL_IN_CONSTANT_POOL (decl)); alignment = DECL_ALIGN (decl); size = get_constant_size (DECL_INITIAL (decl)); if ((flag_sanitize & SANITIZE_ADDRESS) @@ -7333,8 +7340,9 @@ output_object_block (struct object_block *block) { HOST_WIDE_INT size; decl = SYMBOL_REF_DECL (symbol); - assemble_constant_contents (DECL_INITIAL (decl), XSTR (symbol, 0), - DECL_ALIGN (decl)); + assemble_constant_contents + (DECL_INITIAL (decl), XSTR (symbol, 0), DECL_ALIGN (decl)); + size = get_constant_size (DECL_INITIAL (decl)); offset += size; if ((flag_sanitize & SANITIZE_ADDRESS) diff --git a/contrib/gcc-5.0/gcc/varpool.c b/contrib/gcc-5.0/gcc/varpool.c index 707f62f0d8..ce6427956d 100644 --- a/contrib/gcc-5.0/gcc/varpool.c +++ b/contrib/gcc-5.0/gcc/varpool.c @@ -173,7 +173,7 @@ varpool_node::get_create (tree decl) node = varpool_node::create_empty (); node->decl = decl; - if ((flag_openacc || flag_openmp) + if ((flag_openacc || flag_openmp) && !DECL_EXTERNAL (decl) && lookup_attribute ("omp declare target", DECL_ATTRIBUTES (decl))) { node->offloadable = 1; @@ -195,6 +195,11 @@ void varpool_node::remove (void) { symtab->call_varpool_removal_hooks (this); + if (lto_file_data) + { + lto_free_function_in_decl_state_for_node (this); + lto_file_data = NULL; + } /* When streaming we can have multiple nodes associated with decl. */ if (symtab->state == LTO_STREAMING) @@ -323,6 +328,7 @@ varpool_node::get_constructor (void) name); lto_input_variable_constructor (file_data, this, data); + gcc_assert (DECL_INITIAL (decl) != error_mark_node); lto_stats.num_function_bodies++; lto_free_section_data (file_data, LTO_section_function_body, name, data, len); diff --git a/contrib/gcc-5.0/libstdc++-v3/include/bits/regex.h b/contrib/gcc-5.0/libstdc++-v3/include/bits/regex.h index 2b09da696f..a23c2c9b3c 100644 --- a/contrib/gcc-5.0/libstdc++-v3/include/bits/regex.h +++ b/contrib/gcc-5.0/libstdc++-v3/include/bits/regex.h @@ -1483,17 +1483,6 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 // [7.10] Class template match_results - /* - * Special sub_match object representing an unmatched sub-expression. - */ - template - inline const sub_match<_Bi_iter>& - __unmatched_sub() - { - static const sub_match<_Bi_iter> __unmatched = sub_match<_Bi_iter>(); - return __unmatched; - } - /** * @brief The results of a match or search operation. * @@ -1523,15 +1512,20 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 { private: /* - * The vector base is empty if this does not represent a successful match. - * Otherwise it contains n+3 elements where n is the number of marked + * The vector base is empty if this does not represent a match (!ready()); + * Otherwise if it's a match failure, it contains 3 elements: + * [0] unmatched + * [1] prefix + * [2] suffix + * Otherwise it contains n+4 elements where n is the number of marked * sub-expressions: * [0] entire match * [1] 1st marked subexpression * ... * [n] nth marked subexpression - * [n+1] prefix - * [n+2] suffix + * [n+1] unmatched + * [n+2] prefix + * [n+3] suffix */ typedef std::vector, _Alloc> _Base_type; typedef std::iterator_traits<_Bi_iter> __iter_traits; @@ -1623,10 +1617,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 */ size_type size() const - { - size_type __size = _Base_type::size(); - return (__size && _Base_type::operator[](0).matched) ? __size - 2 : 0; - } + { return _Base_type::empty() ? 0 : _Base_type::size() - 3; } size_type max_size() const @@ -1670,15 +1661,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 * is zero (the default), in which case this function returns the offset * from the beginning of the target sequence to the beginning of the * match. - * - * Returns -1 if @p __sub is out of range. */ difference_type position(size_type __sub = 0) const - { - return __sub < size() ? std::distance(_M_begin, - (*this)[__sub].first) : -1; - } + { return std::distance(_M_begin, (*this)[__sub].first); } /** * @brief Gets the match or submatch converted to a string type. @@ -1691,7 +1677,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 */ string_type str(size_type __sub = 0) const - { return (*this)[__sub].str(); } + { return string_type((*this)[__sub]); } /** * @brief Gets a %sub_match reference for the match or submatch. @@ -1707,10 +1693,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 const_reference operator[](size_type __sub) const { - _GLIBCXX_DEBUG_ASSERT( ready() ); - return __sub < size() - ? _Base_type::operator[](__sub) - : __unmatched_sub<_Bi_iter>(); + _GLIBCXX_DEBUG_ASSERT( ready() ); + return __sub < size() + ? _Base_type::operator[](__sub) + : _M_unmatched_sub(); } /** @@ -1724,10 +1710,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 const_reference prefix() const { - _GLIBCXX_DEBUG_ASSERT( ready() ); - return !empty() - ? _Base_type::operator[](_Base_type::size() - 2) - : __unmatched_sub<_Bi_iter>(); + _GLIBCXX_DEBUG_ASSERT( ready() ); + return !empty() ? _M_prefix() : _M_unmatched_sub(); } /** @@ -1742,9 +1726,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 suffix() const { _GLIBCXX_DEBUG_ASSERT( ready() ); - return !empty() - ? _Base_type::operator[](_Base_type::size() - 1) - : __unmatched_sub<_Bi_iter>(); + return !empty() ? _M_suffix() : _M_unmatched_sub(); } /** @@ -1766,7 +1748,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 */ const_iterator end() const - { return _Base_type::end() - 2; } + { return _Base_type::end() - 3; } /** * @brief Gets an iterator to one-past-the-end of the collection. @@ -1883,6 +1865,34 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 const basic_regex<_Cp, _Rp>&, regex_constants::match_flag_type); + void + _M_resize(unsigned int __size) + { _Base_type::resize(__size + 3); } + + const_reference + _M_unmatched_sub() const + { return _Base_type::operator[](_Base_type::size() - 3); } + + sub_match<_Bi_iter>& + _M_unmatched_sub() + { return _Base_type::operator[](_Base_type::size() - 3); } + + const_reference + _M_prefix() const + { return _Base_type::operator[](_Base_type::size() - 2); } + + sub_match<_Bi_iter>& + _M_prefix() + { return _Base_type::operator[](_Base_type::size() - 2); } + + const_reference + _M_suffix() const + { return _Base_type::operator[](_Base_type::size() - 1); } + + sub_match<_Bi_iter>& + _M_suffix() + { return _Base_type::operator[](_Base_type::size() - 1); } + _Bi_iter _M_begin; }; diff --git a/contrib/gcc-5.0/libstdc++-v3/include/bits/regex.tcc b/contrib/gcc-5.0/libstdc++-v3/include/bits/regex.tcc index aad56e08c8..823ad51c3e 100644 --- a/contrib/gcc-5.0/libstdc++-v3/include/bits/regex.tcc +++ b/contrib/gcc-5.0/libstdc++-v3/include/bits/regex.tcc @@ -63,7 +63,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION typename match_results<_BiIter, _Alloc>::_Base_type& __res = __m; __m._M_begin = __s; - __res.resize(__re._M_automaton->_M_sub_count() + 2); + __m._M_resize(__re._M_automaton->_M_sub_count()); for (auto& __it : __res) __it.matched = false; @@ -99,8 +99,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION for (auto& __it : __res) if (!__it.matched) __it.first = __it.second = __e; - auto& __pre = __res[__res.size()-2]; - auto& __suf = __res[__res.size()-1]; + auto& __pre = __m._M_prefix(); + auto& __suf = __m._M_suffix(); if (__match_mode) { __pre.matched = false; @@ -120,6 +120,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __suf.matched = (__suf.first != __suf.second); } } + else + { + __m._M_resize(0); + for (auto& __it : __res) + { + __it.matched = false; + __it.first = __it.second = __e; + } + } return __ret; } @@ -374,7 +383,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION auto __output = [&](size_t __idx) { - auto& __sub = _Base_type::operator[](__idx); + auto& __sub = (*this)[__idx]; if (__sub.matched) __out = std::copy(__sub.first, __sub.second, __out); }; @@ -425,9 +434,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION else if (__eat('&')) __output(0); else if (__eat('`')) - __output(_Base_type::size()-2); + { + auto& __sub = _M_prefix(); + if (__sub.matched) + __out = std::copy(__sub.first, __sub.second, __out); + } else if (__eat('\'')) - __output(_Base_type::size()-1); + { + auto& __sub = _M_suffix(); + if (__sub.matched) + __out = std::copy(__sub.first, __sub.second, __out); + } else if (__fctyp.is(__ctype_type::digit, *__next)) { long __num = __traits.value(*__next, 10); @@ -532,7 +549,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION | regex_constants::match_continuous)) { _GLIBCXX_DEBUG_ASSERT(_M_match[0].matched); - auto& __prefix = _M_match.at(_M_match.size()); + auto& __prefix = _M_match._M_prefix(); __prefix.first = __prefix_first; __prefix.matched = __prefix.first != __prefix.second; // [28.12.1.4.5] @@ -547,7 +564,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION if (regex_search(__start, _M_end, _M_match, *_M_pregex, _M_flags)) { _GLIBCXX_DEBUG_ASSERT(_M_match[0].matched); - auto& __prefix = _M_match.at(_M_match.size()); + auto& __prefix = _M_match._M_prefix(); __prefix.first = __prefix_first; __prefix.matched = __prefix.first != __prefix.second; // [28.12.1.4.5] diff --git a/contrib/gcc-5.0/libstdc++-v3/include/experimental/system_error b/contrib/gcc-5.0/libstdc++-v3/include/experimental/system_error index 5c49ac751d..ba3f8befd8 100644 --- a/contrib/gcc-5.0/libstdc++-v3/include/experimental/system_error +++ b/contrib/gcc-5.0/libstdc++-v3/include/experimental/system_error @@ -31,7 +31,7 @@ // #ifndef _GLIBCXX_EXPERIMENTAL_SYSTEM_ERROR -#define _GLIBCXX_EXPERIMENTAL_CHRONO 1 +#define _GLIBCXX_EXPERIMENTAL_SYSTEM_ERROR 1 #pragma GCC system_header -- 2.41.0