OSDN Git Service

2006-02-08 Paolo Bonzini <bonzini@gnu.org>
[pf3gnuchains/gcc-fork.git] / gcc / cfgexpand.c
index a3bd41c..c0bf209 100644 (file)
@@ -46,7 +46,7 @@ Boston, MA 02110-1301, USA.  */
    re-distribute it when the conditional expands into multiple conditionals.
    This is however difficult to do.  */
 static void
-add_reg_br_prob_note (FILE *dump_file, rtx last, int probability)
+add_reg_br_prob_note (rtx last, int probability)
 {
   if (profile_status == PROFILE_ABSENT)
     return;
@@ -272,11 +272,39 @@ stack_var_conflict_p (size_t x, size_t y)
   gcc_assert (index < stack_vars_conflict_alloc);
   return stack_vars_conflict[index];
 }
-  
+/* Returns true if TYPE is or contains a union type.  */
+
+static bool
+aggregate_contains_union_type (tree type)
+{
+  tree field;
+
+  if (TREE_CODE (type) == UNION_TYPE
+      || TREE_CODE (type) == QUAL_UNION_TYPE)
+    return true;
+  if (TREE_CODE (type) == ARRAY_TYPE)
+    return aggregate_contains_union_type (TREE_TYPE (type));
+  if (TREE_CODE (type) != RECORD_TYPE)
+    return false;
+
+  for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
+    if (TREE_CODE (field) == FIELD_DECL)
+      if (aggregate_contains_union_type (TREE_TYPE (field)))
+       return true;
+
+  return false;
+}
+
 /* A subroutine of expand_used_vars.  If two variables X and Y have alias
    sets that do not conflict, then do add a conflict for these variables
-   in the interference graph.  We also have to mind MEM_IN_STRUCT_P and
-   MEM_SCALAR_P.  */
+   in the interference graph.  We also need to make sure to add conflicts
+   for union containing structures.  Else RTL alias analysis comes along
+   and due to type based aliasing rules decides that for two overlapping
+   union temporaries { short s; int i; } accesses to the same mem through
+   different types may not alias and happily reorders stores across
+   life-time boundaries of the temporaries (See PR25654).
+   We also have to mind MEM_IN_STRUCT_P and MEM_SCALAR_P.  */
 
 static void
 add_alias_set_conflicts (void)
@@ -285,14 +313,25 @@ add_alias_set_conflicts (void)
 
   for (i = 0; i < n; ++i)
     {
-      bool aggr_i = AGGREGATE_TYPE_P (TREE_TYPE (stack_vars[i].decl));
-      HOST_WIDE_INT set_i = get_alias_set (stack_vars[i].decl);
+      tree type_i = TREE_TYPE (stack_vars[i].decl);
+      bool aggr_i = AGGREGATE_TYPE_P (type_i);
+      bool contains_union;
 
+      contains_union = aggregate_contains_union_type (type_i);
       for (j = 0; j < i; ++j)
        {
-         bool aggr_j = AGGREGATE_TYPE_P (TREE_TYPE (stack_vars[j].decl));
-         HOST_WIDE_INT set_j = get_alias_set (stack_vars[j].decl);
-         if (aggr_i != aggr_j || !alias_sets_conflict_p (set_i, set_j))
+         tree type_j = TREE_TYPE (stack_vars[j].decl);
+         bool aggr_j = AGGREGATE_TYPE_P (type_j);
+         if (aggr_i != aggr_j
+             /* Either the objects conflict by means of type based
+                aliasing rules, or we need to add a conflict.  */
+             || !objects_must_conflict_p (type_i, type_j)
+             /* In case the types do not conflict ensure that access
+                to elements will conflict.  In case of unions we have
+                to be careful as type based aliasing rules may say
+                access to the same memory does not conflict.  So play
+                safe and add a conflict in this case.  */
+             || contains_union)
            add_stack_var_conflict (i, j);
        }
     }
