re PR target/65697 (__atomic memory barriers not strong enough for __sync builtins)
[gcc.git] / gcc / tree-sra.c
index f2013f8d61ab22307c0d330482ec9cdec2b410b2..7f242f72c0c1290de3ae73b9612f2b0fbfaf8907 100644 (file)
@@ -1,7 +1,7 @@
 /* Scalar Replacement of Aggregates (SRA) converts some structure
    references into scalar references, exposing them to the scalar
    optimizers.
-   Copyright (C) 2008-2014 Free Software Foundation, Inc.
+   Copyright (C) 2008-2015 Free Software Foundation, Inc.
    Contributed by Martin Jambor <mjambor@suse.cz>
 
 This file is part of GCC.
@@ -74,18 +74,14 @@ along with GCC; see the file COPYING3.  If not see
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
-#include "hash-map.h"
-#include "hash-table.h"
 #include "alloc-pool.h"
 #include "tm.h"
+#include "alias.h"
+#include "symtab.h"
 #include "tree.h"
+#include "fold-const.h"
 #include "predict.h"
-#include "vec.h"
-#include "hashtab.h"
-#include "hash-set.h"
-#include "machmode.h"
 #include "hard-reg-set.h"
-#include "input.h"
 #include "function.h"
 #include "dominance.h"
 #include "cfg.h"
@@ -94,7 +90,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "internal-fn.h"
 #include "tree-eh.h"
 #include "gimple-expr.h"
-#include "is-a.h"
 #include "gimple.h"
 #include "stor-layout.h"
 #include "gimplify.h"
@@ -108,15 +103,25 @@ along with GCC; see the file COPYING3.  If not see
 #include "ssa-iterators.h"
 #include "stringpool.h"
 #include "tree-ssanames.h"
+#include "rtl.h"
+#include "flags.h"
+#include "insn-config.h"
+#include "expmed.h"
+#include "dojump.h"
+#include "explow.h"
+#include "calls.h"
+#include "emit-rtl.h"
+#include "varasm.h"
+#include "stmt.h"
 #include "expr.h"
 #include "tree-dfa.h"
 #include "tree-ssa.h"
 #include "tree-pass.h"
+#include "cgraph.h"
+#include "symbol-summary.h"
 #include "ipa-prop.h"
-#include "statistics.h"
 #include "params.h"
 #include "target.h"
-#include "flags.h"
 #include "dbgcnt.h"
 #include "tree-inline.h"
 #include "gimple-pretty-print.h"
@@ -279,13 +284,28 @@ struct access
   /* Set when we discover that this pointer is not safe to dereference in the
      caller.  */
   unsigned grp_not_necessarilly_dereferenced : 1;
+
+  /* Pool allocation new operator.  */
+  inline void *operator new (size_t)
+  {
+    return pool.allocate ();
+  }
+
+  /* Delete operator utilizing pool allocation.  */
+  inline void operator delete (void *ptr)
+  {
+    pool.remove ((access *) ptr);
+  }
+
+  /* Memory allocation pool.  */
+  static pool_allocator<access> pool;
 };
 
 typedef struct access *access_p;
 
 
 /* Alloc pool for allocating access structures.  */
-static alloc_pool access_pool;
+pool_allocator<struct access> access::pool ("SRA accesses", 16);
 
 /* A structure linking lhs and rhs accesses from an aggregate assignment.  They
    are used to propagate subaccesses from rhs to lhs as long as they don't
@@ -294,28 +314,41 @@ struct assign_link
 {
   struct access *lacc, *racc;
   struct assign_link *next;
+
+  /* Pool allocation new operator.  */
+  inline void *operator new (size_t)
+  {
+    return pool.allocate ();
+  }
+
+  /* Delete operator utilizing pool allocation.  */
+  inline void operator delete (void *ptr)
+  {
+    pool.remove ((assign_link *) ptr);
+  }
+
+  /* Memory allocation pool.  */
+  static pool_allocator<assign_link> pool;
 };
 
 /* Alloc pool for allocating assign link structures.  */
