Update gcc-50 to SVN version 221044
authorJohn Marino <draco@marino.st>
Fri, 27 Feb 2015 08:01:52 +0000 (09:01 +0100)
committerJohn Marino <draco@marino.st>
Fri, 27 Feb 2015 10:12:51 +0000 (11:12 +0100)
Last Changed Date: 2015-02-27 09:37:51 +0100 (Fri, 27 Feb 2015)

57 files changed:
contrib/gcc-5.0/LAST_UPDATED
contrib/gcc-5.0/gcc/DATESTAMP
contrib/gcc-5.0/gcc/builtin-types.def
contrib/gcc-5.0/gcc/builtins.c
contrib/gcc-5.0/gcc/c-family/c-common.c
contrib/gcc-5.0/gcc/cgraph.c
contrib/gcc-5.0/gcc/cgraph.h
contrib/gcc-5.0/gcc/cgraphclones.c
contrib/gcc-5.0/gcc/cgraphunit.c
contrib/gcc-5.0/gcc/common.opt
contrib/gcc-5.0/gcc/config/i386/i386.c
contrib/gcc-5.0/gcc/config/i386/i386.h
contrib/gcc-5.0/gcc/cp/constexpr.c
contrib/gcc-5.0/gcc/cp/decl.c
contrib/gcc-5.0/gcc/cp/decl2.c
contrib/gcc-5.0/gcc/data-streamer-in.c
contrib/gcc-5.0/gcc/doc/extend.texi
contrib/gcc-5.0/gcc/doc/rtl.texi
contrib/gcc-5.0/gcc/doc/tm.texi
contrib/gcc-5.0/gcc/dwarf2out.c
contrib/gcc-5.0/gcc/gimple.h
contrib/gcc-5.0/gcc/gimplify.c
contrib/gcc-5.0/gcc/ipa-icf-gimple.c
contrib/gcc-5.0/gcc/ipa-icf.c
contrib/gcc-5.0/gcc/ipa-icf.h
contrib/gcc-5.0/gcc/ipa-inline-analysis.c
contrib/gcc-5.0/gcc/ipa-inline.c
contrib/gcc-5.0/gcc/ipa-prop.c
contrib/gcc-5.0/gcc/ipa-ref.h
contrib/gcc-5.0/gcc/ipa-visibility.c
contrib/gcc-5.0/gcc/ira-color.c
contrib/gcc-5.0/gcc/lra-remat.c
contrib/gcc-5.0/gcc/lto-cgraph.c
contrib/gcc-5.0/gcc/lto-section-in.c
contrib/gcc-5.0/gcc/lto-streamer-in.c
contrib/gcc-5.0/gcc/lto-streamer-out.c
contrib/gcc-5.0/gcc/lto-streamer.h
contrib/gcc-5.0/gcc/lto/lto-lang.c
contrib/gcc-5.0/gcc/lto/lto.c
contrib/gcc-5.0/gcc/omp-builtins.def
contrib/gcc-5.0/gcc/omp-low.c
contrib/gcc-5.0/gcc/passes.c
contrib/gcc-5.0/gcc/real.c
contrib/gcc-5.0/gcc/real.h
contrib/gcc-5.0/gcc/symtab.c
contrib/gcc-5.0/gcc/target.def
contrib/gcc-5.0/gcc/tree-ssa-math-opts.c
contrib/gcc-5.0/gcc/tree-ssa-propagate.c
contrib/gcc-5.0/gcc/tree-ssa-reassoc.c
contrib/gcc-5.0/gcc/tree-ssa-threadupdate.c
contrib/gcc-5.0/gcc/tree-streamer-in.c
contrib/gcc-5.0/gcc/tree-streamer-out.c
contrib/gcc-5.0/gcc/tree-streamer.c
contrib/gcc-5.0/gcc/tree-streamer.h
contrib/gcc-5.0/gcc/tree-vect-loop.c
contrib/gcc-5.0/gcc/wide-int.cc
contrib/gcc-5.0/libgcc/config/nvptx/t-nvptx

index cf7d741..738c046 100644 (file)
@@ -1,2 +1,2 @@
-220871
-Last Changed Date: 2015-02-20 15:40:00 +0100 (Fri, 20 Feb 2015)
+221044
+Last Changed Date: 2015-02-27 09:37:51 +0100 (Fri, 27 Feb 2015)
index 3412677..0e34531 100644 (file)
@@ -492,6 +492,8 @@ DEF_FUNCTION_TYPE_5 (BT_FN_BOOL_VPTR_PTR_I8_INT_INT,
                     BT_BOOL, BT_VOLATILE_PTR, BT_PTR, BT_I8, BT_INT, BT_INT)
 DEF_FUNCTION_TYPE_5 (BT_FN_BOOL_VPTR_PTR_I16_INT_INT,
                     BT_BOOL, BT_VOLATILE_PTR, BT_PTR, BT_I16, BT_INT, BT_INT)
+DEF_FUNCTION_TYPE_5 (BT_FN_VOID_INT_SIZE_PTR_PTR_PTR,
+                    BT_VOID, BT_INT, BT_SIZE, BT_PTR, BT_PTR, BT_PTR)
 DEF_FUNCTION_TYPE_5 (BT_FN_VOID_OMPFN_PTR_UINT_UINT_UINT,
                     BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR, BT_UINT, BT_UINT,
                     BT_UINT)
@@ -588,12 +590,12 @@ DEF_FUNCTION_TYPE_VAR_5 (BT_FN_INT_STRING_SIZE_INT_SIZE_CONST_STRING_VAR,
 DEF_FUNCTION_TYPE_VAR_5 (BT_FN_INT_INT_INT_INT_INT_INT_VAR,
                         BT_INT, BT_INT, BT_INT, BT_INT, BT_INT, BT_INT)
 
-DEF_FUNCTION_TYPE_VAR_8 (BT_FN_VOID_INT_PTR_SIZE_PTR_PTR_PTR_INT_INT_VAR,
-                        BT_VOID, BT_INT, BT_PTR, BT_SIZE, BT_PTR, BT_PTR,
+DEF_FUNCTION_TYPE_VAR_7 (BT_FN_VOID_INT_SIZE_PTR_PTR_PTR_INT_INT_VAR,
+                        BT_VOID, BT_INT, BT_SIZE, BT_PTR, BT_PTR,
                         BT_PTR, BT_INT, BT_INT)
 
-DEF_FUNCTION_TYPE_VAR_12 (BT_FN_VOID_INT_OMPFN_PTR_SIZE_PTR_PTR_PTR_INT_INT_INT_INT_INT_VAR,
-                         BT_VOID, BT_INT, BT_PTR_FN_VOID_PTR, BT_PTR, BT_SIZE,
+DEF_FUNCTION_TYPE_VAR_11 (BT_FN_VOID_INT_OMPFN_SIZE_PTR_PTR_PTR_INT_INT_INT_INT_INT_VAR,
+                         BT_VOID, BT_INT, BT_PTR_FN_VOID_PTR, BT_SIZE,
                          BT_PTR, BT_PTR, BT_PTR, BT_INT, BT_INT, BT_INT,
                          BT_INT, BT_INT)
 
index 8f3c0bc..fb871e6 100644 (file)
@@ -359,13 +359,15 @@ get_object_alignment_2 (tree exp, unsigned int *alignp,
       tree addr = TREE_OPERAND (exp, 0);
       unsigned ptr_align;
       unsigned HOST_WIDE_INT ptr_bitpos;
+      unsigned HOST_WIDE_INT ptr_bitmask = ~0;
 
+      /* If the address is explicitely aligned, handle that.  */
       if (TREE_CODE (addr) == BIT_AND_EXPR
          && TREE_CODE (TREE_OPERAND (addr, 1)) == INTEGER_CST)
        {
-         align = (TREE_INT_CST_LOW (TREE_OPERAND (addr, 1))
-                   & -TREE_INT_CST_LOW (TREE_OPERAND (addr, 1)));
-         align *= BITS_PER_UNIT;
+         ptr_bitmask = TREE_INT_CST_LOW (TREE_OPERAND (addr, 1));
+         ptr_bitmask *= BITS_PER_UNIT;
+         align = ptr_bitmask & -ptr_bitmask;
          addr = TREE_OPERAND (addr, 0);
        }
 
@@ -373,6 +375,9 @@ get_object_alignment_2 (tree exp, unsigned int *alignp,
        = get_pointer_alignment_1 (addr, &ptr_align, &ptr_bitpos);
       align = MAX (ptr_align, align);
 
+      /* Re-apply explicit alignment to the bitpos.  */
+      ptr_bitpos &= ptr_bitmask;
+
       /* The alignment of the pointer operand in a TARGET_MEM_REF
         has to take the variable offset parts into account.  */
       if (TREE_CODE (exp) == TARGET_MEM_REF)
index 3c18d1c..8c23e09 100644 (file)
@@ -5236,12 +5236,11 @@ enum c_builtin_type
 #define DEF_FUNCTION_TYPE_VAR_3(NAME, RETURN, ARG1, ARG2, ARG3) NAME,
 #define DEF_FUNCTION_TYPE_VAR_4(NAME, RETURN, ARG1, ARG2, ARG3, ARG4) NAME,
 #define DEF_FUNCTION_TYPE_VAR_5(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) \
-  NAME,
-#define DEF_FUNCTION_TYPE_VAR_8(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
-                               ARG6, ARG7, ARG8) NAME,
-#define DEF_FUNCTION_TYPE_VAR_12(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
-                                ARG6, ARG7, ARG8, ARG9, ARG10, ARG11,       \
-                                ARG12) NAME,
+                               NAME,
+#define DEF_FUNCTION_TYPE_VAR_7(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
+                               ARG6, ARG7) NAME,
+#define DEF_FUNCTION_TYPE_VAR_11(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
+                                ARG6, ARG7, ARG8, ARG9, ARG10, ARG11) NAME,
 #define DEF_POINTER_TYPE(NAME, TYPE) NAME,
 #include "builtin-types.def"
 #undef DEF_PRIMITIVE_TYPE
@@ -5260,8 +5259,8 @@ enum c_builtin_type
 #undef DEF_FUNCTION_TYPE_VAR_3
 #undef DEF_FUNCTION_TYPE_VAR_4
 #undef DEF_FUNCTION_TYPE_VAR_5
-#undef DEF_FUNCTION_TYPE_VAR_8
-#undef DEF_FUNCTION_TYPE_VAR_12
+#undef DEF_FUNCTION_TYPE_VAR_7
+#undef DEF_FUNCTION_TYPE_VAR_11
 #undef DEF_POINTER_TYPE
   BT_LAST
 };
@@ -5354,14 +5353,13 @@ c_define_builtins (tree va_list_ref_type_node, tree va_list_arg_type_node)
   def_fn_type (ENUM, RETURN, 1, 4, ARG1, ARG2, ARG3, ARG4);
 #define DEF_FUNCTION_TYPE_VAR_5(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) \
   def_fn_type (ENUM, RETURN, 1, 5, ARG1, ARG2, ARG3, ARG4, ARG5);
-#define DEF_FUNCTION_TYPE_VAR_8(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
-                               ARG6, ARG7, ARG8)                           \
-  def_fn_type (ENUM, RETURN, 1, 8, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6,      \
-              ARG7, ARG8);
-#define DEF_FUNCTION_TYPE_VAR_12(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
-                                ARG6, ARG7, ARG8, ARG9, ARG10, ARG11, ARG12) \
-  def_fn_type (ENUM, RETURN, 1, 12, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6,      \
-              ARG7, ARG8, ARG9, ARG10, ARG11, ARG12);
+#define DEF_FUNCTION_TYPE_VAR_7(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
+                               ARG6, ARG7)                             \
+  def_fn_type (ENUM, RETURN, 1, 7, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7);
+#define DEF_FUNCTION_TYPE_VAR_11(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
+                                ARG6, ARG7, ARG8, ARG9, ARG10, ARG11) \
+  def_fn_type (ENUM, RETURN, 1, 11, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6,      \
+              ARG7, ARG8, ARG9, ARG10, ARG11);
 #define DEF_POINTER_TYPE(ENUM, TYPE) \
   builtin_types[(int) ENUM] = build_pointer_type (builtin_types[(int) TYPE]);
 
@@ -5383,8 +5381,8 @@ c_define_builtins (tree va_list_ref_type_node, tree va_list_arg_type_node)
 #undef DEF_FUNCTION_TYPE_VAR_3
 #undef DEF_FUNCTION_TYPE_VAR_4
 #undef DEF_FUNCTION_TYPE_VAR_5
-#undef DEF_FUNCTION_TYPE_VAR_8
-#undef DEF_FUNCTION_TYPE_VAR_12
+#undef DEF_FUNCTION_TYPE_VAR_7
+#undef DEF_FUNCTION_TYPE_VAR_11
 #undef DEF_POINTER_TYPE
   builtin_types[(int) BT_LAST] = NULL_TREE;
 
index 1ad08dc..5555439 100644 (file)
@@ -2630,7 +2630,7 @@ cgraph_edge::verify_corresponds_to_fndecl (tree decl)
   if (!node
       || node->body_removed
       || node->in_other_partition
-      || node->icf_merged
+      || callee->icf_merged
       || callee->in_other_partition)
     return false;
 
index ec3cccd..ff437cf 100644 (file)
@@ -326,9 +326,6 @@ public:
   /* Return true if ONE and TWO are part of the same COMDAT group.  */
   inline bool in_same_comdat_group_p (symtab_node *target);
 
-  /* Return true when there is a reference to node and it is not vtable.  */
-  bool address_taken_from_non_vtable_p (void);
-
   /* Return true if symbol is known to be nonzero.  */
   bool nonzero_address ();
 
@@ -337,6 +334,15 @@ public:
      return 2 otherwise.   */
   int equal_address_to (symtab_node *s2);
 
+  /* Return true if symbol's address may possibly be compared to other
+     symbol's address.  */
+  bool address_matters_p ();
+
+  /* Return true if NODE's address can be compared.  This use properties
+     of NODE only and does not look if the address is actually taken in
+     interesting way.  For that use ADDRESS_MATTERS_P instead.  */
+  bool address_can_be_compared_p (void);
+
   /* Return symbol table node associated with DECL, if any,
      and NULL otherwise.  */
   static inline symtab_node *get (const_tree decl)