@@ -552,6 +591,10 @@ expand_one_stack_var (tree var)
 static void
 expand_one_static_var (tree var)
 {
+  /* In unit-at-a-time all the static variables are expanded at the end
+     of compilation process.  */
+  if (flag_unit_at_a_time)
+    return;
   /* If this is an inlined copy of a static local variable,
      look up the original.  */
   var = DECL_ORIGIN (var);
@@ -770,15 +813,14 @@ stack_protect_classify_type (tree type)
          || t == signed_char_type_node
          || t == unsigned_char_type_node)
        {
-         HOST_WIDE_INT max = PARAM_VALUE (PARAM_SSP_BUFFER_SIZE);
-         HOST_WIDE_INT len;
+         unsigned HOST_WIDE_INT max = PARAM_VALUE (PARAM_SSP_BUFFER_SIZE);
+         unsigned HOST_WIDE_INT len;
 
-         if (!TYPE_DOMAIN (type)
-             || !TYPE_MAX_VALUE (TYPE_DOMAIN (type))
-             || !host_integerp (TYPE_MAX_VALUE (TYPE_DOMAIN (type)), 1))
-           len = max + 1;
+         if (!TYPE_SIZE_UNIT (type)
+             || !host_integerp (TYPE_SIZE_UNIT (type), 1))
+           len = max;
          else
-           len = tree_low_cst (TYPE_MAX_VALUE (TYPE_DOMAIN (type)), 1);
+           len = tree_low_cst (TYPE_SIZE_UNIT (type), 1);
 
          if (len < max)
            ret = SPCT_HAS_SMALL_CHAR_ARRAY | SPCT_HAS_ARRAY;
@@ -805,8 +847,8 @@ stack_protect_classify_type (tree type)
   return ret;
 }
 
-/* Return non-zero if DECL should be segregated into the "vulnerable" upper
-   part of the local stack frame.  Remember if we ever return non-zero for
+/* Return nonzero if DECL should be segregated into the "vulnerable" upper
+   part of the local stack frame.  Remember if we ever return nonzero for
    any variable in this function.  The return value is the phase number in
    which the variable should be allocated.  */
 