-static alloc_pool link_pool;
+pool_allocator<assign_link> assign_link::pool ("SRA links", 16);
 
 /* Base (tree) -> Vector (vec<access_p> *) map.  */
 static hash_map<tree, auto_vec<access_p> > *base_access_vec;
 
 /* Candidate hash table helpers.  */
 
-struct uid_decl_hasher : typed_noop_remove <tree_node>
+struct uid_decl_hasher : nofree_ptr_hash <tree_node>
 {
-  typedef tree_node value_type;
-  typedef tree_node compare_type;
-  static inline hashval_t hash (const value_type *);
-  static inline bool equal (const value_type *, const compare_type *);
+  static inline hashval_t hash (const tree_node *);
+  static inline bool equal (const tree_node *, const tree_node *);
 };
 
 /* Hash a tree in a uid_decl_map.  */
 
 inline hashval_t
-uid_decl_hasher::hash (const value_type *item)
+uid_decl_hasher::hash (const tree_node *item)
 {
   return item->decl_minimal.uid;
 }
@@ -323,7 +356,7 @@ uid_decl_hasher::hash (const value_type *item)
 /* Return true if the DECL_UID in both trees are equal.  */
 
 inline bool
-uid_decl_hasher::equal (const value_type *a, const compare_type *b)
+uid_decl_hasher::equal (const tree_node *a, const tree_node *b)
 {
   return (a->decl_minimal.uid == b->decl_minimal.uid);
 }
@@ -669,8 +702,6 @@ sra_initialize (void)
   should_scalarize_away_bitmap = BITMAP_ALLOC (NULL);
   cannot_scalarize_away_bitmap = BITMAP_ALLOC (NULL);
   gcc_obstack_init (&name_obstack);
-  access_pool = create_alloc_pool ("SRA accesses", sizeof (struct access), 16);
-  link_pool = create_alloc_pool ("SRA links", sizeof (struct assign_link), 16);
   base_access_vec = new hash_map<tree, auto_vec<access_p> >;
   memset (&sra_stats, 0, sizeof (sra_stats));
   encountered_apply_args = false;
@@ -688,8 +719,8 @@ sra_deinitialize (void)
   candidates = NULL;
   BITMAP_FREE (should_scalarize_away_bitmap);
   BITMAP_FREE (cannot_scalarize_away_bitmap);
-  free_alloc_pool (access_pool);
-  free_alloc_pool (link_pool);
+  access::pool.release ();
+  assign_link::pool.release ();
   obstack_free (&name_obstack, NULL);
 
   delete base_access_vec;