@@ -3022,6 +3028,43 @@ varpool_node::call_for_symbol_and_aliases (bool (*callback) (varpool_node *,
   return false;
 }
 
+/* Return true if NODE's address can be compared.  */
+
+inline bool
+symtab_node::address_can_be_compared_p ()
+{
+  /* Address of virtual tables and functions is never compared.  */
+  if (DECL_VIRTUAL_P (decl))
+    return false;
+  /* Address of C++ cdtors is never compared.  */
+  if (is_a <cgraph_node *> (this)
+      && (DECL_CXX_CONSTRUCTOR_P (decl)
+         || DECL_CXX_DESTRUCTOR_P (decl)))
+    return false;
+  /* Constant pool symbols addresses are never compared.
+     flag_merge_constants permits us to assume the same on readonly vars.  */
+  if (is_a <varpool_node *> (this)
+      && (DECL_IN_CONSTANT_POOL (decl)
+         || (flag_merge_constants >= 2
+             && TREE_READONLY (decl) && !TREE_THIS_VOLATILE (decl))))
+    return false;
+  return true;
+}
+
+/* Return true if refernece may be used in address compare.  */
+
+inline bool
+ipa_ref::address_matters_p ()
+{
+  if (use != IPA_REF_ADDR)
+    return false;
+  /* Addresses taken from virtual tables are never compared.  */
+  if (is_a <varpool_node *> (referring)
+      && DECL_VIRTUAL_P (referring->decl))
+    return false;
+  return referred->address_can_be_compared_p ();
+}
+
 /* Build polymorphic call context for indirect call E.  */
 
 inline
index d0a5f70..c740176 100644 (file)
@@ -471,6 +471,8 @@ cgraph_node::create_clone (tree decl, gcov_type gcov_count, int freq,
   new_node->frequency = frequency;
   new_node->tp_first_run = tp_first_run;
   new_node->tm_clone = tm_clone;
+  new_node->icf_merged = icf_merged;
+  new_node->merged = merged;
 
   new_node->clone.tree_map = NULL;
   new_node->clone.args_to_skip = args_to_skip;
index 942826d..9f6878a 100644 (file)
@@ -2468,6 +2468,7 @@ cgraph_node::create_wrapper (cgraph_node *target)
   release_body (true);
   reset ();
 
+  DECL_UNINLINABLE (decl) = false;
   DECL_RESULT (decl) = decl_result;
   DECL_INITIAL (decl) = NULL;
   allocate_struct_function (decl, false);
index 4fa12f5..b49ac46 100644 (file)
@@ -1644,11 +1644,11 @@ Report on permanent memory allocation in WPA only
 ; string constants and constants from constant pool, if 2 also constant
 ; variables.
 fmerge-all-constants
-Common Report Var(flag_merge_constants,2) Init(1) Optimization
+Common Report Var(flag_merge_constants,2) Init(1)
 Attempt to merge identical constants and constant variables
 
 fmerge-constants
-Common Report Var(flag_merge_constants,1) Optimization
+Common Report Var(flag_merge_constants,1)
 Attempt to merge identical constants across compilation units
 
 fmerge-debug-strings
index 71a5b22..bec1324 100644 (file)
@@ -2463,6 +2463,7 @@ static void ix86_function_specific_save (struct cl_target_option *,
                                         struct gcc_options *opts);
 static void ix86_function_specific_restore (struct gcc_options *opts,
                                            struct cl_target_option *);
+static void ix86_function_specific_post_stream_in (struct cl_target_option *);
 static void ix86_function_specific_print (FILE *, int,
                                          struct cl_target_option *);
 static bool ix86_valid_target_attribute_p (tree, tree, tree, int);
@@ -4571,6 +4572,57 @@ ix86_function_specific_restore (struct gcc_options *opts,
     set_ix86_tune_features (ix86_tune, false);
 }
 
+/* Adjust target options after streaming them in.  This is mainly about
+   reconciling them with global options.  */
+
+static void
+ix86_function_specific_post_stream_in (struct cl_target_option *ptr)
+{
+  /* flag_pic is a global option, but ix86_cmodel is target saved option
+     partly computed from flag_pic.  If flag_pic is on, adjust x_ix86_cmodel
+     for PIC, or error out.  */
+  if (flag_pic)
+    switch (ptr->x_ix86_cmodel)
+      {
+      case CM_SMALL:
+       ptr->x_ix86_cmodel = CM_SMALL_PIC;
+       break;
+
+      case CM_MEDIUM:
+       ptr->x_ix86_cmodel = CM_MEDIUM_PIC;
+       break;
+
+      case CM_LARGE:
+       ptr->x_ix86_cmodel = CM_LARGE_PIC;
+       break;
+
+      case CM_KERNEL:
+       error ("code model %s does not support PIC mode", "kernel");
+       break;
+
+      default:
+       break;
+      }
+  else
+    switch (ptr->x_ix86_cmodel)
+      {
+      case CM_SMALL_PIC:
+       ptr->x_ix86_cmodel = CM_SMALL;
+       break;
+
+      case CM_MEDIUM_PIC:
+       ptr->x_ix86_cmodel = CM_MEDIUM;
+       break;
+
+      case CM_LARGE_PIC:
+       ptr->x_ix86_cmodel = CM_LARGE;
+       break;
+
+      default:
+       break;
+      }
+}
+
 /* Print the current options */
 
 static void
@@ -6068,6 +6120,9 @@ ix86_function_arg_regno_p (int regno)
   int i;
   const int *parm_regs;
 
+  if (TARGET_MPX && BND_REGNO_P (regno))
+    return true;
+
   if (!TARGET_64BIT)
     {
       if (TARGET_MACHO)
@@ -26737,7 +26792,11 @@ ix86_sched_reorder (FILE *dump, int sched_verbose, rtx_insn **ready,
       ready[n_ready - 1] = insn;
       return issue_rate;
     }
-  if (clock_var != 0 && swap_top_of_ready_list (ready, n_ready))
+
+  /* Skip selective scheduling since HID is not populated in it.  */
+  if (clock_var != 0
+      && !sel_sched_p ()
+      && swap_top_of_ready_list (ready, n_ready))
     {
       if (sched_verbose > 1)
        fprintf (dump, ";;\tslm sched_reorder: swap %d and %d insns\n",
@@ -26846,6 +26905,16 @@ avoid_func_arg_motion (rtx_insn *first_arg, rtx_insn *insn)
   rtx set;
   rtx tmp;
 
+  /* Add anti dependencies for bounds stores.  */
+  if (INSN_P (insn)
+      && GET_CODE (PATTERN (insn)) == PARALLEL
+      && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == UNSPEC
+      && XINT (XVECEXP (PATTERN (insn), 0, 0), 1) == UNSPEC_BNDSTX)
+    {
+      add_dependence (first_arg, insn, REG_DEP_ANTI);
+      return;
+    }
+
   set = single_set (insn);
   if (!set)
     return;
@@ -52007,6 +52076,9 @@ ix86_initialize_bounds (tree var, tree lb, tree ub, tree *stmts)
 #undef TARGET_OPTION_RESTORE
 #define TARGET_OPTION_RESTORE ix86_function_specific_restore
 
+#undef TARGET_OPTION_POST_STREAM_IN
+#define TARGET_OPTION_POST_STREAM_IN ix86_function_specific_post_stream_in
+
 #undef TARGET_OPTION_PRINT
 #define TARGET_OPTION_PRINT ix86_function_specific_print
 
@@ -52131,6 +52203,9 @@ ix86_initialize_bounds (tree var, tree lb, tree ub, tree *stmts)
 #define TARGET_OFFLOAD_OPTIONS \
   ix86_offload_options
 
+#undef TARGET_ABSOLUTE_BIGGEST_ALIGNMENT
+#define TARGET_ABSOLUTE_BIGGEST_ALIGNMENT 512
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
 #include "gt-i386.h"
index 5d1e5e0..1e755d3 100644 (file)
@@ -795,7 +795,10 @@ extern const char *host_detect_local_cpu (int argc, const char **argv);
    rounder than this.
 
    Pentium+ prefers DFmode values to be aligned to 64 bit boundary
-   and Pentium Pro XFmode values at 128 bit boundaries.  */
+   and Pentium Pro XFmode values at 128 bit boundaries.
+
+   When increasing the maximum, also update
+   TARGET_ABSOLUTE_BIGGEST_ALIGNMENT.  */
 
 #define BIGGEST_ALIGNMENT \
   (TARGET_AVX512F ? 512 : (TARGET_AVX ? 256 : 128))
index 32a23ff..f7e8ce9 100644 (file)
@@ -3113,9 +3113,10 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
       break;
 
     case RETURN_EXPR:
-      r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0),
-                                       lval,
-                                       non_constant_p, overflow_p);
+      if (TREE_OPERAND (t, 0) != NULL_TREE)
+       r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0),
+                                         lval,
+                                         non_constant_p, overflow_p);
       *jump_target = t;
       break;
 
index 67c5ae7..83e060b 100644 (file)
@@ -13721,9 +13721,7 @@ start_preparsed_function (tree decl1, tree attrs, int flags)
       || (DECL_CONSTRUCTOR_P (decl1)
          && targetm.cxx.cdtor_returns_this ()))
     {
-      cdtor_label = build_decl (input_location, 
-                               LABEL_DECL, NULL_TREE, void_type_node);
-      DECL_CONTEXT (cdtor_label) = current_function_decl;
+      cdtor_label = create_artificial_label (input_location);
     }
 
   start_fname_decls ();
index a7bc08f..a4a5ebf 100644 (file)
@@ -2175,6 +2175,7 @@ constrain_visibility (tree decl, int visibility, bool tmpl)
          TREE_PUBLIC (decl) = 0;
          DECL_WEAK (decl) = 0;
          DECL_COMMON (decl) = 0;
