From: John Marino Date: Sun, 8 Mar 2015 08:16:16 +0000 (+0100) Subject: Update gcc-50 to SVN version 221261 X-Git-Tag: v4.2.0rc~647^2 X-Git-Url: https://gitweb.dragonflybsd.org/dragonfly.git/commitdiff_plain/7de7a9db1fcc34bb0d65b6aa985e0b973bd681b5 Update gcc-50 to SVN version 221261 Last Changed Date: 2015-03-08 01:16:18 +0100 (Sun, 08 Mar 2015) --- diff --git a/contrib/gcc-5.0/LAST_UPDATED b/contrib/gcc-5.0/LAST_UPDATED index 738c0468f7..3a6f495175 100644 --- a/contrib/gcc-5.0/LAST_UPDATED +++ b/contrib/gcc-5.0/LAST_UPDATED @@ -1,2 +1,2 @@ -221044 -Last Changed Date: 2015-02-27 09:37:51 +0100 (Fri, 27 Feb 2015) +221261 +Last Changed Date: 2015-03-08 01:16:18 +0100 (Sun, 08 Mar 2015) diff --git a/contrib/gcc-5.0/gcc/DATESTAMP b/contrib/gcc-5.0/gcc/DATESTAMP index 2826df1756..0b9fb17858 100644 --- a/contrib/gcc-5.0/gcc/DATESTAMP +++ b/contrib/gcc-5.0/gcc/DATESTAMP @@ -1 +1 @@ -20150227 +20150308 diff --git a/contrib/gcc-5.0/gcc/builtins.c b/contrib/gcc-5.0/gcc/builtins.c index fb871e696a..92637771ea 100644 --- a/contrib/gcc-5.0/gcc/builtins.c +++ b/contrib/gcc-5.0/gcc/builtins.c @@ -802,10 +802,8 @@ expand_builtin_return_addr (enum built_in_function fndecl_code, int count) register. There is no way to access it off of the current frame pointer, but it can be accessed off the previous frame pointer by reading the value from the register window save area. */ -#ifdef RETURN_ADDR_IN_PREVIOUS_FRAME - if (fndecl_code == BUILT_IN_RETURN_ADDRESS) + if (RETURN_ADDR_IN_PREVIOUS_FRAME && fndecl_code == BUILT_IN_RETURN_ADDRESS) count--; -#endif /* Scan back COUNT frames to the specified frame. */ for (i = 0; i < count; i++) diff --git a/contrib/gcc-5.0/gcc/c-family/c-ada-spec.c b/contrib/gcc-5.0/gcc/c-family/c-ada-spec.c index 945fa7cdb3..fcd27037d5 100644 --- a/contrib/gcc-5.0/gcc/c-family/c-ada-spec.c +++ b/contrib/gcc-5.0/gcc/c-family/c-ada-spec.c @@ -961,7 +961,7 @@ is_tagged_type (const_tree type) return false; for (tmp = TYPE_METHODS (type); tmp; tmp = TREE_CHAIN (tmp)) - if (DECL_VINDEX (tmp)) + if (TREE_CODE (tmp) == FUNCTION_DECL && DECL_VINDEX (tmp)) return true; return false; @@ -1390,7 +1390,7 @@ dump_ada_double_name (pretty_printer *buffer, tree t1, tree t2, const char *s) pp_underscore (buffer); - if (DECL_NAME (t1)) + if (DECL_NAME (t2)) pp_ada_tree_identifier (buffer, DECL_NAME (t2), t2, false); else { @@ -1730,10 +1730,15 @@ dump_template_types (pretty_printer *buffer, tree types, int spc) static int dump_ada_template (pretty_printer *buffer, tree t, int spc) { - /* DECL_VINDEX is DECL_TEMPLATE_INSTANTIATIONS in this context. */ - tree inst = DECL_VINDEX (t); - /* DECL_RESULT_FLD is DECL_TEMPLATE_RESULT in this context. */ - tree result = DECL_RESULT_FLD (t); + /* DECL_SIZE_UNIT is DECL_TEMPLATE_INSTANTIATIONS in this context. */ + tree inst = DECL_SIZE_UNIT (t); + /* This emulates DECL_TEMPLATE_RESULT in this context. */ + struct tree_template_decl { + struct tree_decl_common common; + tree arguments; + tree result; + }; + tree result = ((struct tree_template_decl *) t)->result; int num_inst = 0; /* Don't look at template declarations declaring something coming from @@ -1750,7 +1755,7 @@ dump_ada_template (pretty_printer *buffer, tree t, int spc) if (TREE_VEC_LENGTH (types) == 0) break; - if (!TYPE_P (instance) || !TYPE_METHODS (instance)) + if (!RECORD_OR_UNION_TYPE_P (instance) || !TYPE_METHODS (instance)) break; num_inst++; @@ -2536,18 +2541,9 @@ static void print_destructor (pretty_printer *buffer, tree t) { tree decl_name = DECL_NAME (DECL_ORIGIN (t)); - const char *s = IDENTIFIER_POINTER (decl_name); - if (*s == '_') - { - for (s += 2; *s != ' '; s++) - pp_character (buffer, *s); - } - else - { - pp_string (buffer, "Delete_"); - pp_ada_tree_identifier (buffer, decl_name, t, false); - } + pp_string (buffer, "Delete_"); + pp_ada_tree_identifier (buffer, decl_name, t, false); } /* Return the name of type T. */ diff --git a/contrib/gcc-5.0/gcc/c-family/c-pragma.c b/contrib/gcc-5.0/gcc/c-family/c-pragma.c index 718a310cf5..6894f0e7c3 100644 --- a/contrib/gcc-5.0/gcc/c-family/c-pragma.c +++ b/contrib/gcc-5.0/gcc/c-family/c-pragma.c @@ -392,6 +392,9 @@ handle_pragma_weak (cpp_reader * ARG_UNUSED (dummy)) decl = identifier_global_value (name); if (decl && DECL_P (decl)) { + if (!VAR_OR_FUNCTION_DECL_P (decl)) + GCC_BAD2 ("%<#pragma weak%> declaration of %q+D not allowed," + " ignored", decl); apply_pragma_weak (decl, value); if (value) { diff --git a/contrib/gcc-5.0/gcc/c-family/c-ubsan.c b/contrib/gcc-5.0/gcc/c-family/c-ubsan.c index 90d59c03a1..a14426f962 100644 --- a/contrib/gcc-5.0/gcc/c-family/c-ubsan.c +++ b/contrib/gcc-5.0/gcc/c-family/c-ubsan.c @@ -303,8 +303,9 @@ ubsan_instrument_bounds (location_t loc, tree array, tree *index, /* Detect flexible array members and suchlike. */ tree base = get_base_address (array); - if (base && (TREE_CODE (base) == INDIRECT_REF - || TREE_CODE (base) == MEM_REF)) + if (TREE_CODE (array) == COMPONENT_REF + && base && (TREE_CODE (base) == INDIRECT_REF + || TREE_CODE (base) == MEM_REF)) { tree next = NULL_TREE; tree cref = array; diff --git a/contrib/gcc-5.0/gcc/c-family/c.opt b/contrib/gcc-5.0/gcc/c-family/c.opt index fd00407251..b3c8ceedd2 100644 --- a/contrib/gcc-5.0/gcc/c-family/c.opt +++ b/contrib/gcc-5.0/gcc/c-family/c.opt @@ -456,7 +456,7 @@ C ObjC C++ ObjC++ Var(warn_format_security) Warning LangEnabledBy(C ObjC C++ Obj Warn about possible security problems with format functions Wformat-signedness -C ObjC C++ ObjC++ Var(warn_format_signedness) Warning LangEnabledBy(C ObjC C++ ObjC++,Wformat=, warn_format >= 2, 0) +C ObjC C++ ObjC++ Var(warn_format_signedness) Warning Warn about sign differences with format functions Wformat-y2k diff --git a/contrib/gcc-5.0/gcc/c/c-decl.c b/contrib/gcc-5.0/gcc/c/c-decl.c index 8eeee9c53d..749785801e 100644 --- a/contrib/gcc-5.0/gcc/c/c-decl.c +++ b/contrib/gcc-5.0/gcc/c/c-decl.c @@ -4460,8 +4460,8 @@ start_decl (struct c_declarator *declarator, struct c_declspecs *declspecs, decl = grokdeclarator (declarator, declspecs, NORMAL, initialized, NULL, &attributes, &expr, NULL, deprecated_state); - if (!decl) - return 0; + if (!decl || decl == error_mark_node) + return NULL_TREE; if (expr) add_stmt (fold_convert (void_type_node, expr)); diff --git a/contrib/gcc-5.0/gcc/cfgexpand.c b/contrib/gcc-5.0/gcc/cfgexpand.c index 7dfe1f6e7f..569cd0d239 100644 --- a/contrib/gcc-5.0/gcc/cfgexpand.c +++ b/contrib/gcc-5.0/gcc/cfgexpand.c @@ -973,6 +973,13 @@ expand_stack_vars (bool (*pred) (size_t), struct stack_vars_data *data) i = stack_vars_sorted[si]; alignb = stack_vars[i].alignb; + /* All "large" alignment decls come before all "small" alignment + decls, but "large" alignment decls are not sorted based on + their alignment. Increase large_align to track the largest + required alignment. */ + if ((alignb * BITS_PER_UNIT) > large_align) + large_align = alignb * BITS_PER_UNIT; + /* Stop when we get to the first decl with "small" alignment. */ if (alignb * BITS_PER_UNIT <= MAX_SUPPORTED_STACK_ALIGNMENT) break; diff --git a/contrib/gcc-5.0/gcc/cgraph.c b/contrib/gcc-5.0/gcc/cgraph.c index 5555439215..b2109bd517 100644 --- a/contrib/gcc-5.0/gcc/cgraph.c +++ b/contrib/gcc-5.0/gcc/cgraph.c @@ -2411,18 +2411,57 @@ nonremovable_p (cgraph_node *node, void *) return !node->can_remove_if_no_direct_calls_and_refs_p (); } -/* Return true when function cgraph_node and its aliases can be removed from - callgraph if all direct calls are eliminated. */ +/* Return true if whole comdat group can be removed if there are no direct + calls to THIS. */ bool cgraph_node::can_remove_if_no_direct_calls_p (void) { - /* Extern inlines can always go, we will use the external definition. */ - if (DECL_EXTERNAL (decl)) - return true; - if (address_taken) + struct ipa_ref *ref; + + /* For local symbols or non-comdat group it is the same as + can_remove_if_no_direct_calls_p. */ + if (!externally_visible || !same_comdat_group) + { + if (DECL_EXTERNAL (decl)) + return true; + if (address_taken) + return false; + return !call_for_symbol_and_aliases (nonremovable_p, NULL, true); + } + + /* 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. */ + if (!can_remove_if_no_direct_calls_and_refs_p ()) return false; - return !call_for_symbol_and_aliases (nonremovable_p, NULL, true); + + /* Check that all refs come from within the comdat group. */ + for (int i = 0; iterate_referring (i, ref); i++) + if (ref->referring->get_comdat_group () != get_comdat_group ()) + return false; + + struct cgraph_node *target = ultimate_alias_target (); + for (cgraph_node *next = dyn_cast (same_comdat_group); + next != this; next = dyn_cast (next->same_comdat_group)) + { + if (!externally_visible) + continue; + if (!next->alias + && !next->can_remove_if_no_direct_calls_and_refs_p ()) + return false; + + /* 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 ()) + 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; } /* Return true when function cgraph_node can be expected to be removed @@ -2442,19 +2481,47 @@ cgraph_node::can_remove_if_no_direct_calls_p (void) bool cgraph_node::will_be_removed_from_program_if_no_direct_calls_p (void) { + struct ipa_ref *ref; gcc_assert (!global.inlined_to); + if (DECL_EXTERNAL (decl)) + return true; - if (call_for_symbol_and_aliases (used_from_object_file_p_worker, - NULL, true)) - return false; if (!in_lto_p && !flag_whole_program) - return only_called_directly_p (); - else { - if (DECL_EXTERNAL (decl)) - return true; - return can_remove_if_no_direct_calls_p (); + /* If the symbol is in comdat group, we need to verify that whole comdat + group becomes unreachable. Technically we could skip references from + within the group, too. */ + if (!only_called_directly_p ()) + return false; + if (same_comdat_group && externally_visible) + { + struct cgraph_node *target = ultimate_alias_target (); + for (cgraph_node *next = dyn_cast (same_comdat_group); + next != this; + next = dyn_cast (next->same_comdat_group)) + { + if (!externally_visible) + continue; + if (!next->alias + && !next->only_called_directly_p ()) + return false; + + /* 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 ()) + 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 (); } @@ -3325,4 +3392,16 @@ cgraph_node::call_for_symbol_and_aliases_1 (bool (*callback) (cgraph_node *, } return false; } + +/* Return true if NODE has thunk. */ + +bool +cgraph_node::has_thunk_p (cgraph_node *node, void *) +{ + for (cgraph_edge *e = node->callers; e; e = e->next_caller) + if (e->caller->thunk.thunk_p) + return true; + return false; +} + #include "gt-cgraph.h" diff --git a/contrib/gcc-5.0/gcc/cgraph.h b/contrib/gcc-5.0/gcc/cgraph.h index ff437cf18b..c4f39bab4e 100644 --- a/contrib/gcc-5.0/gcc/cgraph.h +++ b/contrib/gcc-5.0/gcc/cgraph.h @@ -258,8 +258,8 @@ public: When INCLUDE_OVERWRITABLE is false, overwritable aliases and thunks are skipped. */ bool call_for_symbol_and_aliases (bool (*callback) (symtab_node *, void *), - void *data, - bool include_overwrite); + void *data, + bool include_overwrite); /* If node can not be interposable by static or dynamic linker to point to different definition, return this symbol. Otherwise look for alias with @@ -1187,12 +1187,6 @@ public: returns cgraph_node::get (DECL). */ static cgraph_node * create_same_body_alias (tree alias, tree decl); - /* Worker for cgraph_can_remove_if_no_direct_calls_p. */ - static bool used_from_object_file_p_worker (cgraph_node *node, void *) - { - return node->used_from_object_file_p (); - } - /* Verify whole cgraph structure. */ static void DEBUG_FUNCTION verify_cgraph_nodes (void); @@ -1204,6 +1198,9 @@ public: with (not necessarily cgraph_node (DECL). */ static cgraph_node *create_alias (tree alias, tree target); + /* Return true if NODE has thunk. */ + static bool has_thunk_p (cgraph_node *node, void *); + cgraph_edge *callees; cgraph_edge *callers; /* List of edges representing indirect calls with a yet undetermined @@ -2733,6 +2730,7 @@ cgraph_node::only_called_directly_or_aliased_p (void) && !DECL_VIRTUAL_P (decl) && !DECL_STATIC_CONSTRUCTOR (decl) && !DECL_STATIC_DESTRUCTOR (decl) + && !used_from_object_file_p () && !externally_visible); } diff --git a/contrib/gcc-5.0/gcc/cgraphunit.c b/contrib/gcc-5.0/gcc/cgraphunit.c index 9f6878a19e..e640907550 100644 --- a/contrib/gcc-5.0/gcc/cgraphunit.c +++ b/contrib/gcc-5.0/gcc/cgraphunit.c @@ -1680,6 +1680,14 @@ cgraph_node::expand_thunk (bool output_asm_thunks, bool force_gimple_thunk) callees->call_stmt = call; gimple_call_set_from_thunk (call, true); gimple_call_set_with_bounds (call, instrumentation_clone); + + /* Return slot optimization is always possible and in fact requred to + return values with DECL_BY_REFERENCE. */ + if (aggregate_value_p (resdecl, TREE_TYPE (thunk_fndecl)) + && (!is_gimple_reg_type (TREE_TYPE (resdecl)) + || DECL_BY_REFERENCE (resdecl))) + gimple_call_set_return_slot_opt (call, true); + if (restmp && !alias_is_noreturn) { gimple_call_set_lhs (call, restmp); diff --git a/contrib/gcc-5.0/gcc/config/i386/i386.c b/contrib/gcc-5.0/gcc/config/i386/i386.c index bec1324990..ab8f03acdc 100644 --- a/contrib/gcc-5.0/gcc/config/i386/i386.c +++ b/contrib/gcc-5.0/gcc/config/i386/i386.c @@ -7914,6 +7914,11 @@ ix86_pass_by_reference (cumulative_args_t cum_v, machine_mode mode, { CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v); + /* Bounds are never passed by reference. */ + if ((type && POINTER_BOUNDS_TYPE_P (type)) + || POINTER_BOUNDS_MODE_P (mode)) + return false; + /* See Windows x64 Software Convention. */ if (TARGET_64BIT && (cum ? cum->call_abi : ix86_abi) == MS_ABI) { diff --git a/contrib/gcc-5.0/gcc/config/i386/i386.md b/contrib/gcc-5.0/gcc/config/i386/i386.md index 2d3d07585c..8a80415b9a 100644 --- a/contrib/gcc-5.0/gcc/config/i386/i386.md +++ b/contrib/gcc-5.0/gcc/config/i386/i386.md @@ -7331,6 +7331,32 @@ [(set_attr "type" "multi") (set_attr "mode" "")]) +;; Optimize division or modulo by constant power of 2, if the constant +;; materializes only after expansion. +(define_insn_and_split "*udivmod4_pow2" + [(set (match_operand:SWI48 0 "register_operand" "=r") + (udiv:SWI48 (match_operand:SWI48 2 "register_operand" "0") + (match_operand:SWI48 3 "const_int_operand" "n"))) + (set (match_operand:SWI48 1 "register_operand" "=r") + (umod:SWI48 (match_dup 2) (match_dup 3))) + (clobber (reg:CC FLAGS_REG))] + "UINTVAL (operands[3]) - 2 < * BITS_PER_UNIT + && (UINTVAL (operands[3]) & (UINTVAL (operands[3]) - 1)) == 0" + "#" + "&& 1" + [(set (match_dup 1) (match_dup 2)) + (parallel [(set (match_dup 0) (lshiftrt: (match_dup 2) (match_dup 4))) + (clobber (reg:CC FLAGS_REG))]) + (parallel [(set (match_dup 1) (and: (match_dup 1) (match_dup 5))) + (clobber (reg:CC FLAGS_REG))])] +{ + int v = exact_log2 (UINTVAL (operands[3])); + operands[4] = GEN_INT (v); + operands[5] = GEN_INT ((HOST_WIDE_INT_1U << v) - 1); +} + [(set_attr "type" "multi") + (set_attr "mode" "")]) + (define_insn "*udivmod4_noext" [(set (match_operand:SWIM248 0 "register_operand" "=a") (udiv:SWIM248 (match_operand:SWIM248 2 "register_operand" "0") diff --git a/contrib/gcc-5.0/gcc/cp/constexpr.c b/contrib/gcc-5.0/gcc/cp/constexpr.c index f7e8ce949f..1b5f50cb49 100644 --- a/contrib/gcc-5.0/gcc/cp/constexpr.c +++ b/contrib/gcc-5.0/gcc/cp/constexpr.c @@ -2955,8 +2955,8 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, if (lval) return t; /* We ask for an rvalue for the RESULT_DECL when indirecting - through an invisible reference. */ - gcc_assert (DECL_BY_REFERENCE (t)); + through an invisible reference, or in named return value + optimization. */ return (*ctx->values->get (t)); case VAR_DECL: diff --git a/contrib/gcc-5.0/gcc/cp/ptree.c b/contrib/gcc-5.0/gcc/cp/ptree.c index 79c80a30d9..2d0b584e7a 100644 --- a/contrib/gcc-5.0/gcc/cp/ptree.c +++ b/contrib/gcc-5.0/gcc/cp/ptree.c @@ -203,6 +203,34 @@ cxx_print_identifier (FILE *file, tree node, int indent) print_node (file, "template", IDENTIFIER_TEMPLATE (node), indent + 4); } +void +cxx_print_lambda_node (FILE *file, tree node, int indent) +{ + if (LAMBDA_EXPR_MUTABLE_P (node)) + fprintf (file, " /mutable"); + fprintf (file, " default_capture_mode=["); + switch (LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (node)) + { + case CPLD_NONE: + fprintf (file, "NONE"); + break; + case CPLD_COPY: + fprintf (file, "COPY"); + break; + case CPLD_REFERENCE: + fprintf (file, "CPLD_REFERENCE"); + break; + default: + fprintf (file, "??"); + break; + } + fprintf (file, "] "); + print_node (file, "capture_list", LAMBDA_EXPR_CAPTURE_LIST (node), indent + 4); + print_node (file, "this_capture", LAMBDA_EXPR_THIS_CAPTURE (node), indent + 4); + print_node (file, "return_type", LAMBDA_EXPR_RETURN_TYPE (node), indent + 4); + print_node (file, "closure", LAMBDA_EXPR_CLOSURE (node), indent + 4); +} + void cxx_print_xnode (FILE *file, tree node, int indent) { @@ -243,6 +271,9 @@ cxx_print_xnode (FILE *file, tree node, int indent) print_node (file, "pattern", DEFERRED_NOEXCEPT_PATTERN (node), indent+4); print_node (file, "args", DEFERRED_NOEXCEPT_ARGS (node), indent+4); break; + case LAMBDA_EXPR: + cxx_print_lambda_node (file, node, indent); + break; default: break; } diff --git a/contrib/gcc-5.0/gcc/defaults.h b/contrib/gcc-5.0/gcc/defaults.h index 5cef92c8f3..1d5479895e 100644 --- a/contrib/gcc-5.0/gcc/defaults.h +++ b/contrib/gcc-5.0/gcc/defaults.h @@ -1095,6 +1095,10 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #define FRAME_GROWS_DOWNWARD 0 #endif +#ifndef RETURN_ADDR_IN_PREVIOUS_FRAME +#define RETURN_ADDR_IN_PREVIOUS_FRAME 0 +#endif + /* On most machines, the CFA coincides with the first incoming parm. */ #ifndef ARG_POINTER_CFA_OFFSET #define ARG_POINTER_CFA_OFFSET(FNDECL) \ diff --git a/contrib/gcc-5.0/gcc/doc/extend.texi b/contrib/gcc-5.0/gcc/doc/extend.texi index c066d32274..eb818613ee 100644 --- a/contrib/gcc-5.0/gcc/doc/extend.texi +++ b/contrib/gcc-5.0/gcc/doc/extend.texi @@ -17274,24 +17274,11 @@ and suitable fallback code always needs to be supplied. Start a RTM (Restricted Transactional Memory) transaction. Returns @code{_XBEGIN_STARTED} when the transaction started successfully (note this is not 0, so the constant has to be -explicitly tested). If the transaction aborts, all side-effects -are undone and an abort code is returned. There is no guarantee -any transaction ever succeeds, so there always needs to be a valid -fallback path. -@end deftypefn - -@smallexample -#include - -if ((status = _xbegin ()) == _XBEGIN_STARTED) @{ - ... transaction code... - _xend (); -@} else @{ - ... non transactional fallback path... -@} -@end smallexample +explicitly tested). -If the transaction aborts, the return value is one of: +If the transaction aborts, all side-effects +are undone and an abort code encoded as a bit mask is returned. +The following macros are defined: @table @code @item _XABORT_EXPLICIT @@ -17309,6 +17296,11 @@ Transaction abort due to a debug trap. Transaction abort in an inner nested transaction. @end table +There is no guarantee +any transaction ever succeeds, so there always needs to be a valid +fallback path. +@end deftypefn + @deftypefn {RTM Function} {void} _xend () Commit the current transaction. When no transaction is active this faults. All memory side-effects of the transaction become visible @@ -17325,6 +17317,37 @@ The @var{status} is an 8-bit constant; its value is encoded in the return value from @code{_xbegin}. @end deftypefn +Here is an example showing handling for @code{_XABORT_RETRY} +and a fallback path for other failures: + +@smallexample +#include + +int n_tries, max_tries; +unsigned status = _XABORT_EXPLICIT; +... + +for (n_tries = 0; n_tries < max_tries; n_tries++) + @{ + status = _xbegin (); + if (status == _XBEGIN_STARTED || !(status & _XABORT_RETRY)) + break; + @} +if (status == _XBEGIN_STARTED) + @{ + ... transaction code... + _xend (); + @} +else + @{ + ... non-transactional fallback path... + @} +@end smallexample + +@noindent +Note that, in most cases, the transactional and non-transactional code +must synchronize together to ensure consistency. + @node Target Format Checks @section Format Checks Specific to Particular Target Machines diff --git a/contrib/gcc-5.0/gcc/doc/invoke.texi b/contrib/gcc-5.0/gcc/doc/invoke.texi index ef4cc75ba5..67814d40d5 100644 --- a/contrib/gcc-5.0/gcc/doc/invoke.texi +++ b/contrib/gcc-5.0/gcc/doc/invoke.texi @@ -3631,7 +3631,7 @@ The C standard specifies that zero-length formats are allowed. @opindex Wformat=2 Enable @option{-Wformat} plus additional format checks. Currently equivalent to @option{-Wformat -Wformat-nonliteral -Wformat-security --Wformat-signedness -Wformat-y2k}. +-Wformat-y2k}. @item -Wformat-nonliteral @opindex Wformat-nonliteral @@ -5704,8 +5704,8 @@ a++; @item -fsanitize=bounds @opindex fsanitize=bounds This option enables instrumentation of array bounds. Various out of bounds -accesses are detected. Flexible array members and initializers of variables -with static storage are not instrumented. +accesses are detected. Flexible array members, flexible array member-like +arrays, and initializers of variables with static storage are not instrumented. @item -fsanitize=alignment @opindex fsanitize=alignment @@ -10570,6 +10570,14 @@ by this parameter. The default value of the parameter is 2, which is the minimal number of registers needed by typical instructions. This value is the best found from numerous experiments. +@item lra-inheritance-ebb-probability-cutoff +LRA tries to reuse values reloaded in registers in subsequent insns. +This optimization is called inheritance. EBB is used as a region to +do this optimization. The parameter defines a minimal fall-through +edge probability in percentage used to add BB to inheritance EBB in +LRA. The default value of the parameter is 40. The value was chosen +from numerous runs of SPEC2000 on x86-64. + @item loop-invariant-max-bbs-in-loop Loop invariant motion can be very expensive, both in compilation time and in amount of needed compile-time memory, with very large loops. Loops @@ -18620,12 +18628,13 @@ Supported values for @var{cpu_type} are @samp{401}, @samp{403}, @samp{e6500}, @samp{ec603e}, @samp{G3}, @samp{G4}, @samp{G5}, @samp{titan}, @samp{power3}, @samp{power4}, @samp{power5}, @samp{power5+}, @samp{power6}, @samp{power6x}, @samp{power7}, @samp{power8}, @samp{powerpc}, -@samp{powerpc64}, and @samp{rs64}. +@samp{powerpc64}, @samp{powerpc64le}, and @samp{rs64}. -@option{-mcpu=powerpc}, and @option{-mcpu=powerpc64} specify pure 32-bit -PowerPC and 64-bit PowerPC architecture machine -types, with an appropriate, generic processor model assumed for -scheduling purposes. +@option{-mcpu=powerpc}, @option{-mcpu=powerpc64}, and +@option{-mcpu=powerpc64le} specify pure 32-bit PowerPC (either +endian), 64-bit big endian PowerPC and 64-bit little endian PowerPC +architecture machine types, with an appropriate, generic processor +model assumed for scheduling purposes. The other options specify a specific processor. Code generated under those options runs best on that processor, and may not run at all on @@ -23636,7 +23645,7 @@ GCC@. A good explanation of the benefits offered by ensuring ELF symbols have the correct visibility is given by ``How To Write Shared Libraries'' by Ulrich Drepper (which can be found at -@w{@uref{http://people.redhat.com/~drepper/}})---however a superior +@w{@uref{http://www.akkadia.org/drepper/}})---however a superior solution made possible by this option to marking things hidden when the default is public is to make the default hidden and mark things public. This is the norm with DLLs on Windows and with @option{-fvisibility=hidden} diff --git a/contrib/gcc-5.0/gcc/doc/md.texi b/contrib/gcc-5.0/gcc/doc/md.texi index f2c25c2a45..bc1ec9d4f0 100644 --- a/contrib/gcc-5.0/gcc/doc/md.texi +++ b/contrib/gcc-5.0/gcc/doc/md.texi @@ -1512,7 +1512,7 @@ but if reloading is needed, some other alternative will be used. @cindex caret @item ^ This constraint is analogous to @samp{?} but it disparages slightly -the alternative only if the operand with the @samp{?} needs a reload. +the alternative only if the operand with the @samp{^} needs a reload. @cindex @samp{$} in constraint @cindex dollar sign diff --git a/contrib/gcc-5.0/gcc/doc/tm.texi b/contrib/gcc-5.0/gcc/doc/tm.texi index 6e5d2c0441..6c5bfabfaa 100644 --- a/contrib/gcc-5.0/gcc/doc/tm.texi +++ b/contrib/gcc-5.0/gcc/doc/tm.texi @@ -3045,7 +3045,7 @@ A C expression whose value is RTL representing the value of the return address for the frame @var{count} steps up from the current frame, after the prologue. @var{frameaddr} is the frame pointer of the @var{count} frame, or the frame pointer of the @var{count} @minus{} 1 frame if -@code{RETURN_ADDR_IN_PREVIOUS_FRAME} is defined. +@code{RETURN_ADDR_IN_PREVIOUS_FRAME} is nonzero. The value of the expression must always be the correct address when @var{count} is zero, but may be @code{NULL_RTX} if there is no way to @@ -3053,8 +3053,9 @@ determine the return address of other frames. @end defmac @defmac RETURN_ADDR_IN_PREVIOUS_FRAME -Define this if the return address of a particular stack frame is accessed -from the frame pointer of the previous stack frame. +Define this macro to nonzero value if the return address of a particular +stack frame is accessed from the frame pointer of the previous stack +frame. The zero default for this macro is suitable for most ports. @end defmac @defmac INCOMING_RETURN_ADDR_RTX diff --git a/contrib/gcc-5.0/gcc/expmed.c b/contrib/gcc-5.0/gcc/expmed.c index 18e62a000b..0034203c2f 100644 --- a/contrib/gcc-5.0/gcc/expmed.c +++ b/contrib/gcc-5.0/gcc/expmed.c @@ -976,7 +976,7 @@ store_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize, /* Storing any naturally aligned field can be done with a simple store. For targets that support fast unaligned memory, any naturally sized, unit aligned field can be done directly. */ - if (simple_mem_bitfield_p (str_rtx, bitsize, bitnum, fieldmode)) + if (bitsize == GET_MODE_BITSIZE (fieldmode)) { str_rtx = adjust_bitfield_address (str_rtx, fieldmode, bitnum / BITS_PER_UNIT); @@ -984,12 +984,16 @@ store_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize, } else { + rtx temp; + str_rtx = narrow_bit_field_mem (str_rtx, fieldmode, bitsize, bitnum, &bitnum); - /* Explicitly override the C/C++ memory model; ignore the - bit range so that we can do the access in the mode mandated - by -fstrict-volatile-bitfields instead. */ - store_fixed_bit_field_1 (str_rtx, bitsize, bitnum, value); + temp = copy_to_reg (str_rtx); + if (!store_bit_field_1 (temp, bitsize, bitnum, 0, 0, + fieldmode, value, true)) + gcc_unreachable (); + + emit_move_insn (str_rtx, temp); } return; @@ -1786,24 +1790,20 @@ extract_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize, if (strict_volatile_bitfield_p (str_rtx, bitsize, bitnum, mode1, 0, 0)) { - rtx result; - /* Extraction of a full MODE1 value can be done with a load as long as the field is on a byte boundary and is sufficiently aligned. */ - if (simple_mem_bitfield_p (str_rtx, bitsize, bitnum, mode1)) - result = adjust_bitfield_address (str_rtx, mode1, - bitnum / BITS_PER_UNIT); - else + if (bitsize == GET_MODE_BITSIZE(mode1)) { - str_rtx = narrow_bit_field_mem (str_rtx, mode1, bitsize, bitnum, - &bitnum); - result = extract_fixed_bit_field_1 (mode, str_rtx, bitsize, bitnum, - target, unsignedp); + rtx result = adjust_bitfield_address (str_rtx, mode1, + bitnum / BITS_PER_UNIT); + return convert_extracted_bit_field (result, mode, tmode, unsignedp); } - return convert_extracted_bit_field (result, mode, tmode, unsignedp); + str_rtx = narrow_bit_field_mem (str_rtx, mode1, bitsize, bitnum, + &bitnum); + str_rtx = copy_to_reg (str_rtx); } - + return extract_bit_field_1 (str_rtx, bitsize, bitnum, unsignedp, target, mode, tmode, true); } diff --git a/contrib/gcc-5.0/gcc/fold-const.c b/contrib/gcc-5.0/gcc/fold-const.c index 83771207c4..0834d47fa0 100644 --- a/contrib/gcc-5.0/gcc/fold-const.c +++ b/contrib/gcc-5.0/gcc/fold-const.c @@ -16019,8 +16019,8 @@ round_up_loc (location_t loc, tree value, unsigned int divisor) return value; overflow_p = TREE_OVERFLOW (value); - val &= ~(divisor - 1); - val += divisor; + val += divisor - 1; + val &= - (int) divisor; if (val == 0) overflow_p = true; @@ -16032,7 +16032,7 @@ round_up_loc (location_t loc, tree value, unsigned int divisor) t = build_int_cst (TREE_TYPE (value), divisor - 1); value = size_binop_loc (loc, PLUS_EXPR, value, t); - t = build_int_cst (TREE_TYPE (value), -divisor); + t = build_int_cst (TREE_TYPE (value), - (int) divisor); value = size_binop_loc (loc, BIT_AND_EXPR, value, t); } } diff --git a/contrib/gcc-5.0/gcc/ipa-devirt.c b/contrib/gcc-5.0/gcc/ipa-devirt.c index c3f8b156a5..fe29932c3e 100644 --- a/contrib/gcc-5.0/gcc/ipa-devirt.c +++ b/contrib/gcc-5.0/gcc/ipa-devirt.c @@ -1459,7 +1459,6 @@ add_type_duplicate (odr_type val, tree type) && polymorphic_type_binfo_p (TYPE_BINFO (type1)) != polymorphic_type_binfo_p (TYPE_BINFO (type2)))) { - gcc_assert (val->odr_violated); base_mismatch = true; break; } diff --git a/contrib/gcc-5.0/gcc/ipa-icf-gimple.c b/contrib/gcc-5.0/gcc/ipa-icf-gimple.c index 53d2c38bc9..4f1a8ce6e9 100644 --- a/contrib/gcc-5.0/gcc/ipa-icf-gimple.c +++ b/contrib/gcc-5.0/gcc/ipa-icf-gimple.c @@ -77,6 +77,7 @@ along with GCC; see the file COPYING3. If not see #include #include "tree-ssanames.h" #include "tree-eh.h" +#include "builtins.h" #include "ipa-icf-gimple.h" #include "ipa-icf.h" @@ -286,6 +287,41 @@ func_checker::compare_memory_operand (tree t1, tree t2) if (ao_ref_alias_set (&r1) != ao_ref_alias_set (&r2) || ao_ref_base_alias_set (&r1) != ao_ref_base_alias_set (&r2)) return return_false_with_msg ("ao alias sets are different"); + + /* We can't simply use get_object_alignment_1 on the full + reference as for accesses with variable indexes this reports + too conservative alignment. We also can't use the ao_ref_base + base objects as ao_ref_base happily strips MEM_REFs around + decls even though that may carry alignment info. */ + b1 = t1; + while (handled_component_p (b1)) + b1 = TREE_OPERAND (b1, 0); + b2 = t2; + while (handled_component_p (b2)) + b2 = TREE_OPERAND (b2, 0); + unsigned int align1, align2; + unsigned HOST_WIDE_INT tem; + get_object_alignment_1 (b1, &align1, &tem); + get_object_alignment_1 (b2, &align2, &tem); + if (align1 != align2) + return return_false_with_msg ("different access alignment"); + + /* Similarly we have to compare dependence info where equality + tells us we are safe (even some unequal values would be safe + but then we have to maintain a map of bases and cliques). */ + unsigned short clique1 = 0, base1 = 0, clique2 = 0, base2 = 0; + if (TREE_CODE (b1) == MEM_REF) + { + clique1 = MR_DEPENDENCE_CLIQUE (b1); + base1 = MR_DEPENDENCE_BASE (b1); + } + if (TREE_CODE (b2) == MEM_REF) + { + clique2 = MR_DEPENDENCE_CLIQUE (b2); + base2 = MR_DEPENDENCE_BASE (b2); + } + if (clique1 != clique2 || base1 != base2) + return return_false_with_msg ("different dependence info"); } return compare_operand (t1, t2); @@ -312,10 +348,9 @@ func_checker::compare_cst_or_decl (tree t1, tree t2) return return_with_debug (ret); } case FUNCTION_DECL: - { - ret = compare_function_decl (t1, t2); - return return_with_debug (ret); - } + /* All function decls are in the symbol table and known to match + before we start comparing bodies. */ + return true; case VAR_DECL: return return_with_debug (compare_variable_decl (t1, t2)); case FIELD_DECL: @@ -448,18 +483,23 @@ func_checker::compare_operand (tree t1, tree t2) /* Virtual table call. */ case OBJ_TYPE_REF: { - x1 = TREE_OPERAND (t1, 0); - x2 = TREE_OPERAND (t2, 0); - y1 = TREE_OPERAND (t1, 1); - y2 = TREE_OPERAND (t2, 1); - z1 = TREE_OPERAND (t1, 2); - z2 = TREE_OPERAND (t2, 2); - - ret = compare_ssa_name (x1, x2) - && compare_operand (y1, y2) - && compare_cst_or_decl (z1, z2); - - return return_with_debug (ret); + if (!compare_ssa_name (OBJ_TYPE_REF_EXPR (t1), OBJ_TYPE_REF_EXPR (t2))) + return return_false (); + if (opt_for_fn (m_source_func_decl, flag_devirtualize) + && virtual_method_call_p (t1)) + { + if (tree_to_uhwi (OBJ_TYPE_REF_TOKEN (t1)) + != tree_to_uhwi (OBJ_TYPE_REF_TOKEN (t2))) + return return_false_with_msg ("OBJ_TYPE_REF token mismatch"); + if (!types_same_for_odr (obj_type_ref_class (t1), + obj_type_ref_class (t2))) + return return_false_with_msg ("OBJ_TYPE_REF OTR type mismatch"); + if (!compare_ssa_name (OBJ_TYPE_REF_OBJECT (t1), + OBJ_TYPE_REF_OBJECT (t2))) + return return_false_with_msg ("OBJ_TYPE_REF object mismatch"); + } + + return return_with_debug (true); } case IMAGPART_EXPR: case REALPART_EXPR: @@ -532,39 +572,6 @@ func_checker::compare_tree_list_operand (tree t1, tree t2) return true; } -/* Verifies that trees T1 and T2, representing function declarations - are equivalent from perspective of ICF. */ - -bool -func_checker::compare_function_decl (tree t1, tree t2) -{ - bool ret = false; - - if (t1 == t2) - return true; - - symtab_node *n1 = symtab_node::get (t1); - symtab_node *n2 = symtab_node::get (t2); - - if (m_ignored_source_nodes != NULL && m_ignored_target_nodes != NULL) - { - ret = m_ignored_source_nodes->contains (n1) - && m_ignored_target_nodes->contains (n2); - - if (ret) - return true; - } - - /* If function decl is WEAKREF, we compare targets. */ - cgraph_node *f1 = cgraph_node::get (t1); - cgraph_node *f2 = cgraph_node::get (t2); - - if(f1 && f2 && f1->weakref && f2->weakref) - ret = f1->alias_target == f2->alias_target; - - return ret; -} - /* Verifies that trees T1 and T2 do correspond. */ bool @@ -575,6 +582,9 @@ func_checker::compare_variable_decl (tree t1, tree t2) if (t1 == t2) return true; + if (DECL_ALIGN (t1) != DECL_ALIGN (t2)) + return return_false_with_msg ("alignments are different"); + if (DECL_HARD_REGISTER (t1) != DECL_HARD_REGISTER (t2)) return return_false_with_msg ("DECL_HARD_REGISTER are different"); @@ -582,20 +592,10 @@ func_checker::compare_variable_decl (tree t1, tree t2) && DECL_ASSEMBLER_NAME (t1) != DECL_ASSEMBLER_NAME (t2)) return return_false_with_msg ("HARD REGISTERS are different"); - if (TREE_CODE (t1) == VAR_DECL && (DECL_EXTERNAL (t1) || TREE_STATIC (t1))) - { - symtab_node *n1 = symtab_node::get (t1); - symtab_node *n2 = symtab_node::get (t2); - - if (m_ignored_source_nodes != NULL && m_ignored_target_nodes != NULL) - { - ret = m_ignored_source_nodes->contains (n1) - && m_ignored_target_nodes->contains (n2); - - if (ret) - return true; - } - } + /* Symbol table variables are known to match before we start comparing + bodies. */ + if (decl_in_symtab_p (t1)) + return decl_in_symtab_p (t2); ret = compare_decl (t1, t2); return return_with_debug (ret); diff --git a/contrib/gcc-5.0/gcc/ipa-icf.c b/contrib/gcc-5.0/gcc/ipa-icf.c index 5d50b6f639..7c4c852ed5 100644 --- a/contrib/gcc-5.0/gcc/ipa-icf.c +++ b/contrib/gcc-5.0/gcc/ipa-icf.c @@ -53,6 +53,7 @@ along with GCC; see the file COPYING3. If not see #include "config.h" #include "system.h" +#include #include "coretypes.h" #include "hash-set.h" #include "machmode.h" @@ -119,9 +120,9 @@ along with GCC; see the file COPYING3. If not see #include "lto-streamer.h" #include "data-streamer.h" #include "ipa-utils.h" -#include #include "ipa-icf-gimple.h" #include "ipa-icf.h" +#include "stor-layout.h" using namespace ipa_icf_gimple; @@ -335,17 +336,40 @@ sem_function::get_hash (void) /* For a given symbol table nodes N1 and N2, we check that FUNCTION_DECLs point to a same function. Comparison can be skipped if IGNORED_NODES - contains these nodes. */ + contains these nodes. ADDRESS indicate if address is taken. */ bool -sem_function::compare_cgraph_references (hash_map - &ignored_nodes, - symtab_node *n1, symtab_node *n2) +sem_item::compare_cgraph_references ( + hash_map &ignored_nodes, + symtab_node *n1, symtab_node *n2, bool address) { - if (n1 == n2 || (ignored_nodes.get (n1) && ignored_nodes.get (n2))) + enum availability avail1, avail2; + + if (n1 == n2) + return true; + + /* Merging two definitions with a reference to equivalent vtables, but + belonging to a different type may result in ipa-polymorphic-call analysis + giving a wrong answer about the dynamic type of instance. */ + if (is_a (n1) + && (DECL_VIRTUAL_P (n1->decl) || DECL_VIRTUAL_P (n2->decl)) + && (DECL_VIRTUAL_P (n1->decl) != DECL_VIRTUAL_P (n2->decl) + || !types_must_be_same_for_odr (DECL_CONTEXT (n1->decl), + DECL_CONTEXT (n2->decl)))) + return return_false_with_msg + ("references to virtual tables can not be merged"); + + if (address && n1->equal_address_to (n2) == 1) + return true; + if (!address && n1->semantically_equivalent_p (n2)) return true; - /* TODO: add more precise comparison for weakrefs, etc. */ + n1 = n1->ultimate_alias_target (&avail1); + n2 = n2->ultimate_alias_target (&avail2); + + if (avail1 >= AVAIL_INTERPOSABLE && ignored_nodes.get (n1) + && avail2 >= AVAIL_INTERPOSABLE && ignored_nodes.get (n2)) + return true; return return_false_with_msg ("different references"); } @@ -397,6 +421,10 @@ sem_function::equals_wpa (sem_item *item, m_compared_func->arg_types[i], is_not_leaf, i == 0)) return return_false_with_msg ("argument type is different"); + if (POINTER_TYPE_P (arg_types[i]) + && (TYPE_RESTRICT (arg_types[i]) + != TYPE_RESTRICT (m_compared_func->arg_types[i]))) + return return_false_with_msg ("argument restrict flag mismatch"); } /* Result type checking. */ @@ -407,12 +435,18 @@ sem_function::equals_wpa (sem_item *item, if (node->num_references () != item->node->num_references ()) return return_false_with_msg ("different number of references"); + if (comp_type_attributes (TREE_TYPE (decl), + TREE_TYPE (item->decl)) != 1) + return return_false_with_msg ("different type attributes"); + ipa_ref *ref = NULL, *ref2 = NULL; for (unsigned i = 0; node->iterate_reference (i, ref); i++) { item->node->iterate_reference (i, ref2); - if (!compare_cgraph_references (ignored_nodes, ref->referred, ref2->referred)) + if (!compare_cgraph_references (ignored_nodes, ref->referred, + ref2->referred, + ref->address_matters_p ())) return false; } @@ -421,7 +455,8 @@ sem_function::equals_wpa (sem_item *item, while (e1 && e2) { - if (!compare_cgraph_references (ignored_nodes, e1->callee, e2->callee)) + if (!compare_cgraph_references (ignored_nodes, e1->callee, + e2->callee, false)) return false; e1 = e1->next_callee; @@ -619,6 +654,30 @@ 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; } @@ -632,7 +691,7 @@ set_local (cgraph_node *node, void *data) return false; } -/* TREE_ADDRESSABLE of NODE to true if DATA is non-NULL. +/* TREE_ADDRESSABLE of NODE to true. Helper for call_for_symbol_thunks_and_aliases. */ static bool @@ -642,6 +701,16 @@ set_addressable (varpool_node *node, void *) return false; } +/* Clear DECL_RTL of NODE. + Helper for call_for_symbol_thunks_and_aliases. */ + +static bool +clear_decl_rtl (symtab_node *node, void *) +{ + SET_DECL_RTL (node->decl, NULL); + return false; +} + /* Redirect all callers of N and its aliases to TO. Remove aliases if possible. Return number of redirections made. */ @@ -650,12 +719,22 @@ redirect_all_callers (cgraph_node *n, cgraph_node *to) { int nredirected = 0; ipa_ref *ref; + cgraph_edge *e = n->callers; - while (n->callers) + while (e) { - cgraph_edge *e = n->callers; - e->redirect_callee (to); - nredirected++; + /* Redirecting thunks to interposable symbols or symbols in other sections + may not be supported by target output code. Play safe for now and + punt on redirection. */ + if (!e->caller->thunk.thunk_p) + { + struct cgraph_edge *nexte = e->next_caller; + e->redirect_callee (to); + e = nexte; + nredirected++; + } + else + e = e->next_callee; } for (unsigned i = 0; n->iterate_direct_aliases (i, ref);) { @@ -670,6 +749,8 @@ redirect_all_callers (cgraph_node *n, cgraph_node *to) { nredirected += redirect_all_callers (n_alias, to); if (n_alias->can_remove_if_no_direct_calls_p () + && !n_alias->call_for_symbol_and_aliases (cgraph_node::has_thunk_p, + NULL, true) && !n_alias->has_aliases_p ()) n_alias->remove (); } @@ -699,6 +780,7 @@ sem_function::merge (sem_item *alias_item) bool remove = false; bool original_discardable = false; + bool original_discarded = false; bool original_address_matters = original->address_matters_p (); bool alias_address_matters = alias->address_matters_p (); @@ -727,15 +809,16 @@ sem_function::merge (sem_item *alias_item) } /* See if original is in a section that can be discarded if the main - symbol is not used. + symbol is not used. */ - Also consider case where we have resolution info and we know that + if (original->can_be_discarded_p ()) + original_discardable = true; + /* Also consider case where we have resolution info and we know that original's definition is not going to be used. In this case we can not create alias to original. */ - if (original->can_be_discarded_p () - || (node->resolution != LDPR_UNKNOWN - && !decl_binds_to_current_def_p (node->decl))) - original_discardable = true; + if (node->resolution != LDPR_UNKNOWN + && !decl_binds_to_current_def_p (node->decl)) + original_discardable = original_discarded = true; /* Creating a symtab alias is the optimal way to merge. It however can not be used in the following cases: @@ -745,12 +828,18 @@ sem_function::merge (sem_item *alias_item) it is an external functions where we can not create an alias (ORIGINAL_DISCARDABLE) 3) if target do not support symbol aliases. + 4) original and alias lie in different comdat groups. If we can not produce alias, we will turn ALIAS into WRAPPER of ORIGINAL and/or redirect all callers from ALIAS to ORIGINAL. */ if ((original_address_matters && alias_address_matters) - || original_discardable - || !sem_item::target_supports_symbol_aliases_p ()) + || (original_discardable + && (!DECL_COMDAT_GROUP (alias->decl) + || (DECL_COMDAT_GROUP (alias->decl) + != DECL_COMDAT_GROUP (original->decl)))) + || original_discarded + || !sem_item::target_supports_symbol_aliases_p () + || DECL_COMDAT_GROUP (alias->decl) != DECL_COMDAT_GROUP (original->decl)) { /* First see if we can produce wrapper. */ @@ -758,7 +847,7 @@ sem_function::merge (sem_item *alias_item) comdat group. Other compiler producing the body of the another comdat group may make opossite decision and with unfortunate linker choices this may close a loop. */ - if (DECL_COMDAT_GROUP (alias->decl) + if (DECL_COMDAT_GROUP (original->decl) && DECL_COMDAT_GROUP (alias->decl) && (DECL_COMDAT_GROUP (alias->decl) != DECL_COMDAT_GROUP (original->decl))) { @@ -815,26 +904,27 @@ sem_function::merge (sem_item *alias_item) /* Work out the symbol the wrapper should call. If ORIGINAL is interposable, we need to call a local alias. - Also produce local alias (if possible) as an optimization. */ - if (!original_discardable - || (DECL_COMDAT_GROUP (original->decl) - && (DECL_COMDAT_GROUP (original->decl) - == DECL_COMDAT_GROUP (alias->decl)))) + Also produce local alias (if possible) as an optimization. + + Local aliases can not be created inside comdat groups because that + prevents inlining. */ + if (!original_discardable && !original->get_comdat_group ()) { local_original = dyn_cast (original->noninterposable_alias ()); if (!local_original && original->get_availability () > AVAIL_INTERPOSABLE) local_original = original; - /* If original is COMDAT local, we can not really redirect external - callers to it. */ - if (original->comdat_local_p ()) - redirect_callers = false; } /* If we can not use local alias, fallback to the original when possible. */ else if (original->get_availability () > AVAIL_INTERPOSABLE) local_original = original; + + /* If original is COMDAT local, we can not really redirect calls outside + of its comdat group to it. */ + if (original->comdat_local_p ()) + redirect_callers = false; if (!local_original) { if (dump_file) @@ -851,6 +941,8 @@ sem_function::merge (sem_item *alias_item) return false; } if (!create_wrapper + && !alias->call_for_symbol_and_aliases (cgraph_node::has_thunk_p, + NULL, true) && !alias->can_remove_if_no_direct_calls_p ()) { if (dump_file) @@ -893,6 +985,9 @@ sem_function::merge (sem_item *alias_item) ipa_merge_profiles (original, alias); alias->release_body (true); alias->reset (); + /* Notice global symbol possibly produced RTL. */ + ((symtab_node *)alias)->call_for_symbol_and_aliases (clear_decl_rtl, + NULL, true); /* Create the alias. */ cgraph_node::create_alias (alias_func->decl, decl); @@ -916,7 +1011,10 @@ sem_function::merge (sem_item *alias_item) if (dump_file) fprintf (dump_file, "Unified; Wrapper has been created.\n\n"); } - gcc_assert (alias->icf_merged || remove); + + /* It's possible that redirection can hit thunks that block + redirection opportunities. */ + gcc_assert (alias->icf_merged || remove || redirect_callers); original->icf_merged = true; /* Inform the inliner about cross-module merging. */ @@ -972,7 +1070,8 @@ sem_function::init (void) unsigned nondbg_stmt_count = 0; edge e; - for (edge_iterator ei = ei_start (bb->preds); ei_cond (ei, &e); ei_next (&ei)) + for (edge_iterator ei = ei_start (bb->preds); ei_cond (ei, &e); + ei_next (&ei)) cfg_checksum = iterative_hash_host_wide_int (e->flags, cfg_checksum); @@ -981,9 +1080,10 @@ sem_function::init (void) { gimple stmt = gsi_stmt (gsi); - if (gimple_code (stmt) != GIMPLE_DEBUG) + if (gimple_code (stmt) != GIMPLE_DEBUG + && gimple_code (stmt) != GIMPLE_PREDICT) { - hash_stmt (&hstate, stmt); + hash_stmt (stmt, hstate); nondbg_stmt_count++; } } @@ -993,7 +1093,8 @@ sem_function::init (void) /* Inserting basic block to hash table. */ sem_bb *semantic_bb = new sem_bb (bb, nondbg_stmt_count, - EDGE_COUNT (bb->preds) + EDGE_COUNT (bb->succs)); + EDGE_COUNT (bb->preds) + + EDGE_COUNT (bb->succs)); bb_sorted.safe_push (semantic_bb); } @@ -1001,52 +1102,119 @@ sem_function::init (void) parse_tree_args (); } +/* Accumulate to HSTATE a hash of expression EXP. + Identical to inchash::add_expr, but guaranteed to be stable across LTO + and DECL equality classes. */ + +void +sem_item::add_expr (const_tree exp, inchash::hash &hstate) +{ + if (exp == NULL_TREE) + { + hstate.merge_hash (0); + return; + } + + /* Handled component can be matched in a cureful way proving equivalence + even if they syntactically differ. Just skip them. */ + STRIP_NOPS (exp); + while (handled_component_p (exp)) + exp = TREE_OPERAND (exp, 0); + + enum tree_code code = TREE_CODE (exp); + hstate.add_int (code); + + switch (code) + { + /* Use inchash::add_expr for everything that is LTO stable. */ + case VOID_CST: + case INTEGER_CST: + case REAL_CST: + case FIXED_CST: + case STRING_CST: + case COMPLEX_CST: + case VECTOR_CST: + inchash::add_expr (exp, hstate); + break; + case CONSTRUCTOR: + { + unsigned HOST_WIDE_INT idx; + tree value; + + hstate.add_wide_int (int_size_in_bytes (TREE_TYPE (exp))); + + FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (exp), idx, value) + if (value) + add_expr (value, hstate); + break; + } + case ADDR_EXPR: + case FDESC_EXPR: + add_expr (get_base_address (TREE_OPERAND (exp, 0)), hstate); + break; + case SSA_NAME: + case VAR_DECL: + case CONST_DECL: + case PARM_DECL: + hstate.add_wide_int (int_size_in_bytes (TREE_TYPE (exp))); + break; + case MEM_REF: + case POINTER_PLUS_EXPR: + case MINUS_EXPR: + case RANGE_EXPR: + add_expr (TREE_OPERAND (exp, 0), hstate); + add_expr (TREE_OPERAND (exp, 1), hstate); + break; + case PLUS_EXPR: + { + inchash::hash one, two; + add_expr (TREE_OPERAND (exp, 0), one); + add_expr (TREE_OPERAND (exp, 1), two); + hstate.add_commutative (one, two); + } + break; + CASE_CONVERT: + hstate.add_wide_int (int_size_in_bytes (TREE_TYPE (exp))); + return add_expr (TREE_OPERAND (exp, 0), hstate); + default: + break; + } +} + /* Improve accumulated hash for HSTATE based on a gimple statement STMT. */ void -sem_function::hash_stmt (inchash::hash *hstate, gimple stmt) +sem_function::hash_stmt (gimple stmt, inchash::hash &hstate) { enum gimple_code code = gimple_code (stmt); - hstate->add_int (code); + hstate.add_int (code); - if (code == GIMPLE_CALL) + switch (code) { - /* Checking of argument. */ - for (unsigned i = 0; i < gimple_call_num_args (stmt); ++i) + case GIMPLE_ASSIGN: + if (commutative_tree_code (gimple_assign_rhs_code (stmt)) + || commutative_ternary_tree_code (gimple_assign_rhs_code (stmt))) { - tree argument = gimple_call_arg (stmt, i); + inchash::hash one, two; - switch (TREE_CODE (argument)) - { - case INTEGER_CST: - if (tree_fits_shwi_p (argument)) - hstate->add_wide_int (tree_to_shwi (argument)); - else if (tree_fits_uhwi_p (argument)) - hstate->add_wide_int (tree_to_uhwi (argument)); - break; - case REAL_CST: - REAL_VALUE_TYPE c; - HOST_WIDE_INT n; - - c = TREE_REAL_CST (argument); - n = real_to_integer (&c); - - hstate->add_wide_int (n); - break; - case ADDR_EXPR: - { - tree addr_operand = TREE_OPERAND (argument, 0); - - if (TREE_CODE (addr_operand) == STRING_CST) - hstate->add (TREE_STRING_POINTER (addr_operand), - TREE_STRING_LENGTH (addr_operand)); - break; - } - default: - break; - } + add_expr (gimple_assign_rhs1 (stmt), one); + add_expr (gimple_assign_rhs2 (stmt), two); + hstate.add_commutative (one, two); + add_expr (gimple_assign_lhs (stmt), hstate); + break; } + /* ... fall through ... */ + case GIMPLE_CALL: + case GIMPLE_ASM: + case GIMPLE_COND: + case GIMPLE_GOTO: + case GIMPLE_RETURN: + /* All these statements are equivalent if their operands are. */ + for (unsigned i = 0; i < gimple_num_ops (stmt); ++i) + add_expr (gimple_op (stmt, i), hstate); + default: + break; } } @@ -1071,7 +1239,7 @@ sem_function::parse (cgraph_node *node, bitmap_obstack *stack) tree fndecl = node->decl; function *func = DECL_STRUCT_FUNCTION (fndecl); - /* TODO: add support for thunks and aliases. */ + /* TODO: add support for thunks. */ if (!func || !node->has_gimple_body_p ()) return NULL; @@ -1267,20 +1435,98 @@ sem_variable::sem_variable (varpool_node *node, hashval_t _hash, gcc_checking_assert (get_node ()); } +/* Fast equality function based on knowledge known in WPA. */ + +bool +sem_variable::equals_wpa (sem_item *item, + hash_map &ignored_nodes) +{ + gcc_assert (item->type == VAR); + + if (node->num_references () != item->node->num_references ()) + return return_false_with_msg ("different number of references"); + + if (DECL_TLS_MODEL (decl) || DECL_TLS_MODEL (item->decl)) + return return_false_with_msg ("TLS model"); + + if (DECL_ALIGN (decl) != DECL_ALIGN (item->decl)) + return return_false_with_msg ("alignment mismatch"); + + if (DECL_VIRTUAL_P (decl) != DECL_VIRTUAL_P (item->decl)) + return return_false_with_msg ("Virtual flag mismatch"); + + if (DECL_SIZE (decl) != DECL_SIZE (item->decl) + && ((!DECL_SIZE (decl) || !DECL_SIZE (item->decl)) + || !operand_equal_p (DECL_SIZE (decl), + DECL_SIZE (item->decl), OEP_ONLY_CONST))) + return return_false_with_msg ("size mismatch"); + + /* Do not attempt to mix data from different user sections; + we do not know what user intends with those. */ + if (((DECL_SECTION_NAME (decl) && !node->implicit_section) + || (DECL_SECTION_NAME (item->decl) && !item->node->implicit_section)) + && DECL_SECTION_NAME (decl) != DECL_SECTION_NAME (item->decl)) + return return_false_with_msg ("user section mismatch"); + + if (DECL_IN_TEXT_SECTION (decl) != DECL_IN_TEXT_SECTION (item->decl)) + return return_false_with_msg ("text section"); + + ipa_ref *ref = NULL, *ref2 = NULL; + for (unsigned i = 0; node->iterate_reference (i, ref); i++) + { + item->node->iterate_reference (i, ref2); + + if (!compare_cgraph_references (ignored_nodes, + ref->referred, ref2->referred, + ref->address_matters_p ())) + return false; + + /* DECL_FINAL_P flag on methods referred by virtual tables is used + to decide on completeness possible_polymorphic_call_targets lists + and therefore it must match. */ + if ((DECL_VIRTUAL_P (decl) || DECL_VIRTUAL_P (item->decl)) + && (DECL_VIRTUAL_P (ref->referred->decl) + || DECL_VIRTUAL_P (ref2->referred->decl)) + && ((DECL_VIRTUAL_P (ref->referred->decl) + != DECL_VIRTUAL_P (ref2->referred->decl)) + || (DECL_FINAL_P (ref->referred->decl) + != DECL_FINAL_P (ref2->referred->decl)))) + return return_false_with_msg ("virtual or final flag mismatch"); + } + + return true; +} + +/* Returns true if the item equals to ITEM given as argument. */ + /* Returns true if the item equals to ITEM given as argument. */ bool sem_variable::equals (sem_item *item, - hash_map & ARG_UNUSED (ignored_nodes)) + hash_map &) { gcc_assert (item->type == VAR); + bool ret; + + if (DECL_INITIAL (decl) == error_mark_node && in_lto_p) + dyn_cast (node)->get_constructor (); + if (DECL_INITIAL (item->decl) == error_mark_node && in_lto_p) + dyn_cast (item->node)->get_constructor (); - sem_variable *v = static_cast(item); + /* As seen in PR ipa/65303 we have to compare variables types. */ + if (!func_checker::compatible_types_p (TREE_TYPE (decl), + TREE_TYPE (item->decl))) + return return_false_with_msg ("variables types are different"); - if (!ctor || !v->ctor) - return return_false_with_msg ("ctor is missing for semantic variable"); + ret = sem_variable::equals (DECL_INITIAL (decl), + DECL_INITIAL (item->node->decl)); + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, + "Equals called for vars:%s:%s (%u:%u) (%s:%s) with result: %s\n\n", + name(), item->name (), node->order, item->node->order, asm_name (), + item->asm_name (), ret ? "true" : "false"); - return sem_variable::equals (ctor, v->ctor); + return ret; } /* Compares trees T1 and T2 for semantic equality. */ @@ -1288,28 +1534,57 @@ sem_variable::equals (sem_item *item, bool sem_variable::equals (tree t1, tree t2) { + if (!t1 || !t2) + return return_with_debug (t1 == t2); + if (t1 == t2) + return true; tree_code tc1 = TREE_CODE (t1); tree_code tc2 = TREE_CODE (t2); if (tc1 != tc2) - return false; + return return_false_with_msg ("TREE_CODE mismatch"); switch (tc1) { case CONSTRUCTOR: { - unsigned len1 = vec_safe_length (CONSTRUCTOR_ELTS (t1)); - unsigned len2 = vec_safe_length (CONSTRUCTOR_ELTS (t2)); + vec *v1, *v2; + unsigned HOST_WIDE_INT idx; - if (len1 != len2) - return false; + enum tree_code typecode = TREE_CODE (TREE_TYPE (t1)); + if (typecode != TREE_CODE (TREE_TYPE (t2))) + return return_false_with_msg ("constructor type mismatch"); - for (unsigned i = 0; i < len1; i++) - if (!sem_variable::equals (CONSTRUCTOR_ELT (t1, i)->value, - CONSTRUCTOR_ELT (t2, i)->value) - || CONSTRUCTOR_ELT (t1, i)->index != CONSTRUCTOR_ELT (t2, i)->index) - return false; + if (typecode == ARRAY_TYPE) + { + HOST_WIDE_INT size_1 = int_size_in_bytes (TREE_TYPE (t1)); + /* For arrays, check that the sizes all match. */ + if (TYPE_MODE (TREE_TYPE (t1)) != TYPE_MODE (TREE_TYPE (t2)) + || size_1 == -1 + || size_1 != int_size_in_bytes (TREE_TYPE (t2))) + return return_false_with_msg ("constructor array size mismatch"); + } + else if (!func_checker::compatible_types_p (TREE_TYPE (t1), + TREE_TYPE (t2))) + return return_false_with_msg ("constructor type incompatible"); + + v1 = CONSTRUCTOR_ELTS (t1); + v2 = CONSTRUCTOR_ELTS (t2); + if (vec_safe_length (v1) != vec_safe_length (v2)) + return return_false_with_msg ("constructor number of elts mismatch"); + for (idx = 0; idx < vec_safe_length (v1); ++idx) + { + constructor_elt *c1 = &(*v1)[idx]; + constructor_elt *c2 = &(*v2)[idx]; + + /* Check that each value is the same... */ + if (!sem_variable::equals (c1->value, c2->value)) + return false; + /* ... and that they apply to the same fields! */ + if (!sem_variable::equals (c1->index, c2->index)) + return false; + } return true; } case MEM_REF: @@ -1324,32 +1599,100 @@ sem_variable::equals (tree t1, tree t2) return return_false (); /* Type of the offset on MEM_REF does not matter. */ - return sem_variable::equals (x1, x2) - && wi::to_offset (y1) == wi::to_offset (y2); + return return_with_debug (sem_variable::equals (x1, x2) + && wi::to_offset (y1) + == wi::to_offset (y2)); } - case NOP_EXPR: case ADDR_EXPR: + case FDESC_EXPR: { tree op1 = TREE_OPERAND (t1, 0); tree op2 = TREE_OPERAND (t2, 0); return sem_variable::equals (op1, op2); } + /* References to other vars/decls are compared using ipa-ref. */ case FUNCTION_DECL: case VAR_DECL: + if (decl_in_symtab_p (t1) && decl_in_symtab_p (t2)) + return true; + return return_false_with_msg ("Declaration mismatch"); + case CONST_DECL: + /* TODO: We can check CONST_DECL by its DECL_INITIAL, but for that we + need to process its VAR/FUNCTION references without relying on ipa-ref + compare. */ case FIELD_DECL: case LABEL_DECL: - return t1 == t2; + return return_false_with_msg ("Declaration mismatch"); case INTEGER_CST: - return func_checker::compatible_types_p (TREE_TYPE (t1), TREE_TYPE (t2), - true) - && wi::to_offset (t1) == wi::to_offset (t2); + /* Integer constants are the same only if the same width of type. */ + if (TYPE_PRECISION (TREE_TYPE (t1)) != TYPE_PRECISION (TREE_TYPE (t2))) + return return_false_with_msg ("INTEGER_CST precision mismatch"); + if (TYPE_MODE (TREE_TYPE (t1)) != TYPE_MODE (TREE_TYPE (t2))) + return return_false_with_msg ("INTEGER_CST mode mismatch"); + return return_with_debug (tree_int_cst_equal (t1, t2)); case STRING_CST: - case REAL_CST: + if (TYPE_MODE (TREE_TYPE (t1)) != TYPE_MODE (TREE_TYPE (t2))) + return return_false_with_msg ("STRING_CST mode mismatch"); + if (TREE_STRING_LENGTH (t1) != TREE_STRING_LENGTH (t2)) + return return_false_with_msg ("STRING_CST length mismatch"); + if (memcmp (TREE_STRING_POINTER (t1), TREE_STRING_POINTER (t2), + TREE_STRING_LENGTH (t1))) + return return_false_with_msg ("STRING_CST mismatch"); + return true; + case FIXED_CST: + /* Fixed constants are the same only if the same width of type. */ + if (TYPE_PRECISION (TREE_TYPE (t1)) != TYPE_PRECISION (TREE_TYPE (t2))) + return return_false_with_msg ("FIXED_CST precision mismatch"); + + return return_with_debug (FIXED_VALUES_IDENTICAL (TREE_FIXED_CST (t1), + TREE_FIXED_CST (t2))); case COMPLEX_CST: - return operand_equal_p (t1, t2, OEP_ONLY_CONST); - case COMPONENT_REF: + return (sem_variable::equals (TREE_REALPART (t1), TREE_REALPART (t2)) + && sem_variable::equals (TREE_IMAGPART (t1), TREE_IMAGPART (t2))); + case REAL_CST: + /* Real constants are the same only if the same width of type. */ + if (TYPE_PRECISION (TREE_TYPE (t1)) != TYPE_PRECISION (TREE_TYPE (t2))) + return return_false_with_msg ("REAL_CST precision mismatch"); + return return_with_debug (REAL_VALUES_IDENTICAL (TREE_REAL_CST (t1), + TREE_REAL_CST (t2))); + case VECTOR_CST: + { + unsigned i; + + if (VECTOR_CST_NELTS (t1) != VECTOR_CST_NELTS (t2)) + return return_false_with_msg ("VECTOR_CST nelts mismatch"); + + for (i = 0; i < VECTOR_CST_NELTS (t1); ++i) + if (!sem_variable::equals (VECTOR_CST_ELT (t1, i), + VECTOR_CST_ELT (t2, i))) + return 0; + + return 1; + } case ARRAY_REF: + case ARRAY_RANGE_REF: + { + tree x1 = TREE_OPERAND (t1, 0); + tree x2 = TREE_OPERAND (t2, 0); + tree y1 = TREE_OPERAND (t1, 1); + tree y2 = TREE_OPERAND (t2, 1); + + if (!sem_variable::equals (x1, x2) || !sem_variable::equals (y1, y2)) + return false; + if (!sem_variable::equals (array_ref_low_bound (t1), + array_ref_low_bound (t2))) + return false; + if (!sem_variable::equals (array_ref_element_size (t1), + array_ref_element_size (t2))) + return false; + return true; + } + + case COMPONENT_REF: case POINTER_PLUS_EXPR: + case PLUS_EXPR: + case MINUS_EXPR: + case RANGE_EXPR: { tree x1 = TREE_OPERAND (t1, 0); tree x2 = TREE_OPERAND (t2, 0); @@ -1358,6 +1701,13 @@ sem_variable::equals (tree t1, tree t2) return sem_variable::equals (x1, x2) && sem_variable::equals (y1, y2); } + + CASE_CONVERT: + case VIEW_CONVERT_EXPR: + if (!func_checker::compatible_types_p (TREE_TYPE (t1), TREE_TYPE (t2), + true)) + return return_false (); + return sem_variable::equals (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0)); case ERROR_MARK: return return_false_with_msg ("ERROR_MARK"); default: @@ -1370,21 +1720,8 @@ sem_variable::equals (tree t1, tree t2) sem_variable * sem_variable::parse (varpool_node *node, bitmap_obstack *stack) { - tree decl = node->decl; - - bool readonly = TYPE_P (decl) ? TYPE_READONLY (decl) : TREE_READONLY (decl); - if (!readonly) - return NULL; - - bool can_handle = DECL_VIRTUAL_P (decl) - || flag_merge_constants >= 2 - || (!TREE_ADDRESSABLE (decl) && !node->externally_visible); - - if (!can_handle || DECL_EXTERNAL (decl)) - return NULL; - - tree ctor = ctor_for_folding (decl); - if (!ctor) + if (TREE_THIS_VOLATILE (node->decl) || DECL_HARD_REGISTER (node->decl) + || node->alias) return NULL; sem_variable *v = new sem_variable (node, 0, stack); @@ -1400,19 +1737,19 @@ hashval_t sem_variable::get_hash (void) { if (hash) - return hash; + return hash; + /* All WPA streamed in symbols should have their hashes computed at compile + time. At this point, the constructor may not be in memory at all. + DECL_INITIAL (decl) would be error_mark_node in that case. */ + gcc_assert (!node->lto_file_data); + tree ctor = DECL_INITIAL (decl); inchash::hash hstate; hstate.add_int (456346417); - hstate.add_int (TREE_CODE (ctor)); - - if (TREE_CODE (ctor) == CONSTRUCTOR) - { - unsigned length = vec_safe_length (CONSTRUCTOR_ELTS (ctor)); - hstate.add_int (length); - } - + if (DECL_SIZE (decl) && tree_fits_shwi_p (DECL_SIZE (decl))) + hstate.add_wide_int (tree_to_shwi (DECL_SIZE (decl))); + add_expr (ctor, hstate); hash = hstate.end (); return hash; @@ -1492,11 +1829,16 @@ sem_variable::merge (sem_item *alias_item) "adress of original and alias may be compared.\n\n"); return false; } + if (DECL_COMDAT_GROUP (original->decl) != DECL_COMDAT_GROUP (alias->decl)) + { + if (dump_file) + fprintf (dump_file, "Not unifying; alias cannot be created; " + "across comdat group boundary\n\n"); + + return false; + } - if (original_discardable - && (!DECL_COMDAT_GROUP (original->decl) - || (DECL_COMDAT_GROUP (original->decl) - != DECL_COMDAT_GROUP (alias->decl)))) + if (original_discardable) { if (dump_file) fprintf (dump_file, "Not unifying; alias cannot be created; " @@ -1512,6 +1854,8 @@ sem_variable::merge (sem_item *alias_item) alias->analyzed = false; DECL_INITIAL (alias->decl) = NULL; + ((symtab_node *)alias)->call_for_symbol_and_aliases (clear_decl_rtl, + NULL, true); alias->need_bounds_init = false; alias->remove_all_references (); if (TREE_ADDRESSABLE (alias->decl)) @@ -1862,7 +2206,14 @@ sem_item_optimizer::filter_removed_items (void) if (!flag_ipa_icf_variables) remove_item (item); else - filtered.safe_push (item); + { + /* Filter out non-readonly variables. */ + tree decl = item->decl; + if (TREE_READONLY (decl)) + filtered.safe_push (item); + else + remove_item (item); + } } } @@ -1873,9 +2224,11 @@ sem_item_optimizer::filter_removed_items (void) m_items.safe_push (filtered[i]); } -/* Optimizer entry point. */ +/* Optimizer entry point which returns true in case it processes + a merge operation. True is returned if there's a merge operation + processed. */ -void +bool sem_item_optimizer::execute (void) { filter_removed_items (); @@ -1920,10 +2273,12 @@ sem_item_optimizer::execute (void) process_cong_reduction (); dump_cong_classes (); verify_classes (); - merge_classes (prev_class_count); + bool merged_p = merge_classes (prev_class_count); if (dump_file && (dump_flags & TDF_DETAILS)) symtab_node::dump_table (dump_file); + + return merged_p; } /* Function responsible for visiting all potential functions and @@ -2022,7 +2377,8 @@ sem_item_optimizer::build_graph (void) cgraph_edge *e = cnode->callees; while (e) { - sem_item **slot = m_symtab_node_map.get (e->callee); + sem_item **slot = m_symtab_node_map.get + (e->callee->ultimate_alias_target ()); if (slot) item->add_reference (*slot); @@ -2033,7 +2389,8 @@ sem_item_optimizer::build_graph (void) ipa_ref *ref = NULL; for (unsigned i = 0; item->node->iterate_reference (i, ref); i++) { - sem_item **slot = m_symtab_node_map.get (ref->referred); + sem_item **slot = m_symtab_node_map.get + (ref->referred->ultimate_alias_target ()); if (slot) item->add_reference (*slot); } @@ -2574,9 +2931,10 @@ sem_item_optimizer::dump_cong_classes (void) /* After reduction is done, we can declare all items in a group to be equal. PREV_CLASS_COUNT is start number of classes - before reduction. */ + before reduction. True is returned if there's a merge operation + processed. */ -void +bool sem_item_optimizer::merge_classes (unsigned int prev_class_count) { unsigned int item_count = m_items.length (); @@ -2586,6 +2944,8 @@ sem_item_optimizer::merge_classes (unsigned int prev_class_count) unsigned int non_singular_classes_count = 0; unsigned int non_singular_classes_sum = 0; + bool merged_p = false; + for (hash_table::iterator it = m_classes.begin (); it != m_classes.end (); ++it) for (unsigned int i = 0; i < (*it)->classes.length (); i++) @@ -2656,9 +3016,11 @@ sem_item_optimizer::merge_classes (unsigned int prev_class_count) alias->dump_to_file (dump_file); } - source->merge (alias); + merged_p |= source->merge (alias); } } + + return merged_p; } /* Dump function prints all class members to a FILE with an INDENT. */ @@ -2735,12 +3097,12 @@ ipa_icf_driver (void) { gcc_assert (optimizer); - optimizer->execute (); + bool merged_p = optimizer->execute (); delete optimizer; optimizer = NULL; - return 0; + return merged_p ? TODO_remove_functions : 0; } const pass_data pass_data_ipa_icf = diff --git a/contrib/gcc-5.0/gcc/ipa-icf.h b/contrib/gcc-5.0/gcc/ipa-icf.h index 9e762398ab..1481353388 100644 --- a/contrib/gcc-5.0/gcc/ipa-icf.h +++ b/contrib/gcc-5.0/gcc/ipa-icf.h @@ -110,7 +110,8 @@ struct symbol_compare_hashmap_traits: default_hashmap_traits equal_keys (const symbol_compare_collection *a, const symbol_compare_collection *b) { - if (a->m_references.length () != b->m_references.length ()) + if (a->m_references.length () != b->m_references.length () + || a->m_interposables.length () != b->m_interposables.length ()) return false; for (unsigned i = 0; i < a->m_references.length (); i++) @@ -241,6 +242,17 @@ protected: /* Cached, once calculated hash for the item. */ hashval_t hash; + /* Accumulate to HSTATE a hash of constructor expression EXP. */ + static void add_expr (const_tree exp, inchash::hash &hstate); + + /* For a given symbol table nodes N1 and N2, we check that FUNCTION_DECLs + point to a same function. Comparison can be skipped if IGNORED_NODES + contains these nodes. ADDRESS indicate if address is taken. */ + bool compare_cgraph_references (hash_map + &ignored_nodes, + symtab_node *n1, symtab_node *n2, + bool address); + private: /* Initialize internal data structures. Bitmap STACK is used for bitmap memory allocation process. */ @@ -289,7 +301,7 @@ public: } /* Improve accumulated hash for HSTATE based on a gimple statement STMT. */ - void hash_stmt (inchash::hash *inchash, gimple stmt); + void hash_stmt (gimple stmt, inchash::hash &inchash); /* Return true if polymorphic comparison must be processed. */ bool compare_polymorphic_p (void); @@ -350,13 +362,6 @@ private: ICF flags are the same. */ bool compare_edge_flags (cgraph_edge *e1, cgraph_edge *e2); - /* For a given symbol table nodes N1 and N2, we check that FUNCTION_DECLs - point to a same function. Comparison can be skipped if IGNORED_NODES - contains these nodes. */ - bool compare_cgraph_references (hash_map - &ignored_nodes, - symtab_node *n1, symtab_node *n2); - /* Processes function equality comparison. */ bool equals_private (sem_item *item, hash_map &ignored_nodes); @@ -388,7 +393,6 @@ public: inline virtual void init (void) { decl = get_node ()->decl; - ctor = ctor_for_folding (decl); } virtual hashval_t get_hash (void); @@ -398,12 +402,8 @@ public: hash_map &ignored_nodes); /* Fast equality variable based on knowledge known in WPA. */ - inline virtual bool equals_wpa (sem_item *item, - hash_map & ARG_UNUSED(ignored_nodes)) - { - gcc_assert (item->type == VAR); - return true; - } + virtual bool equals_wpa (sem_item *item, + hash_map &ignored_nodes); /* Returns varpool_node. */ inline varpool_node *get_node (void) @@ -414,9 +414,6 @@ public: /* Parser function that visits a varpool NODE. */ static sem_variable *parse (varpool_node *node, bitmap_obstack *stack); - /* Variable constructor. */ - tree ctor; - private: /* Iterates though a constructor and identifies tree references we are interested in semantic function equality. */ @@ -427,7 +424,6 @@ private: /* Compare that symbol sections are either NULL or have same name. */ bool compare_sections (sem_variable *alias); - }; // class sem_variable class sem_item_optimizer; @@ -474,8 +470,10 @@ public: read-only variables that can be merged. */ void parse_funcs_and_vars (void); - /* Optimizer entry point. */ - void execute (void); + /* Optimizer entry point which returns true in case it processes + a merge operation. True is returned if there's a merge operation + processed. */ + bool execute (void); /* Dump function. */ void dump (void); @@ -549,8 +547,9 @@ private: /* After reduction is done, we can declare all items in a group to be equal. PREV_CLASS_COUNT is start number of classes - before reduction. */ - void merge_classes (unsigned int prev_class_count); + before reduction. True is returned if there's a merge operation + processed. */ + bool merge_classes (unsigned int prev_class_count); /* Adds a newly created congruence class CLS to worklist. */ void worklist_push (congruence_class *cls); diff --git a/contrib/gcc-5.0/gcc/ipa-inline-analysis.c b/contrib/gcc-5.0/gcc/ipa-inline-analysis.c index be178ad445..d747163061 100644 --- a/contrib/gcc-5.0/gcc/ipa-inline-analysis.c +++ b/contrib/gcc-5.0/gcc/ipa-inline-analysis.c @@ -1291,7 +1291,8 @@ inline_summary_t::duplicate (cgraph_node *src, set_hint_predicate (&info->array_index, p); } } - inline_update_overall_summary (dst); + if (!dst->global.inlined_to) + inline_update_overall_summary (dst); } @@ -3924,10 +3925,11 @@ do_estimate_growth_1 (struct cgraph_node *node, void *data) continue; } - if (e->caller == d->node - || (e->caller->global.inlined_to - && e->caller->global.inlined_to == d->node)) - d->self_recursive = true; + if (e->recursive_p ()) + { + d->self_recursive = true; + continue; + } d->growth += estimate_edge_growth (e); } return false; @@ -4005,6 +4007,8 @@ growth_likely_positive (struct cgraph_node *node, struct cgraph_edge *e; gcc_checking_assert (edge_growth > 0); + 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 @@ -4012,18 +4016,13 @@ growth_likely_positive (struct cgraph_node *node, 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. - - Consequently we ask cgraph_can_remove_if_no_direct_calls_p - instead of - cgraph_will_be_removed_from_program_if_no_direct_calls */ - if (DECL_EXTERNAL (node->decl) - || !node->can_remove_if_no_direct_calls_p ()) - return true; - - if (!node->will_be_removed_from_program_if_no_direct_calls_p () - && (!DECL_COMDAT (node->decl) - || !node->can_remove_if_no_direct_calls_p ())) + 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; max_callers = inline_summaries->get (node)->size * 4 / edge_growth + 2; diff --git a/contrib/gcc-5.0/gcc/ipa-inline-transform.c b/contrib/gcc-5.0/gcc/ipa-inline-transform.c index 52493cc4d0..43bb41fa8f 100644 --- a/contrib/gcc-5.0/gcc/ipa-inline-transform.c +++ b/contrib/gcc-5.0/gcc/ipa-inline-transform.c @@ -112,9 +112,12 @@ can_remove_node_now_p_1 (struct cgraph_node *node, struct cgraph_edge *e) } /* FIXME: When address is taken of DECL_EXTERNAL function we still can remove its offline copy, but we would need to keep unanalyzed node in - the callgraph so references can point to it. */ + the callgraph so references can point to it. + + Also for comdat group we can ignore references inside a group as we + want to prove the group as a whole to be dead. */ return (!node->address_taken - && node->can_remove_if_no_direct_calls_p () + && node->can_remove_if_no_direct_calls_and_refs_p () /* Inlining might enable more devirtualizing, so we want to remove those only after all devirtualizable virtual calls are processed. Lacking may edges in callgraph we just preserve them post @@ -213,7 +216,7 @@ clone_inlined_nodes (struct cgraph_edge *e, bool duplicate, For now we keep the ohter functions in the group in program until cgraph_remove_unreachable_functions gets rid of them. */ gcc_assert (!e->callee->global.inlined_to); - e->callee->dissolve_same_comdat_group_list (); + e->callee->remove_from_same_comdat_group (); if (e->callee->definition && inline_account_function_p (e->callee)) { @@ -243,7 +246,7 @@ clone_inlined_nodes (struct cgraph_edge *e, bool duplicate, } } else - e->callee->dissolve_same_comdat_group_list (); + e->callee->remove_from_same_comdat_group (); e->callee->global.inlined_to = inlining_into; diff --git a/contrib/gcc-5.0/gcc/ipa-inline.c b/contrib/gcc-5.0/gcc/ipa-inline.c index c445f0a7a5..dd2e64ce28 100644 --- a/contrib/gcc-5.0/gcc/ipa-inline.c +++ b/contrib/gcc-5.0/gcc/ipa-inline.c @@ -310,7 +310,7 @@ sanitize_attrs_match_for_inline_p (const_tree caller, const_tree callee) static bool can_inline_edge_p (struct cgraph_edge *e, bool report, - bool disregard_limits = false) + bool disregard_limits = false, bool early = false) { bool inlinable = true; enum availability avail; @@ -409,39 +409,48 @@ can_inline_edge_p (struct cgraph_edge *e, bool report, Not even for always_inline declared functions. */ /* Strictly speaking only when the callee contains signed integer math where overflow is undefined. */ - if ((opt_for_fn (e->caller->decl, flag_strict_overflow) - != opt_for_fn (e->caller->decl, flag_strict_overflow)) - || (opt_for_fn (e->caller->decl, flag_wrapv) - != opt_for_fn (e->caller->decl, flag_wrapv)) - || (opt_for_fn (e->caller->decl, flag_trapv) - != opt_for_fn (e->caller->decl, flag_trapv)) + if ((opt_for_fn (caller->decl, flag_strict_overflow) + != opt_for_fn (caller->decl, flag_strict_overflow)) + || (opt_for_fn (caller->decl, flag_wrapv) + != opt_for_fn (caller->decl, flag_wrapv)) + || (opt_for_fn (caller->decl, flag_trapv) + != opt_for_fn (caller->decl, flag_trapv)) /* Strictly speaking only when the callee contains memory accesses that are not using alias-set zero anyway. */ - || (opt_for_fn (e->caller->decl, flag_strict_aliasing) - != opt_for_fn (e->caller->decl, flag_strict_aliasing)) + || (opt_for_fn (caller->decl, flag_strict_aliasing) + != opt_for_fn (caller->decl, flag_strict_aliasing)) /* Strictly speaking only when the callee uses FP math. */ - || (opt_for_fn (e->caller->decl, flag_rounding_math) - != opt_for_fn (e->caller->decl, flag_rounding_math)) - || (opt_for_fn (e->caller->decl, flag_trapping_math) - != opt_for_fn (e->caller->decl, flag_trapping_math)) - || (opt_for_fn (e->caller->decl, flag_unsafe_math_optimizations) - != opt_for_fn (e->caller->decl, flag_unsafe_math_optimizations)) - || (opt_for_fn (e->caller->decl, flag_finite_math_only) - != opt_for_fn (e->caller->decl, flag_finite_math_only)) - || (opt_for_fn (e->caller->decl, flag_signaling_nans) - != opt_for_fn (e->caller->decl, flag_signaling_nans)) - || (opt_for_fn (e->caller->decl, flag_cx_limited_range) - != opt_for_fn (e->caller->decl, flag_cx_limited_range)) - || (opt_for_fn (e->caller->decl, flag_signed_zeros) - != opt_for_fn (e->caller->decl, flag_signed_zeros)) - || (opt_for_fn (e->caller->decl, flag_associative_math) - != opt_for_fn (e->caller->decl, flag_associative_math)) - || (opt_for_fn (e->caller->decl, flag_reciprocal_math) - != opt_for_fn (e->caller->decl, flag_reciprocal_math)) + || (opt_for_fn (caller->decl, flag_rounding_math) + != opt_for_fn (caller->decl, flag_rounding_math)) + || (opt_for_fn (caller->decl, flag_trapping_math) + != opt_for_fn (caller->decl, flag_trapping_math)) + || (opt_for_fn (caller->decl, flag_unsafe_math_optimizations) + != opt_for_fn (caller->decl, flag_unsafe_math_optimizations)) + || (opt_for_fn (caller->decl, flag_finite_math_only) + != opt_for_fn (caller->decl, flag_finite_math_only)) + || (opt_for_fn (caller->decl, flag_signaling_nans) + != opt_for_fn (caller->decl, flag_signaling_nans)) + || (opt_for_fn (caller->decl, flag_cx_limited_range) + != opt_for_fn (caller->decl, flag_cx_limited_range)) + || (opt_for_fn (caller->decl, flag_signed_zeros) + != opt_for_fn (caller->decl, flag_signed_zeros)) + || (opt_for_fn (caller->decl, flag_associative_math) + != opt_for_fn (caller->decl, flag_associative_math)) + || (opt_for_fn (caller->decl, flag_reciprocal_math) + != opt_for_fn (caller->decl, flag_reciprocal_math)) /* Strictly speaking only when the callee contains function calls that may end up setting errno. */ - || (opt_for_fn (e->caller->decl, flag_errno_math) - != opt_for_fn (e->caller->decl, flag_errno_math))) + || (opt_for_fn (caller->decl, flag_errno_math) + != opt_for_fn (caller->decl, flag_errno_math)) + /* When devirtualization is diabled for callee, it is not safe + to inline it as we possibly mangled the type info. + Allow early inlining of always inlines. */ + || (opt_for_fn (caller->decl, flag_devirtualize) + && !opt_for_fn (callee->decl, flag_devirtualize) + && (!early + || (!DECL_DISREGARD_INLINE_LIMITS (callee->decl) + || !lookup_attribute ("always_inline", + DECL_ATTRIBUTES (callee->decl)))))) { e->inline_failed = CIF_OPTIMIZATION_MISMATCH; inlinable = false; @@ -532,7 +541,7 @@ can_early_inline_edge_p (struct cgraph_edge *e) fprintf (dump_file, " edge not inlinable: not in SSA form\n"); return false; } - if (!can_inline_edge_p (e, true)) + if (!can_inline_edge_p (e, true, false, true)) return false; return true; } @@ -943,6 +952,8 @@ check_callers (struct cgraph_node *node, void *has_hot_call) return true; if (!can_inline_edge_p (e, true)) return true; + if (e->recursive_p ()) + return true; if (!(*(bool *)has_hot_call) && e->maybe_hot_p ()) *(bool *)has_hot_call = true; } @@ -1701,7 +1712,7 @@ inline_small_functions (void) FOR_EACH_DEFINED_FUNCTION (node) { bool update = false; - struct cgraph_edge *next; + struct cgraph_edge *next = NULL; bool has_speculative = false; if (dump_file) @@ -2085,6 +2096,15 @@ inline_to_all_callers (struct cgraph_node *node, void *data) { struct cgraph_node *caller = node->callers->caller; + if (!can_inline_edge_p (node->callers, true) + || node->callers->recursive_p ()) + { + if (dump_file) + fprintf (dump_file, "Uninlinable call found; giving up.\n"); + *num_calls = 0; + return false; + } + if (dump_file) { fprintf (dump_file, diff --git a/contrib/gcc-5.0/gcc/ipa-polymorphic-call.c b/contrib/gcc-5.0/gcc/ipa-polymorphic-call.c index aaa549e03d..90303f1bcf 100644 --- a/contrib/gcc-5.0/gcc/ipa-polymorphic-call.c +++ b/contrib/gcc-5.0/gcc/ipa-polymorphic-call.c @@ -81,6 +81,8 @@ along with GCC; see the file COPYING3. If not see #include "data-streamer.h" #include "lto-streamer.h" #include "streamer-hooks.h" +#include "tree-ssa-operands.h" +#include "tree-into-ssa.h" /* Return true when TYPE contains an polymorphic type and thus is interesting for devirtualization machinery. */ @@ -804,7 +806,9 @@ walk_ssa_copies (tree op, hash_set **global_visited = NULL) STRIP_NOPS (op); while (TREE_CODE (op) == SSA_NAME && !SSA_NAME_IS_DEFAULT_DEF (op) - && SSA_NAME_DEF_STMT (op) + /* We might be called via fold_stmt during cfgcleanup where + SSA form need not be up-to-date. */ + && !name_registered_for_update_p (op) && (gimple_assign_single_p (SSA_NAME_DEF_STMT (op)) || gimple_code (SSA_NAME_DEF_STMT (op)) == GIMPLE_PHI)) { diff --git a/contrib/gcc-5.0/gcc/lra-assigns.c b/contrib/gcc-5.0/gcc/lra-assigns.c index 2462af5f17..e19156b328 100644 --- a/contrib/gcc-5.0/gcc/lra-assigns.c +++ b/contrib/gcc-5.0/gcc/lra-assigns.c @@ -491,10 +491,13 @@ adjust_hard_regno_cost (int hard_regno, int incr) pseudos in complicated situations where pseudo sizes are different. If TRY_ONLY_HARD_REGNO >= 0, consider only that hard register, - otherwise consider all hard registers in REGNO's class. */ + otherwise consider all hard registers in REGNO's class. + + If REGNO_SET is not empty, only hard registers from the set are + considered. */ static int -find_hard_regno_for (int regno, int *cost, int try_only_hard_regno, - bool first_p) +find_hard_regno_for_1 (int regno, int *cost, int try_only_hard_regno, + bool first_p, HARD_REG_SET regno_set) { HARD_REG_SET conflict_set; int best_cost = INT_MAX, best_priority = INT_MIN, best_usage = INT_MAX; @@ -509,7 +512,13 @@ find_hard_regno_for (int regno, int *cost, int try_only_hard_regno, bool *rclass_intersect_p; HARD_REG_SET impossible_start_hard_regs, available_regs; - COPY_HARD_REG_SET (conflict_set, lra_no_alloc_regs); + if (hard_reg_set_empty_p (regno_set)) + COPY_HARD_REG_SET (conflict_set, lra_no_alloc_regs); + else + { + COMPL_HARD_REG_SET (conflict_set, regno_set); + IOR_HARD_REG_SET (conflict_set, lra_no_alloc_regs); + } rclass = regno_allocno_class_array[regno]; rclass_intersect_p = ira_reg_classes_intersect_p[rclass]; curr_hard_regno_costs_check++; @@ -680,6 +689,33 @@ find_hard_regno_for (int regno, int *cost, int try_only_hard_regno, return best_hard_regno; } +/* A wrapper for find_hard_regno_for_1 (see comments for that function + description). This function tries to find a hard register for + preferred class first if it is worth. */ +static int +find_hard_regno_for (int regno, int *cost, int try_only_hard_regno, bool first_p) +{ + int hard_regno; + HARD_REG_SET regno_set; + + /* Only original pseudos can have a different preferred class. */ + if (try_only_hard_regno < 0 && regno < lra_new_regno_start) + { + enum reg_class pref_class = reg_preferred_class (regno); + + if (regno_allocno_class_array[regno] != pref_class) + { + hard_regno = find_hard_regno_for_1 (regno, cost, -1, first_p, + reg_class_contents[pref_class]); + if (hard_regno >= 0) + return hard_regno; + } + } + CLEAR_HARD_REG_SET (regno_set); + return find_hard_regno_for_1 (regno, cost, try_only_hard_regno, first_p, + regno_set); +} + /* Current value used for checking elements in update_hard_regno_preference_check. */ static int curr_update_hard_regno_preference_check; diff --git a/contrib/gcc-5.0/gcc/lra-constraints.c b/contrib/gcc-5.0/gcc/lra-constraints.c index 827c453b0f..0ddd842dee 100644 --- a/contrib/gcc-5.0/gcc/lra-constraints.c +++ b/contrib/gcc-5.0/gcc/lra-constraints.c @@ -154,6 +154,7 @@ #include "df.h" #include "ira.h" #include "rtl-error.h" +#include "params.h" #include "lra-int.h" /* Value of LRA_CURR_RELOAD_NUM at the beginning of BB of the current @@ -5694,7 +5695,8 @@ inherit_in_ebb (rtx_insn *head, rtx_insn *tail) /* This value affects EBB forming. If probability of edge from EBB to a BB is not greater than the following value, we don't add the BB to EBB. */ -#define EBB_PROBABILITY_CUTOFF ((REG_BR_PROB_BASE * 50) / 100) +#define EBB_PROBABILITY_CUTOFF \ + ((REG_BR_PROB_BASE * LRA_INHERITANCE_EBB_PROBABILITY_CUTOFF) / 100) /* Current number of inheritance/split iteration. */ int lra_inheritance_iter; @@ -5740,7 +5742,7 @@ lra_inheritance (void) e = find_fallthru_edge (bb->succs); if (! e) break; - if (e->probability <= EBB_PROBABILITY_CUTOFF) + if (e->probability < EBB_PROBABILITY_CUTOFF) break; bb = bb->next_bb; } diff --git a/contrib/gcc-5.0/gcc/lra-int.h b/contrib/gcc-5.0/gcc/lra-int.h index 972030992b..735259123d 100644 --- a/contrib/gcc-5.0/gcc/lra-int.h +++ b/contrib/gcc-5.0/gcc/lra-int.h @@ -321,6 +321,7 @@ extern void lra_create_copy (int, int, int); extern lra_copy_t lra_get_copy (int); extern bool lra_former_scratch_p (int); extern bool lra_former_scratch_operand_p (rtx_insn *, int); +extern void lra_register_new_scratch_op (rtx_insn *, int); extern int lra_new_regno_start; extern int lra_constraint_new_regno_start; diff --git a/contrib/gcc-5.0/gcc/lra-remat.c b/contrib/gcc-5.0/gcc/lra-remat.c index fb0eb3c1f7..ac82779571 100644 --- a/contrib/gcc-5.0/gcc/lra-remat.c +++ b/contrib/gcc-5.0/gcc/lra-remat.c @@ -1044,6 +1044,29 @@ get_hard_regs (struct lra_insn_reg *reg, int &nregs) return hard_regno; } +/* Make copy of and register scratch pseudos in rematerialized insn + REMAT_INSN. */ +static void +update_scratch_ops (rtx_insn *remat_insn) +{ + lra_insn_recog_data_t id = lra_get_insn_recog_data (remat_insn); + struct lra_static_insn_data *static_id = id->insn_static_data; + for (int i = 0; i < static_id->n_operands; i++) + { + rtx *loc = id->operand_loc[i]; + if (! REG_P (*loc)) + continue; + int regno = REGNO (*loc); + if (! lra_former_scratch_p (regno)) + continue; + *loc = lra_create_new_reg (GET_MODE (*loc), *loc, + lra_get_allocno_class (regno), + "scratch pseudo copy"); + lra_register_new_scratch_op (remat_insn, i); + } + +} + /* Insert rematerialization insns using the data-flow data calculated earlier. */ static bool @@ -1193,6 +1216,7 @@ do_remat (void) HOST_WIDE_INT sp_offset_change = cand_sp_offset - id->sp_offset; if (sp_offset_change != 0) change_sp_offset (remat_insn, sp_offset_change); + update_scratch_ops (remat_insn); lra_process_new_insns (insn, remat_insn, NULL, "Inserting rematerialization insn"); lra_set_insn_deleted (insn); diff --git a/contrib/gcc-5.0/gcc/lra.c b/contrib/gcc-5.0/gcc/lra.c index abe0c334b3..727a70e063 100644 --- a/contrib/gcc-5.0/gcc/lra.c +++ b/contrib/gcc-5.0/gcc/lra.c @@ -1907,6 +1907,24 @@ lra_former_scratch_operand_p (rtx_insn *insn, int nop) INSN_UID (insn) * MAX_RECOG_OPERANDS + nop) != 0; } +/* Register operand NOP in INSN as a former scratch. It will be + changed to scratch back, if it is necessary, at the LRA end. */ +void +lra_register_new_scratch_op (rtx_insn *insn, int nop) +{ + lra_insn_recog_data_t id = lra_get_insn_recog_data (insn); + rtx op = *id->operand_loc[nop]; + sloc_t loc = XNEW (struct sloc); + lra_assert (REG_P (op)); + loc->insn = insn; + loc->nop = nop; + scratches.safe_push (loc); + bitmap_set_bit (&scratch_bitmap, REGNO (op)); + bitmap_set_bit (&scratch_operand_bitmap, + INSN_UID (insn) * MAX_RECOG_OPERANDS + nop); + add_reg_note (insn, REG_UNUSED, op); +} + /* Change scratches onto pseudos and save their location. */ static void remove_scratches (void) @@ -1916,7 +1934,6 @@ remove_scratches (void) basic_block bb; rtx_insn *insn; rtx reg; - sloc_t loc; lra_insn_recog_data_t id; struct lra_static_insn_data *static_id; @@ -1938,15 +1955,7 @@ remove_scratches (void) *id->operand_loc[i] = reg = lra_create_new_reg (static_id->operand[i].mode, *id->operand_loc[i], ALL_REGS, NULL); - add_reg_note (insn, REG_UNUSED, reg); - lra_update_dup (id, i); - loc = XNEW (struct sloc); - loc->insn = insn; - loc->nop = i; - scratches.safe_push (loc); - bitmap_set_bit (&scratch_bitmap, REGNO (*id->operand_loc[i])); - bitmap_set_bit (&scratch_operand_bitmap, - INSN_UID (insn) * MAX_RECOG_OPERANDS + i); + lra_register_new_scratch_op (insn, i); if (lra_dump_file != NULL) fprintf (lra_dump_file, "Removing SCRATCH in insn #%u (nop %d)\n", diff --git a/contrib/gcc-5.0/gcc/params.def b/contrib/gcc-5.0/gcc/params.def index 4d3b398259..f890cb0e17 100644 --- a/contrib/gcc-5.0/gcc/params.def +++ b/contrib/gcc-5.0/gcc/params.def @@ -836,6 +836,11 @@ DEFPARAM (PARAM_LRA_MAX_CONSIDERED_RELOAD_PSEUDOS, "The max number of reload pseudos which are considered during spilling a non-reload pseudo", 500, 0, 0) +DEFPARAM (PARAM_LRA_INHERITANCE_EBB_PROBABILITY_CUTOFF, + "lra-inheritance-ebb-probability-cutoff", + "Minimal fall-through edge probability in percentage used to add BB to inheritance EBB in LRA", + 40, 0, 100) + /* Switch initialization conversion will refuse to create arrays that are bigger than this parameter times the number of switch branches. */ diff --git a/contrib/gcc-5.0/gcc/params.h b/contrib/gcc-5.0/gcc/params.h index 2e50ff474c..28d077f5b1 100644 --- a/contrib/gcc-5.0/gcc/params.h +++ b/contrib/gcc-5.0/gcc/params.h @@ -202,6 +202,8 @@ extern void init_param_values (int *params); PARAM_VALUE (PARAM_IRA_LOOP_RESERVED_REGS) #define LRA_MAX_CONSIDERED_RELOAD_PSEUDOS \ PARAM_VALUE (PARAM_LRA_MAX_CONSIDERED_RELOAD_PSEUDOS) +#define LRA_INHERITANCE_EBB_PROBABILITY_CUTOFF \ + PARAM_VALUE (PARAM_LRA_INHERITANCE_EBB_PROBABILITY_CUTOFF) #define SWITCH_CONVERSION_BRANCH_RATIO \ PARAM_VALUE (PARAM_SWITCH_CONVERSION_BRANCH_RATIO) #define LOOP_INVARIANT_MAX_BBS_IN_LOOP \ diff --git a/contrib/gcc-5.0/gcc/real.c b/contrib/gcc-5.0/gcc/real.c index 1d1d510333..43f124e05f 100644 --- a/contrib/gcc-5.0/gcc/real.c +++ b/contrib/gcc-5.0/gcc/real.c @@ -2075,7 +2075,7 @@ real_from_string (REAL_VALUE_TYPE *r, const char *str) because the hex digits used in real_from_mpfr did not start with a digit 8 to f, but the exponent bounds above should have avoided underflow or overflow. */ - gcc_assert (r->cl = rvc_normal); + gcc_assert (r->cl == rvc_normal); /* Set a sticky bit if mpfr_strtofr was inexact. */ r->sig[0] |= inexact; mpfr_clear (m); diff --git a/contrib/gcc-5.0/gcc/stor-layout.c b/contrib/gcc-5.0/gcc/stor-layout.c index 273a12b0cf..f18f1ac527 100644 --- a/contrib/gcc-5.0/gcc/stor-layout.c +++ b/contrib/gcc-5.0/gcc/stor-layout.c @@ -1627,11 +1627,6 @@ finalize_record_size (record_layout_info rli) unpadded_size_unit = size_binop (PLUS_EXPR, unpadded_size_unit, size_one_node); - if (TREE_CODE (unpadded_size_unit) == INTEGER_CST - && !TREE_OVERFLOW (unpadded_size_unit) - && !valid_constant_size_p (unpadded_size_unit)) - error ("type %qT is too large", rli->t); - /* Round the size up to be a multiple of the required alignment. */ TYPE_SIZE (rli->t) = round_up (unpadded_size, TYPE_ALIGN (rli->t)); TYPE_SIZE_UNIT (rli->t) diff --git a/contrib/gcc-5.0/gcc/tree-chkp.c b/contrib/gcc-5.0/gcc/tree-chkp.c index b0a3a1547f..d2df4bad0f 100644 --- a/contrib/gcc-5.0/gcc/tree-chkp.c +++ b/contrib/gcc-5.0/gcc/tree-chkp.c @@ -1268,7 +1268,8 @@ chkp_check_lower (tree addr, tree bounds, gimple check; tree node; - if (bounds == chkp_get_zero_bounds ()) + if (!chkp_function_instrumented_p (current_function_decl) + && bounds == chkp_get_zero_bounds ()) return; if (dirflag == integer_zero_node @@ -1314,7 +1315,8 @@ chkp_check_upper (tree addr, tree bounds, gimple check; tree node; - if (bounds == chkp_get_zero_bounds ()) + if (!chkp_function_instrumented_p (current_function_decl) + && bounds == chkp_get_zero_bounds ()) return; if (dirflag == integer_zero_node @@ -4306,6 +4308,10 @@ chkp_fini (void) free_dominance_info (CDI_POST_DOMINATORS); bitmap_obstack_release (NULL); + + entry_block = NULL; + zero_bounds = NULL_TREE; + none_bounds = NULL_TREE; } /* Main instrumentation pass function. */ diff --git a/contrib/gcc-5.0/gcc/tree-sra.c b/contrib/gcc-5.0/gcc/tree-sra.c index 023b817230..3527a47256 100644 --- a/contrib/gcc-5.0/gcc/tree-sra.c +++ b/contrib/gcc-5.0/gcc/tree-sra.c @@ -4947,8 +4947,8 @@ convert_callers (struct cgraph_node *node, tree old_decl, { basic_block this_block; - node->call_for_symbol_thunks_and_aliases (convert_callers_for_node, - &adjustments, false); + node->call_for_symbol_and_aliases (convert_callers_for_node, + &adjustments, false); if (!encountered_recursive_call) return; @@ -5009,13 +5009,60 @@ modify_function (struct cgraph_node *node, ipa_parm_adjustment_vec adjustments) return cfg_changed; } -/* If NODE has a caller, return true. */ +/* Means of communication between ipa_sra_check_caller and + ipa_sra_preliminary_function_checks. */ + +struct ipa_sra_check_caller_data +{ + bool has_callers; + bool bad_arg_alignment; + bool has_thunk; +}; + +/* If NODE has a caller, mark that fact in DATA which is pointer to + ipa_sra_check_caller_data. Also check all aggregate arguments in all known + calls if they are unit aligned and if not, set the appropriate flag in DATA + too. */ static bool -has_caller_p (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED) +ipa_sra_check_caller (struct cgraph_node *node, void *data) { - if (node->callers) - return true; + if (!node->callers) + return false; + + struct ipa_sra_check_caller_data *iscc; + iscc = (struct ipa_sra_check_caller_data *) data; + iscc->has_callers = true; + + for (cgraph_edge *cs = node->callers; cs; cs = cs->next_caller) + { + if (cs->caller->thunk.thunk_p) + { + iscc->has_thunk = true; + return true; + } + gimple call_stmt = cs->call_stmt; + unsigned count = gimple_call_num_args (call_stmt); + for (unsigned i = 0; i < count; i++) + { + tree arg = gimple_call_arg (call_stmt, i); + if (is_gimple_reg (arg)) + continue; + + tree offset; + HOST_WIDE_INT bitsize, bitpos; + machine_mode mode; + int unsignedp, volatilep = 0; + get_inner_reference (arg, &bitsize, &bitpos, &offset, &mode, + &unsignedp, &volatilep, false); + if (bitpos % BITS_PER_UNIT) + { + iscc->bad_arg_alignment = true; + return true; + } + } + } + return false; } @@ -5070,14 +5117,6 @@ ipa_sra_preliminary_function_checks (struct cgraph_node *node) return false; } - if (!node->call_for_symbol_thunks_and_aliases (has_caller_p, NULL, true)) - { - if (dump_file) - fprintf (dump_file, - "Function has no callers in this compilation unit.\n"); - return false; - } - if (cfun->stdarg) { if (dump_file) @@ -5096,6 +5135,33 @@ ipa_sra_preliminary_function_checks (struct cgraph_node *node) return false; } + struct ipa_sra_check_caller_data iscc; + memset (&iscc, 0, sizeof(iscc)); + node->call_for_symbol_and_aliases (ipa_sra_check_caller, &iscc, true); + if (!iscc.has_callers) + { + if (dump_file) + fprintf (dump_file, + "Function has no callers in this compilation unit.\n"); + return false; + } + + if (iscc.bad_arg_alignment) + { + if (dump_file) + fprintf (dump_file, + "A function call has an argument with non-unit alignment.\n"); + return false; + } + + if (iscc.has_thunk) + { + if (dump_file) + fprintf (dump_file, + "A has thunk.\n"); + return false; + } + return true; } @@ -5121,7 +5187,7 @@ ipa_early_sra (void) goto simple_out; } - if (node->call_for_symbol_thunks_and_aliases + if (node->call_for_symbol_and_aliases (some_callers_have_mismatched_arguments_p, NULL, true)) { if (dump_file) @@ -5130,7 +5196,7 @@ ipa_early_sra (void) goto simple_out; } - if (node->call_for_symbol_thunks_and_aliases + if (node->call_for_symbol_and_aliases (some_callers_have_no_vuse_p, NULL, true)) { if (dump_file) diff --git a/contrib/gcc-5.0/gcc/tree-ssa-coalesce.c b/contrib/gcc-5.0/gcc/tree-ssa-coalesce.c index be696fe814..1afeefef2e 100644 --- a/contrib/gcc-5.0/gcc/tree-ssa-coalesce.c +++ b/contrib/gcc-5.0/gcc/tree-ssa-coalesce.c @@ -1344,7 +1344,7 @@ coalesce_ssa_name (void) if (dump_file && (dump_flags & TDF_DETAILS)) dump_var_map (dump_file, map); - liveinfo = calculate_live_ranges (map); + liveinfo = calculate_live_ranges (map, false); if (dump_file && (dump_flags & TDF_DETAILS)) dump_live_info (dump_file, liveinfo, LIVEDUMP_ENTRY); diff --git a/contrib/gcc-5.0/gcc/tree-ssa-dom.c b/contrib/gcc-5.0/gcc/tree-ssa-dom.c index 096e471267..d230ce1c7b 100644 --- a/contrib/gcc-5.0/gcc/tree-ssa-dom.c +++ b/contrib/gcc-5.0/gcc/tree-ssa-dom.c @@ -2649,19 +2649,22 @@ lookup_avail_expr (gimple stmt, bool insert) && walk_non_aliased_vuses (&ref, vuse2, vuse_eq, NULL, NULL, vuse1) != NULL)) { - struct expr_hash_elt *element2 = XNEW (struct expr_hash_elt); - *element2 = element; - element2->stamp = element2; - - /* Insert the expr into the hash by replacing the current - entry and recording the value to restore in the - aval_exprs_stack. */ - avail_exprs_stack.safe_push (std::make_pair (element2, *slot)); - *slot = element2; - if (dump_file && (dump_flags & TDF_DETAILS)) + if (insert) { - fprintf (dump_file, "2>>> "); - print_expr_hash_elt (dump_file, *slot); + struct expr_hash_elt *element2 = XNEW (struct expr_hash_elt); + *element2 = element; + element2->stamp = element2; + + /* Insert the expr into the hash by replacing the current + entry and recording the value to restore in the + avail_exprs_stack. */ + avail_exprs_stack.safe_push (std::make_pair (element2, *slot)); + *slot = element2; + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "2>>> "); + print_expr_hash_elt (dump_file, *slot); + } } return NULL_TREE; } diff --git a/contrib/gcc-5.0/gcc/tree-ssa-live.c b/contrib/gcc-5.0/gcc/tree-ssa-live.c index cc164fb32b..e0c4266938 100644 --- a/contrib/gcc-5.0/gcc/tree-ssa-live.c +++ b/contrib/gcc-5.0/gcc/tree-ssa-live.c @@ -973,13 +973,6 @@ remove_unused_locals (void) timevar_pop (TV_REMOVE_UNUSED); } -/* Obstack for globale liveness info bitmaps. We don't want to put these - on the default obstack because these bitmaps can grow quite large and - we'll hold on to all that memory until the end of the compiler run. - As a bonus, delete_tree_live_info can destroy all the bitmaps by just - releasing the whole obstack. */ -static bitmap_obstack liveness_bitmap_obstack; - /* Allocate and return a new live range information object base on MAP. */ static tree_live_info_p @@ -992,18 +985,20 @@ new_tree_live_info (var_map map) live->map = map; live->num_blocks = last_basic_block_for_fn (cfun); + bitmap_obstack_initialize (&live->livein_obstack); + bitmap_obstack_initialize (&live->liveout_obstack); live->livein = XNEWVEC (bitmap_head, last_basic_block_for_fn (cfun)); FOR_EACH_BB_FN (bb, cfun) - bitmap_initialize (&live->livein[bb->index], &liveness_bitmap_obstack); + bitmap_initialize (&live->livein[bb->index], &live->livein_obstack); live->liveout = XNEWVEC (bitmap_head, last_basic_block_for_fn (cfun)); FOR_EACH_BB_FN (bb, cfun) - bitmap_initialize (&live->liveout[bb->index], &liveness_bitmap_obstack); + bitmap_initialize (&live->liveout[bb->index], &live->liveout_obstack); live->work_stack = XNEWVEC (int, last_basic_block_for_fn (cfun)); live->stack_top = live->work_stack; - live->global = BITMAP_ALLOC (&liveness_bitmap_obstack); + live->global = BITMAP_ALLOC (NULL); return live; } @@ -1013,10 +1008,18 @@ new_tree_live_info (var_map map) void delete_tree_live_info (tree_live_info_p live) { - bitmap_obstack_release (&liveness_bitmap_obstack); + if (live->livein) + { + bitmap_obstack_release (&live->livein_obstack); + free (live->livein); + } + if (live->liveout) + { + bitmap_obstack_release (&live->liveout_obstack); + free (live->liveout); + } + BITMAP_FREE (live->global); free (live->work_stack); - free (live->liveout); - free (live->livein); free (live); } @@ -1027,8 +1030,7 @@ delete_tree_live_info (tree_live_info_p live) it each time. */ static void -loe_visit_block (tree_live_info_p live, basic_block bb, sbitmap visited, - bitmap tmp) +loe_visit_block (tree_live_info_p live, basic_block bb, sbitmap visited) { edge e; bool change; @@ -1046,17 +1048,17 @@ loe_visit_block (tree_live_info_p live, basic_block bb, sbitmap visited, pred_bb = e->src; if (pred_bb == ENTRY_BLOCK_PTR_FOR_FN (cfun)) continue; - /* TMP is variables live-on-entry from BB that aren't defined in the + /* Variables live-on-entry from BB that aren't defined in the predecessor block. This should be the live on entry vars to pred. Note that liveout is the DEFs in a block while live on entry is - being calculated. */ - bitmap_and_compl (tmp, loe, &live->liveout[pred_bb->index]); - - /* Add these bits to live-on-entry for the pred. if there are any + being calculated. + Add these bits to live-on-entry for the pred. if there are any changes, and pred_bb has been visited already, add it to the revisit stack. */ - change = bitmap_ior_into (live_on_entry (live, pred_bb), tmp); - if (bitmap_bit_p (visited, pred_bb->index) && change) + change = bitmap_ior_and_compl_into (live_on_entry (live, pred_bb), + loe, &live->liveout[pred_bb->index]); + if (change + && bitmap_bit_p (visited, pred_bb->index)) { bitmap_clear_bit (visited, pred_bb->index); *(live->stack_top)++ = pred_bb->index; @@ -1074,23 +1076,21 @@ live_worklist (tree_live_info_p live) unsigned b; basic_block bb; sbitmap visited = sbitmap_alloc (last_basic_block_for_fn (cfun) + 1); - bitmap tmp = BITMAP_ALLOC (&liveness_bitmap_obstack); bitmap_clear (visited); /* Visit all the blocks in reverse order and propagate live on entry values into the predecessors blocks. */ FOR_EACH_BB_REVERSE_FN (bb, cfun) - loe_visit_block (live, bb, visited, tmp); + loe_visit_block (live, bb, visited); /* Process any blocks which require further iteration. */ while (live->stack_top != live->work_stack) { b = *--(live->stack_top); - loe_visit_block (live, BASIC_BLOCK_FOR_FN (cfun, b), visited, tmp); + loe_visit_block (live, BASIC_BLOCK_FOR_FN (cfun, b), visited); } - BITMAP_FREE (tmp); sbitmap_free (visited); } @@ -1175,7 +1175,7 @@ set_var_live_on_entry (tree ssa_name, tree_live_info_p live) /* Calculate the live on exit vectors based on the entry info in LIVEINFO. */ -void +static void calculate_live_on_exit (tree_live_info_p liveinfo) { basic_block bb; @@ -1226,13 +1226,12 @@ calculate_live_on_exit (tree_live_info_p liveinfo) each partition. Return a new live info object. */ tree_live_info_p -calculate_live_ranges (var_map map) +calculate_live_ranges (var_map map, bool want_livein) { tree var; unsigned i; tree_live_info_p live; - bitmap_obstack_initialize (&liveness_bitmap_obstack); live = new_tree_live_info (map); for (i = 0; i < num_var_partitions (map); i++) { @@ -1248,6 +1247,14 @@ calculate_live_ranges (var_map map) #endif calculate_live_on_exit (live); + + if (!want_livein) + { + bitmap_obstack_release (&live->livein_obstack); + free (live->livein); + live->livein = NULL; + } + return live; } diff --git a/contrib/gcc-5.0/gcc/tree-ssa-live.h b/contrib/gcc-5.0/gcc/tree-ssa-live.h index f872910089..d5d78209ce 100644 --- a/contrib/gcc-5.0/gcc/tree-ssa-live.h +++ b/contrib/gcc-5.0/gcc/tree-ssa-live.h @@ -242,6 +242,10 @@ typedef struct tree_live_info_d /* Top of workstack. */ int *stack_top; + + /* Obstacks to allocate the bitmaps on. */ + bitmap_obstack livein_obstack; + bitmap_obstack liveout_obstack; } *tree_live_info_p; @@ -249,8 +253,7 @@ typedef struct tree_live_info_d #define LIVEDUMP_EXIT 0x02 #define LIVEDUMP_ALL (LIVEDUMP_ENTRY | LIVEDUMP_EXIT) extern void delete_tree_live_info (tree_live_info_p); -extern void calculate_live_on_exit (tree_live_info_p); -extern tree_live_info_p calculate_live_ranges (var_map); +extern tree_live_info_p calculate_live_ranges (var_map, bool); extern void debug (tree_live_info_d &ref); extern void debug (tree_live_info_d *ptr); extern void dump_live_info (FILE *, tree_live_info_p, int); diff --git a/contrib/gcc-5.0/gcc/tree-ssa-phiopt.c b/contrib/gcc-5.0/gcc/tree-ssa-phiopt.c index c7fb073129..14a7122f97 100644 --- a/contrib/gcc-5.0/gcc/tree-ssa-phiopt.c +++ b/contrib/gcc-5.0/gcc/tree-ssa-phiopt.c @@ -96,8 +96,6 @@ static bool minmax_replacement (basic_block, basic_block, edge, edge, gimple, tree, tree); static bool abs_replacement (basic_block, basic_block, edge, edge, gimple, tree, tree); -static bool neg_replacement (basic_block, basic_block, - edge, edge, gimple, tree, tree); static bool cond_store_replacement (basic_block, basic_block, edge, edge, hash_set *); static bool cond_if_else_store_replacement (basic_block, basic_block, basic_block); @@ -209,23 +207,6 @@ tree_ssa_phiopt_worker (bool do_store_elim, bool do_hoist_loads) /* Calculate the set of non-trapping memory accesses. */ nontrap = get_non_trapping (); - /* The replacement of conditional negation with a non-branching - sequence is really only a win when optimizing for speed and we - can avoid transformations by gimple if-conversion that result - in poor RTL generation. - - Ideally either gimple if-conversion or the RTL expanders will - be improved and the code to emit branchless conditional negation - can be removed. */ - bool replace_conditional_negation = false; - if (!do_store_elim) - replace_conditional_negation - = ((!optimize_size && optimize >= 2) - || (((flag_tree_loop_vectorize || cfun->has_force_vectorize_loops) - && flag_tree_loop_if_convert != 0) - || flag_tree_loop_if_convert == 1 - || flag_tree_loop_if_convert_stores == 1)); - /* Search every basic block for COND_EXPR we may be able to optimize. We walk the blocks in order that guarantees that a block with @@ -380,9 +361,6 @@ tree_ssa_phiopt_worker (bool do_store_elim, bool do_hoist_loads) cfgchanged = true; else if (abs_replacement (bb, bb1, e1, e2, phi, arg0, arg1)) cfgchanged = true; - else if (replace_conditional_negation - && neg_replacement (bb, bb1, e1, e2, phi, arg0, arg1)) - cfgchanged = true; else if (minmax_replacement (bb, bb1, e1, e2, phi, arg0, arg1)) cfgchanged = true; } @@ -1319,140 +1297,6 @@ abs_replacement (basic_block cond_bb, basic_block middle_bb, return true; } -/* The function neg_replacement replaces conditional negation with - equivalent straight line code. Returns TRUE if replacement is done, - otherwise returns FALSE. - - COND_BB branches around negation occuring in MIDDLE_BB. - - E0 and E1 are edges out of COND_BB. E0 reaches MIDDLE_BB and - E1 reaches the other successor which should contain PHI with - arguments ARG0 and ARG1. - - Assuming negation is to occur when the condition is true, - then the non-branching sequence is: - - result = (rhs ^ -cond) + cond - - Inverting the condition or its result gives us negation - when the original condition is false. */ - -static bool -neg_replacement (basic_block cond_bb, basic_block middle_bb, - edge e0 ATTRIBUTE_UNUSED, edge e1, - gimple phi, tree arg0, tree arg1) -{ - gimple new_stmt, cond; - gimple_stmt_iterator gsi; - gimple assign; - edge true_edge, false_edge; - tree rhs, lhs; - enum tree_code cond_code; - bool invert = false; - - /* This transformation performs logical operations on the - incoming arguments. So force them to be integral types. */ - if (!INTEGRAL_TYPE_P (TREE_TYPE (arg0))) - return false; - - /* OTHER_BLOCK must have only one executable statement which must have the - form arg0 = -arg1 or arg1 = -arg0. */ - - assign = last_and_only_stmt (middle_bb); - /* If we did not find the proper negation assignment, then we can not - optimize. */ - if (assign == NULL) - return false; - - /* If we got here, then we have found the only executable statement - in OTHER_BLOCK. If it is anything other than arg0 = -arg1 or - arg1 = -arg0, then we can not optimize. */ - if (gimple_code (assign) != GIMPLE_ASSIGN) - return false; - - lhs = gimple_assign_lhs (assign); - - if (gimple_assign_rhs_code (assign) != NEGATE_EXPR) - return false; - - rhs = gimple_assign_rhs1 (assign); - - /* The assignment has to be arg0 = -arg1 or arg1 = -arg0. */ - if (!(lhs == arg0 && rhs == arg1) - && !(lhs == arg1 && rhs == arg0)) - return false; - - /* The basic sequence assumes we negate when the condition is true. - If we need the opposite, then we will either need to invert the - condition or its result. */ - extract_true_false_edges_from_block (cond_bb, &true_edge, &false_edge); - invert = false_edge->dest == middle_bb; - - /* Unlike abs_replacement, we can handle arbitrary conditionals here. */ - cond = last_stmt (cond_bb); - cond_code = gimple_cond_code (cond); - - /* If inversion is needed, first try to invert the test since - that's cheapest. */ - if (invert) - { - bool honor_nans = HONOR_NANS (gimple_cond_lhs (cond)); - enum tree_code new_code = invert_tree_comparison (cond_code, honor_nans); - - /* If invert_tree_comparison was successful, then use its return - value as the new code and note that inversion is no longer - needed. */ - if (new_code != ERROR_MARK) - { - cond_code = new_code; - invert = false; - } - } - - tree cond_val = make_ssa_name (boolean_type_node); - new_stmt = gimple_build_assign (cond_val, cond_code, - gimple_cond_lhs (cond), - gimple_cond_rhs (cond)); - gsi = gsi_last_bb (cond_bb); - gsi_insert_before (&gsi, new_stmt, GSI_NEW_STMT); - - /* If we still need inversion, then invert the result of the - condition. */ - if (invert) - { - tree tmp = make_ssa_name (boolean_type_node); - new_stmt = gimple_build_assign (tmp, BIT_XOR_EXPR, cond_val, - boolean_true_node); - gsi_insert_after (&gsi, new_stmt, GSI_NEW_STMT); - cond_val = tmp; - } - - /* Get the condition in the right type so that we can perform - logical and arithmetic operations on it. */ - tree cond_val_converted = make_ssa_name (TREE_TYPE (rhs)); - new_stmt = gimple_build_assign (cond_val_converted, NOP_EXPR, cond_val); - gsi_insert_after (&gsi, new_stmt, GSI_NEW_STMT); - - tree neg_cond_val_converted = make_ssa_name (TREE_TYPE (rhs)); - new_stmt = gimple_build_assign (neg_cond_val_converted, NEGATE_EXPR, - cond_val_converted); - gsi_insert_after (&gsi, new_stmt, GSI_NEW_STMT); - - tree tmp = make_ssa_name (TREE_TYPE (rhs)); - new_stmt = gimple_build_assign (tmp, BIT_XOR_EXPR, rhs, - neg_cond_val_converted); - gsi_insert_after (&gsi, new_stmt, GSI_NEW_STMT); - - tree new_lhs = make_ssa_name (TREE_TYPE (rhs)); - new_stmt = gimple_build_assign (new_lhs, PLUS_EXPR, tmp, cond_val_converted); - gsi_insert_after (&gsi, new_stmt, GSI_NEW_STMT); - - replace_phi_edge_with_variable (cond_bb, e1, phi, new_lhs); - - /* Note that we optimized this PHI. */ - return true; -} - /* Auxiliary functions to determine the set of memory accesses which can't trap because they are preceded by accesses to the same memory portion. We do that for MEM_REFs, so we only need to track 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 2c74060d79..ffe83e2b2f 100644 --- a/contrib/gcc-5.0/gcc/tree-vect-data-refs.c +++ b/contrib/gcc-5.0/gcc/tree-vect-data-refs.c @@ -650,7 +650,8 @@ vect_compute_data_ref_alignment (struct data_reference *dr) tree base, base_addr; bool base_aligned; tree misalign; - tree aligned_to, alignment; + tree aligned_to; + unsigned HOST_WIDE_INT alignment; if (dump_enabled_p ()) dump_printf_loc (MSG_NOTE, vect_location, @@ -720,36 +721,43 @@ vect_compute_data_ref_alignment (struct data_reference *dr) } } - base = build_fold_indirect_ref (base_addr); - alignment = ssize_int (TYPE_ALIGN (vectype)/BITS_PER_UNIT); + alignment = TYPE_ALIGN_UNIT (vectype); - if ((aligned_to && tree_int_cst_compare (aligned_to, alignment) < 0) + if ((compare_tree_int (aligned_to, alignment) < 0) || !misalign) { if (dump_enabled_p ()) { dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, "Unknown alignment for access: "); - dump_generic_expr (MSG_MISSED_OPTIMIZATION, TDF_SLIM, base); + dump_generic_expr (MSG_MISSED_OPTIMIZATION, TDF_SLIM, ref); dump_printf (MSG_MISSED_OPTIMIZATION, "\n"); } return true; } - if ((DECL_P (base) - && tree_int_cst_compare (ssize_int (DECL_ALIGN_UNIT (base)), - alignment) >= 0) - || (TREE_CODE (base_addr) == SSA_NAME - && tree_int_cst_compare (ssize_int (TYPE_ALIGN_UNIT (TREE_TYPE ( - TREE_TYPE (base_addr)))), - alignment) >= 0) - || (get_pointer_alignment (base_addr) >= TYPE_ALIGN (vectype))) + /* To look at alignment of the base we have to preserve an inner MEM_REF + as that carries alignment information of the actual access. */ + base = ref; + while (handled_component_p (base)) + base = TREE_OPERAND (base, 0); + if (TREE_CODE (base) == MEM_REF) + base = build2 (MEM_REF, TREE_TYPE (base), base_addr, + build_int_cst (TREE_TYPE (TREE_OPERAND (base, 1)), 0)); + + if (get_object_alignment (base) >= TYPE_ALIGN (vectype)) base_aligned = true; else base_aligned = false; if (!base_aligned) { + /* Strip an inner MEM_REF to a bare decl if possible. */ + if (TREE_CODE (base) == MEM_REF + && integer_zerop (TREE_OPERAND (base, 1)) + && 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 @@ -784,7 +792,7 @@ vect_compute_data_ref_alignment (struct data_reference *dr) /* If this is a backward running DR then first access in the larger vectype actually is N-1 elements before the address in the DR. Adjust misalign accordingly. */ - if (tree_int_cst_compare (DR_STEP (dr), size_zero_node) < 0) + if (tree_int_cst_sgn (DR_STEP (dr)) < 0) { tree offset = ssize_int (TYPE_VECTOR_SUBPARTS (vectype) - 1); /* DR_STEP(dr) is the same as -TYPE_SIZE of the scalar type, @@ -794,19 +802,8 @@ vect_compute_data_ref_alignment (struct data_reference *dr) misalign = size_binop (PLUS_EXPR, misalign, offset); } - /* Modulo alignment. */ - misalign = size_binop (FLOOR_MOD_EXPR, misalign, alignment); - - if (!tree_fits_uhwi_p (misalign)) - { - /* Negative or overflowed misalignment value. */ - if (dump_enabled_p ()) - dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, - "unexpected misalign value\n"); - return false; - } - - SET_DR_MISALIGNMENT (dr, tree_to_uhwi (misalign)); + SET_DR_MISALIGNMENT (dr, + wi::mod_floor (misalign, alignment, SIGNED).to_uhwi ()); if (dump_enabled_p ()) { diff --git a/contrib/gcc-5.0/gcc/tree.c b/contrib/gcc-5.0/gcc/tree.c index 29f70f8ec1..0b8e8961b0 100644 --- a/contrib/gcc-5.0/gcc/tree.c +++ b/contrib/gcc-5.0/gcc/tree.c @@ -5081,9 +5081,15 @@ free_lang_data_in_type (tree type) if (TYPE_BINFO (type)) { free_lang_data_in_binfo (TYPE_BINFO (type)); + /* We need to preserve link to bases and virtual table for all + polymorphic types to make devirtualization machinery working. + Debug output cares only about bases, but output also + virtual table pointers so merging of -fdevirtualize and + -fno-devirtualize units is easier. */ if ((!BINFO_VTABLE (TYPE_BINFO (type)) || !flag_devirtualize) - && (!BINFO_N_BASE_BINFOS (TYPE_BINFO (type)) + && ((!BINFO_N_BASE_BINFOS (TYPE_BINFO (type)) + && !BINFO_VTABLE (TYPE_BINFO (type))) || debug_info_level != DINFO_LEVEL_NONE)) TYPE_BINFO (type) = NULL; } diff --git a/contrib/gcc-5.0/gcc/tree.h b/contrib/gcc-5.0/gcc/tree.h index c3e9a63e96..8f93a512a7 100644 --- a/contrib/gcc-5.0/gcc/tree.h +++ b/contrib/gcc-5.0/gcc/tree.h @@ -3278,6 +3278,11 @@ non_type_check (const_tree __t, const char *__f, int __l, const char *__g) return __t; } +# if GCC_VERSION >= 4006 +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wstrict-overflow" +#endif + inline const_tree * tree_vec_elt_check (const_tree __t, int __i, const char *__f, int __l, const char *__g) @@ -3290,6 +3295,10 @@ tree_vec_elt_check (const_tree __t, int __i, //return &__t->vec.a[__i]; } +# if GCC_VERSION >= 4006 +#pragma GCC diagnostic pop +#endif + inline const_tree * omp_clause_elt_check (const_tree __t, int __i, const char *__f, int __l, const char *__g) diff --git a/contrib/gcc-5.0/gcc/value-prof.c b/contrib/gcc-5.0/gcc/value-prof.c index 1de8e1b806..b16bce8746 100644 --- a/contrib/gcc-5.0/gcc/value-prof.c +++ b/contrib/gcc-5.0/gcc/value-prof.c @@ -1576,6 +1576,8 @@ gimple_ic (gcall *icall_stmt, struct cgraph_node *direct_call, PHI_ARG_DEF_FROM_EDGE (phi, e_eh)); } } + if (!stmt_could_throw_p (dcall_stmt)) + gimple_purge_dead_eh_edges (dcall_bb); return dcall_stmt; } diff --git a/contrib/gcc-5.0/include/ansidecl.h b/contrib/gcc-5.0/include/ansidecl.h index 0fb23bba79..04d75c33f7 100644 --- a/contrib/gcc-5.0/include/ansidecl.h +++ b/contrib/gcc-5.0/include/ansidecl.h @@ -276,6 +276,15 @@ So instead we use the macro below and test it against specific values. */ # endif /* GNUC >= 4.3 */ #endif /* ATTRIBUTE_HOT */ +/* Attribute 'no_sanitize_undefined' was valid as of gcc 4.9. */ +#ifndef ATTRIBUTE_NO_SANITIZE_UNDEFINED +# if (GCC_VERSION >= 4009) +# define ATTRIBUTE_NO_SANITIZE_UNDEFINED __attribute__ ((no_sanitize_undefined)) +# else +# define ATTRIBUTE_NO_SANITIZE_UNDEFINED +# endif /* GNUC >= 4.9 */ +#endif /* ATTRIBUTE_NO_SANITIZE_UNDEFINED */ + /* We use __extension__ in some places to suppress -pedantic warnings about GCC extensions. This feature didn't work properly before gcc 2.8. */ diff --git a/contrib/gcc-5.0/libcpp/lex.c b/contrib/gcc-5.0/libcpp/lex.c index 4638510166..0dc4737118 100644 --- a/contrib/gcc-5.0/libcpp/lex.c +++ b/contrib/gcc-5.0/libcpp/lex.c @@ -519,6 +519,7 @@ init_vectorized_lexer (void) and VSX unaligned loads (when VSX is available). This is otherwise the same as the pre-GCC 5 version. */ +ATTRIBUTE_NO_SANITIZE_UNDEFINED static const uchar * search_line_fast (const uchar *s, const uchar *end ATTRIBUTE_UNUSED) { diff --git a/contrib/gcc-5.0/libgcc/config/gthr-vxworks.h b/contrib/gcc-5.0/libgcc/config/gthr-vxworks.h index 2f64b010ed..c90879a21b 100644 --- a/contrib/gcc-5.0/libgcc/config/gthr-vxworks.h +++ b/contrib/gcc-5.0/libgcc/config/gthr-vxworks.h @@ -36,7 +36,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #ifdef __cplusplus #define UNUSED(x) #else -#define UNUSED(x) x __attribute__((unused)) +#define UNUSED(x) x __attribute__((__unused__)) #endif #ifdef __cplusplus diff --git a/contrib/gcc-5.0/libgcc/gthr-single.h b/contrib/gcc-5.0/libgcc/gthr-single.h index f084fe2515..bddded4f24 100644 --- a/contrib/gcc-5.0/libgcc/gthr-single.h +++ b/contrib/gcc-5.0/libgcc/gthr-single.h @@ -38,7 +38,7 @@ typedef int __gthread_recursive_mutex_t; #define __GTHREAD_MUTEX_INIT_FUNCTION(mx) #define __GTHREAD_RECURSIVE_MUTEX_INIT 0 -#define UNUSED __attribute__((unused)) +#define UNUSED __attribute__((__unused__)) #ifdef _LIBOBJC diff --git a/contrib/gcc-5.0/libgcc/libgcov-util.c b/contrib/gcc-5.0/libgcc/libgcov-util.c index f9c1c679f8..d76c2eb485 100644 --- a/contrib/gcc-5.0/libgcc/libgcov-util.c +++ b/contrib/gcc-5.0/libgcc/libgcov-util.c @@ -52,7 +52,9 @@ void gcov_set_verbose (void) #include "obstack.h" #include +#ifdef HAVE_FTW_H #include +#endif static void tag_function (unsigned, unsigned); static void tag_blocks (unsigned, unsigned); @@ -380,6 +382,7 @@ read_gcda_file (const char *filename) return obj_info; } +#ifdef HAVE_FTW_H /* This will be called by ftw(). It opens and read a gcda file FILENAME. Return a non-zero value to stop the tree walk. */ @@ -417,6 +420,7 @@ ftw_read_file (const char *filename, return 0; } +#endif /* Initializer for reading a profile dir. */ @@ -451,7 +455,9 @@ gcov_read_profile_dir (const char* dir_name, int recompute_summary ATTRIBUTE_UNU fnotice (stderr, "%s is not a directory\n", dir_name); return NULL; } +#ifdef HAVE_FTW_H ftw (".", ftw_read_file, 50); +#endif ret = chdir (pwd); free (pwd); diff --git a/contrib/gcc-5.0/libstdc++-v3/include/bits/locale_conv.h b/contrib/gcc-5.0/libstdc++-v3/include/bits/locale_conv.h index c8a44f4242..9b49617b7a 100644 --- a/contrib/gcc-5.0/libstdc++-v3/include/bits/locale_conv.h +++ b/contrib/gcc-5.0/libstdc++-v3/include/bits/locale_conv.h @@ -198,18 +198,27 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION auto __outstr = __err ? _OutStr(__err->get_allocator()) : _OutStr(); size_t __outchars = 0; auto __next = __first; + const auto __maxlen = _M_cvt->max_length(); codecvt_base::result __result; do { - __outstr.resize(__outstr.size() + (__last - __next)); + __outstr.resize(__outstr.size() + (__last - __next) + __maxlen); auto __outnext = &__outstr.front() + __outchars; auto const __outlast = &__outstr.back() + 1; __result = ((*_M_cvt).*__memfn)(_M_state, __next, __last, __next, __outnext, __outlast, __outnext); __outchars = __outnext - &__outstr.front(); } - while (__result == codecvt_base::partial && __next != __last); + while (__result == codecvt_base::partial && __next != __last + && (__outstr.size() - __outchars) < __maxlen); + + if (__result == codecvt_base::noconv) + { + __outstr.assign(__first, __last); + _M_count = __outstr.size(); + return __outstr; + } __outstr.resize(__outchars); _M_count = __next - __first; @@ -428,7 +437,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return _M_put(__next, __pending); if (!_M_put(__outbuf, __outnext - __outbuf)) - return false; + return false; } while (__next != __last && __next != __start); diff --git a/contrib/gcc-5.0/libstdc++-v3/include/std/codecvt b/contrib/gcc-5.0/libstdc++-v3/include/std/codecvt index d58a0ecd67..e4a7d5bbb6 100644 --- a/contrib/gcc-5.0/libstdc++-v3/include/std/codecvt +++ b/contrib/gcc-5.0/libstdc++-v3/include/std/codecvt @@ -148,7 +148,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION public: \ explicit \ _NAME(size_t __refs = 0) \ - : __ ## _NAME ## _base<_ELEM>(_Maxcode, _Mode, __refs) { } \ + : __ ## _NAME ## _base<_ELEM>(std::min(_Maxcode, 0x10fffful), \ + _Mode, __refs) \ + { } \ } template class __codecvt_utf8_base; diff --git a/contrib/gcc-5.0/libstdc++-v3/include/std/future b/contrib/gcc-5.0/libstdc++-v3/include/std/future index cb0226dec4..fc3f8162ae 100644 --- a/contrib/gcc-5.0/libstdc++-v3/include/std/future +++ b/contrib/gcc-5.0/libstdc++-v3/include/std/future @@ -98,7 +98,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION public: explicit future_error(error_code __ec) - : logic_error("std::future_error"), _M_code(__ec) + : logic_error("std::future_error: " + __ec.message()), _M_code(__ec) { } virtual ~future_error() noexcept; diff --git a/contrib/gcc-5.0/libstdc++-v3/include/std/scoped_allocator b/contrib/gcc-5.0/libstdc++-v3/include/std/scoped_allocator index 1be10b294c..d163edd109 100644 --- a/contrib/gcc-5.0/libstdc++-v3/include/std/scoped_allocator +++ b/contrib/gcc-5.0/libstdc++-v3/include/std/scoped_allocator @@ -105,6 +105,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __inner_type_impl() = default; __inner_type_impl(const __inner_type_impl&) = default; __inner_type_impl(__inner_type_impl&&) = default; + __inner_type_impl& operator=(const __inner_type_impl&) = default; + __inner_type_impl& operator=(__inner_type_impl&&) = default; template __inner_type_impl(const __inner_type_impl<_Alloc>& __other) @@ -136,6 +138,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __inner_type_impl() = default; __inner_type_impl(const __inner_type_impl&) = default; __inner_type_impl(__inner_type_impl&&) = default; + __inner_type_impl& operator=(const __inner_type_impl&) = default; + __inner_type_impl& operator=(__inner_type_impl&&) = default; template __inner_type_impl(const __inner_type_impl<_Allocs...>& __other) @@ -310,6 +314,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _M_inner(std::move(__other._M_inner)) { } + scoped_allocator_adaptor& + operator=(const scoped_allocator_adaptor&) = default; + + scoped_allocator_adaptor& + operator=(scoped_allocator_adaptor&&) = default; + inner_allocator_type& inner_allocator() noexcept { return _M_inner._M_get(this); } diff --git a/contrib/gcc-5.0/libstdc++-v3/include/std/stdexcept b/contrib/gcc-5.0/libstdc++-v3/include/std/stdexcept index bf3e618128..24289194d0 100644 --- a/contrib/gcc-5.0/libstdc++-v3/include/std/stdexcept +++ b/contrib/gcc-5.0/libstdc++-v3/include/std/stdexcept @@ -80,7 +80,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION union { __str _M_s; - char _M_bytes[sizeof(_M_s)]; + char _M_bytes[sizeof(__str)]; }; __sso_string() _GLIBCXX_USE_NOEXCEPT; diff --git a/contrib/gcc-5.0/libstdc++-v3/src/c++11/codecvt.cc b/contrib/gcc-5.0/libstdc++-v3/src/c++11/codecvt.cc index aebd3f3498..83ee6e0683 100644 --- a/contrib/gcc-5.0/libstdc++-v3/src/c++11/codecvt.cc +++ b/contrib/gcc-5.0/libstdc++-v3/src/c++11/codecvt.cc @@ -35,8 +35,14 @@ namespace { // Largest code point that fits in a single UTF-16 code unit. const char32_t max_single_utf16_unit = 0xFFFF; + const char32_t max_code_point = 0x10FFFF; + // The functions below rely on maxcode < incomplete_mb_character + // (which is enforced by the codecvt_utf* classes on construction). + const char32_t incomplete_mb_character = char32_t(-2); + const char32_t invalid_mb_sequence = char32_t(-1); + template struct range { @@ -131,13 +137,13 @@ namespace // Read a codepoint from a UTF-8 multibyte sequence. // Updates from.next if the codepoint is not greater than maxcode. - // Returns -1 if there is an invalid or incomplete multibyte character. + // Returns invalid_mb_sequence, incomplete_mb_character or the code point. char32_t read_utf8_code_point(range& from, unsigned long maxcode) { - size_t avail = from.size(); + const size_t avail = from.size(); if (avail == 0) - return -1; + return incomplete_mb_character; unsigned char c1 = from.next[0]; // https://en.wikipedia.org/wiki/UTF-8#Sample_code if (c1 < 0x80) @@ -146,14 +152,14 @@ namespace return c1; } else if (c1 < 0xC2) // continuation or overlong 2-byte sequence - return -1; + return invalid_mb_sequence; else if (c1 < 0xE0) // 2-byte sequence { if (avail < 2) - return -1; + return incomplete_mb_character; unsigned char c2 = from.next[1]; if ((c2 & 0xC0) != 0x80) - return -1; + return invalid_mb_sequence; char32_t c = (c1 << 6) + c2 - 0x3080; if (c <= maxcode) from.next += 2; @@ -162,15 +168,15 @@ namespace else if (c1 < 0xF0) // 3-byte sequence { if (avail < 3) - return -1; + return incomplete_mb_character; unsigned char c2 = from.next[1]; if ((c2 & 0xC0) != 0x80) - return -1; + return invalid_mb_sequence; if (c1 == 0xE0 && c2 < 0xA0) // overlong - return -1; + return invalid_mb_sequence; unsigned char c3 = from.next[2]; if ((c3 & 0xC0) != 0x80) - return -1; + return invalid_mb_sequence; char32_t c = (c1 << 12) + (c2 << 6) + c3 - 0xE2080; if (c <= maxcode) from.next += 3; @@ -179,27 +185,27 @@ namespace else if (c1 < 0xF5) // 4-byte sequence { if (avail < 4) - return -1; + return incomplete_mb_character; unsigned char c2 = from.next[1]; if ((c2 & 0xC0) != 0x80) - return -1; + return invalid_mb_sequence; if (c1 == 0xF0 && c2 < 0x90) // overlong - return -1; + return invalid_mb_sequence; if (c1 == 0xF4 && c2 >= 0x90) // > U+10FFFF - return -1; + return invalid_mb_sequence; unsigned char c3 = from.next[2]; if ((c3 & 0xC0) != 0x80) - return -1; + return invalid_mb_sequence; unsigned char c4 = from.next[3]; if ((c4 & 0xC0) != 0x80) - return -1; + return invalid_mb_sequence; char32_t c = (c1 << 18) + (c2 << 12) + (c3 << 6) + c4 - 0x3C82080; if (c <= maxcode) from.next += 4; return c; } else // > U+10FFFF - return -1; + return invalid_mb_sequence; } bool @@ -250,27 +256,54 @@ namespace #endif } + // Return true if c is a high-surrogate (aka leading) code point. + inline bool + is_high_surrogate(char32_t c) + { + return c >= 0xD800 && c <= 0xDBFF; + } + + // Return true if c is a low-surrogate (aka trailing) code point. + inline bool + is_low_surrogate(char32_t c) + { + return c >= 0xDC00 && c <= 0xDFFF; + } + + inline char32_t + surrogate_pair_to_code_point(char32_t high, char32_t low) + { + return (high << 10) + low - 0x35FDC00; + } + // Read a codepoint from a UTF-16 multibyte sequence. // The sequence's endianness is indicated by (mode & little_endian). // Updates from.next if the codepoint is not greater than maxcode. - // Returns -1 if there is an incomplete multibyte character. + // Returns invalid_mb_sequence, incomplete_mb_character or the code point. char32_t read_utf16_code_point(range& from, unsigned long maxcode, codecvt_mode mode) { + const size_t avail = from.size(); + if (avail == 0) + return incomplete_mb_character; int inc = 1; char32_t c = adjust_byte_order(from.next[0], mode); - if (c >= 0xD800 && c <= 0xDBFF) + if (is_high_surrogate(c)) { - if (from.size() < 2) - return -1; + if (avail < 2) + return incomplete_mb_character; const char16_t c2 = adjust_byte_order(from.next[1], mode); - if (c2 >= 0xDC00 && c2 <= 0xDFFF) + if (is_low_surrogate(c2)) { - c = (c << 10) + c2 - 0x35FDC00; + c = surrogate_pair_to_code_point(c, c2); inc = 2; } + else + return invalid_mb_sequence; } + else if (is_low_surrogate(c)) + return invalid_mb_sequence; if (c <= maxcode) from.next += inc; return c; @@ -314,8 +347,8 @@ namespace while (from.size() && to.size()) { const char32_t codepoint = read_utf8_code_point(from, maxcode); - if (codepoint == char32_t(-1)) - break; + if (codepoint == incomplete_mb_character) + return codecvt_base::partial; if (codepoint > maxcode) return codecvt_base::error; *to.next++ = codepoint; @@ -352,8 +385,8 @@ namespace while (from.size() && to.size()) { const char32_t codepoint = read_utf16_code_point(from, maxcode, mode); - if (codepoint == char32_t(-1)) - break; + if (codepoint == incomplete_mb_character) + return codecvt_base::partial; if (codepoint > maxcode) return codecvt_base::error; *to.next++ = codepoint; @@ -389,11 +422,9 @@ namespace read_utf8_bom(from, mode); while (from.size() && to.size()) { - const char* first = from.next; - if ((unsigned char)*first >= 0xF0 && to.size() < 2) - return codecvt_base::partial; + const char* const first = from.next; const char32_t codepoint = read_utf8_code_point(from, maxcode); - if (codepoint == char32_t(-1)) + if (codepoint == incomplete_mb_character) return codecvt_base::partial; if (codepoint > maxcode) return codecvt_base::error; @@ -418,20 +449,22 @@ namespace { char32_t c = from.next[0]; int inc = 1; - if (c >= 0xD800 && c <= 0xDBFF) // start of surrogate pair + if (is_high_surrogate(c)) { if (from.size() < 2) return codecvt_base::ok; // stop converting at this point const char32_t c2 = from.next[1]; - if (c2 >= 0xDC00 && c2 <= 0xDFFF) + if (is_low_surrogate(c2)) { + c = surrogate_pair_to_code_point(c, c2); inc = 2; - c = (c << 10) + c2 - 0x35FDC00; } else return codecvt_base::error; } + else if (is_low_surrogate(c)) + return codecvt_base::error; if (c > maxcode) return codecvt_base::error; if (!write_utf8_code_point(to, c)) @@ -452,8 +485,8 @@ namespace while (count+1 < max) { char32_t c = read_utf8_code_point(from, maxcode); - if (c == char32_t(-1)) - break; + if (c > maxcode) + return from.next; else if (c > max_single_utf16_unit) ++count; ++count; @@ -489,7 +522,7 @@ namespace while (from.size() && to.size()) { char16_t c = from.next[0]; - if (c >= 0xD800 && c <= 0xDBFF) // start of surrogate pair + if (is_high_surrogate(c)) return codecvt_base::error; if (c > maxcode) return codecvt_base::error; @@ -510,9 +543,9 @@ namespace while (from.size() && to.size()) { const char32_t c = read_utf16_code_point(from, maxcode, mode); - if (c == char32_t(-1)) - break; - if (c >= maxcode) + if (c == incomplete_mb_character) + return codecvt_base::partial; + if (c > maxcode) return codecvt_base::error; *to.next++ = c; } diff --git a/contrib/gcc-5.0/libstdc++-v3/src/c++11/future.cc b/contrib/gcc-5.0/libstdc++-v3/src/c++11/future.cc index c711a5fe82..3cf503b6b3 100644 --- a/contrib/gcc-5.0/libstdc++-v3/src/c++11/future.cc +++ b/contrib/gcc-5.0/libstdc++-v3/src/c++11/future.cc @@ -75,7 +75,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION future_error::~future_error() noexcept { } const char* - future_error::what() const noexcept { return _M_code.message().c_str(); } + future_error::what() const noexcept { return logic_error::what(); } #if defined(_GLIBCXX_HAS_GTHREADS) && defined(_GLIBCXX_USE_C99_STDINT_TR1) \ && (ATOMIC_INT_LOCK_FREE > 1)