OSDN Git Service

2011-09-01 Robert Dewar <dewar@adacore.com>
[pf3gnuchains/gcc-fork.git] / gcc / tree-inline.c
index 440699f..741e8e4 100644 (file)
@@ -1,5 +1,5 @@
 /* Tree inlining.
-   Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+   Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
    Free Software Foundation, Inc.
    Contributed by Alexandre Oliva <aoliva@redhat.com>
 
@@ -188,6 +188,33 @@ remap_ssa_name (tree name, copy_body_data *id)
 
   if (processing_debug_stmt)
     {
+      if (TREE_CODE (SSA_NAME_VAR (name)) == PARM_DECL
+         && SSA_NAME_IS_DEFAULT_DEF (name)
+         && id->entry_bb == NULL
+         && single_succ_p (ENTRY_BLOCK_PTR))
+       {
+         tree vexpr = make_node (DEBUG_EXPR_DECL);
+         gimple def_temp;
+         gimple_stmt_iterator gsi;
+         tree val = SSA_NAME_VAR (name);
+
+         n = (tree *) pointer_map_contains (id->decl_map, val);
+         if (n != NULL)
+           val = *n;
+         if (TREE_CODE (val) != PARM_DECL)
+           {
+             processing_debug_stmt = -1;
+             return name;
+           }
+         def_temp = gimple_build_debug_source_bind (vexpr, val, NULL);
+         DECL_ARTIFICIAL (vexpr) = 1;
+         TREE_TYPE (vexpr) = TREE_TYPE (name);
+         DECL_MODE (vexpr) = DECL_MODE (SSA_NAME_VAR (name));
+         gsi = gsi_after_labels (single_succ (ENTRY_BLOCK_PTR));
+         gsi_insert_before (&gsi, def_temp, GSI_SAME_STMT);
+         return vexpr;
+       }
+
       processing_debug_stmt = -1;
       return name;
     }
@@ -663,6 +690,9 @@ copy_statement_list (tree *tp)
     {
       tree stmt = tsi_stmt (oi);
       if (TREE_CODE (stmt) == STATEMENT_LIST)
+       /* This copy is not redundant; tsi_link_after will smash this
+          STATEMENT_LIST into the end of the one we're building, and we
+          don't want to do that with the original.  */
        copy_statement_list (&stmt);
       tsi_link_after (&ni, stmt, TSI_CONTINUE_LINKING);
     }