+         DECL_COMDAT (decl) = false;
          if (TREE_CODE (decl) == FUNCTION_DECL
              || TREE_CODE (decl) == VAR_DECL)
            {
@@ -2215,9 +2216,12 @@ constrain_visibility_for_template (tree decl, tree targs)
       tree arg = TREE_VEC_ELT (args, i-1);
       if (TYPE_P (arg))
        vis = type_visibility (arg);
-      else if (TREE_TYPE (arg) && POINTER_TYPE_P (TREE_TYPE (arg)))
+      else
        {
-         STRIP_NOPS (arg);
+         if (REFERENCE_REF_P (arg))
+           arg = TREE_OPERAND (arg, 0);
+         if (TREE_TYPE (arg))
+           STRIP_NOPS (arg);
          if (TREE_CODE (arg) == ADDR_EXPR)
            arg = TREE_OPERAND (arg, 0);
          if (VAR_OR_FUNCTION_DECL_P (arg))
index 897ceab..424d522 100644 (file)
@@ -70,7 +70,7 @@ string_for_index (struct data_in *data_in, unsigned int loc, unsigned int *rlen)
     }
 
   /* Get the string stored at location LOC in DATA_IN->STRINGS.  */
-  lto_input_block str_tab (data_in->strings, loc - 1, data_in->strings_len);
+  lto_input_block str_tab (data_in->strings, loc - 1, data_in->strings_len, NULL);
   len = streamer_read_uhwi (&str_tab);
   *rlen = len;
 
index 54c1941..c066d32 100644 (file)
@@ -2985,7 +2985,7 @@ which this handler should be assigned.  If the argument is a name it
 is treated as a symbolic name for the vector slot.  These names should
 match up with appropriate entries in the linker script.  By default
 the names @code{watchdog} for vector 26, @code{nmi} for vector 30 and
-@code{reset} for vector 31 are recognised.
+@code{reset} for vector 31 are recognized.
 
 You can also use the following function attributes to modify how
 normal functions interact with interrupt functions:
@@ -3388,7 +3388,7 @@ the function label.  A second argument can be used to specify the
 number of halfwords to be added after the function label.  For
 both arguments the maximum allowed value is 1000000.
 
-If both ar guments are zero, hotpatching is disabled.
+If both arguments are zero, hotpatching is disabled.
 
 @item naked
 @cindex function without a prologue/epilogue code
@@ -4633,7 +4633,7 @@ This example uses the @code{cold} label attribute to indicate the
 
    asm goto ("some asm" : : : : NoError);
 
-/* This branch (the fallthru from the asm) is less commonly used */
+/* This branch (the fall-through from the asm) is less commonly used */
 ErrorHandling: 
    __attribute__((cold, unused)); /* Semi-colon is required here */
    printf("error\n");
@@ -8988,7 +8988,7 @@ returns -1.
 @node Cilk Plus Builtins
 @section Cilk Plus C/C++ Language Extension Built-in Functions
 
-GCC provides support for the following built-in reduction funtions if Cilk Plus
+GCC provides support for the following built-in reduction functions if Cilk Plus
 is enabled. Cilk Plus can be enabled using the @option{-fcilkplus} flag.
 
 @itemize @bullet
@@ -10744,7 +10744,7 @@ __v8hi __builtin_arc_vupsbaw (__v8hi)
 __v8hi __builtin_arc_vupsbw (__v8hi)
 @end example
 
-The followign take two @code{int} arguments and return no result:
+The following take two @code{int} arguments and return no result:
 @example
 void __builtin_arc_vdirun (int, int)
 void __builtin_arc_vdorun (int, int)
@@ -10983,11 +10983,11 @@ intrinsics can be found at
 The built-in intrinsics for the Advanced SIMD extension are available when
 NEON is enabled.
 
-Currently, ARM and AArch64 back-ends do not support ACLE 2.0 fully.  Both
-back-ends support CRC32 intrinsics from @file{arm_acle.h}.  The ARM backend's
-16-bit floating-point Advanded SIMD Intrinsics currently comply to ACLE v1.1.
-AArch64's backend does not have support for 16-bit floating point Advanced SIMD
-Intrinsics yet.
+Currently, ARM and AArch64 back ends do not support ACLE 2.0 fully.  Both
+back ends support CRC32 intrinsics from @file{arm_acle.h}.  The ARM back end's
+16-bit floating-point Advanced SIMD intrinsics currently comply to ACLE v1.1.
+AArch64's back end does not have support for 16-bit floating point Advanced SIMD
+intrinsics yet.
 
 See @ref{ARM Options} and @ref{AArch64 Options} for more information on the
 availability of extensions.
@@ -12451,7 +12451,7 @@ unsigned int addg6s (unsigned int, unsigned int);
 @end smallexample
 
 The @code{__builtin_divde}, @code{__builtin_divdeo},
-@code{__builitin_divdeu}, @code{__builtin_divdeou} functions require a
+@code{__builtin_divdeu}, @code{__builtin_divdeou} functions require a
 64-bit environment support ISA 2.06 or later.
 
 The following built-in functions are available for the PowerPC family
@@ -12467,9 +12467,9 @@ _Decimal128 __builtin_denbcdq (int, _Decimal128);
 _Decimal64 __builtin_diex (_Decimal64, _Decimal64);
 _Decimal128 _builtin_diexq (_Decimal128, _Decimal128);
 _Decimal64 __builtin_dscli (_Decimal64, int);
-_Decimal128 __builitn_dscliq (_Decimal128, int);
+_Decimal128 __builtin_dscliq (_Decimal128, int);
 _Decimal64 __builtin_dscri (_Decimal64, int);
-_Decimal128 __builitn_dscriq (_Decimal128, int);
+_Decimal128 __builtin_dscriq (_Decimal128, int);
 unsigned long long __builtin_unpack_dec128 (_Decimal128, int);
 _Decimal128 __builtin_pack_dec128 (unsigned long long, unsigned long long);
 @end smallexample
@@ -15079,7 +15079,7 @@ must be a constant integer in the range of 0 to 15.
 @subsection PowerPC Hardware Transactional Memory Built-in Functions
 GCC provides two interfaces for accessing the Hardware Transactional
 Memory (HTM) instructions available on some of the PowerPC family
-of prcoessors (eg, POWER8).  The two interfaces come in a low level
+of processors (eg, POWER8).  The two interfaces come in a low level
 interface, consisting of built-in functions specific to PowerPC and a
 higher level interface consisting of inline functions that are common
 between PowerPC and S/390.
@@ -19255,4 +19255,4 @@ than no arguments, as C++ demands.
 @end table
 
 @c  LocalWords:  emph deftypefn builtin ARCv2EM SIMD builtins msimd
-@c  LocalWords:  typedef v4si v8hi DMA dma vdiwr vdowr followign
+@c  LocalWords:  typedef v4si v8hi DMA dma vdiwr vdowr
index 061ab79..a5275f4 100644 (file)
@@ -2306,8 +2306,8 @@ For unsigned widening multiplication, use the same idiom, but with
 @findex fma
 @item (fma:@var{m} @var{x} @var{y} @var{z})
 Represents the @code{fma}, @code{fmaf}, and @code{fmal} builtin
-functions that do a combined multiply of @var{x} and @var{y} and then
-adding to@var{z} without doing an intermediate rounding step.
+functions, which compute @samp{@var{x} * @var{y} + @var{z}}
+without doing an intermediate rounding step.
 
 @findex div
 @findex ss_div
index 048a28a..6e5d2c0 100644 (file)
@@ -1003,6 +1003,12 @@ bits.  Note that this is not the biggest alignment that is supported,
 just the biggest alignment that, when violated, may cause a fault.
 @end defmac
 
+@deftypevr {Target Hook} HOST_WIDE_INT TARGET_ABSOLUTE_BIGGEST_ALIGNMENT
+If defined, this target hook specifies the absolute biggest alignment
+that a type or variable can have on this machine, otherwise,
+@code{BIGGEST_ALIGNMENT} is used.
+@end deftypevr
+
 @defmac MALLOC_ABI_ALIGNMENT
 Alignment, in bits, a C conformant malloc implementation has to
 provide.  If not defined, the default value is @code{BITS_PER_WORD}.
@@ -9899,6 +9905,12 @@ information in the @code{struct cl_target_option} structure for
 function-specific options to the @code{struct gcc_options} structure.
 @end deftypefn
 
+@deftypefn {Target Hook} void TARGET_OPTION_POST_STREAM_IN (struct cl_target_option *@var{ptr})
+This hook is called to update target-specific information in the
+@code{struct cl_target_option} structure after it is streamed in from
+LTO bytecode.
+@end deftypefn
+
 @deftypefn {Target Hook} void TARGET_OPTION_PRINT (FILE *@var{file}, int @var{indent}, struct cl_target_option *@var{ptr})
 This hook is called to print any additional target-specific
 information in the @code{struct cl_target_option} structure for
index ebf41c8..6c8e51f 100644 (file)
@@ -22621,6 +22621,14 @@ output_macinfo (void)
 static void
 dwarf2out_init (const char *filename ATTRIBUTE_UNUSED)
 {
+  /* This option is currently broken, see (PR53118 and PR46102).  */
+  if (flag_eliminate_dwarf2_dups
+      && strstr (lang_hooks.name, "C++"))
+    {
+      warning (0, "-feliminate-dwarf2-dups is broken for C++, ignoring");
+      flag_eliminate_dwarf2_dups = 0;
+    }
+
   /* Allocate the file_table.  */
   file_table = hash_table<dwarf_file_hasher>::create_ggc (50);
 
index 5503625..95e4fc8 100644 (file)
@@ -1303,7 +1303,7 @@ gcall *gimple_build_call_valist (tree, unsigned, va_list);
 gcall *gimple_build_call_internal (enum internal_fn, unsigned, ...);
 gcall *gimple_build_call_internal_vec (enum internal_fn, vec<tree> );
 gcall *gimple_build_call_from_tree (tree);
-gassign *gimple_build_assign (tree, tree CXX_MEM_STAT_DECL);
+gassign *gimple_build_assign (tree, tree CXX_MEM_STAT_INFO);
 gassign *gimple_build_assign (tree, enum tree_code,
                              tree, tree, tree CXX_MEM_STAT_INFO);
 gassign *gimple_build_assign (tree, enum tree_code,
index 1353ada..d822913 100644 (file)
@@ -8244,10 +8244,10 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
                                     TREE_CODE (*expr_p) == TRY_FINALLY_EXPR
                                     ? GIMPLE_TRY_FINALLY
                                     : GIMPLE_TRY_CATCH);
-           if (LOCATION_LOCUS (saved_location) != UNKNOWN_LOCATION)
-             gimple_set_location (try_, saved_location);
-           else
+           if (EXPR_HAS_LOCATION (save_expr))
              gimple_set_location (try_, EXPR_LOCATION (save_expr));
+           else if (LOCATION_LOCUS (saved_location) != UNKNOWN_LOCATION)
+             gimple_set_location (try_, saved_location);
            if (TREE_CODE (*expr_p) == TRY_CATCH_EXPR)
              gimple_try_set_catch_is_cleanup (try_,
                                               TRY_CATCH_IS_CLEANUP (*expr_p));
index 5b176d0..53d2c38 100644 (file)
@@ -575,6 +575,13 @@ func_checker::compare_variable_decl (tree t1, tree t2)
   if (t1 == t2)
     return true;
 
+  if (DECL_HARD_REGISTER (t1) != DECL_HARD_REGISTER (t2))
+    return return_false_with_msg ("DECL_HARD_REGISTER are different");
+
+  if (DECL_HARD_REGISTER (t1)
+      && 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);
index 494fdcf..5d50b6f 100644 (file)
@@ -126,6 +126,44 @@ along with GCC; see the file COPYING3.  If not see
 using namespace ipa_icf_gimple;
 
 namespace ipa_icf {
+
+/* Constructor.  */
+
+symbol_compare_collection::symbol_compare_collection (symtab_node *node)
+{
+  m_references.create (0);
+  m_interposables.create (0);
+
+  ipa_ref *ref;
+
+  if (is_a <varpool_node *> (node) && DECL_VIRTUAL_P (node->decl))
+    return;
+
+  for (unsigned i = 0; i < node->num_references (); i++)
+    {
+      ref = node->iterate_reference (i, ref);
+      if (ref->address_matters_p ())
+       m_references.safe_push (ref->referred);
+
+      if (ref->referred->get_availability () <= AVAIL_INTERPOSABLE)
+        {
+         if (ref->address_matters_p ())
+           m_references.safe_push (ref->referred);
+         else
+           m_interposables.safe_push (ref->referred);
+       }
+    }
+
+  if (is_a <cgraph_node *> (node))
+    {
+      cgraph_node *cnode = dyn_cast <cgraph_node *> (node);
+
+      for (cgraph_edge *e = cnode->callees; e; e = e->next_callee)
+       if (e->callee->get_availability () <= AVAIL_INTERPOSABLE)
+         m_interposables.safe_push (e->callee);
+    }
+}
+
 /* Constructor for key value pair, where _ITEM is key and _INDEX is a target.  */
 
 sem_usage_pair::sem_usage_pair (sem_item *_item, unsigned int _index):
@@ -594,8 +632,56 @@ set_local (cgraph_node *node, void *data)
   return false;
 }
 
+/* TREE_ADDRESSABLE of NODE to true if DATA is non-NULL.
+   Helper for call_for_symbol_thunks_and_aliases.  */
+
+static bool
+set_addressable (varpool_node *node, void *)
+{
+  TREE_ADDRESSABLE (node->decl) = 1;
+  return false;
+}
+
+/* Redirect all callers of N and its aliases to TO.  Remove aliases if
+   possible.  Return number of redirections made.  */
+
+static int
+redirect_all_callers (cgraph_node *n, cgraph_node *to)
+{
+  int nredirected = 0;
+  ipa_ref *ref;
+
+  while (n->callers)
+    {
+      cgraph_edge *e = n->callers;
+      e->redirect_callee (to);
+      nredirected++;
+    }
+  for (unsigned i = 0; n->iterate_direct_aliases (i, ref);)
+    {
+      bool removed = false;
+      cgraph_node *n_alias = dyn_cast <cgraph_node *> (ref->referring);
+
+      if ((DECL_COMDAT_GROUP (n->decl)
+          && (DECL_COMDAT_GROUP (n->decl)
+              == DECL_COMDAT_GROUP (n_alias->decl)))
+         || (n_alias->get_availability () > AVAIL_INTERPOSABLE
+             && n->get_availability () > AVAIL_INTERPOSABLE))
+       {
+         nredirected += redirect_all_callers (n_alias, to);
+         if (n_alias->can_remove_if_no_direct_calls_p ()
+             && !n_alias->has_aliases_p ())
+           n_alias->remove ();
+       }
+      if (!removed)
+       i++;
+    }
+  return nredirected;
+}
+
 /* Merges instance with an ALIAS_ITEM, where alias, thunk or redirection can
    be applied.  */
+
 bool
 sem_function::merge (sem_item *alias_item)
 {
@@ -604,16 +690,29 @@ sem_function::merge (sem_item *alias_item)
   sem_function *alias_func = static_cast<sem_function *> (alias_item);
 
   cgraph_node *original = get_node ();
-  cgraph_node *local_original = original;
+  cgraph_node *local_original = NULL;
   cgraph_node *alias = alias_func->get_node ();
-  bool original_address_matters;
-  bool alias_address_matters;
 
-  bool create_thunk = false;
+  bool create_wrapper = false;
   bool create_alias = false;
   bool redirect_callers = false;
+  bool remove = false;
+
   bool original_discardable = false;
 
+  bool original_address_matters = original->address_matters_p ();
+  bool alias_address_matters = alias->address_matters_p ();
+
+  if (DECL_NO_INLINE_WARNING_P (original->decl)
+      != DECL_NO_INLINE_WARNING_P (alias->decl))
+    {
+      if (dump_file)
+       fprintf (dump_file,
+                "Not unifying; "
+                "DECL_NO_INLINE_WARNING mismatch.\n\n");
+      return false;
+    }
+
   /* Do not attempt to mix functions from different user sections;
      we do not know what user intends with those.  */
   if (((DECL_SECTION_NAME (original->decl) && !original->implicit_section)
@@ -622,127 +721,173 @@ sem_function::merge (sem_item *alias_item)
     {
       if (dump_file)
        fprintf (dump_file,
-                "Not unifying; original and alias are in different sections.\n\n");
+                "Not unifying; "
+                "original and alias are in different sections.\n\n");
       return false;
     }
 
   /* See if original is in a section that can be discarded if the main
-     symbol is not used.  */
-  if (DECL_EXTERNAL (original->decl))
-    original_discardable = true;
-  if (original->resolution == LDPR_PREEMPTED_REG
-      || original->resolution == LDPR_PREEMPTED_IR)
-    original_discardable = true;
-  if (original->can_be_discarded_p ())
+     symbol is not used.
+
+     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;
 
-  /* See if original and/or alias address can be compared for equality.  */
-  original_address_matters
-    = (!DECL_VIRTUAL_P (original->decl)
-       && (original->externally_visible
-          || original->address_taken_from_non_vtable_p ()));
-  alias_address_matters
-    = (!DECL_VIRTUAL_P (alias->decl)
-       && (alias->externally_visible
-          || alias->address_taken_from_non_vtable_p ()));
-
-  /* If alias and original can be compared for address equality, we need
-     to create a thunk.  Also we can not create extra aliases into discardable
-     section (or we risk link failures when section is discarded).  */
-  if ((original_address_matters
-       && alias_address_matters)
-      || original_discardable)
+  /* Creating a symtab alias is the optimal way to merge.
+     It however can not be used in the following cases:
+
+     1) if ORIGINAL and ALIAS may be possibly compared for address equality.
+     2) if ORIGINAL is in a section that may be discarded by linker or if
+       it is an external functions where we can not create an alias
+       (ORIGINAL_DISCARDABLE)
+     3) if target do not support symbol aliases.
+
+     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 ())
     {
-      create_thunk = !stdarg_p (TREE_TYPE (alias->decl));
-      create_alias = false;
-      /* When both alias and original are not overwritable, we can save
-         the extra thunk wrapper for direct calls.  */
+      /* First see if we can produce wrapper.  */
+
+      /* Do not turn function in one comdat group into wrapper to another
+        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)
+         && (DECL_COMDAT_GROUP (alias->decl)
+             != DECL_COMDAT_GROUP (original->decl)))
+       {
+         if (dump_file)
+           fprintf (dump_file,
+                    "Wrapper cannot be created because of COMDAT\n");
+       }
+      else if (DECL_STATIC_CHAIN (alias->decl))
+        {
+         if (dump_file)
+           fprintf (dump_file,
+                    "Can not create wrapper of nested functions.\n");
+        }
+      /* TODO: We can also deal with variadic functions never calling
+        VA_START.  */
+      else if (stdarg_p (TREE_TYPE (alias->decl)))
+       {
+         if (dump_file)
+           fprintf (dump_file,
+                    "can not create wrapper of stdarg function.\n");
+       }
+      else if (inline_summaries
+              && inline_summaries->get (alias)->self_size <= 2)
+       {
+         if (dump_file)
+           fprintf (dump_file, "Wrapper creation is not "
+                    "profitable (function is too small).\n");
+       }
+      /* If user paid attention to mark function noinline, assume it is
+        somewhat special and do not try to turn it into a wrapper that can
+        not be undone by inliner.  */
+      else if (lookup_attribute ("noinline", DECL_ATTRIBUTES (alias->decl)))
+       {
+         if (dump_file)
+           fprintf (dump_file, "Wrappers are not created for noinline.\n");
+       }
+      else
+        create_wrapper = true;
+
+      /* We can redirect local calls in the case both alias and orignal
+        are not interposable.  */
       redirect_callers
-       = (!original_discardable
-          && alias->get_availability () > AVAIL_INTERPOSABLE
-          && original->get_availability () > AVAIL_INTERPOSABLE
-          && !alias->instrumented_version);
-    }
-  else
-    {
-      create_alias = true;
-      create_thunk = false;
-      redirect_callers = false;
-    }
+       = alias->get_availability () > AVAIL_INTERPOSABLE
+         && original->get_availability () > AVAIL_INTERPOSABLE
+         && !alias->instrumented_version;
 
-  if (create_alias && (DECL_COMDAT_GROUP (alias->decl)
-                      || !sem_item::target_supports_symbol_aliases_p ()))
-    {
-      create_alias = false;
-      create_thunk = true;
-    }
+      if (!redirect_callers && !create_wrapper)
+       {
+         if (dump_file)
+           fprintf (dump_file, "Not unifying; can not redirect callers nor "
+                    "produce wrapper\n\n");
+         return false;
+       }
 
-  /* We want thunk to always jump to the local function body
-     unless the body is comdat and may be optimized out.  */
-  if ((create_thunk || redirect_callers)
-      && (!original_discardable
+      /* 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)))))
-    local_original
-      = dyn_cast <cgraph_node *> (original->noninterposable_alias ());
-
-    if (!local_original)
-      {
-       if (dump_file)
-         fprintf (dump_file, "Noninterposable alias cannot be created.\n\n");
-
-       return false;
-      }
+                 == DECL_COMDAT_GROUP (alias->decl))))
+       {
+         local_original
+           = dyn_cast <cgraph_node *> (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 (!local_original)
+       {
+         if (dump_file)
+           fprintf (dump_file, "Not unifying; "
+                    "can not produce local alias.\n\n");
+         return false;
+       }
 
-  if (!decl_binds_to_current_def_p (alias->decl))
-    {
-      if (dump_file)
-       fprintf (dump_file, "Declaration does not bind to currect definition.\n\n");
-      return false;
+      if (!redirect_callers && !create_wrapper)
+       {
+         if (dump_file)
+           fprintf (dump_file, "Not unifying; "
+                    "can not redirect callers nor produce a wrapper\n\n");
+         return false;
+       }
+      if (!create_wrapper
+         && !alias->can_remove_if_no_direct_calls_p ())
+       {
+         if (dump_file)
+           fprintf (dump_file, "Not unifying; can not make wrapper and "
+                    "function has other uses than direct calls\n\n");
+         return false;
+       }
     }
+  else
+    create_alias = true;
 
   if (redirect_callers)
     {
-      /* If alias is non-overwritable then
-         all direct calls are safe to be redirected to the original.  */
-      bool redirected = false;
-      while (alias->callers)
-       {
-         cgraph_edge *e = alias->callers;
-         e->redirect_callee (local_original);
-         push_cfun (DECL_STRUCT_FUNCTION (e->caller->decl));
+      int nredirected = redirect_all_callers (alias, local_original);
 
-         if (e->call_stmt)
-           e->redirect_call_stmt_to_callee ();
+      if (nredirected)
+       {
+         alias->icf_merged = true;
+         local_original->icf_merged = true;
 
-         pop_cfun ();
-         redirected = true;
+         if (dump_file && nredirected)
+           fprintf (dump_file, "%i local calls have been "
+                    "redirected.\n", nredirected);
        }
 
-      alias->icf_merged = true;
-      if (local_original->lto_file_data
-         && alias->lto_file_data
-         && local_original->lto_file_data != alias->lto_file_data)
-      local_original->merged = true;
-
-      /* The alias function is removed if symbol address
-         does not matter.  */
-      if (!alias_address_matters)
-       alias->remove ();
-
-      if (dump_file && redirected)
-       fprintf (dump_file, "Callgraph local calls have been redirected.\n\n");
+      /* If all callers was redirected, do not produce wrapper.  */
+      if (alias->can_remove_if_no_direct_calls_p ()
+         && !alias->has_aliases_p ())
+       {
+         create_wrapper = false;
+         remove = true;
+       }
+      gcc_assert (!create_alias);
     }
-  /* If the condtion above is not met, we are lucky and can turn the
-     function into real alias.  */
   else if (create_alias)
     {
       alias->icf_merged = true;
-      if (local_original->lto_file_data
-         && alias->lto_file_data
-         && local_original->lto_file_data != alias->lto_file_data)
-      local_original->merged = true;
 
       /* Remove the function's body.  */
       ipa_merge_profiles (original, alias);
@@ -757,39 +902,38 @@ sem_function::merge (sem_item *alias_item)
         (set_local, (void *)(size_t) original->local_p (), true);
 
       if (dump_file)
-       fprintf (dump_file, "Callgraph alias has been created.\n\n");
+       fprintf (dump_file, "Unified; Function alias has been created.\n\n");
     }
-  else if (create_thunk)
+  if (create_wrapper)
     {
-      if (DECL_COMDAT_GROUP (alias->decl))
-       {
-         if (dump_file)
-           fprintf (dump_file, "Callgraph thunk cannot be created because of COMDAT\n");
+      gcc_assert (!create_alias);
+      alias->icf_merged = true;
+      local_original->icf_merged = true;
 
-         return 0;
-       }
+      ipa_merge_profiles (local_original, alias, true);
+      alias->create_wrapper (local_original);
 
-      if (DECL_STATIC_CHAIN (alias->decl))
-        {
-         if (dump_file)
-           fprintf (dump_file, "Thunk creation is risky for static-chain functions.\n\n");
+      if (dump_file)
+       fprintf (dump_file, "Unified; Wrapper has been created.\n\n");
+    }
+  gcc_assert (alias->icf_merged || remove);
+  original->icf_merged = true;
 
-         return 0;
-        }
+  /* Inform the inliner about cross-module merging.  */
+  if ((original->lto_file_data || alias->lto_file_data)
+      && original->lto_file_data != alias->lto_file_data)
+    local_original->merged = original->merged = true;
 
+  if (remove)
+    {
+      ipa_merge_profiles (original, alias);
+      alias->release_body ();
+      alias->reset ();
+      alias->body_removed = true;
       alias->icf_merged = true;
-      if (local_original->lto_file_data
-         && alias->lto_file_data
-         && local_original->lto_file_data != alias->lto_file_data)
-      local_original->merged = true;
-      ipa_merge_profiles (local_original, alias, true);
-      alias->create_wrapper (local_original);
-
       if (dump_file)
-       fprintf (dump_file, "Callgraph thunk has been created.\n\n");
+       fprintf (dump_file, "Unified; Function body was removed.\n");
     }
-  else if (dump_file)
-    fprintf (dump_file, "Callgraph merge operation cannot be performed.\n\n");
 
   return true;
 }
@@ -1285,7 +1429,8 @@ sem_variable::merge (sem_item *alias_item)
   if (!sem_item::target_supports_symbol_aliases_p ())
     {
       if (dump_file)
-       fprintf (dump_file, "Symbol aliases are not supported by target\n\n");
+       fprintf (dump_file, "Not unifying; "
+                "Symbol aliases are not supported by target\n\n");
       return false;
     }
 
@@ -1295,73 +1440,93 @@ sem_variable::merge (sem_item *alias_item)
   varpool_node *alias = alias_var->get_node ();
   bool original_discardable = false;
 
+  bool original_address_matters = original->address_matters_p ();
+  bool alias_address_matters = alias->address_matters_p ();
+
   /* See if original is in a section that can be discarded if the main
-     symbol is not used.  */
-  if (DECL_EXTERNAL (original->decl))
-    original_discardable = true;
-  if (original->resolution == LDPR_PREEMPTED_REG
-      || original->resolution == LDPR_PREEMPTED_IR)
-    original_discardable = true;
-  if (original->can_be_discarded_p ())
+     symbol is not used.
+     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;
 
   gcc_assert (!TREE_ASM_WRITTEN (alias->decl));
 
-  if (original_discardable || DECL_EXTERNAL (alias_var->decl) ||
-      !compare_sections (alias_var))
+  /* Constant pool machinery is not quite ready for aliases.
+     TODO: varasm code contains logic for merging DECL_IN_CONSTANT_POOL.
+     For LTO merging does not happen that is an important missing feature.
+     We can enable merging with LTO if the DECL_IN_CONSTANT_POOL
+     flag is dropped and non-local symbol name is assigned.  */
+  if (DECL_IN_CONSTANT_POOL (alias->decl)
+      || DECL_IN_CONSTANT_POOL (original->decl))
     {
       if (dump_file)
-       fprintf (dump_file, "Varpool alias cannot be created\n\n");
+       fprintf (dump_file,
+                "Not unifying; constant pool variables.\n\n");
+      return false;
+    }
 
+  /* Do not attempt to mix functions from different user sections;
+     we do not know what user intends with those.  */
+  if (((DECL_SECTION_NAME (original->decl) && !original->implicit_section)
+       || (DECL_SECTION_NAME (alias->decl) && !alias->implicit_section))
+      && DECL_SECTION_NAME (original->decl) != DECL_SECTION_NAME (alias->decl))
+    {
+      if (dump_file)
+       fprintf (dump_file,
+                "Not unifying; "
+                "original and alias are in different sections.\n\n");
       return false;
     }
-  else
+
+  /* We can not merge if address comparsion metters.  */
+  if (original_address_matters && alias_address_matters
+      && flag_merge_constants < 2)
     {
-      // alias cycle creation check
-      varpool_node *n = original;
+      if (dump_file)
+       fprintf (dump_file,
+                "Not unifying; "
+                "adress of original and alias may be compared.\n\n");
+      return false;
+    }
 
-      while (n->alias)
-       {
-         n = n->get_alias_target ();
-         if (n == alias)
-           {
-             if (dump_file)
-               fprintf (dump_file, "Varpool alias cannot be created (alias cycle).\n\n");
+  if (original_discardable
+      && (!DECL_COMDAT_GROUP (original->decl)
+         || (DECL_COMDAT_GROUP (original->decl)
+             != DECL_COMDAT_GROUP (alias->decl))))
+    {
+      if (dump_file)
+       fprintf (dump_file, "Not unifying; alias cannot be created; "
+                "target is discardable\n\n");
 
-             return false;
-           }
-       }
+      return false;
+    }
+  else
+    {
+      gcc_assert (!original->alias);
+      gcc_assert (!alias->alias);
 
       alias->analyzed = false;
 
       DECL_INITIAL (alias->decl) = NULL;
       alias->need_bounds_init = false;
       alias->remove_all_references ();
+      if (TREE_ADDRESSABLE (alias->decl))
+        original->call_for_symbol_and_aliases (set_addressable, NULL, true);
 
       varpool_node::create_alias (alias_var->decl, decl);
       alias->resolve_alias (original);
 
       if (dump_file)
-       fprintf (dump_file, "Varpool alias has been created.\n\n");
+       fprintf (dump_file, "Unified; Variable alias has been created.\n\n");
 
       return true;
     }
 }
 
-bool
-sem_variable::compare_sections (sem_variable *alias)
-{
-  const char *source = node->get_section ();
-  const char *target = alias->node->get_section();
-
-  if (source == NULL && target == NULL)
-    return true;
-  else if(!source || !target)
-    return false;
-  else
-    return strcmp (source, target) == 0;
-}
-
 /* Dump symbol to FILE.  */
 
 void
@@ -1500,7 +1665,7 @@ sem_item_optimizer::read_section (lto_file_decl_data *file_data,
   unsigned int count;
 
   lto_input_block ib_main ((const char *) data + main_offset, 0,
-                          header->main_size);
+                          header->main_size, file_data->mode_table);
 
   data_in =
     lto_data_in_create (file_data, (const char *) data + string_offset,
@@ -1714,6 +1879,8 @@ void
 sem_item_optimizer::execute (void)
 {
   filter_removed_items ();
+  unregister_hooks ();
+
   build_hash_based_classes ();
 
   if (dump_file)
@@ -1969,6 +2136,84 @@ sem_item_optimizer::subdivide_classes_by_equality (bool in_wpa)
   verify_classes ();
 }
 
+/* Subdivide classes by address references that members of the class
+   reference. Example can be a pair of functions that have an address
+   taken from a function. If these addresses are different the class
+   is split.  */
+
+unsigned
+sem_item_optimizer::subdivide_classes_by_sensitive_refs ()
+{
+  unsigned newly_created_classes = 0;
+
+  for (hash_table <congruence_class_group_hash>::iterator it = m_classes.begin ();
+       it != m_classes.end (); ++it)
+    {
+      unsigned int class_count = (*it)->classes.length ();
+      auto_vec<congruence_class *> new_classes;
+
+      for (unsigned i = 0; i < class_count; i++)
+       {
+         congruence_class *c = (*it)->classes [i];
+
+         if (c->members.length() > 1)
+           {
+             hash_map <symbol_compare_collection *, vec <sem_item *>,
+               symbol_compare_hashmap_traits> split_map;
+
+             for (unsigned j = 0; j < c->members.length (); j++)
+               {
+                 sem_item *source_node = c->members[j];
+
+                 symbol_compare_collection *collection = new symbol_compare_collection (source_node->node);
+
+                 vec <sem_item *> *slot = &split_map.get_or_insert (collection);
+                 gcc_checking_assert (slot);
+
+                 slot->safe_push (source_node);
+               }
+
+              /* If the map contains more than one key, we have to split the map
+                 appropriately.  */
+             if (split_map.elements () != 1)
+               {
+                 bool first_class = true;
+
+                 hash_map <symbol_compare_collection *, vec <sem_item *>,
+                 symbol_compare_hashmap_traits>::iterator it2 = split_map.begin ();
+                 for (; it2 != split_map.end (); ++it2)
+                   {
+                     congruence_class *new_cls;
+                     new_cls = new congruence_class (class_id++);
+
+                     for (unsigned k = 0; k < (*it2).second.length (); k++)
+                       add_item_to_class (new_cls, (*it2).second[k]);
+
+                     worklist_push (new_cls);
+                     newly_created_classes++;
+
+                     if (first_class)
+                       {
+                         (*it)->classes[i] = new_cls;
+                         first_class = false;
+                       }
+                     else
+                       {
+                         new_classes.safe_push (new_cls);
+                         m_classes_count++;
+                       }
+                   }
+               }
+           }
+         }
+
+       for (unsigned i = 0; i < new_classes.length (); i++)
+         (*it)->classes.safe_push (new_classes[i]);
+    }
+
+  return newly_created_classes;
+}
+
 /* Verify congruence classes if checking is enabled.  */
 
 void
@@ -2258,8 +2503,17 @@ sem_item_optimizer::process_cong_reduction (void)
     fprintf (dump_file, "Congruence class reduction\n");
 
   congruence_class *cls;
+
+  /* Process complete congruence reduction.  */
   while ((cls = worklist_pop ()) != NULL)
     do_congruence_step (cls);
+
+  /* Subdivide newly created classes according to references.  */
+  unsigned new_classes = subdivide_classes_by_sensitive_refs ();
+
+  if (dump_file)
+    fprintf (dump_file, "Address reference subdivision created: %u "
+            "new classes.\n", new_classes);
 }
 
 /* Debug function prints all informations about congruence classes.  */
@@ -2482,7 +2736,6 @@ ipa_icf_driver (void)
   gcc_assert (optimizer);
 
   optimizer->execute ();
-  optimizer->unregister_hooks ();
 
   delete optimizer;
   optimizer = NULL;
index a55699b..9e76239 100644 (file)
@@ -63,6 +63,70 @@ enum sem_item_type
   VAR
 };
 
+/* Class is container for address references for a symtab_node.  */
+
+class symbol_compare_collection
+{
+public:
+  /* Constructor.  */
+  symbol_compare_collection (symtab_node *node);
+
+  /* Destructor.  */
+  ~symbol_compare_collection ()
+  {
+    m_references.release ();
+    m_interposables.release ();
+  }
+
+  /* Vector of address references.  */
+  vec<symtab_node *> m_references;
+
+  /* Vector of interposable references.  */
+  vec<symtab_node *> m_interposables;
+};
+
+/* Hash traits for symbol_compare_collection map.  */
+
+struct symbol_compare_hashmap_traits: default_hashmap_traits
+{
+  static hashval_t
+  hash (const symbol_compare_collection *v)
+  {
+    inchash::hash hstate;
+    hstate.add_int (v->m_references.length ());
+
+    for (unsigned i = 0; i < v->m_references.length (); i++)
+      hstate.add_ptr (v->m_references[i]->ultimate_alias_target ());
+
+    hstate.add_int (v->m_interposables.length ());
+
+    for (unsigned i = 0; i < v->m_interposables.length (); i++)
+      hstate.add_ptr (v->m_interposables[i]->ultimate_alias_target ());
+
+    return hstate.end ();
+  }
+
+  static bool
+  equal_keys (const symbol_compare_collection *a,
+             const symbol_compare_collection *b)
+  {
+    if (a->m_references.length () != b->m_references.length ())
+      return false;
+
+    for (unsigned i = 0; i < a->m_references.length (); i++)
+      if (a->m_references[i]->equal_address_to (b->m_references[i]) != 1)
+       return false;
+
+    for (unsigned i = 0; i < a->m_interposables.length (); i++)
+      if (!a->m_interposables[i]->semantically_equivalent_p
+       (b->m_interposables[i]))
+       return false;
+
+    return true;
+  }
+};
+
+
 /* Semantic item usage pair.  */
 class sem_usage_pair
 {
@@ -467,6 +531,13 @@ private:
      classes. If IN_WPA, fast equality function is invoked.  */
   void subdivide_classes_by_equality (bool in_wpa = false);
 
+  /* Subdivide classes by address and interposable references
+     that members of the class reference.
+     Example can be a pair of functions that have an address
+     taken from a function. If these addresses are different the class
+     is split.  */
+  unsigned subdivide_classes_by_sensitive_refs();
+
   /* Debug function prints all informations about congruence classes.  */
   void dump_cong_classes (void);
 
index ea03f10..be178ad 100644 (file)
@@ -4190,7 +4190,8 @@ inline_read_section (struct lto_file_decl_data *file_data, const char *data,
   unsigned int i, count2, j;
   unsigned int f_count;
 
-  lto_input_block ib ((const char *) data + main_offset, header->main_size);
+  lto_input_block ib ((const char *) data + main_offset, header->main_size,
+                     file_data->mode_table);
 
   data_in =
     lto_data_in_create (file_data, (const char *) data + string_offset,
index 025f7fc..c445f0a 100644 (file)
@@ -2559,6 +2559,19 @@ early_inliner (function *fun)
        {
          timevar_push (TV_INTEGRATION);
          todo |= optimize_inline_calls (current_function_decl);
+         /* optimize_inline_calls call above might have introduced new
+            statements that don't have inline parameters computed.  */
+         for (edge = node->callees; edge; edge = edge->next_callee)
+           {
+             if (inline_edge_summary_vec.length () > (unsigned) edge->uid)
+               {
+                 struct inline_edge_summary *es = inline_edge_summary (edge);
+                 es->call_stmt_size
+                   = estimate_num_insns (edge->call_stmt, &eni_size_weights);
+                 es->call_stmt_time
+                   = estimate_num_insns (edge->call_stmt, &eni_time_weights);
+               }
+           }
          inline_update_overall_summary (node);
          inlined = false;
          timevar_pop (TV_INTEGRATION);
index 908b5ee..cfd9c16 100644 (file)
@@ -4868,7 +4868,7 @@ ipa_prop_read_section (struct lto_file_decl_data *file_data, const char *data,
   unsigned int count;
 
   lto_input_block ib_main ((const char *) data + main_offset,
-                          header->main_size);
+                          header->main_size, file_data->mode_table);
 
   data_in =
     lto_data_in_create (file_data, (const char *) data + string_offset,
@@ -5089,7 +5089,7 @@ read_replacements_section (struct lto_file_decl_data *file_data,
   unsigned int count;
 
   lto_input_block ib_main ((const char *) data + main_offset,
-                          header->main_size);
+                          header->main_size, file_data->mode_table);
 
   data_in = lto_data_in_create (file_data, (const char *) data + string_offset,
                                header->string_size, vNULL);
index aea7f4c..38df8c9 100644 (file)
@@ -47,6 +47,9 @@ public:
      function.  */
   bool cannot_lead_to_return ();
 
+  /* Return true if refernece may be used in address compare.  */
+  bool address_matters_p ();
+
   /* Return reference list this reference is in.  */
   struct ipa_ref_list * referring_ref_list (void);
 
index 9247e29..7614cfb 100644 (file)
@@ -129,27 +129,6 @@ cgraph_node::local_p (void)
                                        
 }
 
-/* Return true when there is a reference to node and it is not vtable.  */
-
-bool
-symtab_node::address_taken_from_non_vtable_p (void)
-{
-  int i;
-  struct ipa_ref *ref = NULL;
-
-  for (i = 0; iterate_referring (i, ref); i++)
-    if (ref->use == IPA_REF_ADDR)
-      {
-       varpool_node *node;
-       if (is_a <cgraph_node *> (ref->referring))
-         return true;
-       node = dyn_cast <varpool_node *> (ref->referring);
-       if (!DECL_VIRTUAL_P (node->decl))
-         return true;
-      }
-  return false;
-}
-
 /* A helper for comdat_can_be_unshared_p.  */
 
 static bool
@@ -157,16 +136,14 @@ comdat_can_be_unshared_p_1 (symtab_node *node)
 {
   if (!node->externally_visible)
     return true;
-  /* When address is taken, we don't know if equality comparison won't
-     break eventually. Exception are virutal functions, C++
-     constructors/destructors and vtables, where this is not possible by
-     language standard.  */
-  if (!DECL_VIRTUAL_P (node->decl)
-      && (TREE_CODE (node->decl) != FUNCTION_DECL
-         || (!DECL_CXX_CONSTRUCTOR_P (node->decl)
-             && !DECL_CXX_DESTRUCTOR_P (node->decl)))
-      && node->address_taken_from_non_vtable_p ())
-    return false;
+  if (node->address_can_be_compared_p ())
+    {
+      struct ipa_ref *ref;
+
+      for (unsigned int i = 0; node->iterate_referring (i, ref); i++)
+       if (ref->address_matters_p ())
+         return false;
+    }
 
   /* If the symbol is used in some weird way, better to not touch it.  */
   if (node->force_output)
@@ -387,7 +364,8 @@ can_replace_by_local_alias_in_vtable (symtab_node *node)
 /* walk_tree callback that rewrites initializer references.   */
 
 static tree
-update_vtable_references (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
+update_vtable_references (tree *tp, int *walk_subtrees,
+                         void *data ATTRIBUTE_UNUSED)
 {
   if (TREE_CODE (*tp) == VAR_DECL
       || TREE_CODE (*tp) == FUNCTION_DECL)
index b77ff69..ff1fe8a 100644 (file)
@@ -3274,7 +3274,11 @@ color_pass (ira_loop_tree_node_t loop_tree_node)
               && (loop_tree_node->reg_pressure[pclass]
                   <= ira_class_hard_regs_num[pclass]))
              || (pic_offset_table_rtx != NULL
-                 && regno == (int) REGNO (pic_offset_table_rtx)))
+                 && regno == (int) REGNO (pic_offset_table_rtx))
+             /* Avoid overlapped multi-registers. Moves between them
+                might result in wrong code generation.  */
+             || (hard_regno >= 0
+                 && ira_reg_class_max_nregs[pclass][mode] > 1))
            {
              if (! ALLOCNO_ASSIGNED_P (subloop_allocno))
                {
index de5081a..fb0eb3c 100644 (file)
@@ -459,6 +459,16 @@ operand_to_remat (rtx_insn *insn)
             reg2 = reg2->next)
          if (reg2->type == OP_OUT && reg->regno == reg2->regno)
            return -1;
+       if (reg->regno < FIRST_PSEUDO_REGISTER)
+         for (struct lra_insn_reg *reg2 = static_id->hard_regs;
+              reg2 != NULL;
+              reg2 = reg2->next)
+           if (reg2->type == OP_OUT
+               && reg->regno <= reg2->regno
+               && (reg2->regno
+                   < (reg->regno
+                      + hard_regno_nregs[reg->regno][reg->biggest_mode])))
+             return -1;
       }
   /* Find the rematerialization operand.  */
   int nop = static_id->n_operands;
index 6add7fd..c875fed 100644 (file)
@@ -2122,7 +2122,7 @@ input_cgraph_opt_section (struct lto_file_decl_data *file_data,
   unsigned int count;
 
   lto_input_block ib_main ((const char *) data + main_offset,
-                          header->main_size);
+                          header->main_size, file_data->mode_table);
 
   data_in =
     lto_data_in_create (file_data, (const char *) data + string_offset,
index 20eded6..092b0e2 100644 (file)
@@ -89,7 +89,8 @@ const char *lto_section_name[LTO_N_SECTION_TYPES] =
   "inline",
   "ipcp_trans",
   "icf",
-  "offload_table"
+  "offload_table",
+  "mode_table"
 };
 
 
@@ -262,7 +263,8 @@ lto_create_simple_input_block (struct lto_file_decl_data *file_data,
     return NULL;
 
   *datar = data;
-  return new lto_input_block (data + main_offset, header->main_size);
+  return new lto_input_block (data + main_offset, header->main_size,
+                             file_data->mode_table);
 }
 
 
index e12d00a..a045b97 100644 (file)
@@ -1116,10 +1116,12 @@ lto_read_body_or_constructor (struct lto_file_decl_data *file_data, struct symta
 
       /* Set up the struct function.  */
       from = data_in->reader_cache->nodes.length ();
-      lto_input_block ib_main (data + main_offset, header->main_size);
+      lto_input_block ib_main (data + main_offset, header->main_size,
+                              file_data->mode_table);
       if (TREE_CODE (node->decl) == FUNCTION_DECL)
        {
-         lto_input_block ib_cfg (data + cfg_offset, header->cfg_size);
+         lto_input_block ib_cfg (data + cfg_offset, header->cfg_size,
+                                 file_data->mode_table);
          input_function (fn_decl, data_in, &ib_main, &ib_cfg);
        }
       else
@@ -1384,7 +1386,8 @@ lto_input_toplevel_asms (struct lto_file_decl_data *file_data, int order_base)
 
   string_offset = sizeof (*header) + header->main_size;
 
-  lto_input_block ib (data + sizeof (*header), header->main_size);
+  lto_input_block ib (data + sizeof (*header), header->main_size,
+                     file_data->mode_table);
 
   data_in = lto_data_in_create (file_data, data + string_offset,
                              header->string_size, vNULL);
@@ -1403,6 +1406,123 @@ lto_input_toplevel_asms (struct lto_file_decl_data *file_data, int order_base)
 }
 
 
+/* Input mode table.  */
+
+void
+lto_input_mode_table (struct lto_file_decl_data *file_data)
+{
+  size_t len;
+  const char *data = lto_get_section_data (file_data, LTO_section_mode_table,
+                                          NULL, &len);
+  if (! data)
+    {
+      internal_error ("cannot read LTO mode table from %s",
+                     file_data->file_name);
+      return;
+    }
+
+  unsigned char *table = ggc_cleared_vec_alloc<unsigned char> (1 << 8);
+  file_data->mode_table = table;
+  const struct lto_simple_header_with_strings *header
+    = (const struct lto_simple_header_with_strings *) data;
+  int string_offset;
+  struct data_in *data_in;
+  string_offset = sizeof (*header) + header->main_size;
+
+  lto_input_block ib (data + sizeof (*header), header->main_size, NULL);
+  data_in = lto_data_in_create (file_data, data + string_offset,
+                               header->string_size, vNULL);
+  bitpack_d bp = streamer_read_bitpack (&ib);
+
+  table[VOIDmode] = VOIDmode;
+  table[BLKmode] = BLKmode;
+  unsigned int m;
+  while ((m = bp_unpack_value (&bp, 8)) != VOIDmode)
+    {
+      enum mode_class mclass
+       = bp_unpack_enum (&bp, mode_class, MAX_MODE_CLASS);
+      unsigned int size = bp_unpack_value (&bp, 8);
+      unsigned int prec = bp_unpack_value (&bp, 16);
+      machine_mode inner = (machine_mode) table[bp_unpack_value (&bp, 8)];
+      unsigned int nunits = bp_unpack_value (&bp, 8);
+      unsigned int ibit = 0, fbit = 0;
+      unsigned int real_fmt_len = 0;
+      const char *real_fmt_name = NULL;
+      switch (mclass)
+       {
+       case MODE_FRACT:
+       case MODE_UFRACT:
+       case MODE_ACCUM:
+       case MODE_UACCUM:
+         ibit = bp_unpack_value (&bp, 8);
+         fbit = bp_unpack_value (&bp, 8);
+         break;
+       case MODE_FLOAT:
+       case MODE_DECIMAL_FLOAT:
+         real_fmt_name = bp_unpack_indexed_string (data_in, &bp,
+                                                   &real_fmt_len);
+         break;
+       default:
+         break;
+       }
+      /* First search just the GET_CLASS_NARROWEST_MODE to wider modes,
+        if not found, fallback to all modes.  */
+      int pass;
+      for (pass = 0; pass < 2; pass++)
+       for (machine_mode mr = pass ? VOIDmode
+                                   : GET_CLASS_NARROWEST_MODE (mclass);
+            pass ? mr < MAX_MACHINE_MODE : mr != VOIDmode;
+            pass ? mr = (machine_mode) (m + 1)
+                 : mr = GET_MODE_WIDER_MODE (mr))
+         if (GET_MODE_CLASS (mr) != mclass
+             || GET_MODE_SIZE (mr) != size
+             || GET_MODE_PRECISION (mr) != prec
+             || GET_MODE_INNER (mr) != inner
+             || GET_MODE_IBIT (mr) != ibit
+             || GET_MODE_FBIT (mr) != fbit
+             || GET_MODE_NUNITS (mr) != nunits)
+           continue;
+         else if ((mclass == MODE_FLOAT || mclass == MODE_DECIMAL_FLOAT)
+                  && strcmp (REAL_MODE_FORMAT (mr)->name, real_fmt_name) != 0)
+           continue;
+         else
+           {
+             table[m] = mr;
+             pass = 2;
+             break;
+           }
+      unsigned int mname_len;
+      const char *mname = bp_unpack_indexed_string (data_in, &bp, &mname_len);
+      if (pass == 2)
+       {
+         switch (mclass)
+           {
+           case MODE_VECTOR_INT:
+           case MODE_VECTOR_FLOAT:
+           case MODE_VECTOR_FRACT:
+           case MODE_VECTOR_UFRACT:
+           case MODE_VECTOR_ACCUM:
+           case MODE_VECTOR_UACCUM:
+             /* For unsupported vector modes just use BLKmode,
+                if the scalar mode is supported.  */
+             if (inner != VOIDmode)
+               {
+                 table[m] = BLKmode;
+                 break;
+               }
+             /* FALLTHRU */
+           default:
+             fatal_error (UNKNOWN_LOCATION, "unsupported mode %s\n", mname);
+             break;
+           }
+       }
+    }
+  lto_data_in_delete (data_in);
+
+  lto_free_section_data (file_data, LTO_section_mode_table, NULL, data, len);
+}
+
+
 /* Initialization for the LTO reader.  */
 
 void
index 0c27c9d..671bac3 100644 (file)
@@ -2642,6 +2642,96 @@ produce_symtab (struct output_block *ob)
 }
 
 
+/* Init the streamer_mode_table for output, where we collect info on what
+   machine_mode values have been streamed.  */
+void
+lto_output_init_mode_table (void)
+{
+  memset (streamer_mode_table, '\0', MAX_MACHINE_MODE);
+}
+
+
+/* Write the mode table.  */
+static void
+lto_write_mode_table (void)
+{
+  struct output_block *ob;
+  ob = create_output_block (LTO_section_mode_table);
+  bitpack_d bp = bitpack_create (ob->main_stream);
+
+  /* Ensure that for GET_MODE_INNER (m) != VOIDmode we have
+     also the inner mode marked.  */
+  for (int i = 0; i < (int) MAX_MACHINE_MODE; i++)
+    if (streamer_mode_table[i])
+      {
+       machine_mode m = (machine_mode) i;
+       if (GET_MODE_INNER (m) != VOIDmode)
+         streamer_mode_table[(int) GET_MODE_INNER (m)] = 1;
+      }
+  /* First stream modes that have GET_MODE_INNER (m) == VOIDmode,
+     so that we can refer to them afterwards.  */
+  for (int pass = 0; pass < 2; pass++)
+    for (int i = 0; i < (int) MAX_MACHINE_MODE; i++)
+      if (streamer_mode_table[i] && i != (int) VOIDmode && i != (int) BLKmode)
+       {
+         machine_mode m = (machine_mode) i;
+         if ((GET_MODE_INNER (m) == VOIDmode) ^ (pass == 0))
+           continue;
+         bp_pack_value (&bp, m, 8);
+         bp_pack_enum (&bp, mode_class, MAX_MODE_CLASS, GET_MODE_CLASS (m));
+         bp_pack_value (&bp, GET_MODE_SIZE (m), 8);
+         bp_pack_value (&bp, GET_MODE_PRECISION (m), 16);
+         bp_pack_value (&bp, GET_MODE_INNER (m), 8);
+         bp_pack_value (&bp, GET_MODE_NUNITS (m), 8);
+         switch (GET_MODE_CLASS (m))
+           {
+           case MODE_FRACT:
+           case MODE_UFRACT:
+           case MODE_ACCUM:
+           case MODE_UACCUM:
+             bp_pack_value (&bp, GET_MODE_IBIT (m), 8);
+             bp_pack_value (&bp, GET_MODE_FBIT (m), 8);
+             break;
+           case MODE_FLOAT:
+           case MODE_DECIMAL_FLOAT:
+             bp_pack_string (ob, &bp, REAL_MODE_FORMAT (m)->name, true);
+             break;
+           default:
+             break;
+           }
+         bp_pack_string (ob, &bp, GET_MODE_NAME (m), true);
+       }
+  bp_pack_value (&bp, VOIDmode, 8);
+
+  streamer_write_bitpack (&bp);
+
+  char *section_name
+    = lto_get_section_name (LTO_section_mode_table, NULL, NULL);
+  lto_begin_section (section_name, !flag_wpa);
+  free (section_name);
+
+  /* The entire header stream is computed here.  */
+  struct lto_simple_header_with_strings header;
+  memset (&header, 0, sizeof (header));
+
+  /* Write the header.  */
+  header.major_version = LTO_major_version;
+  header.minor_version = LTO_minor_version;
+
+  header.main_size = ob->main_stream->total_size;
+  header.string_size = ob->string_stream->total_size;
+  lto_write_data (&header, sizeof header);
+
+  /* Put all of the gimple and the string table out the asm file as a
+     block of text.  */
+  lto_write_stream (ob->main_stream);
+  lto_write_stream (ob->string_stream);
+
+  lto_end_section ();
+  destroy_output_block (ob);
+}
+
+
 /* This pass is run after all of the functions are serialized and all
    of the IPA passes have written their serialized forms.  This pass
    causes the vector of all of the global decls and types used from
@@ -2749,4 +2839,6 @@ produce_asm_for_decls (void)
   lto_symtab_encoder_delete (ob->decl_state->symtab_node_encoder);
   lto_function_decl_states.release ();
   destroy_output_block (ob);
+  if (lto_stream_offload_p)
+    lto_write_mode_table ();
 }
index 2d9f30c..c8862a2 100644 (file)
@@ -248,6 +248,7 @@ enum lto_section_type
   LTO_section_ipcp_transform,
   LTO_section_ipa_icf,
   LTO_section_offload_table,
+  LTO_section_mode_table,
   LTO_N_SECTION_TYPES          /* Must be last.  */
 };
 
@@ -312,12 +313,15 @@ class lto_input_block
 public:
   /* Special constructor for the string table, it abuses this to
      do random access but use the uhwi decoder.  */
-  lto_input_block (const char *data_, unsigned int p_, unsigned int len_)
-      : data (data_), p (p_), len (len_) {}
-  lto_input_block (const char *data_, unsigned int len_)
-      : data (data_), p (0), len (len_) {}
+  lto_input_block (const char *data_, unsigned int p_, unsigned int len_,
+                  const unsigned char *mode_table_)
+      : data (data_), mode_table (mode_table_), p (p_), len (len_) {}
+  lto_input_block (const char *data_, unsigned int len_,
+                  const unsigned char *mode_table_)
+      : data (data_), mode_table (mode_table_), p (0), len (len_) {}
 
   const char *data;
+  const unsigned char *mode_table;
   unsigned int p;
   unsigned int len;
 };
@@ -527,6 +531,9 @@ struct GTY(()) lto_file_decl_data
 
   /* Map assigning declarations their resolutions.  */
   hash_map<tree, ld_plugin_symbol_resolution> * GTY((skip)) resolution_map;
+
+  /* Mode translation table.  */
+  const unsigned char *mode_table;
 };
 
 typedef struct lto_file_decl_data *lto_file_decl_data_ptr;
@@ -775,6 +782,7 @@ extern void lto_input_variable_constructor (struct lto_file_decl_data *,
 extern void lto_input_constructors_and_inits (struct lto_file_decl_data *,
                                              const char *);
 extern void lto_input_toplevel_asms (struct lto_file_decl_data *, int);
+extern void lto_input_mode_table (struct lto_file_decl_data *);
 extern struct data_in *lto_data_in_create (struct lto_file_decl_data *,
                                    const char *, unsigned,
                                    vec<ld_plugin_symbol_resolution_t> );
@@ -807,6 +815,7 @@ void lto_output_decl_state_refs (struct output_block *,
                                 struct lto_output_stream *,
                                 struct lto_out_decl_state *);
 void lto_output_location (struct output_block *, struct bitpack_d *, location_t);
+void lto_output_init_mode_table (void);
 
 
 /* In lto-cgraph.c  */
index aa474e0..073bf17 100644 (file)
@@ -176,12 +176,11 @@ enum lto_builtin_type
 #define DEF_FUNCTION_TYPE_VAR_3(NAME, RETURN, ARG1, ARG2, ARG3) NAME,
 #define DEF_FUNCTION_TYPE_VAR_4(NAME, RETURN, ARG1, ARG2, ARG3, ARG4) NAME,
 #define DEF_FUNCTION_TYPE_VAR_5(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG6) \
-  NAME,
-#define DEF_FUNCTION_TYPE_VAR_8(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
-                               ARG6, ARG7, ARG8) NAME,
-#define DEF_FUNCTION_TYPE_VAR_12(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
-                                ARG6, ARG7, ARG8, ARG9, ARG10, ARG11,       \
-                                ARG12) NAME,
+                               NAME,
+#define DEF_FUNCTION_TYPE_VAR_7(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
+                               ARG6, ARG7) NAME,
+#define DEF_FUNCTION_TYPE_VAR_11(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
+                                ARG6, ARG7, ARG8, ARG9, ARG10, ARG11) NAME,
 #define DEF_POINTER_TYPE(NAME, TYPE) NAME,
 #include "builtin-types.def"
 #undef DEF_PRIMITIVE_TYPE
