OSDN Git Service

* config/i386/i386.md (*popcountsi2_cmp_zext): Remove mode attribute
[pf3gnuchains/gcc-fork.git] / gcc / tree-ssa.c
index 9015d19..7915bb8 100644 (file)
@@ -279,7 +279,7 @@ find_released_ssa_name (tree *tp, int *walk_subtrees, void *data_)
 {
   struct walk_stmt_info *wi = (struct walk_stmt_info *) data_;
 
-  if (wi->is_lhs)
+  if (wi && wi->is_lhs)
     return NULL_TREE;
 
   if (TREE_CODE (*tp) == SSA_NAME)
@@ -295,152 +295,208 @@ find_released_ssa_name (tree *tp, int *walk_subtrees, void *data_)
   return NULL_TREE;
 }
 
-/* Given a VAR whose definition STMT is to be moved to the iterator
-   position TOGSIP in the TOBB basic block, verify whether we're
-   moving it across any of the debug statements that use it, and
-   adjust them as needed.  If TOBB is NULL, then the definition is
-   understood as being removed, and TOGSIP is unused.  */
+/* Insert a DEBUG BIND stmt before the DEF of VAR if VAR is referenced
+   by other DEBUG stmts, and replace uses of the DEF with the
+   newly-created debug temp.  */
+
 void