@@ -813,46 +843,25 @@ remap_gimple_op_r (tree *tp, int *walk_subtrees, void *data)
     {
       /* Otherwise, just copy the node.  Note that copy_tree_r already
         knows not to copy VAR_DECLs, etc., so this is safe.  */
+
+      /* We should never have TREE_BLOCK set on non-statements.  */
+      if (EXPR_P (*tp))
+       gcc_assert (!TREE_BLOCK (*tp));
+
       if (TREE_CODE (*tp) == MEM_REF)
        {
          tree ptr = TREE_OPERAND (*tp, 0);
+         tree type = remap_type (TREE_TYPE (*tp), id);
          tree old = *tp;
-         tree tem;
 
          /* We need to re-canonicalize MEM_REFs from inline substitutions
             that can happen when a pointer argument is an ADDR_EXPR.
             Recurse here manually to allow that.  */
          walk_tree (&ptr, remap_gimple_op_r, data, NULL);
-         if ((tem = maybe_fold_offset_to_reference (EXPR_LOCATION (*tp),
-                                                    ptr,
-                                                    TREE_OPERAND (*tp, 1),
-                                                    TREE_TYPE (*tp)))
-             && TREE_THIS_VOLATILE (tem) == TREE_THIS_VOLATILE (old))
-           {
-             tree *tem_basep = &tem;
-             while (handled_component_p (*tem_basep))
-               tem_basep = &TREE_OPERAND (*tem_basep, 0);
-             if (TREE_CODE (*tem_basep) == MEM_REF)
-               *tem_basep
-                   = build2 (MEM_REF, TREE_TYPE (*tem_basep),
-                             TREE_OPERAND (*tem_basep, 0),
-                             fold_convert (TREE_TYPE (TREE_OPERAND (*tp, 1)),
-                                           TREE_OPERAND (*tem_basep, 1)));
-             else
-               *tem_basep
-                   = build2 (MEM_REF, TREE_TYPE (*tem_basep),
-                             build_fold_addr_expr (*tem_basep),
-                             build_int_cst
-                             (TREE_TYPE (TREE_OPERAND (*tp, 1)), 0));
-             *tp = tem;
-           }
-         else
-           {
-             *tp = fold_build2 (MEM_REF, TREE_TYPE (*tp),
-                                ptr, TREE_OPERAND (*tp, 1));
-             TREE_THIS_VOLATILE (*tp) = TREE_THIS_VOLATILE (old);
-             TREE_THIS_NOTRAP (*tp) = TREE_THIS_NOTRAP (old);
-           }
+         *tp = fold_build2 (MEM_REF, type,
+                            ptr, TREE_OPERAND (*tp, 1));
+         TREE_THIS_NOTRAP (*tp) = TREE_THIS_NOTRAP (old);
+         TREE_THIS_VOLATILE (*tp) = TREE_THIS_VOLATILE (old);
          TREE_NO_WARNING (*tp) = TREE_NO_WARNING (old);
          *walk_subtrees = 0;
          return NULL;
@@ -862,6 +871,9 @@ remap_gimple_op_r (tree *tp, int *walk_subtrees, void *data)
         tweak some special cases.  */
       copy_tree_r (tp, walk_subtrees, NULL);
 
+      if (TREE_CODE (*tp) != OMP_CLAUSE)
+       TREE_TYPE (*tp) = remap_type (TREE_TYPE (*tp), id);
+
       /* Global variables we haven't seen yet need to go into referenced
         vars.  If not referenced from types only.  */
       if (gimple_in_ssa_p (cfun)
@@ -870,13 +882,6 @@ remap_gimple_op_r (tree *tp, int *walk_subtrees, void *data)
          && !processing_debug_stmt)
        add_referenced_var (*tp);
 
-      /* We should never have TREE_BLOCK set on non-statements.  */
-      if (EXPR_P (*tp))
-       gcc_assert (!TREE_BLOCK (*tp));
-
-      if (TREE_CODE (*tp) != OMP_CLAUSE)
-       TREE_TYPE (*tp) = remap_type (TREE_TYPE (*tp), id);
-
       if (TREE_CODE (*tp) == TARGET_EXPR && TREE_OPERAND (*tp, 3))
        {
          /* The copied TARGET_EXPR has never been expanded, even if the
@@ -1204,7 +1209,7 @@ remap_eh_region_tree_nr (tree old_t_nr, copy_body_data *id)
   old_nr = tree_low_cst (old_t_nr, 0);
   new_nr = remap_eh_region_nr (old_nr, id);
 
-  return build_int_cst (NULL, new_nr);
+  return build_int_cst (integer_type_node, new_nr);
 }
 
 /* Helper for copy_bb.  Remap statement STMT using the inlining
@@ -1398,6 +1403,14 @@ remap_gimple_stmt (gimple stmt, copy_body_data *id)
          VEC_safe_push (gimple, heap, id->debug_stmts, copy);
          return copy;
        }
+      if (gimple_debug_source_bind_p (stmt))
+       {
+         copy = gimple_build_debug_source_bind
+                  (gimple_debug_source_bind_get_var (stmt),
+                   gimple_debug_source_bind_get_value (stmt), stmt);
+         VEC_safe_push (gimple, heap, id->debug_stmts, copy);
+         return copy;
+       }
 
       /* Create a new deep copy of the statement.  */
       copy = gimple_copy (stmt);
@@ -1473,7 +1486,7 @@ remap_gimple_stmt (gimple stmt, copy_body_data *id)
 
   gimple_set_block (copy, new_block);
 
-  if (gimple_debug_bind_p (copy))
+  if (gimple_debug_bind_p (copy) || gimple_debug_source_bind_p (copy))
     return copy;
 
   /* Remap all the operands in COPY.  */
@@ -2080,7 +2093,6 @@ initialize_cfun (tree new_fndecl, tree callee_fndecl, gcov_type count)
   cfun->va_list_fpr_size = src_cfun->va_list_fpr_size;
   cfun->has_nonlocal_label = src_cfun->has_nonlocal_label;
   cfun->stdarg = src_cfun->stdarg;
-  cfun->dont_save_pending_sizes_p = src_cfun->dont_save_pending_sizes_p;
   cfun->after_inlining = src_cfun->after_inlining;
   cfun->can_throw_non_call_exceptions
     = src_cfun->can_throw_non_call_exceptions;
@@ -2147,22 +2159,33 @@ maybe_move_debug_stmts_to_successors (copy_body_data *id, basic_block new_bb)
            {
              si = ssi;
              gsi_prev (&ssi);
-             if (!single_pred_p (e->dest))
+             if (!single_pred_p (e->dest) && gimple_debug_bind_p (stmt))
                gimple_debug_bind_reset_value (stmt);
              gsi_remove (&si, false);
              gsi_insert_before (&dsi, stmt, GSI_SAME_STMT);
              continue;
            }
 
-         var = gimple_debug_bind_get_var (stmt);
-         if (single_pred_p (e->dest))
+         if (gimple_debug_bind_p (stmt))
            {
-             value = gimple_debug_bind_get_value (stmt);
-             value = unshare_expr (value);
+             var = gimple_debug_bind_get_var (stmt);
+             if (single_pred_p (e->dest))
+               {
+                 value = gimple_debug_bind_get_value (stmt);
+                 value = unshare_expr (value);
+               }
+             else
+               value = NULL_TREE;
+             new_stmt = gimple_build_debug_bind (var, value, stmt);
+           }
+         else if (gimple_debug_source_bind_p (stmt))
+           {
+             var = gimple_debug_source_bind_get_var (stmt);
+             value = gimple_debug_source_bind_get_value (stmt);
+             new_stmt = gimple_build_debug_source_bind (var, value, stmt);
            }
          else
-           value = NULL_TREE;
-         new_stmt = gimple_build_debug_bind (var, value, stmt);
+           gcc_unreachable ();
          gsi_insert_before (&dsi, new_stmt, GSI_SAME_STMT);
          VEC_safe_push (gimple, heap, id->debug_stmts, new_stmt);
          gsi_prev (&ssi);
@@ -2313,7 +2336,6 @@ copy_debug_stmt (gimple stmt, copy_body_data *id)
   t = id->block;
   if (gimple_block (stmt))
     {
-      tree *n;
       n = (tree *) pointer_map_contains (id->decl_map, gimple_block (stmt));
       if (n)
        t = *n;
@@ -2326,7 +2348,10 @@ copy_debug_stmt (gimple stmt, copy_body_data *id)
 
   processing_debug_stmt = 1;
 
-  t = gimple_debug_bind_get_var (stmt);
+  if (gimple_debug_source_bind_p (stmt))
+    t = gimple_debug_source_bind_get_var (stmt);
+  else
+    t = gimple_debug_bind_get_var (stmt);
 
   if (TREE_CODE (t) == PARM_DECL && id->debug_map
       && (n = (tree *) pointer_map_contains (id->debug_map, t)))
@@ -2343,15 +2368,24 @@ copy_debug_stmt (gimple stmt, copy_body_data *id)
   else
     walk_tree (&t, remap_gimple_op_r, &wi, NULL);
 
-  gimple_debug_bind_set_var (stmt, t);
+  if (gimple_debug_bind_p (stmt))
+    {
+      gimple_debug_bind_set_var (stmt, t);
 
-  if (gimple_debug_bind_has_value_p (stmt))
-    walk_tree (gimple_debug_bind_get_value_ptr (stmt),
-              remap_gimple_op_r, &wi, NULL);
+      if (gimple_debug_bind_has_value_p (stmt))
+       walk_tree (gimple_debug_bind_get_value_ptr (stmt),
+                  remap_gimple_op_r, &wi, NULL);
 
-  /* Punt if any decl couldn't be remapped.  */
-  if (processing_debug_stmt < 0)
-    gimple_debug_bind_reset_value (stmt);
+      /* Punt if any decl couldn't be remapped.  */
+      if (processing_debug_stmt < 0)
+       gimple_debug_bind_reset_value (stmt);
+    }
+  else if (gimple_debug_source_bind_p (stmt))
+    {
+      gimple_debug_source_bind_set_var (stmt, t);
+      walk_tree (gimple_debug_source_bind_get_value_ptr (stmt),
+                remap_gimple_op_r, &wi, NULL);
+    }
 
   processing_debug_stmt = 0;
 
@@ -3188,7 +3222,7 @@ tree_inlinable_function_p (tree fn)
         As a bonus we can now give more details about the reason why a
         function is not inlinable.  */
       if (always_inline)
-       sorry (inline_forbidden_reason, fn);
+       error (inline_forbidden_reason, fn);
       else if (do_warning)
        warning (OPT_Winline, inline_forbidden_reason, fn);
 
@@ -3738,11 +3772,13 @@ expand_call_inline (basic_block bb, gimple stmt, copy_body_data *id)
 
       if (lookup_attribute ("always_inline", DECL_ATTRIBUTES (fn))
          /* Avoid warnings during early inline pass. */
-         && cgraph_global_info_ready)
+         && cgraph_global_info_ready
+         /* PR 20090218-1_0.c. Body can be provided by another module. */
+         && (reason != CIF_BODY_NOT_AVAILABLE || !flag_generate_lto))
        {
-         sorry ("inlining failed in call to %q+F: %s", fn,
-                _(cgraph_inline_failed_string (reason)));
-         sorry ("called from here");
+         error ("inlining failed in call to always_inline %q+F: %s", fn,
+                cgraph_inline_failed_string (reason));
+         error ("called from here");
        }
       else if (warn_inline
               && DECL_DECLARED_INLINE_P (fn)
@@ -4051,6 +4087,14 @@ fold_marked_statements (int first, struct pointer_set_t *statements)
                  if (fold_stmt (&gsi))
                    {
                      gimple new_stmt;
+                     /* If a builtin at the end of a bb folded into nothing,
+                        the following loop won't work.  */
+                     if (gsi_end_p (gsi))
+                       {
+                         cgraph_update_edges_for_call_stmt (old_stmt,
+                                                            old_decl, NULL);
+                         break;
+                       }
                      if (gsi_end_p (i2))
                        i2 = gsi_start_bb (BASIC_BLOCK (first));
                      else
@@ -4271,14 +4315,16 @@ copy_tree_r (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
                                         CONSTRUCTOR_ELTS (*tp));
       *tp = new_tree;
     }
+  else if (code == STATEMENT_LIST)
+    /* We used to just abort on STATEMENT_LIST, but we can run into them
+       with statement-expressions (c++/40975).  */
+    copy_statement_list (tp);
   else if (TREE_CODE_CLASS (code) == tcc_type)
     *walk_subtrees = 0;
   else if (TREE_CODE_CLASS (code) == tcc_declaration)
     *walk_subtrees = 0;
   else if (TREE_CODE_CLASS (code) == tcc_constant)
     *walk_subtrees = 0;
-  else
-    gcc_assert (code != STATEMENT_LIST);
   return NULL_TREE;
 }
 
@@ -4985,6 +5031,20 @@ tree_function_versioning (tree old_decl, tree new_decl,
   new_version_node = cgraph_get_node (new_decl);
   gcc_checking_assert (new_version_node);
 
+  /* Copy over debug args.  */
+  if (DECL_HAS_DEBUG_ARGS_P (old_decl))
+    {
+      VEC(tree, gc) **new_debug_args, **old_debug_args;
+      gcc_checking_assert (decl_debug_args_lookup (new_decl) == NULL);
+      DECL_HAS_DEBUG_ARGS_P (new_decl) = 0;
+      old_debug_args = decl_debug_args_lookup (old_decl);
+      if (old_debug_args)
+       {
+         new_debug_args = decl_debug_args_insert (new_decl);
+         *new_debug_args = VEC_copy (tree, gc, *old_debug_args);
+       }
+    }
+
   /* Output the inlining info for this abstract function, since it has been
      inlined.  If we don't do this now, we can lose the information about the
      variables in the function when the blocks get blown away as soon as we
@@ -5226,7 +5286,7 @@ maybe_inline_call_in_expr (tree exp)
       id.transform_call_graph_edges = CB_CGE_DUPLICATE;
       id.transform_new_cfg = false;
       id.transform_return_to_modify = true;
-      id.transform_lang_insert_block = false;
+      id.transform_lang_insert_block = NULL;
 
       /* Make sure not to unshare trees behind the front-end's back
         since front-end specific mechanisms may rely on sharing.  */