@@ -200,8 +199,8 @@ enum lto_builtin_type
 #undef DEF_FUNCTION_TYPE_VAR_3
 #undef DEF_FUNCTION_TYPE_VAR_4
 #undef DEF_FUNCTION_TYPE_VAR_5
-#undef DEF_FUNCTION_TYPE_VAR_8
-#undef DEF_FUNCTION_TYPE_VAR_12
+#undef DEF_FUNCTION_TYPE_VAR_7
+#undef DEF_FUNCTION_TYPE_VAR_11
 #undef DEF_POINTER_TYPE
   BT_LAST
 };
@@ -686,14 +685,13 @@ lto_define_builtins (tree va_list_ref_type_node ATTRIBUTE_UNUSED,
   def_fn_type (ENUM, RETURN, 1, 4, ARG1, ARG2, ARG3, ARG4);
 #define DEF_FUNCTION_TYPE_VAR_5(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) \
   def_fn_type (ENUM, RETURN, 1, 5, ARG1, ARG2, ARG3, ARG4, ARG5);
-#define DEF_FUNCTION_TYPE_VAR_8(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
-                               ARG6, ARG7, ARG8)                           \
-  def_fn_type (ENUM, RETURN, 1, 8, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6,      \
-              ARG7, ARG8);
-#define DEF_FUNCTION_TYPE_VAR_12(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
-                                ARG6, ARG7, ARG8, ARG9, ARG10, ARG11, ARG12) \
-  def_fn_type (ENUM, RETURN, 1, 12, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6,      \
-              ARG7, ARG8, ARG9, ARG10, ARG11, ARG12);
+#define DEF_FUNCTION_TYPE_VAR_7(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
+                               ARG6, ARG7)                             \
+  def_fn_type (ENUM, RETURN, 1, 7, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7);
+#define DEF_FUNCTION_TYPE_VAR_11(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
+                                ARG6, ARG7, ARG8, ARG9, ARG10, ARG11)  \
+  def_fn_type (ENUM, RETURN, 1, 11, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6,        \
+              ARG7, ARG8, ARG9, ARG10, ARG11);
 #define DEF_POINTER_TYPE(ENUM, TYPE) \
   builtin_types[(int) ENUM] = build_pointer_type (builtin_types[(int) TYPE]);
 