-propagate_var_def_into_debug_stmts (tree var,
-                                   basic_block tobb,
-                                   const gimple_stmt_iterator *togsip)
+insert_debug_temp_for_var_def (gimple_stmt_iterator *gsi, tree var)
 {
   imm_use_iterator imm_iter;
-  gimple stmt;
   use_operand_p use_p;
+  gimple stmt;
+  gimple def_stmt = NULL;
+  int usecount = 0;
   tree value = NULL;
-  bool no_value = false;
 
   if (!MAY_HAVE_DEBUG_STMTS)
     return;
 
-  FOR_EACH_IMM_USE_STMT (stmt, imm_iter, var)
+  /* If this name has already been registered for replacement, do nothing
+     as anything that uses this name isn't in SSA form.  */
+  if (name_registered_for_update_p (var))
+    return;
+
+  /* Check whether there are debug stmts that reference this variable and,
+     if there are, decide whether we should use a debug temp.  */
+  FOR_EACH_IMM_USE_FAST (use_p, imm_iter, var)
     {
-      basic_block bb;
-      gimple_stmt_iterator si;
+      stmt = USE_STMT (use_p);
 
-      if (!is_gimple_debug (stmt))
+      if (!gimple_debug_bind_p (stmt))
        continue;
 
-      if (tobb)
+      if (usecount++)
+       break;
+
+      if (gimple_debug_bind_get_value (stmt) != var)
        {
-         bb = gimple_bb (stmt);
+         /* Count this as an additional use, so as to make sure we
+            use a temp unless VAR's definition has a SINGLE_RHS that
+            can be shared.  */
+         usecount++;
+         break;
+       }
+    }
 
-         if (bb != tobb)
-           {
-             gcc_assert (dom_info_available_p (CDI_DOMINATORS));
-             if (dominated_by_p (CDI_DOMINATORS, bb, tobb))
-               continue;
-           }
-         else
-           {
-             si = *togsip;
+  if (!usecount)
+    return;
 
-             if (gsi_end_p (si))
-               continue;
+  if (gsi)
+    def_stmt = gsi_stmt (*gsi);
+  else
+    def_stmt = SSA_NAME_DEF_STMT (var);
 
-             do
-               {
-                 gsi_prev (&si);
-                 if (gsi_end_p (si))
-                   break;
-               }
-             while (gsi_stmt (si) != stmt);
+  /* If we didn't get an insertion point, and the stmt has already
+     been removed, we won't be able to insert the debug bind stmt, so
+     we'll have to drop debug information.  */
+  if (gimple_code (def_stmt) == GIMPLE_PHI)
+    {
+      value = degenerate_phi_result (def_stmt);
+      if (value && walk_tree (&value, find_released_ssa_name, NULL, NULL))
+       value = NULL;
+    }
+  else if (is_gimple_assign (def_stmt))
+    {
+      bool no_value = false;
 
-             if (gsi_end_p (si))
-               continue;
-           }
+      if (!dom_info_available_p (CDI_DOMINATORS))
+       {
+         struct walk_stmt_info wi;
+
+         memset (&wi, 0, sizeof (wi));
+
+         /* When removing blocks without following reverse dominance
+            order, we may sometimes encounter SSA_NAMEs that have
+            already been released, referenced in other SSA_DEFs that
+            we're about to release.  Consider:
+
+            <bb X>:
+            v_1 = foo;
+
+            <bb Y>:
+            w_2 = v_1 + bar;
+            # DEBUG w => w_2
+
+            If we deleted BB X first, propagating the value of w_2
+            won't do us any good.  It's too late to recover their
+            original definition of v_1: when it was deleted, it was
+            only referenced in other DEFs, it couldn't possibly know
+            it should have been retained, and propagating every
+            single DEF just in case it might have to be propagated
+            into a DEBUG STMT would probably be too wasteful.
+
+            When dominator information is not readily available, we
+            check for and accept some loss of debug information.  But
+            if it is available, there's no excuse for us to remove
+            blocks in the wrong order, so we don't even check for
+            dead SSA NAMEs.  SSA verification shall catch any
+            errors.  */
+         if ((!gsi && !gimple_bb (def_stmt))
+             || walk_gimple_op (def_stmt, find_released_ssa_name, &wi))
+           no_value = true;
        }
 
-      /* Here we compute (lazily) the value assigned to VAR, but we
-        remember if we tried before and failed, so that we don't try
-        again.  */
-      if (!value && !no_value)
+      if (!no_value)
+       value = gimple_assign_rhs_to_tree (def_stmt);
+    }
+
+  if (value)
+    {
+      /* If there's a single use of VAR, and VAR is the entire debug
+        expression (usecount would have been incremented again
+        otherwise), and the definition involves only constants and
+        SSA names, then we can propagate VALUE into this single use,
+        avoiding the temp.
+
+        We can also avoid using a temp if VALUE can be shared and
+        propagated into all uses, without generating expressions that
+        wouldn't be valid gimple RHSs.
+
+        Other cases that would require unsharing or non-gimple RHSs
+        are deferred to a debug temp, although we could avoid temps
+        at the expense of duplication of expressions.  */
+
+      if (CONSTANT_CLASS_P (value)
+         || gimple_code (def_stmt) == GIMPLE_PHI
+         || (usecount == 1
+             && (!gimple_assign_single_p (def_stmt)
+                 || is_gimple_min_invariant (value)))
+         || is_gimple_reg (value))
+       value = unshare_expr (value);
+      else
        {
-         gimple def_stmt = SSA_NAME_DEF_STMT (var);
+         gimple def_temp;
+         tree vexpr = make_node (DEBUG_EXPR_DECL);
 
-         if (is_gimple_assign (def_stmt))
-           {
-             if (!dom_info_available_p (CDI_DOMINATORS))
-               {
-                 struct walk_stmt_info wi;
-
-                 memset (&wi, 0, sizeof (wi));
-
-                 /* When removing blocks without following reverse
-                    dominance order, we may sometimes encounter SSA_NAMEs
-                    that have already been released, referenced in other
-                    SSA_DEFs that we're about to release.  Consider:
-
-                    <bb X>:
-                    v_1 = foo;
-
-                    <bb Y>:
-                    w_2 = v_1 + bar;
-                    # DEBUG w => w_2
-
-                    If we deleted BB X first, propagating the value of
-                    w_2 won't do us any good.  It's too late to recover
-                    their original definition of v_1: when it was
-                    deleted, it was only referenced in other DEFs, it
-                    couldn't possibly know it should have been retained,
-                    and propagating every single DEF just in case it
-                    might have to be propagated into a DEBUG STMT would
-                    probably be too wasteful.
-
-                    When dominator information is not readily
-                    available, we check for and accept some loss of
-                    debug information.  But if it is available,
-                    there's no excuse for us to remove blocks in the
-                    wrong order, so we don't even check for dead SSA
-                    NAMEs.  SSA verification shall catch any
-                    errors.  */
-                 if (!walk_gimple_op (def_stmt, find_released_ssa_name, &wi))
-                   no_value = true;
-               }
+         def_temp = gimple_build_debug_bind (vexpr,
+                                             unshare_expr (value),
+                                             def_stmt);
+
+         DECL_ARTIFICIAL (vexpr) = 1;
+         TREE_TYPE (vexpr) = TREE_TYPE (value);
+         if (DECL_P (value))
+           DECL_MODE (vexpr) = DECL_MODE (value);
+         else
+           DECL_MODE (vexpr) = TYPE_MODE (TREE_TYPE (value));
 
-             if (!no_value)
-               value = gimple_assign_rhs_to_tree (def_stmt);
+         if (gsi)
+           gsi_insert_before (gsi, def_temp, GSI_SAME_STMT);
+         else
+           {
+             gimple_stmt_iterator ngsi = gsi_for_stmt (def_stmt);
+             gsi_insert_before (&ngsi, def_temp, GSI_SAME_STMT);
            }
 
-         if (!value)
-           no_value = true;
+         value = vexpr;
        }
+    }
 
-      if (no_value)
-       gimple_debug_bind_reset_value (stmt);
-      else
+  FOR_EACH_IMM_USE_STMT (stmt, imm_iter, var)
+    {
+      if (!gimple_debug_bind_p (stmt))
+       continue;
+
+      if (value)
        FOR_EACH_IMM_USE_ON_STMT (use_p, imm_iter)
-         SET_USE (use_p, unshare_expr (value));
+         /* unshare_expr is not needed here.  vexpr is either a
+            SINGLE_RHS, that can be safely shared, some other RHS
+            that was unshared when we found it had a single debug
+            use, or a DEBUG_EXPR_DECL, that can be safely
+            shared.  */
+         SET_USE (use_p, value);
+      else
+       gimple_debug_bind_reset_value (stmt);
 
       update_stmt (stmt);
     }
 }
 
 
-/* Given a STMT to be moved to the iterator position TOBSIP in the
-   TOBB basic block, verify whether we're moving it across any of the
-   debug statements that use it.  If TOBB is NULL, then the definition
-   is understood as being removed, and TOBSIP is unused.  */
+/* Insert a DEBUG BIND stmt before STMT for each DEF referenced by
+   other DEBUG stmts, and replace uses of the DEF with the
+   newly-created debug temp.  */
 
 void
-propagate_defs_into_debug_stmts (gimple def, basic_block tobb,
-                                const gimple_stmt_iterator *togsip)
+insert_debug_temps_for_defs (gimple_stmt_iterator *gsi)
 {
+  gimple stmt;
   ssa_op_iter op_iter;
   def_operand_p def_p;
 
   if (!MAY_HAVE_DEBUG_STMTS)
     return;
 
-  FOR_EACH_SSA_DEF_OPERAND (def_p, def, op_iter, SSA_OP_DEF)
+  stmt = gsi_stmt (*gsi);
+
+  FOR_EACH_PHI_OR_STMT_DEF (def_p, stmt, op_iter, SSA_OP_DEF)
     {
       tree var = DEF_FROM_PTR (def_p);
 
       if (TREE_CODE (var) != SSA_NAME)
        continue;
 
-      propagate_var_def_into_debug_stmts (var, tobb, togsip);
+      insert_debug_temp_for_var_def (gsi, var);
     }
 }
 
@@ -673,7 +729,7 @@ verify_use (basic_block bb, basic_block def_bb, use_operand_p use_p,
       err = true;
     }
 
-  /* Make sure the use is in an appropriate list by checking the previous 
+  /* Make sure the use is in an appropriate list by checking the previous
      element to make sure it's the same.  */
   if (use_p->prev == NULL)
     {
@@ -992,7 +1048,7 @@ verify_ssa (bool check_modified_stmt)
     free_dominance_info (CDI_DOMINATORS);
   else
     set_dom_info_availability (CDI_DOMINATORS, orig_dom_state);
-  
+
   BITMAP_FREE (names_defined_in_bb);
   timevar_pop (TV_TREE_SSA_VERIFY);
   return;
@@ -1062,12 +1118,11 @@ void
 init_tree_ssa (struct function *fn)
 {
   fn->gimple_df = GGC_CNEW (struct gimple_df);
-  fn->gimple_df->referenced_vars = htab_create_ggc (20, uid_decl_map_hash, 
+  fn->gimple_df->referenced_vars = htab_create_ggc (20, uid_decl_map_hash,
                                                    uid_decl_map_eq, NULL);
-  fn->gimple_df->default_defs = htab_create_ggc (20, uid_ssaname_map_hash, 
+  fn->gimple_df->default_defs = htab_create_ggc (20, uid_ssaname_map_hash,
                                                 uid_ssaname_map_eq, NULL);
   pt_solution_reset (&fn->gimple_df->escaped);
-  pt_solution_reset (&fn->gimple_df->callused);
   init_ssanames (fn, 0);
   init_phinodes ();
 }
@@ -1086,9 +1141,11 @@ delete_tree_ssa (void)
     {
       if (is_global_var (var))
        continue;
-      if (var->base.ann)
-        ggc_free (var->base.ann);
-      var->base.ann = NULL;
+      if (var_ann (var))
+       {
+         ggc_free (var_ann (var));
+         *DECL_VAR_ANN_PTR (var) = NULL;
+       }
     }
   htab_delete (gimple_referenced_vars (cfun));
   cfun->gimple_df->referenced_vars = NULL;
@@ -1105,7 +1162,6 @@ delete_tree_ssa (void)
   htab_delete (cfun->gimple_df->default_defs);
   cfun->gimple_df->default_defs = NULL;
   pt_solution_reset (&cfun->gimple_df->escaped);
-  pt_solution_reset (&cfun->gimple_df->callused);
   if (cfun->gimple_df->decls_to_pointers != NULL)
     pointer_map_destroy (cfun->gimple_df->decls_to_pointers);
   cfun->gimple_df->decls_to_pointers = NULL;
@@ -1146,15 +1202,15 @@ useless_type_conversion_p (tree outer_type, tree inner_type)
   if (POINTER_TYPE_P (inner_type)
       && POINTER_TYPE_P (outer_type))
     {
+      /* Do not lose casts between pointers to different address spaces.  */
+      if (TYPE_ADDR_SPACE (TREE_TYPE (outer_type))
+         != TYPE_ADDR_SPACE (TREE_TYPE (inner_type)))
+       return false;
+
       /* If the outer type is (void *) or a pointer to an incomplete
         record type or a pointer to an unprototyped function,
         then the conversion is not necessary.  */
       if (VOID_TYPE_P (TREE_TYPE (outer_type))
-         || (AGGREGATE_TYPE_P (TREE_TYPE (outer_type))
-             && TREE_CODE (TREE_TYPE (outer_type)) != ARRAY_TYPE
-             && (TREE_CODE (TREE_TYPE (outer_type))
-                 == TREE_CODE (TREE_TYPE (inner_type)))
-             && !COMPLETE_TYPE_P (TREE_TYPE (outer_type)))
          || ((TREE_CODE (TREE_TYPE (outer_type)) == FUNCTION_TYPE
               || TREE_CODE (TREE_TYPE (outer_type)) == METHOD_TYPE)
              && (TREE_CODE (TREE_TYPE (outer_type))
@@ -1390,7 +1446,7 @@ useless_type_conversion_p (tree outer_type, tree inner_type)
   else if (AGGREGATE_TYPE_P (inner_type)
           && TREE_CODE (inner_type) == TREE_CODE (outer_type))
     return false;
-  
+
   return false;
 }
 
@@ -1440,7 +1496,7 @@ tree_ssa_strip_useless_type_conversions (tree exp)
 
 /* Internal helper for walk_use_def_chains.  VAR, FN and DATA are as
    described in walk_use_def_chains.
-   
+
    VISITED is a pointer set used to mark visited SSA_NAMEs to avoid
       infinite loops.  We used to have a bitmap for this to just mark
       SSA versions we had visited.  But non-sparse bitmaps are way too
@@ -1498,10 +1554,10 @@ walk_use_def_chains_1 (tree var, walk_use_def_chains_fn fn, void *data,
          if (fn (gimple_phi_arg_def (def_stmt, i), def_stmt, data))
            return true;
     }
-  
+
   return false;
 }
-  
+
 
 
 /* Walk use-def chains starting at the SSA variable VAR.  Call
@@ -1509,7 +1565,7 @@ walk_use_def_chains_1 (tree var, walk_use_def_chains_fn fn, void *data,
    arguments: VAR, its defining statement (DEF_STMT) and a generic
    pointer to whatever state information that FN may want to maintain
    (DATA).  FN is able to stop the walk by returning true, otherwise
-   in order to continue the walk, FN should return false.  
+   in order to continue the walk, FN should return false.
 
    Note, that if DEF_STMT is a PHI node, the semantics are slightly
    different.  The first argument to FN is no longer the original
@@ -1603,7 +1659,7 @@ warn_uninit (tree t, const char *gmsgid, void *data)
   /* Do not warn if it can be initialized outside this module.  */
   if (is_global_var (var))
     return;
-  
+
   location = (context != NULL && gimple_has_location (context))
             ? gimple_location (context)
             : DECL_SOURCE_LOCATION (var);
@@ -1660,7 +1716,7 @@ warn_uninitialized_var (tree *tp, int *walk_subtrees, void *data_)
        use_operand_p vuse;
        tree op;
 
-       /* If there is not gimple stmt, 
+       /* If there is not gimple stmt,
           or alias information has not been computed,
           then we cannot check VUSE ops.  */
        if (data->stmt == NULL)
@@ -1675,7 +1731,7 @@ warn_uninitialized_var (tree *tp, int *walk_subtrees, void *data_)
          return NULL_TREE;
 
        op = USE_FROM_PTR (vuse);
-       if (t != SSA_NAME_VAR (op) 
+       if (t != SSA_NAME_VAR (op)
            || !SSA_NAME_IS_DEFAULT_DEF (op))
          return NULL_TREE;
        /* If this is a VUSE of t and it is the default definition,
@@ -1810,7 +1866,7 @@ struct gimple_opt_pass pass_early_warn_uninitialized =
 {
  {
   GIMPLE_PASS,
-  NULL,                                        /* name */
+  "*early_warn_uninitialized",         /* name */
   gate_warn_uninitialized,             /* gate */
   execute_early_warn_uninitialized,    /* execute */
   NULL,                                        /* sub */
@@ -1829,7 +1885,7 @@ struct gimple_opt_pass pass_late_warn_uninitialized =
 {
  {
   GIMPLE_PASS,
-  NULL,                                        /* name */
+  "*late_warn_uninitialized",          /* name */
   gate_warn_uninitialized,             /* gate */
   execute_late_warn_uninitialized,     /* execute */
   NULL,                                        /* sub */
@@ -1874,7 +1930,7 @@ execute_update_addresses_taken (bool do_optimize)
          if (code == GIMPLE_ASSIGN || code == GIMPLE_CALL)
            {
               tree lhs = gimple_get_lhs (stmt);
-              
+
               /* We may not rewrite TMR_SYMBOL to SSA.  */
               if (lhs && TREE_CODE (lhs) == TARGET_MEM_REF
                   && TMR_SYMBOL (lhs))