OSDN Git Service

2012-01-04 Richard Guenther <rguenther@suse.de>
[pf3gnuchains/gcc-fork.git] / gcc / tree-sra.c
index ab60748..db9b9bf 100644 (file)
@@ -1067,26 +1067,29 @@ disqualify_ops_if_throwing_stmt (gimple stmt, tree lhs, tree rhs)
   return false;
 }
 
-/* Return true iff type of EXP is not sufficiently aligned.  */
+/* Return true if EXP is a memory reference less aligned than ALIGN.  This is
+   invoked only on strict-alignment targets.  */
 
 static bool
-tree_non_mode_aligned_mem_p (tree exp)
+tree_non_aligned_mem_p (tree exp, unsigned int align)
 {
-  enum machine_mode mode = TYPE_MODE (TREE_TYPE (exp));
-  unsigned int align;
+  unsigned int exp_align;
 
   if (TREE_CODE (exp) == VIEW_CONVERT_EXPR)
     exp = TREE_OPERAND (exp, 0);
 
-  if (TREE_CODE (exp) == SSA_NAME
-      || TREE_CODE (exp) == MEM_REF
-      || mode == BLKmode
-      || is_gimple_min_invariant (exp)
-      || !STRICT_ALIGNMENT)
+  if (TREE_CODE (exp) == SSA_NAME || is_gimple_min_invariant (exp))
     return false;
 
-  align = get_object_alignment (exp, BIGGEST_ALIGNMENT);
-  if (GET_MODE_ALIGNMENT (mode) > align)
+  /* get_object_alignment will fall back to BITS_PER_UNIT if it cannot
+     compute an explicit alignment.  Pretend that dereferenced pointers
+     are always aligned on strict-alignment targets.  */
+  if (TREE_CODE (exp) == MEM_REF || TREE_CODE (exp) == TARGET_MEM_REF)
+    exp_align = get_object_or_type_alignment (exp);
+  else
+    exp_align = get_object_alignment (exp);
+
+  if (exp_align < align)
     return true;
 
   return false;
@@ -1103,7 +1106,9 @@ build_accesses_from_assign (gimple stmt)
   tree lhs, rhs;
   struct access *lacc, *racc;
 
-  if (!gimple_assign_single_p (stmt))
+  if (!gimple_assign_single_p (stmt)
+      /* Scope clobbers don't influence scalarization.  */
+      || gimple_clobber_p (stmt))
     return false;
 
   lhs = gimple_assign_lhs (stmt);
@@ -1118,7 +1123,9 @@ build_accesses_from_assign (gimple stmt)
   if (lacc)
     {
       lacc->grp_assignment_write = 1;
-      lacc->grp_unscalarizable_region |= tree_non_mode_aligned_mem_p (rhs);
+      if (STRICT_ALIGNMENT
+         && tree_non_aligned_mem_p (rhs, get_object_alignment (lhs)))
+        lacc->grp_unscalarizable_region = 1;
     }
 
   if (racc)
@@ -1127,7 +1134,9 @@ build_accesses_from_assign (gimple stmt)
       if (should_scalarize_away_bitmap && !gimple_has_volatile_ops (stmt)
          && !is_gimple_reg_type (racc->type))
        bitmap_set_bit (should_scalarize_away_bitmap, DECL_UID (racc->base));
-      racc->grp_unscalarizable_region |= tree_non_mode_aligned_mem_p (lhs);
+      if (STRICT_ALIGNMENT
+         && tree_non_aligned_mem_p (lhs, get_object_alignment (rhs)))
+        racc->grp_unscalarizable_region = 1;
     }
 
   if (lacc && racc
@@ -1483,33 +1492,65 @@ build_ref_for_offset (location_t loc, tree base, HOST_WIDE_INT offset,
   return fold_build2_loc (loc, MEM_REF, exp_type, base, off);
 }
 
+DEF_VEC_ALLOC_P_STACK (tree);
+#define VEC_tree_stack_alloc(alloc) VEC_stack_alloc (tree, alloc)
+
 /* Construct a memory reference to a part of an aggregate BASE at the given
-   OFFSET and of the same type as MODEL.  In case this is a reference to a
-   component, the function will replicate the last COMPONENT_REF of model's
-   expr to access it.  GSI and INSERT_AFTER have the same meaning as in
-   build_ref_for_offset.  */
+   OFFSET and of the type of MODEL.  In case this is a chain of references
+   to component, the function will replicate the chain of COMPONENT_REFs of
+   the expression of MODEL to access it.  GSI and INSERT_AFTER have the same
+   meaning as in build_ref_for_offset.  */
 
 static tree
 build_ref_for_model (location_t loc, tree base, HOST_WIDE_INT offset,
                     struct access *model, gimple_stmt_iterator *gsi,
                     bool insert_after)
 {
+  tree type = model->type, t;
+  VEC(tree,stack) *cr_stack = NULL;
+
   if (TREE_CODE (model->expr) == COMPONENT_REF)
     {
-      tree t, exp_type, fld = TREE_OPERAND (model->expr, 1);
-      tree cr_offset = component_ref_field_offset (model->expr);
-
-      gcc_assert (cr_offset && host_integerp (cr_offset, 1));
-      offset -= TREE_INT_CST_LOW (cr_offset) * BITS_PER_UNIT;
-      offset -= TREE_INT_CST_LOW (DECL_FIELD_BIT_OFFSET (fld));
-      exp_type = TREE_TYPE (TREE_OPERAND (model->expr, 0));
-      t = build_ref_for_offset (loc, base, offset, exp_type, gsi, insert_after);
-      return fold_build3_loc (loc, COMPONENT_REF, model->type, t, fld,
-                             TREE_OPERAND (model->expr, 2));
+      tree expr = model->expr;
+
+      /* Create a stack of the COMPONENT_REFs so later we can walk them in
+        order from inner to outer.  */
+      cr_stack = VEC_alloc (tree, stack, 6);
+
+      do {
+       tree field = TREE_OPERAND (expr, 1);
+       tree cr_offset = component_ref_field_offset (expr);
+       gcc_assert (cr_offset && host_integerp (cr_offset, 1));
+
+       offset -= TREE_INT_CST_LOW (cr_offset) * BITS_PER_UNIT;
+       offset -= TREE_INT_CST_LOW (DECL_FIELD_BIT_OFFSET (field));
+
+       VEC_safe_push (tree, stack, cr_stack, expr);
+
+       expr = TREE_OPERAND (expr, 0);
+       type = TREE_TYPE (expr);
+      } while (TREE_CODE (expr) == COMPONENT_REF);
     }
-  else
-    return build_ref_for_offset (loc, base, offset, model->type,
-                                gsi, insert_after);
+
+  t = build_ref_for_offset (loc, base, offset, type, gsi, insert_after);
+
+  if (TREE_CODE (model->expr) == COMPONENT_REF)
+    {
+      unsigned i;
+      tree expr;
+
+      /* Now replicate the chain of COMPONENT_REFs from inner to outer.  */
+      FOR_EACH_VEC_ELT_REVERSE (tree, cr_stack, i, expr)
+       {
+         tree field = TREE_OPERAND (expr, 1);
+         t = fold_build3_loc (loc, COMPONENT_REF, TREE_TYPE (field), t, field,
+                              TREE_OPERAND (expr, 2));
+       }
+
+      VEC_free (tree, stack, cr_stack);
+    }
+
+  return t;
 }
 
 /* Construct a memory reference consisting of component_refs and array_refs to
@@ -1825,7 +1866,6 @@ create_access_replacement (struct access *access, bool rename)
   tree repl;
 
   repl = create_tmp_var (access->type, "SR");
-  get_var_ann (repl);
   add_referenced_var (repl);
   if (rename)
     mark_sym_for_renaming (repl);
@@ -2076,13 +2116,25 @@ analyze_access_subtree (struct access *root, struct access *parent,
          || ((root->grp_scalar_read || root->grp_assignment_read)
              && (root->grp_scalar_write || root->grp_assignment_write))))
     {
+      bool new_integer_type;
+      if (TREE_CODE (root->type) == ENUMERAL_TYPE)
+       {
+         tree rt = root->type;
+         root->type = build_nonstandard_integer_type (TYPE_PRECISION (rt),
+                                                      TYPE_UNSIGNED (rt));
+         new_integer_type = true;
+       }
+      else
+       new_integer_type = false;
+
       if (dump_file && (dump_flags & TDF_DETAILS))
        {
          fprintf (dump_file, "Marking ");
          print_generic_expr (dump_file, root->base, 0);
-         fprintf (dump_file, " offset: %u, size: %u: ",
+         fprintf (dump_file, " offset: %u, size: %u ",
                   (unsigned) root->offset, (unsigned) root->size);
-         fprintf (dump_file, " to be replaced.\n");
+         fprintf (dump_file, " to be replaced%s.\n",
+                  new_integer_type ? " with an integer": "");
        }
 
       root->grp_to_be_replaced = 1;
@@ -2214,21 +2266,23 @@ propagate_subaccesses_across_link (struct access *lacc, struct access *racc)
       || racc->grp_unscalarizable_region)
     return false;
 
-  if (!lacc->first_child && !racc->first_child
-      && is_gimple_reg_type (racc->type))
+  if (is_gimple_reg_type (racc->type))
     {
-      tree t = lacc->base;
-
-      lacc->type = racc->type;
-      if (build_user_friendly_ref_for_offset (&t, TREE_TYPE (t), lacc->offset,
-                                             racc->type))
-       lacc->expr = t;
-      else
+      if (!lacc->first_child && !racc->first_child)
        {
-         lacc->expr = build_ref_for_model (EXPR_LOCATION (lacc->base),
-                                           lacc->base, lacc->offset,
-                                           racc, NULL, false);
-         lacc->grp_no_warning = true;
+         tree t = lacc->base;
+
+         lacc->type = racc->type;
+         if (build_user_friendly_ref_for_offset (&t, TREE_TYPE (t),
+                                                 lacc->offset, racc->type))
+           lacc->expr = t;
+         else
+           {
+             lacc->expr = build_ref_for_model (EXPR_LOCATION (lacc->base),
+                                               lacc->base, lacc->offset,
+                                               racc, NULL, false);
+             lacc->grp_no_warning = true;
+           }
        }
       return false;
     }
@@ -2679,6 +2733,10 @@ load_assign_lhs_subreplacements (struct access *lacc, struct access *top_racc,
              rhs = get_access_replacement (racc);
              if (!useless_type_conversion_p (lacc->type, racc->type))
                rhs = fold_build1_loc (loc, VIEW_CONVERT_EXPR, lacc->type, rhs);
+
+             if (racc->grp_partial_lhs && lacc->grp_partial_lhs)
+               rhs = force_gimple_operand_gsi (old_gsi, rhs, true, NULL_TREE,
+                                               true, GSI_SAME_STMT);
            }
          else
            {
@@ -2694,6 +2752,9 @@ load_assign_lhs_subreplacements (struct access *lacc, struct access *top_racc,
              else
                rhs = build_ref_for_model (loc, top_racc->base, offset, lacc,
                                            new_gsi, true);
+             if (lacc->grp_partial_lhs)
+               rhs = force_gimple_operand_gsi (new_gsi, rhs, true, NULL_TREE,
+                                               false, GSI_NEW_STMT);
            }
 
          stmt = gimple_build_assign (get_access_replacement (lacc), rhs);
@@ -3688,7 +3749,8 @@ access_precludes_ipa_sra_p (struct access *access)
          || gimple_code (access->stmt) == GIMPLE_ASM))
     return true;
 
-  if (tree_non_mode_aligned_mem_p (access->expr))
+  if (STRICT_ALIGNMENT
+      && tree_non_aligned_mem_p (access->expr, TYPE_ALIGN (access->type)))
     return true;
 
   return false;
@@ -4106,7 +4168,6 @@ get_replaced_param_substitute (struct ipa_parm_adjustment *adj)
       DECL_NAME (repl) = get_identifier (pretty_name);
       obstack_free (&name_obstack, pretty_name);
 
-      get_var_ann (repl);
       add_referenced_var (repl);
       adj->new_ssa_base = repl;
     }
@@ -4612,6 +4673,7 @@ modify_function (struct cgraph_node *node, ipa_parm_adjustment_vec adjustments)
   VEC (cgraph_edge_p, heap) * redirect_callers = collect_callers_of_node (node);
 
   rebuild_cgraph_edges ();
+  free_dominance_info (CDI_DOMINATORS);
   pop_cfun ();
   current_function_decl = NULL_TREE;