@@ -715,8 +713,8 @@ lto_define_builtins (tree va_list_ref_type_node ATTRIBUTE_UNUSED,
 #undef DEF_FUNCTION_TYPE_VAR_3
 #undef DEF_FUNCTION_TYPE_VAR_4
 #undef DEF_FUNCTION_TYPE_VAR_5
-#undef DEF_FUNCTION_TYPE_VAR_8
-#undef DEF_FUNCTION_TYPE_VAR_12
+#undef DEF_FUNCTION_TYPE_VAR_7
+#undef DEF_FUNCTION_TYPE_VAR_11
 #undef DEF_POINTER_TYPE
   builtin_types[(int) BT_LAST] = NULL_TREE;
 
index c86f835..ce7e6b1 100644 (file)
@@ -85,6 +85,8 @@ static int lto_parallelism;
 
 static GTY(()) tree first_personality_decl;
 
+static GTY(()) const unsigned char *lto_mode_identity_table;
+
 /* Returns a hash code for P.  */
 
 static hashval_t
@@ -1877,7 +1879,7 @@ lto_read_decls (struct lto_file_decl_data *decl_data, const void *data,
   uint32_t num_decl_states;
 
   lto_input_block ib_main ((const char *) data + main_offset,
-                          header->main_size);
+                          header->main_size, decl_data->mode_table);
 
   data_in = lto_data_in_create (decl_data, (const char *) data + string_offset,
                                header->string_size, resolutions);
@@ -2219,6 +2221,11 @@ lto_file_finalize (struct lto_file_decl_data *file_data, lto_file *file)
 
   file_data->renaming_hash_table = lto_create_renaming_table ();
   file_data->file_name = file->filename;
+#ifdef ACCEL_COMPILER
+  lto_input_mode_table (file_data);
+#else
+  file_data->mode_table = lto_mode_identity_table;
+#endif
   data = lto_get_section_data (file_data, LTO_section_decls, NULL, &len);
   if (data == NULL)
     {
@@ -3394,6 +3401,13 @@ lto_init (void)
   memset (&lto_stats, 0, sizeof (lto_stats));
   bitmap_obstack_initialize (NULL);
   gimple_register_cfg_hooks ();
+#ifndef ACCEL_COMPILER
+  unsigned char *table
+    = ggc_vec_alloc<unsigned char> (MAX_MACHINE_MODE);
+  for (int m = 0; m < MAX_MACHINE_MODE; m++)
+    table[m] = m;
+  lto_mode_identity_table = table;
+#endif
 }
 
 
index 6aea7b7..50f1321 100644 (file)
@@ -32,17 +32,17 @@ along with GCC; see the file COPYING3.  If not see
 DEF_GOACC_BUILTIN (BUILT_IN_ACC_GET_DEVICE_TYPE, "acc_get_device_type",
                   BT_FN_INT, ATTR_NOTHROW_LIST)
 DEF_GOACC_BUILTIN (BUILT_IN_GOACC_DATA_START, "GOACC_data_start",
-                  BT_FN_VOID_INT_PTR_SIZE_PTR_PTR_PTR, ATTR_NOTHROW_LIST)
+                  BT_FN_VOID_INT_SIZE_PTR_PTR_PTR, ATTR_NOTHROW_LIST)
 DEF_GOACC_BUILTIN (BUILT_IN_GOACC_DATA_END, "GOACC_data_end",
                   BT_FN_VOID, ATTR_NOTHROW_LIST)
 DEF_GOACC_BUILTIN (BUILT_IN_GOACC_ENTER_EXIT_DATA, "GOACC_enter_exit_data",
-                  BT_FN_VOID_INT_PTR_SIZE_PTR_PTR_PTR_INT_INT_VAR,
+                  BT_FN_VOID_INT_SIZE_PTR_PTR_PTR_INT_INT_VAR,
                   ATTR_NOTHROW_LIST)
 DEF_GOACC_BUILTIN (BUILT_IN_GOACC_PARALLEL, "GOACC_parallel",
-                  BT_FN_VOID_INT_OMPFN_PTR_SIZE_PTR_PTR_PTR_INT_INT_INT_INT_INT_VAR,
+                  BT_FN_VOID_INT_OMPFN_SIZE_PTR_PTR_PTR_INT_INT_INT_INT_INT_VAR,
                   ATTR_NOTHROW_LIST)
 DEF_GOACC_BUILTIN (BUILT_IN_GOACC_UPDATE, "GOACC_update",
-                  BT_FN_VOID_INT_PTR_SIZE_PTR_PTR_PTR_INT_INT_VAR,
+                  BT_FN_VOID_INT_SIZE_PTR_PTR_PTR_INT_INT_VAR,
                   ATTR_NOTHROW_LIST)
 DEF_GOACC_BUILTIN (BUILT_IN_GOACC_WAIT, "GOACC_wait",
                   BT_FN_VOID_INT_INT_VAR,
index 182836b..75d6707 100644 (file)
@@ -2176,6 +2176,13 @@ create_omp_child_function (omp_context *ctx, bool task_copy)
          }
     }
 