@@ -841,9 +872,8 @@ mark_parm_dereference (tree base, HOST_WIDE_INT dist, gimple stmt)
 static struct access *
 create_access_1 (tree base, HOST_WIDE_INT offset, HOST_WIDE_INT size)
 {
-  struct access *access;
+  struct access *access = new struct access ();
 
-  access = (struct access *) pool_alloc (access_pool);
   memset (access, 0, sizeof (struct access));
   access->base = base;
   access->offset = offset;
@@ -1218,7 +1248,7 @@ build_accesses_from_assign (gimple stmt)
     {
       struct assign_link *link;
 
-      link = (struct assign_link *) pool_alloc (link_pool);
+      link = new assign_link;
       memset (link, 0, sizeof (struct assign_link));
 
       link->lacc = lacc;
@@ -1290,7 +1320,7 @@ scan_function (void)
          switch (gimple_code (stmt))
            {
            case GIMPLE_RETURN:
-             t = gimple_return_retval (stmt);
+             t = gimple_return_retval (as_a <greturn *> (stmt));
              if (t != NULL_TREE)
                ret |= build_access_from_expr (t, stmt, false);
              if (final_bbs)
@@ -1335,21 +1365,24 @@ scan_function (void)
              break;
 
            case GIMPLE_ASM:
-             walk_stmt_load_store_addr_ops (stmt, NULL, NULL, NULL,
-                                            asm_visit_addr);
-             if (final_bbs)
-               bitmap_set_bit (final_bbs, bb->index);
+             {
+               gasm *asm_stmt = as_a <gasm *> (stmt);
+               walk_stmt_load_store_addr_ops (asm_stmt, NULL, NULL, NULL,
+                                              asm_visit_addr);
+               if (final_bbs)
+                 bitmap_set_bit (final_bbs, bb->index);
 
-             for (i = 0; i < gimple_asm_ninputs (stmt); i++)
-               {
-                 t = TREE_VALUE (gimple_asm_input_op (stmt, i));
-                 ret |= build_access_from_expr (t, stmt, false);
-               }
-             for (i = 0; i < gimple_asm_noutputs (stmt); i++)
-               {
-                 t = TREE_VALUE (gimple_asm_output_op (stmt, i));
-                 ret |= build_access_from_expr (t, stmt, true);
-               }
+               for (i = 0; i < gimple_asm_ninputs (asm_stmt); i++)
+                 {
+                   t = TREE_VALUE (gimple_asm_input_op (asm_stmt, i));
+                   ret |= build_access_from_expr (t, asm_stmt, false);
+                 }
+               for (i = 0; i < gimple_asm_noutputs (asm_stmt); i++)
+                 {
+                   t = TREE_VALUE (gimple_asm_output_op (asm_stmt, i));
+                   ret |= build_access_from_expr (t, asm_stmt, true);
+                 }
+             }
              break;
 
            default:
@@ -1538,11 +1571,11 @@ build_ref_for_offset (location_t loc, tree base, HOST_WIDE_INT offset,
      offset such as array[var_index].  */
   if (!base)
     {
-      gimple stmt;
+      gassign *stmt;
       tree tmp, addr;
 
       gcc_checking_assert (gsi);
-      tmp = make_ssa_name (build_pointer_type (TREE_TYPE (prev_base)), NULL);
+      tmp = make_ssa_name (build_pointer_type (TREE_TYPE (prev_base)));
       addr = build_fold_addr_expr (unshare_expr (prev_base));
       STRIP_USELESS_TYPE_CONVERSION (addr);
       stmt = gimple_build_assign (tmp, addr);
@@ -1573,7 +1606,7 @@ build_ref_for_offset (location_t loc, tree base, HOST_WIDE_INT offset,
   misalign = (misalign + offset) & (align - 1);
   if (misalign != 0)
     align = (misalign & -misalign);
-  if (align < TYPE_ALIGN (exp_type))
+  if (align != TYPE_ALIGN (exp_type))
     exp_type = build_aligned_type (exp_type, align);
 
   mem_ref = fold_build2_loc (loc, MEM_REF, exp_type, base, off);
@@ -1984,11 +2017,15 @@ create_access_replacement (struct access *access)
 
   if (access->grp_to_be_debug_replaced)
     {
-      repl = create_tmp_var_raw (access->type, NULL);
+      repl = create_tmp_var_raw (access->type);
       DECL_CONTEXT (repl) = current_function_decl;
     }
   else
-    repl = create_tmp_var (access->type, "SR");
+    /* Drop any special alignment on the type if it's not on the main
+       variant.  This avoids issues with weirdo ABIs like AAPCS.  */
+    repl = create_tmp_var (build_qualified_type
+                            (TYPE_MAIN_VARIANT (access->type),
+                             TYPE_QUALS (access->type)), "SR");
   if (TREE_CODE (access->type) == COMPLEX_TYPE
       || TREE_CODE (access->type) == VECTOR_TYPE)
     {
@@ -2365,13 +2402,12 @@ static struct access *
 create_artificial_child_access (struct access *parent, struct access *model,
                                HOST_WIDE_INT new_offset)
 {
-  struct access *access;
   struct access **child;
   tree expr = parent->base;
 
   gcc_assert (!model->grp_unscalarizable_region);
 
-  access = (struct access *) pool_alloc (access_pool);
+  struct access *access = new struct access ();
   memset (access, 0, sizeof (struct access));
   if (!build_user_friendly_ref_for_offset (&expr, TREE_TYPE (expr), new_offset,
                                           model->type))
@@ -2508,10 +2544,12 @@ analyze_all_variable_accesses (void)
   int res = 0;
   bitmap tmp = BITMAP_ALLOC (NULL);
   bitmap_iterator bi;
-  unsigned i, max_total_scalarization_size;
-
-  max_total_scalarization_size = UNITS_PER_WORD * BITS_PER_UNIT
-    * MOVE_RATIO (optimize_function_for_speed_p (cfun));
+  unsigned i;
+  unsigned max_scalarization_size
+    = (optimize_function_for_size_p (cfun)
+       ? PARAM_VALUE (PARAM_SRA_MAX_SCALARIZATION_SIZE_SIZE)
+       : PARAM_VALUE (PARAM_SRA_MAX_SCALARIZATION_SIZE_SPEED))
+      * BITS_PER_UNIT;
 
   EXECUTE_IF_SET_IN_BITMAP (candidate_bitmap, 0, i, bi)
     if (bitmap_bit_p (should_scalarize_away_bitmap, i)
@@ -2523,7 +2561,7 @@ analyze_all_variable_accesses (void)
            && type_consists_of_records_p (TREE_TYPE (var)))
          {
            if (tree_to_uhwi (TYPE_SIZE (TREE_TYPE (var)))
-               <= max_total_scalarization_size)
+               <= max_scalarization_size)
              {
                completely_scalarize_var (var);
                if (dump_file && (dump_flags & TDF_DETAILS))
@@ -2620,7 +2658,7 @@ generate_subtree_copies (struct access *access, tree agg,
              || access->offset + access->size > start_offset))
        {
          tree expr, repl = get_access_replacement (access);
-         gimple stmt;
+         gassign *stmt;
 
          expr = build_ref_for_model (loc, agg, access->offset - top_offset,
                                      access, gsi, insert_after);
@@ -2658,7 +2696,7 @@ generate_subtree_copies (struct access *access, tree agg,
               && (chunk_size == 0
                   || access->offset + access->size > start_offset))
        {
-         gimple ds;
+         gdebug *ds;
          tree drhs = build_debug_ref_for_model (loc, agg,
                                                 access->offset - top_offset,
                                                 access);
@@ -2694,7 +2732,7 @@ init_subtree_with_zero (struct access *access, gimple_stmt_iterator *gsi,
 
   if (access->grp_to_be_replaced)
     {
-      gimple stmt;
+      gassign *stmt;
 
       stmt = gimple_build_assign (get_access_replacement (access),
                                  build_zero_cst (access->type));
@@ -2707,9 +2745,10 @@ init_subtree_with_zero (struct access *access, gimple_stmt_iterator *gsi,
     }
   else if (access->grp_to_be_debug_replaced)
     {
-      gimple ds = gimple_build_debug_bind (get_access_replacement (access),
-                                          build_zero_cst (access->type),
-                                          gsi_stmt (*gsi));
+      gdebug *ds
+       = gimple_build_debug_bind (get_access_replacement (access),
+                                  build_zero_cst (access->type),
+                                  gsi_stmt (*gsi));
       if (insert_after)
        gsi_insert_after (gsi, ds, GSI_NEW_STMT);
       else
@@ -2720,6 +2759,37 @@ init_subtree_with_zero (struct access *access, gimple_stmt_iterator *gsi,
     init_subtree_with_zero (child, gsi, insert_after, loc);
 }
 
+/* Clobber all scalar replacements in an access subtree.  ACCESS is the the
+   root of the subtree to be processed.  GSI is the statement iterator used
+   for inserting statements which are added after the current statement if
+   INSERT_AFTER is true or before it otherwise.  */
+
+static void
+clobber_subtree (struct access *access, gimple_stmt_iterator *gsi,
+               bool insert_after, location_t loc)
+
+{
+  struct access *child;
+
+  if (access->grp_to_be_replaced)
+    {
+      tree rep = get_access_replacement (access);
+      tree clobber = build_constructor (access->type, NULL);
+      TREE_THIS_VOLATILE (clobber) = 1;
+      gimple stmt = gimple_build_assign (rep, clobber);
+
+      if (insert_after)
+       gsi_insert_after (gsi, stmt, GSI_NEW_STMT);
+      else
+       gsi_insert_before (gsi, stmt, GSI_SAME_STMT);
+      update_stmt (stmt);
+      gimple_set_location (stmt, loc);
+    }
+
+  for (child = access->first_child; child; child = child->next_sibling)
+    clobber_subtree (child, gsi, insert_after, loc);
+}
+
 /* Search for an access representative for the given expression EXPR and
    return it or NULL if it cannot be found.  */
 
@@ -2803,7 +2873,7 @@ sra_modify_expr (tree *expr, gimple_stmt_iterator *gsi, bool write)
 
          if (write)
            {
-             gimple stmt;
+             gassign *stmt;
 
              if (access->grp_partial_lhs)
                ref = force_gimple_operand_gsi (gsi, ref, true, NULL_TREE,
@@ -2814,7 +2884,7 @@ sra_modify_expr (tree *expr, gimple_stmt_iterator *gsi, bool write)
            }
          else
            {
-             gimple stmt;
+             gassign *stmt;
 
              if (access->grp_partial_lhs)
                repl = force_gimple_operand_gsi (gsi, repl, true, NULL_TREE,
@@ -2830,9 +2900,9 @@ sra_modify_expr (tree *expr, gimple_stmt_iterator *gsi, bool write)
     }
   else if (write && access->grp_to_be_debug_replaced)
     {
-      gimple ds = gimple_build_debug_bind (get_access_replacement (access),
-                                          NULL_TREE,
-                                          gsi_stmt (*gsi));
+      gdebug *ds = gimple_build_debug_bind (get_access_replacement (access),
+                                           NULL_TREE,
+                                           gsi_stmt (*gsi));
       gsi_insert_after (gsi, ds, GSI_NEW_STMT);
     }
 
@@ -2932,7 +3002,7 @@ load_assign_lhs_subreplacements (struct access *lacc,
       if (lacc->grp_to_be_replaced)
        {
          struct access *racc;
-         gimple stmt;
+         gassign *stmt;
          tree rhs;
 
          racc = find_access_in_subtree (sad->top_racc, offset, lacc->size);
@@ -2982,7 +3052,7 @@ load_assign_lhs_subreplacements (struct access *lacc,
 
          if (lacc && lacc->grp_to_be_debug_replaced)
            {
-             gimple ds;
+             gdebug *ds;
              tree drhs;
              struct access *racc = find_access_in_subtree (sad->top_racc,
                                                            offset,
@@ -3032,17 +3102,16 @@ static enum assignment_mod_result
 sra_modify_constructor_assign (gimple stmt, gimple_stmt_iterator *gsi)
 {
   tree lhs = gimple_assign_lhs (stmt);
-  struct access *acc;
-  location_t loc;
-
-  acc = get_access_for_expr (lhs);
+  struct access *acc = get_access_for_expr (lhs);
   if (!acc)
     return SRA_AM_NONE;
+  location_t loc = gimple_location (stmt);
 
   if (gimple_clobber_p (stmt))
     {
-      /* Remove clobbers of fully scalarized variables, otherwise
-        do nothing.  */
+      /* Clobber the replacement variable.  */
+      clobber_subtree (acc, gsi, !acc->grp_covered, loc);
+      /* Remove clobbers of fully scalarized variables, they are dead.  */
       if (acc->grp_covered)
        {
          unlink_stmt_vdef (stmt);
@@ -3051,10 +3120,9 @@ sra_modify_constructor_assign (gimple stmt, gimple_stmt_iterator *gsi)
          return SRA_AM_REMOVED;
        }
       else
-       return SRA_AM_NONE;
+       return SRA_AM_MODIFIED;
     }
 
-  loc = gimple_location (stmt);
   if (vec_safe_length (CONSTRUCTOR_ELTS (gimple_assign_rhs1 (stmt))) > 0)
     {
       /* I have never seen this code path trigger but if it can happen the
@@ -3224,7 +3292,7 @@ sra_modify_assign (gimple stmt, gimple_stmt_iterator *gsi)
            drhs = fold_build1_loc (loc, VIEW_CONVERT_EXPR,
                                    TREE_TYPE (dlhs), drhs);
        }
-      gimple ds = gimple_build_debug_bind (dlhs, drhs, stmt);
+      gdebug *ds = gimple_build_debug_bind (dlhs, drhs, stmt);
       gsi_insert_before (gsi, ds, GSI_SAME_STMT);
     }
 
@@ -3394,7 +3462,7 @@ sra_modify_function_body (void)
          switch (gimple_code (stmt))
            {
            case GIMPLE_RETURN:
-             t = gimple_return_retval_ptr (stmt);
+             t = gimple_return_retval_ptr (as_a <greturn *> (stmt));
              if (*t != NULL_TREE)
                modified |= sra_modify_expr (t, &gsi, false);
              break;
@@ -3421,16 +3489,19 @@ sra_modify_function_body (void)
              break;
 
            case GIMPLE_ASM:
-             for (i = 0; i < gimple_asm_ninputs (stmt); i++)
-               {
-                 t = &TREE_VALUE (gimple_asm_input_op (stmt, i));
-                 modified |= sra_modify_expr (t, &gsi, false);
-               }
-             for (i = 0; i < gimple_asm_noutputs (stmt); i++)
-               {
-                 t = &TREE_VALUE (gimple_asm_output_op (stmt, i));
-                 modified |= sra_modify_expr (t, &gsi, true);
-               }
+             {
+               gasm *asm_stmt = as_a <gasm *> (stmt);
+               for (i = 0; i < gimple_asm_ninputs (asm_stmt); i++)
+                 {
+                   t = &TREE_VALUE (gimple_asm_input_op (asm_stmt, i));
+                   modified |= sra_modify_expr (t, &gsi, false);
+                 }
+               for (i = 0; i < gimple_asm_noutputs (asm_stmt); i++)
+                 {
+                   t = &TREE_VALUE (gimple_asm_output_op (asm_stmt, i));
+                   modified |= sra_modify_expr (t, &gsi, true);
+                 }
+             }
              break;
 
            default:
@@ -3928,7 +3999,7 @@ dump_dereferences_table (FILE *f, const char *str, HOST_WIDE_INT *table)
 {
   basic_block bb;
 
-  fprintf (dump_file, str);
+  fprintf (dump_file, "%s", str);
   FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR_FOR_FN (cfun),
                  EXIT_BLOCK_PTR_FOR_FN (cfun), next_bb)
     {
@@ -4558,7 +4629,7 @@ replace_removed_params_ssa_names (gimple stmt,
   else if (is_gimple_call (stmt))
     gimple_call_set_lhs (stmt, name);
   else
-    gimple_phi_set_result (stmt, name);
+    gimple_phi_set_result (as_a <gphi *> (stmt), name);
 
   replace_uses_by (lhs, name);
   release_ssa_name (lhs);
@@ -4654,7 +4725,7 @@ ipa_sra_modify_function_body (ipa_parm_adjustment_vec adjustments)
          switch (gimple_code (stmt))
            {
            case GIMPLE_RETURN:
-             t = gimple_return_retval_ptr (stmt);
+             t = gimple_return_retval_ptr (as_a <greturn *> (stmt));
              if (*t != NULL_TREE)
                modified |= ipa_modify_expr (t, true, adjustments);
              break;
@@ -4682,16 +4753,19 @@ ipa_sra_modify_function_body (ipa_parm_adjustment_vec adjustments)
              break;
 
            case GIMPLE_ASM:
-             for (i = 0; i < gimple_asm_ninputs (stmt); i++)
-               {
-                 t = &TREE_VALUE (gimple_asm_input_op (stmt, i));
-                 modified |= ipa_modify_expr (t, true, adjustments);
-               }
-             for (i = 0; i < gimple_asm_noutputs (stmt); i++)
-               {
-                 t = &TREE_VALUE (gimple_asm_output_op (stmt, i));
-                 modified |= ipa_modify_expr (t, false, adjustments);
-               }
+             {
+               gasm *asm_stmt = as_a <gasm *> (stmt);
+               for (i = 0; i < gimple_asm_ninputs (asm_stmt); i++)
+                 {
+                   t = &TREE_VALUE (gimple_asm_input_op (asm_stmt, i));
+                   modified |= ipa_modify_expr (t, true, adjustments);
+                 }
+               for (i = 0; i < gimple_asm_noutputs (asm_stmt); i++)
+                 {
+                   t = &TREE_VALUE (gimple_asm_output_op (asm_stmt, i));
+                   modified |= ipa_modify_expr (t, false, adjustments);
+                 }
+             }
              break;
 
            default:
@@ -4731,7 +4805,8 @@ sra_ipa_reset_debug_stmts (ipa_parm_adjustment_vec adjustments)
     {
       struct ipa_parm_adjustment *adj;
       imm_use_iterator ui;
-      gimple stmt, def_temp;
+      gimple stmt;
+      gdebug *def_temp;
       tree name, vexpr, copy = NULL_TREE;
       use_operand_p use_p;
 
@@ -4821,7 +4896,21 @@ some_callers_have_mismatched_arguments_p (struct cgraph_node *node,
 {
   struct cgraph_edge *cs;
   for (cs = node->callers; cs; cs = cs->next_caller)
-    if (!callsite_arguments_match_p (cs->call_stmt))
+    if (!cs->call_stmt || !callsite_arguments_match_p (cs->call_stmt))
+      return true;
+
+  return false;
+}
+
+/* Return false if all callers have vuse attached to a call statement.  */
+
+static bool
+some_callers_have_no_vuse_p (struct cgraph_node *node,
+                            void *data ATTRIBUTE_UNUSED)
+{
+  struct cgraph_edge *cs;
+  for (cs = node->callers; cs; cs = cs->next_caller)
+    if (!cs->call_stmt || !gimple_vuse (cs->call_stmt))
       return true;
 
   return false;
@@ -4870,8 +4959,8 @@ convert_callers (struct cgraph_node *node, tree old_decl,
 {
   basic_block this_block;
 
-  node->call_for_symbol_thunks_and_aliases (convert_callers_for_node,
-                                         &adjustments, false);
+  node->call_for_symbol_and_aliases (convert_callers_for_node,
+                                    &adjustments, false);
 
   if (!encountered_recursive_call)
     return;
@@ -4882,9 +4971,10 @@ convert_callers (struct cgraph_node *node, tree old_decl,
 
       for (gsi = gsi_start_bb (this_block); !gsi_end_p (gsi); gsi_next (&gsi))
         {
-         gimple stmt = gsi_stmt (gsi);
+         gcall *stmt;
          tree call_fndecl;
-         if (gimple_code (stmt) != GIMPLE_CALL)
+         stmt = dyn_cast <gcall *> (gsi_stmt (gsi));
+         if (!stmt)
            continue;
          call_fndecl = gimple_call_fndecl (stmt);
          if (call_fndecl == old_decl)
@@ -4931,13 +5021,60 @@ modify_function (struct cgraph_node *node, ipa_parm_adjustment_vec adjustments)
   return cfg_changed;
 }
 
-/* If NODE has a caller, return true.  */
+/* Means of communication between ipa_sra_check_caller and
+   ipa_sra_preliminary_function_checks.  */
+
+struct ipa_sra_check_caller_data
+{
+  bool has_callers;
+  bool bad_arg_alignment;
+  bool has_thunk;
+};
+
+/* If NODE has a caller, mark that fact in DATA which is pointer to
+   ipa_sra_check_caller_data.  Also check all aggregate arguments in all known
+   calls if they are unit aligned and if not, set the appropriate flag in DATA
+   too. */
 
 static bool
-has_caller_p (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED)
+ipa_sra_check_caller (struct cgraph_node *node, void *data)
 {
-  if (node->callers)
-    return true;
+  if (!node->callers)
+    return false;
+
+  struct ipa_sra_check_caller_data *iscc;
+  iscc = (struct ipa_sra_check_caller_data *) data;
+  iscc->has_callers = true;
+
+  for (cgraph_edge *cs = node->callers; cs; cs = cs->next_caller)
+    {
+      if (cs->caller->thunk.thunk_p)
+       {
+         iscc->has_thunk = true;
+         return true;
+       }
+      gimple call_stmt = cs->call_stmt;
+      unsigned count = gimple_call_num_args (call_stmt);
+      for (unsigned i = 0; i < count; i++)
+       {
+         tree arg = gimple_call_arg (call_stmt, i);
+         if (is_gimple_reg (arg))
+             continue;
+
+         tree offset;
+         HOST_WIDE_INT bitsize, bitpos;
+         machine_mode mode;
+         int unsignedp, volatilep = 0;
+         get_inner_reference (arg, &bitsize, &bitpos, &offset, &mode,
+                              &unsignedp, &volatilep, false);
+         if (bitpos % BITS_PER_UNIT)
+           {
+             iscc->bad_arg_alignment = true;
+             return true;
+           }
+       }
+    }
+
   return false;
 }
 
@@ -4984,22 +5121,14 @@ ipa_sra_preliminary_function_checks (struct cgraph_node *node)
       return false;
     }
 
-  if ((DECL_COMDAT (node->decl) || DECL_EXTERNAL (node->decl))
-      && inline_summary (node)->size >= MAX_INLINE_INSNS_AUTO)
+  if ((DECL_ONE_ONLY (node->decl) || DECL_EXTERNAL (node->decl))
+      && inline_summaries->get (node)->size >= MAX_INLINE_INSNS_AUTO)
     {
       if (dump_file)
        fprintf (dump_file, "Function too big to be made truly local.\n");
       return false;
     }
 
-  if (!node->call_for_symbol_thunks_and_aliases (has_caller_p, NULL, true))
-    {
-      if (dump_file)
-       fprintf (dump_file,
-                "Function has no callers in this compilation unit.\n");
-      return false;
-    }
-
   if (cfun->stdarg)
     {
       if (dump_file)
@@ -5018,6 +5147,33 @@ ipa_sra_preliminary_function_checks (struct cgraph_node *node)
       return false;
     }
 
+  struct ipa_sra_check_caller_data iscc;
+  memset (&iscc, 0, sizeof(iscc));
+  node->call_for_symbol_and_aliases (ipa_sra_check_caller, &iscc, true);
+  if (!iscc.has_callers)
+    {
+      if (dump_file)
+       fprintf (dump_file,
+                "Function has no callers in this compilation unit.\n");
+      return false;
+    }
+
+  if (iscc.bad_arg_alignment)
+    {
+      if (dump_file)
+       fprintf (dump_file,
+                "A function call has an argument with non-unit alignment.\n");
+      return false;
+    }
+
+  if (iscc.has_thunk)
+    {
+      if (dump_file)
+       fprintf (dump_file,
+                "A has thunk.\n");
+      return false;
+    }
+
   return true;
 }
 
@@ -5043,7 +5199,7 @@ ipa_early_sra (void)
       goto simple_out;
     }
 
-  if (node->call_for_symbol_thunks_and_aliases
+  if (node->call_for_symbol_and_aliases
        (some_callers_have_mismatched_arguments_p, NULL, true))
     {
       if (dump_file)
@@ -5052,6 +5208,15 @@ ipa_early_sra (void)
       goto simple_out;
     }
 
+  if (node->call_for_symbol_and_aliases
+       (some_callers_have_no_vuse_p, NULL, true))
+    {
+      if (dump_file)
+       fprintf (dump_file, "There are callers with no VUSE attached "
+                "to a call stmt.\n");
+      goto simple_out;
+    }
+
   bb_dereferences = XCNEWVEC (HOST_WIDE_INT,
                                 func_param_count
                                 * last_basic_block_for_fn (cfun));