@@ -1071,7 +1113,7 @@ expand_gimple_cond_expr (basic_block bb, tree stmt)
   if (TREE_CODE (then_exp) == GOTO_EXPR && IS_EMPTY_STMT (else_exp))
     {
       jumpif (pred, label_rtx (GOTO_DESTINATION (then_exp)));
-      add_reg_br_prob_note (dump_file, last, true_edge->probability);
+      add_reg_br_prob_note (last, true_edge->probability);
       maybe_dump_rtl_for_tree_stmt (stmt, last);
       if (EXPR_LOCUS (then_exp))
        emit_line_note (*(EXPR_LOCUS (then_exp)));
@@ -1080,7 +1122,7 @@ expand_gimple_cond_expr (basic_block bb, tree stmt)
   if (TREE_CODE (else_exp) == GOTO_EXPR && IS_EMPTY_STMT (then_exp))
     {
       jumpifnot (pred, label_rtx (GOTO_DESTINATION (else_exp)));
-      add_reg_br_prob_note (dump_file, last, false_edge->probability);
+      add_reg_br_prob_note (last, false_edge->probability);
       maybe_dump_rtl_for_tree_stmt (stmt, last);
       if (EXPR_LOCUS (else_exp))
        emit_line_note (*(EXPR_LOCUS (else_exp)));
@@ -1090,7 +1132,7 @@ expand_gimple_cond_expr (basic_block bb, tree stmt)
              && TREE_CODE (else_exp) == GOTO_EXPR);
 
   jumpif (pred, label_rtx (GOTO_DESTINATION (then_exp)));
-  add_reg_br_prob_note (dump_file, last, true_edge->probability);
+  add_reg_br_prob_note (last, true_edge->probability);
   last = get_last_insn ();
   expand_expr (else_exp, const0_rtx, VOIDmode, 0);
 
@@ -1230,7 +1272,7 @@ expand_gimple_tailcall (basic_block bb, tree stmt, bool *can_fallthru)
 /* Expand basic block BB from GIMPLE trees to RTL.  */
 
 static basic_block
-expand_gimple_basic_block (basic_block bb, FILE * dump_file)
+expand_gimple_basic_block (basic_block bb)
 {
   block_stmt_iterator bsi = bsi_start (bb);
   tree stmt = NULL;
@@ -1460,6 +1502,67 @@ construct_exit_block (void)
   update_bb_for_insn (exit_block);
 }
 
+/* Helper function for discover_nonconstant_array_refs. 
+   Look for ARRAY_REF nodes with non-constant indexes and mark them
+   addressable.  */
+
+static tree
+discover_nonconstant_array_refs_r (tree * tp, int *walk_subtrees,
+                                  void *data ATTRIBUTE_UNUSED)
+{
+  tree t = *tp;
+
+  if (IS_TYPE_OR_DECL_P (t))
+    *walk_subtrees = 0;
+  else if (TREE_CODE (t) == ARRAY_REF || TREE_CODE (t) == ARRAY_RANGE_REF)
+    {
+      while (((TREE_CODE (t) == ARRAY_REF || TREE_CODE (t) == ARRAY_RANGE_REF)
+             && is_gimple_min_invariant (TREE_OPERAND (t, 1))
+             && (!TREE_OPERAND (t, 2)
+                 || is_gimple_min_invariant (TREE_OPERAND (t, 2))))
+            || (TREE_CODE (t) == COMPONENT_REF
+                && (!TREE_OPERAND (t,2)
+                    || is_gimple_min_invariant (TREE_OPERAND (t, 2))))
+            || TREE_CODE (t) == BIT_FIELD_REF
+            || TREE_CODE (t) == REALPART_EXPR
+            || TREE_CODE (t) == IMAGPART_EXPR
+            || TREE_CODE (t) == VIEW_CONVERT_EXPR
+            || TREE_CODE (t) == NOP_EXPR
+            || TREE_CODE (t) == CONVERT_EXPR)
+       t = TREE_OPERAND (t, 0);
+
+      if (TREE_CODE (t) == ARRAY_REF || TREE_CODE (t) == ARRAY_RANGE_REF)
+       {
+         t = get_base_address (t);
+         if (t && DECL_P (t))
+           TREE_ADDRESSABLE (t) = 1;
+       }
+
+      *walk_subtrees = 0;
+    }
+
+  return NULL_TREE;
+}
+
+/* RTL expansion is not able to compile array references with variable
+   offsets for arrays stored in single register.  Discover such
+   expressions and mark variables as addressable to avoid this
+   scenario.  */
+
+static void
+discover_nonconstant_array_refs (void)
+{
+  basic_block bb;
+  block_stmt_iterator bsi;
+
+  FOR_EACH_BB (bb)
+    {
+      for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
+       walk_tree (bsi_stmt_ptr (bsi), discover_nonconstant_array_refs_r,
+                  NULL , NULL);
+    }
+}
+
 /* Translate the intermediate representation contained in the CFG
    from GIMPLE trees to RTL.
 
@@ -1481,6 +1584,9 @@ tree_expand_cfg (void)
   /* Prepare the rtl middle end to start recording block changes.  */
   reset_block_changes ();
 
+  /* Mark arrays indexed with non-constant indices with TREE_ADDRESSABLE.  */
+  discover_nonconstant_array_refs ();
+
   /* Expand the variables recorded during gimple lowering.  */
   expand_used_vars ();
 
@@ -1515,7 +1621,7 @@ tree_expand_cfg (void)
   init_block = construct_init_block ();
 
   FOR_BB_BETWEEN (bb, init_block->next_bb, EXIT_BLOCK_PTR, next_bb)
-    bb = expand_gimple_basic_block (bb, dump_file);
+    bb = expand_gimple_basic_block (bb);
 
   construct_exit_block ();
 
@@ -1576,10 +1682,9 @@ tree_expand_cfg (void)
 
   TREE_ASM_WRITTEN (current_function_decl) = 1;
 
-#ifdef FINALIZE_PIC
-  if (flag_pic)
-    FINALIZE_PIC;
-#endif
+  /* After expanding, the return labels are no longer needed. */
+  return_label = NULL;
+  naked_return_label = NULL;
 }
 
 struct tree_opt_pass pass_expand =
@@ -1594,7 +1699,7 @@ struct tree_opt_pass pass_expand =
   /* ??? If TER is enabled, we actually receive GENERIC.  */
   PROP_gimple_leh | PROP_cfg,           /* properties_required */
   PROP_rtl,                             /* properties_provided */
-  PROP_gimple_leh,                     /* properties_destroyed */
+  PROP_trees,                          /* properties_destroyed */
   0,                                    /* todo_flags_start */
   TODO_dump_func,                       /* todo_flags_finish */
   'r'                                  /* letter */