+  if (cgraph_node::get_create (decl)->offloadable
+      && !lookup_attribute ("omp declare target",
+                           DECL_ATTRIBUTES (current_function_decl)))
+    DECL_ATTRIBUTES (decl)
+      = tree_cons (get_identifier ("omp target entrypoint"),
+                   NULL_TREE, DECL_ATTRIBUTES (decl));
+
   t = build_decl (DECL_SOURCE_LOCATION (decl),
                  RESULT_DECL, NULL_TREE, void_type_node);
   DECL_ARTIFICIAL (t) = 1;
index dff70e5..23a90d9 100644 (file)
@@ -2460,6 +2460,7 @@ ipa_write_summaries_1 (lto_symtab_encoder_t encoder)
   struct lto_out_decl_state *state = lto_new_out_decl_state ();
   state->symtab_node_encoder = encoder;
 
+  lto_output_init_mode_table ();
   lto_push_out_decl_state (state);
 
   gcc_assert (!flag_wpa);
@@ -2581,6 +2582,7 @@ ipa_write_optimization_summaries (lto_symtab_encoder_t encoder)
   lto_symtab_encoder_iterator lsei;
   state->symtab_node_encoder = encoder;
 
+  lto_output_init_mode_table ();
   lto_push_out_decl_state (state);
   for (lsei = lsei_start_function_in_partition (encoder);
        !lsei_end_p (lsei); lsei_next_function_in_partition (&lsei))
index 01b169e..1d1d510 100644 (file)
@@ -3031,7 +3031,8 @@ const struct real_format ieee_single_format =
     true,
     true,
     true,
-    false
+    false,
+    "ieee_single"
   };
 
 const struct real_format mips_single_format =
@@ -3052,7 +3053,8 @@ const struct real_format mips_single_format =
     true,
     true,
     false,
-    true
+    true,
+    "mips_single"
   };
 
 const struct real_format motorola_single_format =
@@ -3073,7 +3075,8 @@ const struct real_format motorola_single_format =
     true,
     true,
     true,
-    true
+    true,
+    "motorola_single"
   };
 
 /*  SPU Single Precision (Extended-Range Mode) format is the same as IEEE
@@ -3105,7 +3108,8 @@ const struct real_format spu_single_format =
     true,
     true,
     false,
-    false
+    false,
+    "spu_single"
   };
 \f
 /* IEEE double-precision format.  */
@@ -3314,7 +3318,8 @@ const struct real_format ieee_double_format =
     true,
     true,
     true,
-    false
+    false,
+    "ieee_double"
   };
 
 const struct real_format mips_double_format =
@@ -3335,7 +3340,8 @@ const struct real_format mips_double_format =
     true,
     true,
     false,
-    true
+    true,
+    "mips_double"
   };
 
 const struct real_format motorola_double_format =
@@ -3356,7 +3362,8 @@ const struct real_format motorola_double_format =
     true,
     true,
     true,
-    true
+    true,
+    "motorola_double"
   };
 \f
 /* IEEE extended real format.  This comes in three flavors: Intel's as
@@ -3700,7 +3707,8 @@ const struct real_format ieee_extended_motorola_format =
     true,
     true,
     true,
-    true
+    true,
+    "ieee_extended_motorola"
   };
 
 const struct real_format ieee_extended_intel_96_format =
@@ -3721,7 +3729,8 @@ const struct real_format ieee_extended_intel_96_format =
     true,
     true,
     true,
-    false
+    false,
+    "ieee_extended_intel_96"
   };
 
 const struct real_format ieee_extended_intel_128_format =
@@ -3742,7 +3751,8 @@ const struct real_format ieee_extended_intel_128_format =
     true,
     true,
     true,
-    false
+    false,
+    "ieee_extended_intel_128"
   };
 
 /* The following caters to i386 systems that set the rounding precision
@@ -3765,7 +3775,8 @@ const struct real_format ieee_extended_intel_96_round_53_format =
     true,
     true,
     true,
-    false
+    false,
+    "ieee_extended_intel_96_round_53"
   };
 \f
 /* IBM 128-bit extended precision format: a pair of IEEE double precision
@@ -3853,7 +3864,8 @@ const struct real_format ibm_extended_format =
     true,
     true,
     true,
-    false
+    false,
+    "ibm_extended"
   };
 
 const struct real_format mips_extended_format =
@@ -3874,7 +3886,8 @@ const struct real_format mips_extended_format =
     true,
     true,
     false,
-    true
+    true,
+    "mips_extended"
   };
 
 \f
@@ -4137,7 +4150,8 @@ const struct real_format ieee_quad_format =
     true,
     true,
     true,
-    false
+    false,
+    "ieee_quad"
   };
 
 const struct real_format mips_quad_format =
@@ -4158,7 +4172,8 @@ const struct real_format mips_quad_format =
     true,
     true,
     false,
-    true
+    true,
+    "mips_quad"
   };
 \f
 /* Descriptions of VAX floating point formats can be found beginning at
@@ -4458,7 +4473,8 @@ const struct real_format vax_f_format =
     false,
     false,
     false,
-    false
+    false,
+    "vax_f"
   };
 
 const struct real_format vax_d_format =
@@ -4479,7 +4495,8 @@ const struct real_format vax_d_format =
     false,
     false,
     false,
-    false
+    false,
+    "vax_d"
   };
 
 const struct real_format vax_g_format =
@@ -4500,7 +4517,8 @@ const struct real_format vax_g_format =
     false,
     false,
     false,
-    false
+    false,
+    "vax_g"
   };
 \f
 /* Encode real R into a single precision DFP value in BUF.  */
@@ -4576,7 +4594,8 @@ const struct real_format decimal_single_format =
     true,
     true,
     true,
-    false
+    false,
+    "decimal_single"
   };
 
 /* Double precision decimal floating point (IEEE 754). */
@@ -4598,7 +4617,8 @@ const struct real_format decimal_double_format =
     true,
     true,
     true,
-    false
+    false,
+    "decimal_double"
   };
 
 /* Quad precision decimal floating point (IEEE 754). */
@@ -4620,7 +4640,8 @@ const struct real_format decimal_quad_format =
     true,
     true,
     true,
-    false
+    false,
+    "decimal_quad"
   };
 \f
 /* Encode half-precision floats.  This routine is used both for the IEEE
@@ -4757,7 +4778,8 @@ const struct real_format ieee_half_format =
     true,
     true,
     true,
-    false
+    false,
+    "ieee_half"
   };
 
 /* ARM's alternative half-precision format, similar to IEEE but with
@@ -4781,7 +4803,8 @@ const struct real_format arm_half_format =
     true,
     true,
     false,
-    false
+    false,
+    "arm_half"
   };
 \f
 /* A synthetic "format" for internal arithmetic.  It's the size of the
@@ -4826,7 +4849,8 @@ const struct real_format real_internal_format =
     false,
     true,
     true,
-    false
+    false,
+    "real_internal"
   };
 \f
 /* Calculate X raised to the integer exponent N in mode MODE and store
index 424a27a..37a8499 100644 (file)
@@ -155,6 +155,7 @@ struct real_format
   bool has_signed_zero;
   bool qnan_msb_set;
   bool canonical_nan_lsbs_set;
+  const char *name;
 };
 
 
index 7a70b10..a46ebd4 100644 (file)
@@ -1156,7 +1156,11 @@ symtab_node::make_decl_local (void)
     return;
 
   if (TREE_CODE (decl) == VAR_DECL)
-    DECL_COMMON (decl) = 0;
+    {
+      DECL_COMMON (decl) = 0;
+      /* ADDRESSABLE flag is not defined for public symbols.  */
+      TREE_ADDRESSABLE (decl) = 1;
+    }
   else gcc_assert (TREE_CODE (decl) == FUNCTION_DECL);
 
   DECL_COMDAT (decl) = 0;
@@ -1165,6 +1169,7 @@ symtab_node::make_decl_local (void)
   DECL_VISIBILITY_SPECIFIED (decl) = 0;
   DECL_VISIBILITY (decl) = VISIBILITY_DEFAULT;
   TREE_PUBLIC (decl) = 0;
+  DECL_DLLIMPORT_P (decl) = 0;
   if (!DECL_RTL_SET_P (decl))
     return;
 
@@ -1512,6 +1517,19 @@ symtab_node::resolve_alias (symtab_node *target)
   /* If alias has address taken, so does the target.  */
   if (address_taken)
     target->ultimate_alias_target ()->address_taken = true;
+
+  /* All non-weakref aliases of THIS are now in fact aliases of TARGET.  */
+  ipa_ref *ref;
+  for (unsigned i = 0; iterate_direct_aliases (i, ref);)
+    {
+      struct symtab_node *alias_alias = ref->referring;
+      if (!alias_alias->weakref)
+       {
+         alias_alias->remove_all_references ();
+         alias_alias->create_reference (target, IPA_REF_ALIAS, NULL);
+       }
+      else i++;
+    }
   return true;
 }
 
@@ -1534,7 +1552,6 @@ symtab_node::noninterposable_alias (symtab_node *node, void *data)
                 != flags_from_decl_or_type (fn->decl))
          || DECL_ATTRIBUTES (node->decl) != DECL_ATTRIBUTES (fn->decl))
        return false;
-
       *(symtab_node **)data = node;
       return true;
     }
@@ -1566,6 +1583,7 @@ symtab_node::noninterposable_alias (void)
 
   /* Otherwise create a new one.  */
   new_decl = copy_node (node->decl);
+  DECL_DLLIMPORT_P (new_decl) = 0;
   DECL_NAME (new_decl) = clone_function_name (node->decl, "localalias");
   if (TREE_CODE (new_decl) == FUNCTION_DECL)
     DECL_STRUCT_FUNCTION (new_decl) = NULL;
@@ -1862,3 +1880,31 @@ symtab_node::call_for_symbol_and_aliases_1 (bool (*callback) (symtab_node *,
     }
   return false;
 }
+
+/* Return ture if address of N is possibly compared.  */
+
+static bool
+address_matters_1 (symtab_node *n, void *)
+{
+  struct ipa_ref *ref;
+
+  if (!n->address_can_be_compared_p ())
+    return false;
+  if (n->externally_visible || n->force_output)
+    return true;
+
+  for (unsigned int i = 0; n->iterate_referring (i, ref); i++)
+    if (ref->address_matters_p ())
+      return true;
+  return false;
+}
+
+/* Return true if symbol's address may possibly be compared to other
+   symbol's address.  */
+
+bool
+symtab_node::address_matters_p ()
+{
+  gcc_assert (!alias);
+  return call_for_symbol_and_aliases (address_matters_1, NULL, true);
+}
index 356f7c1..a00181a 100644 (file)
@@ -1868,6 +1868,13 @@ recorded in the offload function and variable table.",
  void, (tree),
  hook_void_tree)
 
+DEFHOOKPOD
+(absolute_biggest_alignment,
+ "If defined, this target hook specifies the absolute biggest alignment\n\
+that a type or variable can have on this machine, otherwise,\n\
+@code{BIGGEST_ALIGNMENT} is used.",
+ HOST_WIDE_INT, BIGGEST_ALIGNMENT)
+
 /* Allow target specific overriding of option settings after options have
   been changed by an attribute or pragma or when it is reset at the
   end of the code affected by an attribute or pragma.  */
@@ -5494,6 +5501,15 @@ information in the @code{struct cl_target_option} structure for\n\
 function-specific options to the @code{struct gcc_options} structure.",
  void, (struct gcc_options *opts, struct cl_target_option *ptr), NULL)
 
+/* Function to update target-specific option information after being
+   streamed in.  */
+DEFHOOK
+(post_stream_in,
+ "This hook is called to update target-specific information in the\n\
+@code{struct cl_target_option} structure after it is streamed in from\n\
+LTO bytecode.",
+ void, (struct cl_target_option *ptr), NULL)
+
 /* Function to print any extra target state from the target options
    structure.  */
 DEFHOOK
index e30116d..c22a677 100644 (file)
@@ -1780,6 +1780,10 @@ find_bswap_or_nop_load (gimple stmt, tree ref, struct symbolic_number *n)
   int unsignedp, volatilep;
   tree offset, base_addr;
 
+  /* Not prepared to handle PDP endian.  */
+  if (BYTES_BIG_ENDIAN != WORDS_BIG_ENDIAN)
+    return false;
+
   if (!gimple_assign_load_p (stmt) || gimple_has_volatile_ops (stmt))
     return false;
 
@@ -1860,8 +1864,8 @@ perform_symbolic_merge (gimple source_stmt1, struct symbolic_number *n1,
          || !operand_equal_p (n1->base_addr, n2->base_addr, 0))
        return NULL;
 
-      if (!n1->offset != !n2->offset ||
-          (n1->offset && !operand_equal_p (n1->offset, n2->offset, 0)))
+      if (!n1->offset != !n2->offset
+         || (n1->offset && !operand_equal_p (n1->offset, n2->offset, 0)))
        return NULL;
 
       if (n1->bytepos < n2->bytepos)
@@ -1912,8 +1916,8 @@ perform_symbolic_merge (gimple source_stmt1, struct symbolic_number *n1,
       size = TYPE_PRECISION (n1->type) / BITS_PER_UNIT;
       for (i = 0; i < size; i++, inc <<= BITS_PER_MARKER)
        {
-         unsigned marker =
-           (toinc_n_ptr->n >> (i * BITS_PER_MARKER)) & MARKER_MASK;
+         unsigned marker
+           (toinc_n_ptr->n >> (i * BITS_PER_MARKER)) & MARKER_MASK;
          if (marker && marker != MARKER_BYTE_UNKNOWN)
            toinc_n_ptr->n += inc;
        }
@@ -2032,7 +2036,7 @@ find_bswap_or_nop_1 (gimple stmt, struct symbolic_number *n, int limit)
        case RSHIFT_EXPR:
        case LROTATE_EXPR:
        case RROTATE_EXPR:
-         if (!do_shift_rotate (code, n, (int)TREE_INT_CST_LOW (rhs2)))
+         if (!do_shift_rotate (code, n, (int) TREE_INT_CST_LOW (rhs2)))
            return NULL;
          break;
        CASE_CONVERT:
@@ -2104,12 +2108,12 @@ find_bswap_or_nop_1 (gimple stmt, struct symbolic_number *n, int limit)
          if (TYPE_PRECISION (n1.type) != TYPE_PRECISION (n2.type))
            return NULL;
 
-         if (!n1.vuse != !n2.vuse ||
-         (n1.vuse && !operand_equal_p (n1.vuse, n2.vuse, 0)))
+         if (!n1.vuse != !n2.vuse
+             || (n1.vuse && !operand_equal_p (n1.vuse, n2.vuse, 0)))
            return NULL;
 
-         source_stmt =
-           perform_symbolic_merge (source_stmt1, &n1, source_stmt2, &n2, n);
+         source_stmt
+           perform_symbolic_merge (source_stmt1, &n1, source_stmt2, &n2, n);
 
          if (!source_stmt)
            return NULL;
@@ -2153,12 +2157,12 @@ find_bswap_or_nop (gimple stmt, struct symbolic_number *n, bool *bswap)
      in libgcc, and for initial shift/and operation of the src operand.  */
   limit = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (gimple_expr_type (stmt)));
   limit += 1 + (int) ceil_log2 ((unsigned HOST_WIDE_INT) limit);
-  source_stmt =  find_bswap_or_nop_1 (stmt, n, limit);
+  source_stmt = find_bswap_or_nop_1 (stmt, n, limit);
 
   if (!source_stmt)
     return NULL;
 
-  /* Find real size of result (highest non zero byte).  */
+  /* Find real size of result (highest non-zero byte).  */
   if (n->base_addr)
     {
       int rsize;
@@ -2261,8 +2265,30 @@ bswap_replace (gimple cur_stmt, gimple src_stmt, tree fndecl, tree bswap_type,
       tree load_offset_ptr, aligned_load_type;
       gimple addr_stmt, load_stmt;
       unsigned align;
+      HOST_WIDE_INT load_offset = 0;
 
       align = get_object_alignment (src);
+      /* If the new access is smaller than the original one, we need
+        to perform big endian adjustment.  */
+      if (BYTES_BIG_ENDIAN)
+       {
+         HOST_WIDE_INT bitsize, bitpos;
+         machine_mode mode;
+         int unsignedp, volatilep;
+         tree offset;
+
+         get_inner_reference (src, &bitsize, &bitpos, &offset, &mode,
+                              &unsignedp, &volatilep, false);
+         if (n->range < (unsigned HOST_WIDE_INT) bitsize)
+           {
+             load_offset = (bitsize - n->range) / BITS_PER_UNIT;
+             unsigned HOST_WIDE_INT l
+               = (load_offset * BITS_PER_UNIT) & (align - 1);
+             if (l)
+               align = l & -l;
+           }
+       }
+
       if (bswap
          && align < GET_MODE_ALIGNMENT (TYPE_MODE (load_type))
          && SLOW_UNALIGNED_ACCESS (TYPE_MODE (load_type), align))
@@ -2274,10 +2300,10 @@ bswap_replace (gimple cur_stmt, gimple src_stmt, tree fndecl, tree bswap_type,
       gsi_move_before (&gsi, &gsi_ins);
       gsi = gsi_for_stmt (cur_stmt);
 
-      /*  Compute address to load from and cast according to the size
-         of the load.  */
+      /* Compute address to load from and cast according to the size
+        of the load.  */
       addr_expr = build_fold_addr_expr (unshare_expr (src));
-      if (is_gimple_min_invariant (addr_expr))
+      if (is_gimple_mem_ref_addr (addr_expr))
        addr_tmp = addr_expr;
       else
        {
@@ -2291,7 +2317,7 @@ bswap_replace (gimple cur_stmt, gimple src_stmt, tree fndecl, tree bswap_type,
       aligned_load_type = load_type;
       if (align < TYPE_ALIGN (load_type))
        aligned_load_type = build_aligned_type (load_type, align);
-      load_offset_ptr = build_int_cst (n->alias_set, 0);
+      load_offset_ptr = build_int_cst (n->alias_set, load_offset);
       val_expr = fold_build2 (MEM_REF, aligned_load_type, addr_tmp,
                              load_offset_ptr);
 
@@ -2328,7 +2354,7 @@ bswap_replace (gimple cur_stmt, gimple src_stmt, tree fndecl, tree bswap_type,
            {
              fprintf (dump_file,
                       "%d bit load in target endianness found at: ",
-                      (int)n->range);
+                      (int) n->range);
              print_gimple_stmt (dump_file, cur_stmt, 0, 0);
            }
          return true;
@@ -2395,7 +2421,7 @@ bswap_replace (gimple cur_stmt, gimple src_stmt, tree fndecl, tree bswap_type,
   if (dump_file)
     {
       fprintf (dump_file, "%d bit bswap implementation found at: ",
-              (int)n->range);
+              (int) n->range);
       print_gimple_stmt (dump_file, cur_stmt, 0, 0);
     }
 
index 6d665ea..8b82f9e 100644 (file)
@@ -66,6 +66,7 @@
 #include "langhooks.h"
 #include "value-prof.h"
 #include "domwalk.h"
+#include "cfgloop.h"
 
 /* This file implements a generic value propagation engine based on
    the same propagation used by the SSA-CCP algorithm [1].
@@ -992,6 +993,7 @@ replace_phi_args_in (gphi *phi, ssa_prop_get_value_fn get_value)
       print_gimple_stmt (dump_file, phi, 0, TDF_SLIM);
     }
 
+  basic_block bb = gimple_bb (phi);
   for (i = 0; i < gimple_phi_num_args (phi); i++)
     {
       tree arg = gimple_phi_arg_def (phi, i);
@@ -1002,6 +1004,21 @@ replace_phi_args_in (gphi *phi, ssa_prop_get_value_fn get_value)
 
          if (val && val != arg && may_propagate_copy (arg, val))
            {
+             edge e = gimple_phi_arg_edge (phi, i);
+
+             /* Avoid propagating constants into loop latch edge
+                PHI arguments as this makes coalescing the copy
+                across this edge impossible.  If the argument is
+                defined by an assert - otherwise the stmt will
+                get removed without replacing its uses.  */
+             if (TREE_CODE (val) != SSA_NAME
+                 && bb->loop_father->header == bb
+                 && dominated_by_p (CDI_DOMINATORS, e->src, bb)
+                 && is_gimple_assign (SSA_NAME_DEF_STMT (arg))
+                 && (gimple_assign_rhs_code (SSA_NAME_DEF_STMT (arg))
+                     == ASSERT_EXPR))
+               continue;
+
              if (TREE_CODE (val) != SSA_NAME)
                prop_stats.num_const_prop++;
              else
@@ -1014,8 +1031,15 @@ replace_phi_args_in (gphi *phi, ssa_prop_get_value_fn get_value)
                 through an abnormal edge, update the replacement
                 accordingly.  */
              if (TREE_CODE (val) == SSA_NAME
-                 && gimple_phi_arg_edge (phi, i)->flags & EDGE_ABNORMAL)
-               SSA_NAME_OCCURS_IN_ABNORMAL_PHI (val) = 1;
+                 && e->flags & EDGE_ABNORMAL
+                 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (val))
+               {
+                 /* This can only occur for virtual operands, since
+                    for the real ones SSA_NAME_OCCURS_IN_ABNORMAL_PHI (val))
+                    would prevent replacement.  */
+                 gcc_checking_assert (virtual_operand_p (val));
+                 SSA_NAME_OCCURS_IN_ABNORMAL_PHI (val) = 1;
+               }
            }
        }
     }
index ce37053..2e933e7 100644 (file)
@@ -3532,7 +3532,7 @@ rewrite_expr_tree (gimple stmt, unsigned int opindex,
 
   /* The final recursion case for this function is that you have
      exactly two operations left.
-     If we had one exactly one op in the entire list to start with, we
+     If we had exactly one op in the entire list to start with, we
      would have never called this function, and the tail recursion
      rewrites them one at a time.  */
   if (opindex + 2 == ops.length ())
@@ -3553,7 +3553,11 @@ rewrite_expr_tree (gimple stmt, unsigned int opindex,
              print_gimple_stmt (dump_file, stmt, 0, 0);
            }
 
-         if (changed)
+         /* Even when changed is false, reassociation could have e.g. removed
+            some redundant operations, so unless we are just swapping the
+            arguments or unless there is no change at all (then we just
+            return lhs), force creation of a new SSA_NAME.  */
+         if (changed || ((rhs1 != oe2->op || rhs2 != oe1->op) && opindex))
            {
              gimple insert_point = find_insert_point (stmt, oe1->op, oe2->op);
              lhs = make_ssa_name (TREE_TYPE (lhs));
index 3326144..7a159bb 100644 (file)
@@ -197,6 +197,9 @@ dump_jump_thread_path (FILE *dump_file, vec<jump_thread_edge *> path,
       if (path[i]->type == EDGE_NO_COPY_SRC_BLOCK)
        fprintf (dump_file, " (%d, %d) nocopy;",
                 path[i]->e->src->index, path[i]->e->dest->index);
+      if (path[0]->type == EDGE_FSM_THREAD)
+       fprintf (dump_file, " (%d, %d) ",
+                path[i]->e->src->index, path[i]->e->dest->index);
     }
   fputc ('\n', dump_file);
 }
@@ -2473,6 +2476,21 @@ duplicate_seme_region (edge entry, edge exit,
   return true;
 }
 
+/* Return true when PATH is a valid jump-thread path.  */
+
+static bool
+valid_jump_thread_path (vec<jump_thread_edge *> *path)
+{
+  unsigned len = path->length ();
+
+  /* Check that the path is connected.  */
+  for (unsigned int j = 0; j < len - 1; j++)
+    if ((*path)[j]->e->dest != (*path)[j+1]->e->src)
+      return false;
+
+  return true;
+}
+
 /* Walk through all blocks and thread incoming edges to the appropriate
    outgoing edge for each edge pair recorded in THREADED_EDGES.
 
@@ -2505,12 +2523,25 @@ thread_through_all_blocks (bool may_peel_loop_headers)
       vec<jump_thread_edge *> *path = paths[i];
       edge entry = (*path)[0]->e;
 
-      if ((*path)[0]->type != EDGE_FSM_THREAD
-         /* Do not jump-thread twice from the same block.  */
-         || bitmap_bit_p (threaded_blocks, entry->src->index)) {
-       i++;
-       continue;
-      }
+      /* Only code-generate FSM jump-threads in this loop.  */
+      if ((*path)[0]->type != EDGE_FSM_THREAD)
+       {
+         i++;
+         continue;
+       }
+
+      /* Do not jump-thread twice from the same block.  */
+      if (bitmap_bit_p (threaded_blocks, entry->src->index)
+         /* Verify that the jump thread path is still valid: a
+            previous jump-thread may have changed the CFG, and
+            invalidated the current path.  */
+         || !valid_jump_thread_path (path))
+       {
+         /* Remove invalid FSM jump-thread paths.  */
+         delete_jump_thread_path (path);
+         paths.unordered_remove (i);
+         continue;
+       }
 
       unsigned len = path->length ();
       edge exit = (*path)[len - 1]->e;
index 506e676..42e2a73 100644 (file)
@@ -224,7 +224,7 @@ static void
 unpack_ts_fixed_cst_value_fields (struct bitpack_d *bp, tree expr)
 {
   FIXED_VALUE_TYPE *fp = ggc_alloc<fixed_value> ();
-  fp->mode = bp_unpack_enum (bp, machine_mode, MAX_MACHINE_MODE);
+  fp->mode = bp_unpack_machine_mode (bp);
   fp->data.low = bp_unpack_var_len_int (bp);
   fp->data.high = bp_unpack_var_len_int (bp);
   TREE_FIXED_CST_PTR (expr) = fp;
@@ -236,7 +236,7 @@ unpack_ts_fixed_cst_value_fields (struct bitpack_d *bp, tree expr)
 static void
 unpack_ts_decl_common_value_fields (struct bitpack_d *bp, tree expr)
 {
-  DECL_MODE (expr) = bp_unpack_enum (bp, machine_mode, MAX_MACHINE_MODE);
+  DECL_MODE (expr) = bp_unpack_machine_mode (bp);
   DECL_NONLOCAL (expr) = (unsigned) bp_unpack_value (bp, 1);
   DECL_VIRTUAL_P (expr) = (unsigned) bp_unpack_value (bp, 1);
   DECL_IGNORED_P (expr) = (unsigned) bp_unpack_value (bp, 1);
@@ -247,7 +247,10 @@ unpack_ts_decl_common_value_fields (struct bitpack_d *bp, tree expr)
   DECL_EXTERNAL (expr) = (unsigned) bp_unpack_value (bp, 1);
   DECL_GIMPLE_REG_P (expr) = (unsigned) bp_unpack_value (bp, 1);
   DECL_ALIGN (expr) = (unsigned) bp_unpack_var_len_unsigned (bp);
-
+#ifdef ACCEL_COMPILER
+  if (DECL_ALIGN (expr) > targetm.absolute_biggest_alignment)
+    DECL_ALIGN (expr) = targetm.absolute_biggest_alignment;
+#endif
   if (TREE_CODE (expr) == LABEL_DECL)
     {
       EH_LANDING_PAD_NR (expr) = (int) bp_unpack_var_len_unsigned (bp);
@@ -373,7 +376,7 @@ unpack_ts_type_common_value_fields (struct bitpack_d *bp, tree expr)
 {
   machine_mode mode;
 
-  mode = bp_unpack_enum (bp, machine_mode, MAX_MACHINE_MODE);
+  mode = bp_unpack_machine_mode (bp);
   SET_TYPE_MODE (expr, mode);
   TYPE_STRING_FLAG (expr) = (unsigned) bp_unpack_value (bp, 1);
   TYPE_NO_FORCE_BLK (expr) = (unsigned) bp_unpack_value (bp, 1);
@@ -391,6 +394,10 @@ unpack_ts_type_common_value_fields (struct bitpack_d *bp, tree expr)
   TYPE_READONLY (expr) = (unsigned) bp_unpack_value (bp, 1);
   TYPE_PRECISION (expr) = bp_unpack_var_len_unsigned (bp);
   TYPE_ALIGN (expr) = bp_unpack_var_len_unsigned (bp);
+#ifdef ACCEL_COMPILER
+  if (TYPE_ALIGN (expr) > targetm.absolute_biggest_alignment)
+    TYPE_ALIGN (expr) = targetm.absolute_biggest_alignment;
+#endif
   TYPE_ALIAS_SET (expr) = bp_unpack_var_len_int (bp);
 }
 
@@ -552,7 +559,11 @@ streamer_read_tree_bitfields (struct lto_input_block *ib,
 
 #ifndef ACCEL_COMPILER
   if (CODE_CONTAINS_STRUCT (code, TS_TARGET_OPTION))
-    cl_target_option_stream_in (data_in, &bp, TREE_TARGET_OPTION (expr));
+    {
+      cl_target_option_stream_in (data_in, &bp, TREE_TARGET_OPTION (expr));
+      if (targetm.target_option.post_stream_in)
+       targetm.target_option.post_stream_in (TREE_TARGET_OPTION (expr));
+    }
 #endif
 
   if (code == OMP_CLAUSE)
index 36102ed..0e5458b 100644 (file)
@@ -190,7 +190,7 @@ static void
 pack_ts_fixed_cst_value_fields (struct bitpack_d *bp, tree expr)
 {
   struct fixed_value fv = TREE_FIXED_CST (expr);
-  bp_pack_enum (bp, machine_mode, MAX_MACHINE_MODE, fv.mode);
+  bp_pack_machine_mode (bp, fv.mode);
   bp_pack_var_len_int (bp, fv.data.low);
   bp_pack_var_len_int (bp, fv.data.high);
 }
@@ -201,7 +201,7 @@ pack_ts_fixed_cst_value_fields (struct bitpack_d *bp, tree expr)
 static void
 pack_ts_decl_common_value_fields (struct bitpack_d *bp, tree expr)
 {
-  bp_pack_enum (bp, machine_mode, MAX_MACHINE_MODE, DECL_MODE (expr));
+  bp_pack_machine_mode (bp, DECL_MODE (expr));
   bp_pack_value (bp, DECL_NONLOCAL (expr), 1);
   bp_pack_value (bp, DECL_VIRTUAL_P (expr), 1);
   bp_pack_value (bp, DECL_IGNORED_P (expr), 1);
@@ -325,7 +325,7 @@ pack_ts_function_decl_value_fields (struct bitpack_d *bp, tree expr)
 static void
 pack_ts_type_common_value_fields (struct bitpack_d *bp, tree expr)
 {
-  bp_pack_enum (bp, machine_mode, MAX_MACHINE_MODE, TYPE_MODE (expr));
+  bp_pack_machine_mode (bp, TYPE_MODE (expr));
   bp_pack_value (bp, TYPE_STRING_FLAG (expr), 1);
   bp_pack_value (bp, TYPE_NO_FORCE_BLK (expr), 1);
   bp_pack_value (bp, TYPE_NEEDS_CONSTRUCTING (expr), 1);
index 7b35358..2eb0305 100644 (file)
@@ -53,6 +53,14 @@ along with GCC; see the file COPYING3.  If not see
 #include "cgraph.h"
 #include "tree-streamer.h"
 
+/* Table indexed by machine_mode, used for 2 different purposes.
+   During streaming out we record there non-zero value for all modes
+   that were streamed out.
+   During streaming in, we translate the on the disk mode using this
+   table.  For normal LTO it is set to identity, for ACCEL_COMPILER
+   depending on the mode_table content.  */
+unsigned char streamer_mode_table[1 << 8];
+
 /* Check that all the TS_* structures handled by the streamer_write_* and
    streamer_read_* routines are exactly ALL the structures defined in
    treestruct.def.  */
index 7680620..20e2621 100644 (file)
@@ -24,6 +24,7 @@ along with GCC; see the file COPYING3.  If not see
 
 #include "streamer-hooks.h"
 #include "lto-streamer.h"
+#include "data-streamer.h"
 #include "hash-map.h"
 
 /* Cache of pickled nodes.  Used to avoid writing the same node more
@@ -91,6 +92,7 @@ void streamer_write_integer_cst (struct output_block *, tree, bool);
 void streamer_write_builtin (struct output_block *, tree);
 
 /* In tree-streamer.c.  */
+extern unsigned char streamer_mode_table[1 << 8];
 void streamer_check_handled_ts_structures (void);
 bool streamer_tree_cache_insert (struct streamer_tree_cache_d *, tree,
                                 hashval_t, unsigned *);
@@ -119,5 +121,19 @@ streamer_tree_cache_get_hash (struct streamer_tree_cache_d *cache, unsigned ix)
   return cache->hashes[ix];
 }
 
+static inline void
+bp_pack_machine_mode (struct bitpack_d *bp, machine_mode mode)
+{
+  streamer_mode_table[mode] = 1;
+  bp_pack_enum (bp, machine_mode, 1 << 8, mode);
+}
+
+static inline machine_mode
+bp_unpack_machine_mode (struct bitpack_d *bp)
+{
+  return (machine_mode)
+          ((struct lto_input_block *)
+           bp->stream)->mode_table[bp_unpack_enum (bp, machine_mode, 1 << 8)];
+}
 
 #endif  /* GCC_TREE_STREAMER_H  */
index 3e7c701..dd4ada2 100644 (file)
@@ -4981,6 +4981,12 @@ vectorizable_reduction (gimple stmt, gimple_stmt_iterator *gsi,
   if (!vectype_in)
     vectype_in = tem;
   gcc_assert (is_simple_use);
+  if (!found_nested_cycle_def)
+    reduc_def_stmt = def_stmt;
+
+  if (reduc_def_stmt && gimple_code (reduc_def_stmt) != GIMPLE_PHI)
+    return false;
+
   if (!(dt == vect_reduction_def
        || dt == vect_nested_cycle
        || ((dt == vect_internal_def || dt == vect_external_def
@@ -4993,10 +4999,7 @@ vectorizable_reduction (gimple stmt, gimple_stmt_iterator *gsi,
       gcc_assert (orig_stmt);
       return false;
     }
-  if (!found_nested_cycle_def)
-    reduc_def_stmt = def_stmt;
 
-  gcc_assert (gimple_code (reduc_def_stmt) == GIMPLE_PHI);
   if (orig_stmt)
     gcc_assert (orig_stmt == vect_is_simple_reduction (loop_vinfo,
                                                        reduc_def_stmt,
index fd7cbb4..1a7fc14 100644 (file)
@@ -237,7 +237,7 @@ wide_int
 wi::from_mpz (const_tree type, mpz_t x, bool wrap)
 {
   size_t count, numb;
-  int prec = TYPE_PRECISION (type);
+  unsigned int prec = TYPE_PRECISION (type);
   wide_int res = wide_int::create (prec);
 
   if (!wrap)
@@ -261,16 +261,28 @@ wi::from_mpz (const_tree type, mpz_t x, bool wrap)
      for representing the value.  The code to calculate count is
      extracted from the GMP manual, section "Integer Import and Export":
      http://gmplib.org/manual/Integer-Import-and-Export.html  */
-  numb = 8 * sizeof(HOST_WIDE_INT);
+  numb = CHAR_BIT * sizeof (HOST_WIDE_INT);
   count = (mpz_sizeinbase (x, 2) + numb - 1) / numb;
   HOST_WIDE_INT *val = res.write_val ();
-  mpz_export (val, &count, -1, sizeof (HOST_WIDE_INT), 0, 0, x);
+  /* Write directly to the wide_int storage if possible, otherwise leave
+     GMP to allocate the memory for us.  It might be slightly more efficient
+     to use mpz_tdiv_r_2exp for the latter case, but the situation is
+     pathological and it seems safer to operate on the original mpz value
+     in all cases.  */
+  void *valres = mpz_export (count <= WIDE_INT_MAX_ELTS ? val : 0,
+                            &count, -1, sizeof (HOST_WIDE_INT), 0, 0, x);
   if (count < 1)
     {
       val[0] = 0;
       count = 1;
     }
-  res.set_len (count);
+  count = MIN (count, BLOCKS_NEEDED (prec));
+  if (valres != val)
+    {
+      memcpy (val, valres, count * sizeof (HOST_WIDE_INT));
+      free (valres);
+    }
+  res.set_len (canonize (val, count, prec));
 
   if (mpz_sgn (x) < 0)
     res = -res;
@@ -1297,6 +1309,11 @@ wi::mul_internal (HOST_WIDE_INT *val, const HOST_WIDE_INT *op1val,
              return 1;
            }
          umul_ppmm (val[1], val[0], op1.ulow (), op2.ulow ());
+         if (val[1] < 0 && prec > HOST_BITS_PER_WIDE_INT * 2)
+           {
+             val[2] = 0;
+             return 3;
+           }
          return 1 + (val[1] != 0 || val[0] < 0);
        }
       /* Likewise if the output is a full single HWI, except that the
index 08d3a67..34d68cc 100644 (file)
@@ -7,3 +7,8 @@ LIB2FUNCS_EXCLUDE=__main
 
 crt0.o: $(srcdir)/config/nvptx/crt0.s
        cp $< $@
+
+# Prevent building "advanced" stuff (for example, gcov support).  We don't
+# support it, and it may cause the build to fail, because of alloca usage, for
+# example.
+INHIBIT_LIBC_CFLAGS = -Dinhibit_libc